From 08f1c2e93ac6ff6a1eb7d7d81e401b3e44fc7b00 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 13 Jul 2022 19:27:10 -0700 Subject: [PATCH] chainntfns: add new option for conf notifications to send block In this commit, we add a new option for the existing confirmation notification system that optionally allows the caller to specify that a block should be included as well. The only quirk w/ the implementation here is the neutrino backend: usually we get filtered blocks, we so need to first fetch the block again so we can deliver the full block to the notifier. On the notifier end, it'll only be checking for the transactions we care about, to sending a full block doesn't affect the correctness. We also extend the `testBatchConfirmationNotification` test to assert that a block is only included if the caller specifies it. --- chainntnfs/bitcoindnotify/bitcoind.go | 11 ++-- chainntnfs/btcdnotify/btcd.go | 16 ++--- chainntnfs/interface.go | 63 ++++++++++++++++--- chainntnfs/neutrinonotify/neutrino.go | 25 +++++--- chainntnfs/test/test_interface.go | 30 ++++++++- chainntnfs/txnotifier.go | 82 ++++++++++++++++++------ chainntnfs/txnotifier_test.go | 90 +++++++++++---------------- chainreg/no_chain_backend.go | 3 +- discovery/gossiper_test.go | 3 +- funding/manager_test.go | 2 +- lntest/mock/chainnotifier.go | 4 +- sweep/test_utils.go | 4 +- 12 files changed, 224 insertions(+), 109 deletions(-) diff --git a/chainntnfs/bitcoindnotify/bitcoind.go b/chainntnfs/bitcoindnotify/bitcoind.go index a83b26e06..424291351 100644 --- a/chainntnfs/bitcoindnotify/bitcoind.go +++ b/chainntnfs/bitcoindnotify/bitcoind.go @@ -564,6 +564,7 @@ func (b *BitcoindNotifier) confDetailsManually(confRequest chainntnfs.ConfReques BlockHash: blockHash, BlockHeight: height, TxIndex: uint32(txIndex), + Block: block, }, chainntnfs.TxFoundManually, nil } } @@ -584,12 +585,12 @@ func (b *BitcoindNotifier) handleBlockConnected(block chainntnfs.BlockEpoch) err if err != nil { return fmt.Errorf("unable to get block: %v", err) } - txns := btcutil.NewBlock(rawBlock).Transactions() + utilBlock := btcutil.NewBlock(rawBlock) // We'll then extend the txNotifier's height with the information of // this new block, which will handle all of the notification logic for // us. - err = b.txNotifier.ConnectTip(block.Hash, uint32(block.Height), txns) + err = b.txNotifier.ConnectTip(utilBlock, uint32(block.Height)) if err != nil { return fmt.Errorf("unable to connect tip: %v", err) } @@ -844,15 +845,15 @@ func (b *BitcoindNotifier) historicalSpendDetails( // channel. Once it has reached all of its confirmations, a notification will be // sent across the 'Confirmed' channel. func (b *BitcoindNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, - pkScript []byte, - numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) { + pkScript []byte, numConfs, heightHint uint32, + opts ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent, error) { // Register the conf notification with the TxNotifier. A non-nil value // for `dispatch` will be returned if we are required to perform a // manual scan for the confirmation. Otherwise the notifier will begin // watching at tip for the transaction to confirm. ntfn, err := b.txNotifier.RegisterConf( - txid, pkScript, numConfs, heightHint, + txid, pkScript, numConfs, heightHint, opts..., ) if err != nil { return nil, err diff --git a/chainntnfs/btcdnotify/btcd.go b/chainntnfs/btcdnotify/btcd.go index 335adfa90..2ced59754 100644 --- a/chainntnfs/btcdnotify/btcd.go +++ b/chainntnfs/btcdnotify/btcd.go @@ -263,13 +263,14 @@ func (b *BtcdNotifier) onBlockConnected(hash *chainhash.Hash, height int32, t ti // chain. The slice of transactions will only be populated if the block // includes a transaction that confirmed one of our watched txids, or spends // one of the outputs currently being watched. +// // TODO(halseth): this is currently used for complete blocks. Change to use // onFilteredBlockConnected and onFilteredBlockDisconnected, making it easier // to unify with the Neutrino implementation. type filteredBlock struct { hash chainhash.Hash height uint32 - txns []*btcutil.Tx + block *btcutil.Block // connected is true if this update is a new block and false if it is a // disconnected block. @@ -619,6 +620,7 @@ func (b *BtcdNotifier) confDetailsManually(confRequest chainntnfs.ConfRequest, BlockHash: blockHash, BlockHeight: height, TxIndex: uint32(txIndex), + Block: block, }, chainntnfs.TxFoundManually, nil } } @@ -644,16 +646,14 @@ func (b *BtcdNotifier) handleBlockConnected(epoch chainntnfs.BlockEpoch) error { newBlock := &filteredBlock{ hash: *epoch.Hash, height: uint32(epoch.Height), - txns: btcutil.NewBlock(rawBlock).Transactions(), + block: btcutil.NewBlock(rawBlock), connect: true, } // We'll then extend the txNotifier's height with the information of // this new block, which will handle all of the notification logic for // us. - err = b.txNotifier.ConnectTip( - &newBlock.hash, newBlock.height, newBlock.txns, - ) + err = b.txNotifier.ConnectTip(newBlock.block, newBlock.height) if err != nil { return fmt.Errorf("unable to connect tip: %v", err) } @@ -903,15 +903,15 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, // channel. Once it has reached all of its confirmations, a notification will be // sent across the 'Confirmed' channel. func (b *BtcdNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, - pkScript []byte, - numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) { + pkScript []byte, numConfs, heightHint uint32, + opts ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent, error) { // Register the conf notification with the TxNotifier. A non-nil value // for `dispatch` will be returned if we are required to perform a // manual scan for the confirmation. Otherwise the notifier will begin // watching at tip for the transaction to confirm. ntfn, err := b.txNotifier.RegisterConf( - txid, pkScript, numConfs, heightHint, + txid, pkScript, numConfs, heightHint, opts..., ) if err != nil { return nil, err diff --git a/chainntnfs/interface.go b/chainntnfs/interface.go index 724d77094..360dcd455 100644 --- a/chainntnfs/interface.go +++ b/chainntnfs/interface.go @@ -8,7 +8,9 @@ import ( "strings" "sync" + "github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/btcjson" + "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" ) @@ -67,6 +69,31 @@ func (t TxConfStatus) String() string { } } +// notifierOptions is a set of functional options that allow callers to further +// modify the type of chain event notifications they receive. +type notifierOptions struct { + // includeBlock if true, then the dispatched confirmation notification + // will include the block that mined the transaction. + includeBlock bool +} + +// defaultNotifierOptions returns the set of default options for the notifier. +func defaultNotifierOptions() *notifierOptions { + return ¬ifierOptions{} +} + +// NotifierOption is a functional option that allows a caller to modify the +// events received from the notifier. +type NotifierOption func(*notifierOptions) + +// WithIncludeBlock is an optional argument that allows the calelr to specify +// that the block that mined a transaction should be included in the response. +func WithIncludeBlock() NotifierOption { + return func(o *notifierOptions) { + o.includeBlock = true + } +} + // ChainNotifier represents a trusted source to receive notifications concerning // targeted events on the Bitcoin blockchain. The interface specification is // intentionally general in order to support a wide array of chain notification @@ -97,7 +124,8 @@ type ChainNotifier interface { // NOTE: Dispatching notifications to multiple clients subscribed to // the same (txid, numConfs) tuple MUST be supported. RegisterConfirmationsNtfn(txid *chainhash.Hash, pkScript []byte, - numConfs, heightHint uint32) (*ConfirmationEvent, error) + numConfs, heightHint uint32, + opts ...NotifierOption) (*ConfirmationEvent, error) // RegisterSpendNtfn registers an intent to be notified once the target // outpoint is successfully spent within a transaction. The script that @@ -166,6 +194,12 @@ type TxConfirmation struct { // Tx is the transaction for which the notification was requested for. Tx *wire.MsgTx + + // Block is the block that contains the transaction referenced above. + // + // NOTE: This is only specified if the confirmation request opts to + // have the response include the block itself. + Block *wire.MsgBlock } // ConfirmationEvent encapsulates a confirmation notification. With this struct, @@ -628,9 +662,8 @@ type TxIndexConn interface { // block that the transaction confirmed. GetRawTransactionVerbose(*chainhash.Hash) (*btcjson.TxRawResult, error) - // GetBlockVerbose returns the block identified by the chain hash along - // with additional information such as the block's height in the chain. - GetBlockVerbose(*chainhash.Hash) (*btcjson.GetBlockVerboseResult, error) + // GetBlock returns the block identified by the chain hash. + GetBlock(*chainhash.Hash) (*wire.MsgBlock, error) } // ConfDetailsFromTxIndex looks up whether a transaction is already included in @@ -700,26 +733,38 @@ func ConfDetailsFromTxIndex(chainConn TxIndexConn, r ConfRequest, fmt.Errorf("unable to get block hash %v for "+ "historical dispatch: %v", rawTxRes.BlockHash, err) } - block, err := chainConn.GetBlockVerbose(blockHash) + block, err := chainConn.GetBlock(blockHash) if err != nil { return nil, TxNotFoundIndex, fmt.Errorf("unable to get block with hash %v for "+ "historical dispatch: %v", blockHash, err) } + // In the modern chain (the only one we really care about for LN), the + // coinbase transaction of all blocks will include the block height. + // Therefore we can save another query, and just use that height + // directly. + blockHeight, err := blockchain.ExtractCoinbaseHeight( + btcutil.NewTx(block.Transactions[0]), + ) + if err != nil { + return nil, TxNotFoundIndex, fmt.Errorf("unable to extract "+ + "coinbase height: %w", err) + } + // If the block was obtained, locate the transaction's index within the // block so we can give the subscriber full confirmation details. - txidStr := r.TxID.String() - for txIndex, txHash := range block.Tx { - if txHash != txidStr { + for txIndex, blockTx := range block.Transactions { + if blockTx.TxHash() != r.TxID { continue } return &TxConfirmation{ Tx: &tx, BlockHash: blockHash, - BlockHeight: uint32(block.Height), + BlockHeight: uint32(blockHeight), TxIndex: uint32(txIndex), + Block: block, }, TxFoundIndex, nil } diff --git a/chainntnfs/neutrinonotify/neutrino.go b/chainntnfs/neutrinonotify/neutrino.go index 35d789e11..b8286e424 100644 --- a/chainntnfs/neutrinonotify/neutrino.go +++ b/chainntnfs/neutrinonotify/neutrino.go @@ -636,6 +636,7 @@ func (n *NeutrinoNotifier) historicalConfDetails(confRequest chainntnfs.ConfRequ BlockHash: blockHash, BlockHeight: scanHeight, TxIndex: uint32(i), + Block: block.MsgBlock(), }, nil } } @@ -649,11 +650,19 @@ func (n *NeutrinoNotifier) historicalConfDetails(confRequest chainntnfs.ConfRequ // // NOTE: This method must be called with the bestBlockMtx lock held. func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error { - // We'll extend the txNotifier's height with the information of this new - // block, which will handle all of the notification logic for us. - err := n.txNotifier.ConnectTip( - &newBlock.hash, newBlock.height, newBlock.txns, - ) + // We'll extend the txNotifier's height with the information of this + // new block, which will handle all of the notification logic for us. + // + // We actually need the _full_ block here as well in order to be able + // to send the full block back up to the client. The neutrino client + // itself will only dispatch a block if one of the items we're looking + // for matches, so ultimately passing it the full block will still only + // result in the items we care about being dispatched. + rawBlock, err := n.GetBlock(newBlock.hash) + if err != nil { + return fmt.Errorf("unable to get full block: %v", err) + } + err = n.txNotifier.ConnectTip(rawBlock, newBlock.height) if err != nil { return fmt.Errorf("unable to connect tip: %v", err) } @@ -899,15 +908,15 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint, // channel. Once it has reached all of its confirmations, a notification will be // sent across the 'Confirmed' channel. func (n *NeutrinoNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, - pkScript []byte, - numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) { + pkScript []byte, numConfs, heightHint uint32, + opts ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent, error) { // Register the conf notification with the TxNotifier. A non-nil value // for `dispatch` will be returned if we are required to perform a // manual scan for the confirmation. Otherwise the notifier will begin // watching at tip for the transaction to confirm. ntfn, err := n.txNotifier.RegisterConf( - txid, pkScript, numConfs, heightHint, + txid, pkScript, numConfs, heightHint, opts..., ) if err != nil { return nil, err diff --git a/chainntnfs/test/test_interface.go b/chainntnfs/test/test_interface.go index 7faf468b1..3f81e77de 100644 --- a/chainntnfs/test/test_interface.go +++ b/chainntnfs/test/test_interface.go @@ -160,6 +160,13 @@ func testBatchConfirmationNotification(miner *rpctest.Harness, // verify they're each notified at the proper number of confirmations // below. for i, numConfs := range confSpread { + // All the clients with an even index will ask for the block + // along side the conf ntfn. + var opts []chainntnfs.NotifierOption + if i%2 == 0 { + opts = append(opts, chainntnfs.WithIncludeBlock()) + } + txid, pkScript, err := chainntnfs.GetTestTxidAndScript(miner) if err != nil { t.Fatalf("unable to create test addr: %v", err) @@ -168,10 +175,12 @@ func testBatchConfirmationNotification(miner *rpctest.Harness, if scriptDispatch { confIntent, err = notifier.RegisterConfirmationsNtfn( nil, pkScript, numConfs, uint32(currentHeight), + opts..., ) } else { confIntent, err = notifier.RegisterConfirmationsNtfn( txid, pkScript, numConfs, uint32(currentHeight), + opts..., ) } if err != nil { @@ -218,6 +227,12 @@ func testBatchConfirmationNotification(miner *rpctest.Harness, "conf height: expected %v, got %v", initialConfHeight, conf.BlockHeight) } + + // If this is an even client index, then we expect the + // block to be populated. Otherwise, it should be + // empty. + expectBlock := i%2 == 0 + require.Equal(t, expectBlock, conf.Block != nil) continue case <-time.After(20 * time.Second): t.Fatalf("confirmation notification never received: %v", numConfs) @@ -547,6 +562,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, if scriptDispatch { ntfn1, err = notifier.RegisterConfirmationsNtfn( nil, pkScript1, 1, uint32(currentHeight), + chainntnfs.WithIncludeBlock(), ) } else { ntfn1, err = notifier.RegisterConfirmationsNtfn( @@ -579,6 +595,13 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, t.Fatalf("incorrect block height: expected %v, got %v", confInfo.BlockHeight, currentHeight) } + + // Ensure that if this was a script dispatch, the block is set + // as well. + if scriptDispatch { + require.NotNil(t, confInfo.Block) + } + break case <-time.After(20 * time.Second): t.Fatalf("confirmation notification never received") @@ -591,6 +614,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, if scriptDispatch { ntfn2, err = notifier.RegisterConfirmationsNtfn( nil, pkScript2, 3, uint32(currentHeight), + chainntnfs.WithIncludeBlock(), ) } else { ntfn2, err = notifier.RegisterConfirmationsNtfn( @@ -622,6 +646,7 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, if scriptDispatch { ntfn3, err = notifier.RegisterConfirmationsNtfn( nil, pkScript3, 1, uint32(currentHeight-1), + chainntnfs.WithIncludeBlock(), ) } else { ntfn3, err = notifier.RegisterConfirmationsNtfn( @@ -640,7 +665,10 @@ func testTxConfirmedBeforeNtfnRegistration(miner *rpctest.Harness, require.NoError(t, err, "unable to register ntfn") select { - case <-ntfn3.Confirmed: + case confInfo := <-ntfn3.Confirmed: + if scriptDispatch { + require.NotNil(t, confInfo.Block) + } case <-time.After(10 * time.Second): t.Fatalf("confirmation notification never received") } diff --git a/chainntnfs/txnotifier.go b/chainntnfs/txnotifier.go index 409002346..01840a063 100644 --- a/chainntnfs/txnotifier.go +++ b/chainntnfs/txnotifier.go @@ -265,6 +265,10 @@ type ConfNtfn struct { // dispatched is false if the confirmed notification has not been sent yet. dispatched bool + + // includeBlock is true if the dispatched notification should also have + // the block included with it. + includeBlock bool } // HistoricalConfDispatch parametrizes a manual rescan for a particular @@ -576,7 +580,8 @@ func NewTxNotifier(startHeight uint32, reorgSafetyLimit uint32, // newConfNtfn validates all of the parameters required to successfully create // and register a confirmation notification. func (n *TxNotifier) newConfNtfn(txid *chainhash.Hash, - pkScript []byte, numConfs, heightHint uint32) (*ConfNtfn, error) { + pkScript []byte, numConfs, heightHint uint32, + opts *notifierOptions) (*ConfNtfn, error) { // An accompanying output script must always be provided. if len(pkScript) == 0 { @@ -609,7 +614,8 @@ func (n *TxNotifier) newConfNtfn(txid *chainhash.Hash, Event: NewConfirmationEvent(numConfs, func() { n.CancelConf(confRequest, confID) }), - HeightHint: heightHint, + HeightHint: heightHint, + includeBlock: opts.includeBlock, }, nil } @@ -622,7 +628,8 @@ func (n *TxNotifier) newConfNtfn(txid *chainhash.Hash, // UpdateConfDetails method, otherwise we will wait for the transaction/output // script to confirm even though it already has. func (n *TxNotifier) RegisterConf(txid *chainhash.Hash, pkScript []byte, - numConfs, heightHint uint32) (*ConfRegistration, error) { + numConfs, heightHint uint32, + optFuncs ...NotifierOption) (*ConfRegistration, error) { select { case <-n.quit: @@ -630,8 +637,13 @@ func (n *TxNotifier) RegisterConf(txid *chainhash.Hash, pkScript []byte, default: } + opts := defaultNotifierOptions() + for _, optFunc := range optFuncs { + optFunc(opts) + } + // We'll start by performing a series of validation checks. - ntfn, err := n.newConfNtfn(txid, pkScript, numConfs, heightHint) + ntfn, err := n.newConfNtfn(txid, pkScript, numConfs, heightHint, opts) if err != nil { return nil, err } @@ -682,6 +694,14 @@ func (n *TxNotifier) RegisterConf(txid *chainhash.Hash, pkScript []byte, "registration since rescan has finished", ntfn.ConfRequest) + // The default notification we assigned above includes the + // block along with the rest of the details. However not all + // clients want the block, so we make a copy here w/o the block + // if needed so we can give clients only what they ask for. + if !ntfn.includeBlock && confSet.details != nil { + confSet.details.Block = nil + } + err := n.dispatchConfDetails(ntfn, confSet.details) if err != nil { return nil, err @@ -888,7 +908,16 @@ func (n *TxNotifier) UpdateConfDetails(confRequest ConfRequest, // notifications that have not yet been delivered. confSet.details = details for _, ntfn := range confSet.ntfns { - err = n.dispatchConfDetails(ntfn, details) + // The default notification we assigned above includes the + // block along with the rest of the details. However not all + // clients want the block, so we make a copy here w/o the block + // if needed so we can give clients only what they ask for. + confDetails := *details + if !ntfn.includeBlock { + confDetails.Block = nil + } + + err = n.dispatchConfDetails(ntfn, &confDetails) if err != nil { return err } @@ -1207,7 +1236,7 @@ func (n *TxNotifier) ProcessRelevantSpendTx(tx *btcutil.Tx, onSpend := func(request SpendRequest, details *SpendDetail) { spends = append(spends, spend{&request, details}) } - n.filterTx(tx, nil, blockHeight, nil, onSpend) + n.filterTx(nil, tx, blockHeight, nil, onSpend) // After the transaction has been filtered, we can finally dispatch // notifications for each request. @@ -1391,8 +1420,8 @@ func (n *TxNotifier) dispatchSpendDetails(ntfn *SpendNtfn, details *SpendDetail) // NOTE: In order to actually dispatch the relevant transaction notifications to // clients, NotifyHeight must be called with the same block height in order to // maintain correctness. -func (n *TxNotifier) ConnectTip(blockHash *chainhash.Hash, blockHeight uint32, - txns []*btcutil.Tx) error { +func (n *TxNotifier) ConnectTip(block *btcutil.Block, + blockHeight uint32) error { select { case <-n.quit: @@ -1413,13 +1442,18 @@ func (n *TxNotifier) ConnectTip(blockHash *chainhash.Hash, blockHeight uint32, // First, we'll iterate over all the transactions found in this block to // determine if it includes any relevant transactions to the TxNotifier. - Log.Debugf("Filtering %d txns for %d spend requests at height %d", - len(txns), len(n.spendNotifications), blockHeight) - for _, tx := range txns { - n.filterTx( - tx, blockHash, blockHeight, n.handleConfDetailsAtTip, - n.handleSpendDetailsAtTip, - ) + if block != nil { + Log.Debugf("Filtering %d txns for %d spend requests at "+ + "height %d", len(block.Transactions()), + len(n.spendNotifications), blockHeight) + + for _, tx := range block.Transactions() { + n.filterTx( + block, tx, blockHeight, + n.handleConfDetailsAtTip, + n.handleSpendDetailsAtTip, + ) + } } // Now that we've determined which requests were confirmed and spent @@ -1469,7 +1503,7 @@ func (n *TxNotifier) ConnectTip(blockHash *chainhash.Hash, blockHeight uint32, // filterTx determines whether the transaction spends or confirms any // outstanding pending requests. The onConf and onSpend callbacks can be used to // retrieve all the requests fulfilled by this transaction as they occur. -func (n *TxNotifier) filterTx(tx *btcutil.Tx, blockHash *chainhash.Hash, +func (n *TxNotifier) filterTx(block *btcutil.Block, tx *btcutil.Tx, blockHeight uint32, onConf func(ConfRequest, *TxConfirmation), onSpend func(SpendRequest, *SpendDetail)) { @@ -1548,13 +1582,14 @@ func (n *TxNotifier) filterTx(tx *btcutil.Tx, blockHash *chainhash.Hash, notifyDetails := func(confRequest ConfRequest) { Log.Debugf("Found initial confirmation of %v: "+ "height=%d, hash=%v", confRequest, - blockHeight, blockHash) + blockHeight, block.Hash()) details := &TxConfirmation{ Tx: tx.MsgTx(), - BlockHash: blockHash, + BlockHash: block.Hash(), BlockHeight: blockHeight, TxIndex: uint32(tx.Index()), + Block: block.MsgBlock(), } onConf(confRequest, details) @@ -1721,8 +1756,17 @@ func (n *TxNotifier) NotifyHeight(height uint32) error { Log.Infof("Dispatching %v confirmation notification for %v", ntfn.NumConfirmations, ntfn.ConfRequest) + // The default notification we assigned above includes the + // block along with the rest of the details. However not all + // clients want the block, so we make a copy here w/o the block + // if needed so we can give clients only what they ask for. + confDetails := *confSet.details + if !ntfn.includeBlock { + confDetails.Block = nil + } + select { - case ntfn.Event.Confirmed <- confSet.details: + case ntfn.Event.Confirmed <- &confDetails: ntfn.dispatched = true case <-n.quit: return ErrTxNotifierExiting diff --git a/chainntnfs/txnotifier_test.go b/chainntnfs/txnotifier_test.go index 85c502c4f..354c2103b 100644 --- a/chainntnfs/txnotifier_test.go +++ b/chainntnfs/txnotifier_test.go @@ -256,7 +256,7 @@ func TestTxNotifierFutureConfDispatch(t *testing.T) { Transactions: []*wire.MsgTx{&tx1, &tx2}, }) - err = n.ConnectTip(block1.Hash(), 11, block1.Transactions()) + err = n.ConnectTip(block1, 11) require.NoError(t, err, "Failed to connect block") if err := n.NotifyHeight(11); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -316,7 +316,7 @@ func TestTxNotifierFutureConfDispatch(t *testing.T) { // Create a new block and add it to the TxNotifier at the next height. // This should confirm tx2. block2 := btcutil.NewBlock(&wire.MsgBlock{}) - err = n.ConnectTip(block2.Hash(), 12, block2.Transactions()) + err = n.ConnectTip(block2, 12) require.NoError(t, err, "Failed to connect block") if err := n.NotifyHeight(12); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -460,7 +460,7 @@ func TestTxNotifierHistoricalConfDispatch(t *testing.T) { Transactions: []*wire.MsgTx{&tx3}, }) - err = n.ConnectTip(block.Hash(), 11, block.Transactions()) + err = n.ConnectTip(block, 11) require.NoError(t, err, "Failed to connect block") if err := n.NotifyHeight(11); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -536,7 +536,7 @@ func TestTxNotifierFutureSpendDispatch(t *testing.T) { block := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{spendTx}, }) - err = n.ConnectTip(block.Hash(), 11, block.Transactions()) + err = n.ConnectTip(block, 11) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(11); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -569,7 +569,7 @@ func TestTxNotifierFutureSpendDispatch(t *testing.T) { block = btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{spendOfSpend}, }) - err = n.ConnectTip(block.Hash(), 12, block.Transactions()) + err = n.ConnectTip(block, 12) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(12); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -609,7 +609,7 @@ func TestTxNotifierFutureConfDispatchReuseSafe(t *testing.T) { Transactions: []*wire.MsgTx{&tx1}, }) currentBlock++ - err = n.ConnectTip(block.Hash(), currentBlock, block.Transactions()) + err = n.ConnectTip(block, currentBlock) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(currentBlock); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -662,7 +662,7 @@ func TestTxNotifierFutureConfDispatchReuseSafe(t *testing.T) { Transactions: []*wire.MsgTx{&tx2}, }) currentBlock++ - err = n.ConnectTip(block2.Hash(), currentBlock, block2.Transactions()) + err = n.ConnectTip(block2, currentBlock) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(currentBlock); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -706,9 +706,7 @@ func TestTxNotifierFutureConfDispatchReuseSafe(t *testing.T) { for currentBlock < 15 { block := btcutil.NewBlock(&wire.MsgBlock{}) currentBlock++ - err = n.ConnectTip( - block.Hash(), currentBlock, block.Transactions(), - ) + err = n.ConnectTip(block, currentBlock) if err != nil { t.Fatalf("unable to connect block: %v", err) } @@ -801,7 +799,7 @@ func TestTxNotifierHistoricalSpendDispatch(t *testing.T) { block := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{spendOfSpend}, }) - err = n.ConnectTip(block.Hash(), startingHeight+1, block.Transactions()) + err = n.ConnectTip(block, startingHeight+1) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(startingHeight + 1); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1110,7 +1108,7 @@ func TestTxNotifierCancelConf(t *testing.T) { // Cancel the second notification before connecting the block. ntfn2.Event.Cancel() - err = n.ConnectTip(block.Hash(), startingHeight+1, block.Transactions()) + err = n.ConnectTip(block, startingHeight+1) require.NoError(t, err, "unable to connect block") // Cancel the third notification before notifying to ensure its queued @@ -1155,7 +1153,7 @@ func TestTxNotifierCancelConf(t *testing.T) { Transactions: []*wire.MsgTx{}, }) - err = n.ConnectTip(block1.Hash(), startingHeight+2, block1.Transactions()) + err = n.ConnectTip(block1, startingHeight+2) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(startingHeight + 2); err != nil { @@ -1187,7 +1185,7 @@ func TestTxNotifierCancelConf(t *testing.T) { Transactions: []*wire.MsgTx{}, }) - err = n.ConnectTip(block2.Hash(), startingHeight+3, block2.Transactions()) + err = n.ConnectTip(block2, startingHeight+3) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(startingHeight + 3); err != nil { @@ -1241,7 +1239,7 @@ func TestTxNotifierCancelSpend(t *testing.T) { // cancel the second request. n.CancelSpend(ntfn2.HistoricalDispatch.SpendRequest, 2) - err = n.ConnectTip(block.Hash(), startingHeight+1, block.Transactions()) + err = n.ConnectTip(block, startingHeight+1) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(startingHeight + 1); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1320,13 +1318,13 @@ func TestTxNotifierConfReorg(t *testing.T) { block1 := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{&tx1}, }) - if err := n.ConnectTip(nil, 8, block1.Transactions()); err != nil { + if err := n.ConnectTip(block1, 8); err != nil { t.Fatalf("Failed to connect block: %v", err) } if err := n.NotifyHeight(8); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) } - if err := n.ConnectTip(nil, 9, nil); err != nil { + if err := n.ConnectTip(nil, 9); err != nil { t.Fatalf("Failed to connect block: %v", err) } if err := n.NotifyHeight(9); err != nil { @@ -1336,7 +1334,7 @@ func TestTxNotifierConfReorg(t *testing.T) { block2 := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{&tx2, &tx3}, }) - if err := n.ConnectTip(nil, 10, block2.Transactions()); err != nil { + if err := n.ConnectTip(block2, 10); err != nil { t.Fatalf("Failed to connect block: %v", err) } if err := n.NotifyHeight(10); err != nil { @@ -1399,14 +1397,14 @@ func TestTxNotifierConfReorg(t *testing.T) { t.Fatalf("Failed to connect block: %v", err) } - if err := n.ConnectTip(nil, 10, nil); err != nil { + if err := n.ConnectTip(nil, 10); err != nil { t.Fatalf("Failed to connect block: %v", err) } if err := n.NotifyHeight(10); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) } - if err := n.ConnectTip(nil, 11, nil); err != nil { + if err := n.ConnectTip(nil, 11); err != nil { t.Fatalf("Failed to connect block: %v", err) } if err := n.NotifyHeight(11); err != nil { @@ -1456,13 +1454,13 @@ func TestTxNotifierConfReorg(t *testing.T) { }) block4 := btcutil.NewBlock(&wire.MsgBlock{}) - err = n.ConnectTip(block3.Hash(), 12, block3.Transactions()) + err = n.ConnectTip(block3, 12) require.NoError(t, err, "Failed to connect block") if err := n.NotifyHeight(12); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) } - err = n.ConnectTip(block4.Hash(), 13, block4.Transactions()) + err = n.ConnectTip(block4, 13) require.NoError(t, err, "Failed to connect block") if err := n.NotifyHeight(13); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1600,7 +1598,7 @@ func TestTxNotifierSpendReorg(t *testing.T) { block1 := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{spendTx1}, }) - err = n.ConnectTip(block1.Hash(), startingHeight+1, block1.Transactions()) + err = n.ConnectTip(block1, startingHeight+1) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(startingHeight + 1); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1628,7 +1626,7 @@ func TestTxNotifierSpendReorg(t *testing.T) { block2 := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{spendTx2}, }) - err = n.ConnectTip(block2.Hash(), startingHeight+2, block2.Transactions()) + err = n.ConnectTip(block2, startingHeight+2) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(startingHeight + 2); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1680,9 +1678,7 @@ func TestTxNotifierSpendReorg(t *testing.T) { // We'll now extend the chain with an empty block, to ensure that we can // properly detect when an outpoint has been re-spent at a later height. emptyBlock := btcutil.NewBlock(&wire.MsgBlock{}) - err = n.ConnectTip( - emptyBlock.Hash(), startingHeight+2, emptyBlock.Transactions(), - ) + err = n.ConnectTip(emptyBlock, startingHeight+2) require.NoError(t, err, "unable to disconnect block") if err := n.NotifyHeight(startingHeight + 2); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1703,9 +1699,7 @@ func TestTxNotifierSpendReorg(t *testing.T) { // Finally, extend the chain with another block containing the same // spending transaction of the second outpoint. - err = n.ConnectTip( - block2.Hash(), startingHeight+3, block2.Transactions(), - ) + err = n.ConnectTip(block2, startingHeight+3) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(startingHeight + 3); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1767,7 +1761,7 @@ func TestTxNotifierSpendReorgMissed(t *testing.T) { block := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{spendTx}, }) - err := n.ConnectTip(block.Hash(), startingHeight+1, block.Transactions()) + err := n.ConnectTip(block, startingHeight+1) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(startingHeight + 1); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1875,7 +1869,7 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { Transactions: []*wire.MsgTx{&txDummy}, }) - err = n.ConnectTip(block1.Hash(), txDummyHeight, block1.Transactions()) + err = n.ConnectTip(block1, txDummyHeight) require.NoError(t, err, "Failed to connect block") if err := n.NotifyHeight(txDummyHeight); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1912,7 +1906,7 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { Transactions: []*wire.MsgTx{&tx1}, }) - err = n.ConnectTip(block2.Hash(), tx1Height, block2.Transactions()) + err = n.ConnectTip(block2, tx1Height) require.NoError(t, err, "Failed to connect block") if err := n.NotifyHeight(tx1Height); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -1941,7 +1935,7 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { Transactions: []*wire.MsgTx{&tx2}, }) - err = n.ConnectTip(block3.Hash(), tx2Height, block3.Transactions()) + err = n.ConnectTip(block3, tx2Height) require.NoError(t, err, "Failed to connect block") if err := n.NotifyHeight(tx2Height); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -2037,9 +2031,7 @@ func TestTxNotifierSpendHintCache(t *testing.T) { // Create a new empty block and extend the chain. emptyBlock := btcutil.NewBlock(&wire.MsgBlock{}) - err = n.ConnectTip( - emptyBlock.Hash(), dummyHeight, emptyBlock.Transactions(), - ) + err = n.ConnectTip(emptyBlock, dummyHeight) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(dummyHeight); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -2079,7 +2071,7 @@ func TestTxNotifierSpendHintCache(t *testing.T) { block1 := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{spendTx1}, }) - err = n.ConnectTip(block1.Hash(), op1Height, block1.Transactions()) + err = n.ConnectTip(block1, op1Height) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(op1Height); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -2108,7 +2100,7 @@ func TestTxNotifierSpendHintCache(t *testing.T) { block2 := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{spendTx2}, }) - err = n.ConnectTip(block2.Hash(), op2Height, block2.Transactions()) + err = n.ConnectTip(block2, op2Height) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(op2Height); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -2194,9 +2186,7 @@ func TestTxNotifierSpendDuringHistoricalRescan(t *testing.T) { // Create a new empty block and extend the chain. height := uint32(startingHeight) + 1 emptyBlock := btcutil.NewBlock(&wire.MsgBlock{}) - err = n.ConnectTip( - emptyBlock.Hash(), height, emptyBlock.Transactions(), - ) + err = n.ConnectTip(emptyBlock, height) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(height); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -2237,9 +2227,7 @@ func TestTxNotifierSpendDuringHistoricalRescan(t *testing.T) { block = btcutil.NewBlock(&wire.MsgBlock{}) } - err = n.ConnectTip( - block.Hash(), height, block.Transactions(), - ) + err = n.ConnectTip(block, height) if err != nil { t.Fatalf("unable to connect block: %v", err) } @@ -2290,7 +2278,7 @@ func TestTxNotifierSpendDuringHistoricalRescan(t *testing.T) { block2 := btcutil.NewBlock(&wire.MsgBlock{ Transactions: []*wire.MsgTx{spendTx2}, }) - err = n.ConnectTip(block2.Hash(), height, block2.Transactions()) + err = n.ConnectTip(block2, height) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(height); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -2309,9 +2297,7 @@ func TestTxNotifierSpendDuringHistoricalRescan(t *testing.T) { height++ block := btcutil.NewBlock(&wire.MsgBlock{}) - err := n.ConnectTip( - block.Hash(), height, block.Transactions(), - ) + err := n.ConnectTip(block, height) if err != nil { t.Fatalf("unable to connect block: %v", err) } @@ -2368,7 +2354,7 @@ func TestTxNotifierNtfnDone(t *testing.T) { Transactions: []*wire.MsgTx{tx, spendTx}, }) - err = n.ConnectTip(block.Hash(), 11, block.Transactions()) + err = n.ConnectTip(block, 11) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(11); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -2418,7 +2404,7 @@ func TestTxNotifierNtfnDone(t *testing.T) { // We'll reconnect the block that satisfies both of these requests. // We should see notifications dispatched for both once again. - err = n.ConnectTip(block.Hash(), 11, block.Transactions()) + err = n.ConnectTip(block, 11) require.NoError(t, err, "unable to connect block") if err := n.NotifyHeight(11); err != nil { t.Fatalf("unable to dispatch notifications: %v", err) @@ -2442,7 +2428,7 @@ func TestTxNotifierNtfnDone(t *testing.T) { nextHeight := uint32(12) for i := nextHeight; i < nextHeight+reorgSafetyLimit; i++ { dummyBlock := btcutil.NewBlock(&wire.MsgBlock{}) - if err := n.ConnectTip(dummyBlock.Hash(), i, nil); err != nil { + if err := n.ConnectTip(dummyBlock, i); err != nil { t.Fatalf("unable to connect block: %v", err) } } diff --git a/chainreg/no_chain_backend.go b/chainreg/no_chain_backend.go index 244fe025e..84019a401 100644 --- a/chainreg/no_chain_backend.go +++ b/chainreg/no_chain_backend.go @@ -57,7 +57,8 @@ func (n *NoChainBackend) RelayFeePerKW() chainfee.SatPerKWeight { } func (n *NoChainBackend) RegisterConfirmationsNtfn(*chainhash.Hash, []byte, - uint32, uint32) (*chainntnfs.ConfirmationEvent, error) { + uint32, uint32, + ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent, error) { return nil, errNotImplemented } diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 4b053ba80..8ddde84e3 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -420,7 +420,8 @@ func newMockNotifier() *mockNotifier { } func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, - _ []byte, numConfs, _ uint32) (*chainntnfs.ConfirmationEvent, error) { + _ []byte, numConfs, _ uint32, + opts ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent, error) { return nil, nil } diff --git a/funding/manager_test.go b/funding/manager_test.go index 28eb2e637..93b450a73 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -164,7 +164,7 @@ type mockNotifier struct { } func (m *mockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, - _ []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) { + _ []byte, numConfs, heightHint uint32, opts ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent, error) { if numConfs == 6 { return &chainntnfs.ConfirmationEvent{ diff --git a/lntest/mock/chainnotifier.go b/lntest/mock/chainnotifier.go index b7c9377c2..ddce8defa 100644 --- a/lntest/mock/chainnotifier.go +++ b/lntest/mock/chainnotifier.go @@ -16,8 +16,8 @@ type ChainNotifier struct { // RegisterConfirmationsNtfn returns a ConfirmationEvent that contains a channel // that the tx confirmation will go over. func (c *ChainNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, - pkScript []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, - error) { + pkScript []byte, numConfs, heightHint uint32, + opts ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent, error) { return &chainntnfs.ConfirmationEvent{ Confirmed: c.ConfChan, diff --git a/sweep/test_utils.go b/sweep/test_utils.go index 475aaf5af..86dfd6d2b 100644 --- a/sweep/test_utils.go +++ b/sweep/test_utils.go @@ -109,8 +109,8 @@ func (m *MockNotifier) sendSpend(channel chan *chainntnfs.SpendDetail, // RegisterConfirmationsNtfn registers for tx confirm notifications. func (m *MockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, - _ []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, - error) { + _ []byte, numConfs, heightHint uint32, + opt ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent, error) { return &chainntnfs.ConfirmationEvent{ Confirmed: m.getConfChannel(txid),