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),