Skip to content

Commit

Permalink
V0.1.0 (#10)
Browse files Browse the repository at this point in the history
* config: add Views

* refac views channels

* fix config default

* views: menu

* config default: add comment

* fix config default

* README: enhance config section

* fix README

* controller: F2 Menu

* views: transactions

* fix views: set current in layout

* fix menu

* ft transactions

* fix Help

* fix controller Menu

* view: transaction

* refac controller

* fix ui controller

* try some bold

* fix cursor

* refac color

* focus column transactions

* controller: add keyBinding Menu m

* help view: add menu

* fix cursor: push to the right

* refac remove current model

* ui: txs and channels sortable

* fix focus column

* view transaction: transaction dest addresses

* fix menu

* refac controller

* channels: sort

* rename current column

* refac cursor

* refac currentColumnIndex

* set cursor if view deleted

* remove previous

* clean view.View

* controller: ToggleView

* fix menu

* view txs: add config

* feat order

* fix channels sort
* feat transactions sort
* feat help: add asc/desc
* fix README
* color: magenta
* fix color
* fix views menu
* fix views help
* network backend: SubscribeTransactions
* pubsub: transactions
* controller.Listen: refresh transactions
* fix controller
* fix controller pubsub: no need for wallet ticker
* fix models transactions
* views channels: column SENT and RECEIVED
* update version
* fix README
* fix README
* fix models sort
* fix readme and default config
* fix readme
  • Loading branch information
edouardparis authored May 14, 2019
1 parent 3149082 commit f72c5ca
Show file tree
Hide file tree
Showing 30 changed files with 2,065 additions and 392 deletions.
41 changes: 38 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

`lntop` is an interactive text-mode channels viewer for Unix systems.

![lntop-v0.0.0](http://paris.iiens.net/lntop-v0.0.0.png?)
*lntop-v0.0.0*
![lntop-v0.1.0](http://paris.iiens.net/lntop-v0.1.0.png)
*lntop-v0.1.0*

## Install

Expand All @@ -22,6 +22,9 @@ cd lntop && export GO111MODULE=on && go install -mod=vendor ./...

First time `lntop` is used a config file `.lntop/config.toml` is created
in the user home directory.

Change macaroon path according to your network.

```toml
[logger]
type = "production"
Expand All @@ -37,8 +40,40 @@ macaroon_timeout = 60
max_msg_recv_size = 52428800
conn_timeout = 1000000
pool_capacity = 3

[views]
# views.channels is the view displaying channel list.
[views.channels]
# It is possible to add, remove and order columns of the
# table with the array columns. The available values are:
columns = [
"STATUS", # status of the channel
"ALIAS", # alias of the channel node
"GAUGE", # ascii bar with percent local/capacity
"LOCAL", # the local amount of the channel
"CAP", # the total capacity of the channel
"SENT", # the total amount sent
"RECEIVED", # the total amount received
"HTLC", # the number of pending HTLC
"UNSETTLED", # the amount unsettled in the channel
"CFEE", # the commit fee
"LAST UPDATE", # last update of the channel
"PRIVATE", # true if channel is private
"ID", # the id of the channel
]

[views.transactions]
# It is possible to add, remove and order columns of the
# table with the array columns. The available values are:
columns = [
"DATE", # date of the transaction
"HEIGHT", # block height of the transaction
"CONFIR", # number of confirmations
"AMOUNT", # amount moved by the transaction
"FEE", # fee of the transaction
"ADDRESSES", # number of transaction output addresses
]
```
Change macaroon path according to your network.

## Docker

Expand Down
2 changes: 1 addition & 1 deletion cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/edouardparis/lntop/ui"
)

const version = "v0.0.3"
const version = "v0.1.0"

// New creates a new cli app.
func New() *cli.App {
Expand Down
10 changes: 10 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
type Config struct {
Logger Logger `toml:"logger"`
Network Network `toml:"network"`
Views Views `toml:"views"`
}

type Logger struct {
Expand All @@ -34,6 +35,15 @@ type Network struct {
PoolCapacity int `toml:"pool_capacity"`
}

type Views struct {
Channels *View `toml:"channels"`
Transactions *View `toml:"transactions"`
}

type View struct {
Columns []string `toml:"columns"`
}

func Load(path string) (*Config, error) {
c := &Config{}

Expand Down
33 changes: 33 additions & 0 deletions config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,39 @@ macaroon_timeout = %[8]d
max_msg_recv_size = %[9]d
conn_timeout = %[10]d
pool_capacity = %[11]d
[views]
# views.channels is the view displaying channel list.
[views.channels]
# It is possible to add, remove and order columns of the
# table with the array columns. The available values are:
columns = [
"STATUS", # status of the channel
"ALIAS", # alias of the channel node
"GAUGE", # ascii bar with percent local/capacity
"LOCAL", # the local amount of the channel
"CAP", # the total capacity of the channel
"SENT", # the total amount sent
"RECEIVED", # the total amount received
"HTLC", # the number of pending HTLC
"UNSETTLED", # the amount unsettled in the channel
"CFEE", # the commit fee
"LAST UPDATE", # last update of the channel
"PRIVATE", # true if channel is private
"ID", # the id of the channel
]
[views.transactions]
# It is possible to add, remove and order columns of the
# table with the array columns. The available values are:
columns = [
"DATE", # date of the transaction
"HEIGHT", # block height of the transaction
"CONFIR", # number of confirmations
"AMOUNT", # amount moved by the transaction
"FEE", # fee of the transaction
"ADDRESSES", # number of transaction output addresses
]
`,
cfg.Logger.Type,
cfg.Logger.Dest,
Expand Down
11 changes: 6 additions & 5 deletions events/events.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package events

const (
PeerUpdated = "peer.updated"
BlockReceived = "block.received"
InvoiceCreated = "invoice.created"
InvoiceSettled = "invoice.settled"
ChannelPending = "channel.pending"
ChannelActive = "channel.active"
ChannelInactive = "channel.inactive"
ChannelBalanceUpdated = "channel.balance.updated"
ChannelInactive = "channel.inactive"
ChannelPending = "channel.pending"
InvoiceCreated = "invoice.created"
InvoiceSettled = "invoice.settled"
PeerUpdated = "peer.updated"
TransactionCreated = "transaction.created"
WalletBalanceUpdated = "wallet.balance.updated"
)

Expand Down
4 changes: 4 additions & 0 deletions network/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ type Backend interface {
DecodePayReq(context.Context, string) (*models.PayReq, error)

SendPayment(context.Context, *models.PayReq) (*models.Payment, error)

GetTransactions(context.Context) ([]*models.Transaction, error)

SubscribeTransactions(context.Context, chan *models.Transaction) error
}
49 changes: 49 additions & 0 deletions network/backend/lnd/lnd.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,38 @@ func (l Backend) SubscribeInvoice(ctx context.Context, channelInvoice chan *mode
}
}

func (l Backend) SubscribeTransactions(ctx context.Context, channel chan *models.Transaction) error {
clt, err := l.Client(ctx)
if err != nil {
return err
}
defer clt.Close()

cltTransactions, err := clt.SubscribeTransactions(ctx, &lnrpc.GetTransactionsRequest{})
if err != nil {
return err
}

for {
select {
case <-ctx.Done():
break
default:
transaction, err := cltTransactions.Recv()
if err != nil {
st, ok := status.FromError(err)
if ok && st.Code() == codes.Canceled {
l.logger.Debug("stopping subscribe transactions: context canceled")
return nil
}
return err
}

channel <- protoToTransaction(transaction)
}
}
}

func (l Backend) SubscribeChannels(ctx context.Context, events chan *models.ChannelUpdate) error {
_, err := l.Client(ctx)
if err != nil {
Expand Down Expand Up @@ -134,6 +166,23 @@ func (l Backend) NewClientConn() (*grpc.ClientConn, error) {
return newClientConn(l.cfg)
}

func (l Backend) GetTransactions(ctx context.Context) ([]*models.Transaction, error) {
l.logger.Debug("Get transactions...")
clt, err := l.Client(ctx)
if err != nil {
return nil, err
}
defer clt.Close()

req := &lnrpc.GetTransactionsRequest{}
resp, err := clt.GetTransactions(ctx, req)
if err != nil {
return nil, errors.WithStack(err)
}

return protoToTransactions(resp), nil
}

func (l Backend) GetWalletBalance(ctx context.Context) (*models.WalletBalance, error) {
l.logger.Debug("Retrieve wallet balance...")

Expand Down
25 changes: 25 additions & 0 deletions network/backend/lnd/proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,28 @@ func protoToRoutingPolicy(resp *lnrpc.RoutingPolicy) *models.RoutingPolicy {
Disabled: resp.Disabled,
}
}

func protoToTransactions(resp *lnrpc.TransactionDetails) []*models.Transaction {
if resp == nil {
return nil
}

transactions := make([]*models.Transaction, len(resp.Transactions))
for i := range resp.Transactions {
transactions[i] = protoToTransaction(resp.Transactions[i])
}
return transactions
}

func protoToTransaction(resp *lnrpc.Transaction) *models.Transaction {
return &models.Transaction{
TxHash: resp.TxHash,
Amount: resp.Amount,
NumConfirmations: resp.NumConfirmations,
BlockHash: resp.BlockHash,
BlockHeight: resp.BlockHeight,
Date: time.Unix(int64(resp.TimeStamp), 0),
TotalFees: resp.TotalFees,
DestAddresses: resp.DestAddresses,
}
}
10 changes: 9 additions & 1 deletion network/backend/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,22 @@ func (b *Backend) SubscribeChannels(context.Context, chan *models.ChannelUpdate)
return nil
}

func (l *Backend) GetNode(ctx context.Context, pubkey string) (*models.Node, error) {
func (b *Backend) SubscribeTransactions(ctx context.Context, channel chan *models.Transaction) error {
return nil
}

func (b *Backend) GetNode(ctx context.Context, pubkey string) (*models.Node, error) {
return &models.Node{}, nil
}

func (b *Backend) GetWalletBalance(ctx context.Context) (*models.WalletBalance, error) {
return &models.WalletBalance{}, nil
}

func (b *Backend) GetTransactions(ctx context.Context) ([]*models.Transaction, error) {
return []*models.Transaction{}, nil
}

func (b *Backend) GetChannelsBalance(ctx context.Context) (*models.ChannelsBalance, error) {
return &models.ChannelsBalance{}, nil
}
Expand Down
22 changes: 22 additions & 0 deletions network/models/transaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package models

import "time"

type Transaction struct {
// / The transaction hash
TxHash string
// / The transaction amount, denominated in satoshis
Amount int64
// / The number of confirmations
NumConfirmations int32
// / The hash of the block this transaction was included in
BlockHash string
// / The height of the block this transaction was included in
BlockHeight int32
// / Timestamp of this transaction
Date time.Time
// / Fees paid for this transaction
TotalFees int64
// / Addresses that received funds for this transaction
DestAddresses []string
}
33 changes: 32 additions & 1 deletion pubsub/pubsub.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,35 @@ func (p *PubSub) invoices(ctx context.Context, sub chan *events.Event) {
}()
}

func (p *PubSub) transactions(ctx context.Context, sub chan *events.Event) {
p.wg.Add(3)
transactions := make(chan *models.Transaction)
ctx, cancel := context.WithCancel(ctx)

go func() {
for tx := range transactions {
p.logger.Debug("receive transaction", logging.String("tx_hash", tx.TxHash))
sub <- events.New(events.TransactionCreated)
}
p.wg.Done()
}()

go func() {
err := p.network.SubscribeTransactions(ctx, transactions)
if err != nil {
p.logger.Error("SubscribeTransactions returned an error", logging.Error(err))
}
p.wg.Done()
}()

go func() {
<-p.stop
cancel()
close(transactions)
p.wg.Done()
}()
}

func (p *PubSub) Stop() {
p.stop <- true
close(p.stop)
Expand All @@ -69,10 +98,12 @@ func (p *PubSub) Run(ctx context.Context, sub chan *events.Event) {
p.logger.Debug("Starting...")

p.invoices(ctx, sub)
p.transactions(ctx, sub)
p.ticker(ctx, sub,
withTickerInfo(),
withTickerChannelsBalance(),
withTickerWalletBalance(),
// no need for ticker Wallet balance, transactions subscriber is enough
// withTickerWalletBalance(),
)

<-p.stop
Expand Down
Loading

0 comments on commit f72c5ca

Please sign in to comment.