From 617716ce9ad68561348e72c99d59d026d809d6a1 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Fri, 14 Oct 2016 20:15:50 -0700 Subject: [PATCH] lnwallet/btcwallet: implement ListTransactionDetails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implements the new ListTransactionDetails method within btcwallet’s concrete implementation of the WalletController interface. Both mined and unmined transactions are currently returned via the same method. Unmined transactions are indicated by their lack of an inclusion block hash and lack of confirmations. --- lnwallet/btcwallet/btcwallet.go | 114 ++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/lnwallet/btcwallet/btcwallet.go b/lnwallet/btcwallet/btcwallet.go index 29b9f933..620cd16f 100644 --- a/lnwallet/btcwallet/btcwallet.go +++ b/lnwallet/btcwallet/btcwallet.go @@ -1,6 +1,7 @@ package btcwallet import ( + "bytes" "encoding/hex" "fmt" "math" @@ -378,3 +379,116 @@ func (b *BtcWallet) ListUnspentWitness(minConfs int32) ([]*lnwallet.Utxo, error) func (b *BtcWallet) PublishTransaction(tx *wire.MsgTx) error { return b.wallet.PublishTransaction(tx) } + +// extractBalanceDelta extracts the net balance delta from the PoV of the +// wallet given a TransactionSummary. +func extractBalanceDelta(txSummary base.TransactionSummary) (btcutil.Amount, error) { + tx := wire.NewMsgTx() + txReader := bytes.NewReader(txSummary.Transaction) + if err := tx.Deserialize(txReader); err != nil { + return -1, nil + } + + // For each input we debit the wallet's outflow for this transaction, + // and for each output we credit the wallet's inflow for this + // transaction. + var balanceDelta btcutil.Amount + for _, input := range txSummary.MyInputs { + balanceDelta -= input.PreviousAmount + } + for _, output := range txSummary.MyOutputs { + balanceDelta += btcutil.Amount(tx.TxOut[output.Index].Value) + } + + return balanceDelta, nil +} + +// minedTransactionsToDetails is a helper function which converts a summary +// information about mined transactions to a TransactionDetail. +func minedTransactionsToDetails(currentHeight int32, + block base.Block) ([]*lnwallet.TransactionDetail, error) { + + details := make([]*lnwallet.TransactionDetail, 0, len(block.Transactions)) + for _, tx := range block.Transactions { + txDetail := &lnwallet.TransactionDetail{ + Hash: *tx.Hash, + NumConfirmations: currentHeight - block.Height + 1, + BlockHash: block.Hash, + BlockHeight: block.Height, + Timestamp: block.Timestamp, + TotalFees: int64(tx.Fee), + } + + balanceDelta, err := extractBalanceDelta(tx) + if err != nil { + return nil, err + } + txDetail.Value = balanceDelta + + details = append(details, txDetail) + } + + return details, nil +} + +// unminedTransactionsToDetail is a helper funciton which converts a summary +// for a unconfirmed transaction to a transaction detail. +func unminedTransactionsToDetail(summary base.TransactionSummary) (*lnwallet.TransactionDetail, error) { + txDetail := &lnwallet.TransactionDetail{ + Hash: *summary.Hash, + TotalFees: int64(summary.Fee), + Timestamp: summary.Timestamp, + } + + balanceDelta, err := extractBalanceDelta(summary) + if err != nil { + return nil, err + } + txDetail.Value = balanceDelta + + return txDetail, nil +} + +// ListTransactionDetails returns a list of all transactions which are +// relevant to the wallet. +// +// This is a part of the WalletController interface. +func (b *BtcWallet) ListTransactionDetails() ([]*lnwallet.TransactionDetail, error) { + // Grab the best block the wallet knows of, we'll use this to calculate + // # of confirmations shortly below. + bestBlock := b.wallet.Manager.SyncedTo() + currentHeight := bestBlock.Height + + // TODO(roasbeef): can replace with start "wallet birthday" + start := base.NewBlockIdentifierFromHeight(0) + stop := base.NewBlockIdentifierFromHeight(bestBlock.Height) + txns, err := b.wallet.GetTransactions(start, stop, nil) + if err != nil { + return nil, err + } + + txDetails := make([]*lnwallet.TransactionDetail, 0, + len(txns.MinedTransactions)+len(txns.UnminedTransactions)) + + // For both confirmed and unconfirme dtransactions, create a + // TransactionDetail which re-packages the data returned by the base + // wallet. + for _, blockPackage := range txns.MinedTransactions { + details, err := minedTransactionsToDetails(currentHeight, blockPackage) + if err != nil { + return nil, err + } + + txDetails = append(txDetails, details...) + } + for _, tx := range txns.UnminedTransactions { + detail, err := unminedTransactionsToDetail(tx) + if err != nil { + return nil, err + } + + txDetails = append(txDetails, detail) + } + + return txDetails, nil +}