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.
This commit is contained in:
Olaoluwa Osuntokun committed 2022-08-01 19:59:21 -07:00
1 parent fec8fd9c63
commit 08f1c2e93a
12 files changed
+224 -109

No files matched your search

+6 -5
View File
@@ -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
+8 -8
View File
@@ -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
+54 -9
View File
@@ -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 &notifierOptions{}
}
// 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
}
+17 -8
View File
@@ -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
+29 -1
View File
@@ -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")
}
+63 -19
View File
@@ -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
+38 -52
View File
@@ -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)
}
}
+2 -1
View File
@@ -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
}
+2 -1
View File
@@ -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
}
+1 -1
View File
@@ -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{
+2 -2
View File
@@ -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,
+2 -2
View File
@@ -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),