From 5089311ca1d2b5775b70aa8f6f51b25c4a0b7d7b Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Fri, 16 Aug 2019 19:55:26 -0700 Subject: [PATCH] chainntnfs: refactor common registration code within RegisterConfirmationsNtfn --- chainntnfs/bitcoindnotify/bitcoind.go | 29 +-- chainntnfs/btcdnotify/btcd.go | 29 +-- chainntnfs/neutrinonotify/neutrino.go | 35 +--- chainntnfs/txnotifier.go | 105 ++++++++-- chainntnfs/txnotifier_test.go | 289 ++++++++------------------ 5 files changed, 192 insertions(+), 295 deletions(-) diff --git a/chainntnfs/bitcoindnotify/bitcoind.go b/chainntnfs/bitcoindnotify/bitcoind.go index 2c02167b..d5203de2 100644 --- a/chainntnfs/bitcoindnotify/bitcoind.go +++ b/chainntnfs/bitcoindnotify/bitcoind.go @@ -39,7 +39,6 @@ type chainUpdate struct { // chain client. Multiple concurrent clients are supported. All notifications // are achieved via non-blocking sends on client channels. type BitcoindNotifier struct { - confClientCounter uint64 // To be used atomically. spendClientCounter uint64 // To be used atomically. epochClientCounter uint64 // To be used atomically. @@ -827,41 +826,23 @@ func (b *BitcoindNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, pkScript []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) { - // Construct a notification request for the transaction and send it to - // the main event loop. - confID := atomic.AddUint64(&b.confClientCounter, 1) - confRequest, err := chainntnfs.NewConfRequest(txid, pkScript) - if err != nil { - return nil, err - } - ntfn := &chainntnfs.ConfNtfn{ - ConfID: confID, - ConfRequest: confRequest, - NumConfirmations: numConfs, - Event: chainntnfs.NewConfirmationEvent(numConfs, func() { - b.txNotifier.CancelConf(confRequest, confID) - }), - HeightHint: heightHint, - } - - chainntnfs.Log.Infof("New confirmation subscription: %v, num_confs=%v", - confRequest, numConfs) - // 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. - dispatch, _, err := b.txNotifier.RegisterConf(ntfn) + ntfn, err := b.txNotifier.RegisterConf( + txid, pkScript, numConfs, heightHint, + ) if err != nil { return nil, err } - if dispatch == nil { + if ntfn.HistoricalDispatch == nil { return ntfn.Event, nil } select { - case b.notificationRegistry <- dispatch: + case b.notificationRegistry <- ntfn.HistoricalDispatch: return ntfn.Event, nil case <-b.quit: return nil, chainntnfs.ErrChainNotifierShuttingDown diff --git a/chainntnfs/btcdnotify/btcd.go b/chainntnfs/btcdnotify/btcd.go index bfe42da0..c174f4c8 100644 --- a/chainntnfs/btcdnotify/btcd.go +++ b/chainntnfs/btcdnotify/btcd.go @@ -50,7 +50,6 @@ type txUpdate struct { // notifications. Multiple concurrent clients are supported. All notifications // are achieved via non-blocking sends on client channels. type BtcdNotifier struct { - confClientCounter uint64 // To be used aotmically. spendClientCounter uint64 // To be used atomically. epochClientCounter uint64 // To be used atomically. @@ -851,41 +850,23 @@ func (b *BtcdNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, pkScript []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) { - // Construct a notification request for the transaction and send it to - // the main event loop. - confID := atomic.AddUint64(&b.confClientCounter, 1) - confRequest, err := chainntnfs.NewConfRequest(txid, pkScript) - if err != nil { - return nil, err - } - ntfn := &chainntnfs.ConfNtfn{ - ConfID: confID, - ConfRequest: confRequest, - NumConfirmations: numConfs, - Event: chainntnfs.NewConfirmationEvent(numConfs, func() { - b.txNotifier.CancelConf(confRequest, confID) - }), - HeightHint: heightHint, - } - - chainntnfs.Log.Infof("New confirmation subscription: %v, num_confs=%v ", - confRequest, numConfs) - // 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. - dispatch, _, err := b.txNotifier.RegisterConf(ntfn) + ntfn, err := b.txNotifier.RegisterConf( + txid, pkScript, numConfs, heightHint, + ) if err != nil { return nil, err } - if dispatch == nil { + if ntfn.HistoricalDispatch == nil { return ntfn.Event, nil } select { - case b.notificationRegistry <- dispatch: + case b.notificationRegistry <- ntfn.HistoricalDispatch: return ntfn.Event, nil case <-b.quit: return nil, chainntnfs.ErrChainNotifierShuttingDown diff --git a/chainntnfs/neutrinonotify/neutrino.go b/chainntnfs/neutrinonotify/neutrino.go index bc5c27d7..76f6dcbc 100644 --- a/chainntnfs/neutrinonotify/neutrino.go +++ b/chainntnfs/neutrinonotify/neutrino.go @@ -37,7 +37,6 @@ const ( // TODO(roasbeef): heavily consolidate with NeutrinoNotifier code // * maybe combine into single package? type NeutrinoNotifier struct { - confClientCounter uint64 // To be used atomically. spendClientCounter uint64 // To be used atomically. epochClientCounter uint64 // To be used atomically. @@ -820,31 +819,13 @@ func (n *NeutrinoNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, pkScript []byte, numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) { - // Construct a notification request for the transaction and send it to - // the main event loop. - confID := atomic.AddUint64(&n.confClientCounter, 1) - confRequest, err := chainntnfs.NewConfRequest(txid, pkScript) - if err != nil { - return nil, err - } - ntfn := &chainntnfs.ConfNtfn{ - ConfID: confID, - ConfRequest: confRequest, - NumConfirmations: numConfs, - Event: chainntnfs.NewConfirmationEvent(numConfs, func() { - n.txNotifier.CancelConf(confRequest, confID) - }), - HeightHint: heightHint, - } - - chainntnfs.Log.Infof("New confirmation subscription: %v, num_confs=%v", - confRequest, numConfs) - // 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. - dispatch, txNotifierTip, err := n.txNotifier.RegisterConf(ntfn) + ntfn, err := n.txNotifier.RegisterConf( + txid, pkScript, numConfs, heightHint, + ) if err != nil { return nil, err } @@ -859,9 +840,7 @@ func (n *NeutrinoNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, // type so we can instruct neutrino to match if the transaction // containing the script is found in a block. params := n.p2pNode.ChainParams() - _, addrs, _, err := txscript.ExtractPkScriptAddrs( - confRequest.PkScript.Script(), ¶ms, - ) + _, addrs, _, err := txscript.ExtractPkScriptAddrs(pkScript, ¶ms) if err != nil { return nil, fmt.Errorf("unable to extract script: %v", err) } @@ -873,7 +852,7 @@ func (n *NeutrinoNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, case n.notificationRegistry <- &rescanFilterUpdate{ updateOptions: []neutrino.UpdateOption{ neutrino.AddAddrs(addrs...), - neutrino.Rewind(txNotifierTip), + neutrino.Rewind(ntfn.Height), neutrino.DisableDisconnectedNtfns(true), }, errChan: errChan, @@ -893,14 +872,14 @@ func (n *NeutrinoNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash, // If a historical rescan was not requested by the txNotifier, then we // can return to the caller. - if dispatch == nil { + if ntfn.HistoricalDispatch == nil { return ntfn.Event, nil } // Finally, with the filter updated, we can dispatch the historical // rescan to ensure we can detect if the event happened in the past. select { - case n.notificationRegistry <- dispatch: + case n.notificationRegistry <- ntfn.HistoricalDispatch: case <-n.quit: return nil, chainntnfs.ErrChainNotifierShuttingDown } diff --git a/chainntnfs/txnotifier.go b/chainntnfs/txnotifier.go index 0cc6948b..5e503f21 100644 --- a/chainntnfs/txnotifier.go +++ b/chainntnfs/txnotifier.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "sync" + "sync/atomic" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" @@ -255,6 +256,25 @@ type HistoricalConfDispatch struct { EndHeight uint32 } +// ConfRegistration encompasses all of the information required for callers to +// retrieve details about a confirmation event. +type ConfRegistration struct { + // Event contains references to the channels that the notifications are + // to be sent over. + Event *ConfirmationEvent + + // HistoricalDispatch, if non-nil, signals to the client who registered + // the notification that they are responsible for attempting to manually + // rescan blocks for the txid/output script between the start and end + // heights. + HistoricalDispatch *HistoricalConfDispatch + + // Height is the height of the TxNotifier at the time the confirmation + // notification was registered. This can be used so that backends can + // request to be notified of confirmations from this point forwards. + Height uint32 +} + // SpendRequest encapsulates a request for a spend notification of either an // outpoint or output script. type SpendRequest struct { @@ -401,6 +421,8 @@ type HistoricalSpendDispatch struct { // The TxNotifier will watch the blockchain as new blocks come in, in order to // satisfy its client requests. type TxNotifier struct { + confClientCounter uint64 // To be used atomically. + // currentHeight is the height of the tracked blockchain. It is used to // determine the number of confirmations a tx has and ensure blocks are // connected and disconnected in order. @@ -484,34 +506,60 @@ 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) { + + confRequest, err := NewConfRequest(txid, pkScript) + if err != nil { + return nil, err + } + + // Enforce that we will not dispatch confirmations beyond the reorg + // safety limit. + if numConfs > n.reorgSafetyLimit { + return nil, ErrTxMaxConfs + } + + confID := atomic.AddUint64(&n.confClientCounter, 1) + return &ConfNtfn{ + ConfID: confID, + ConfRequest: confRequest, + NumConfirmations: numConfs, + Event: NewConfirmationEvent(numConfs, func() { + n.CancelConf(confRequest, confID) + }), + HeightHint: heightHint, + }, nil +} + // RegisterConf handles a new confirmation notification request. The client will // be notified when the transaction/output script gets a sufficient number of -// confirmations in the blockchain. The registration succeeds if no error is -// returned. If the returned HistoricalConfDispatch is non-nil, the caller is -// responsible for attempting to manually rescan blocks for the txid/output -// script between the start and end heights. The notifier's current height is -// also returned so that backends can request to be notified of confirmations -// from this point forwards. +// confirmations in the blockchain. // // NOTE: If the transaction/output script has already been included in a block // on the chain, the confirmation details must be provided with the // UpdateConfDetails method, otherwise we will wait for the transaction/output // script to confirm even though it already has. -func (n *TxNotifier) RegisterConf(ntfn *ConfNtfn) (*HistoricalConfDispatch, - uint32, error) { +func (n *TxNotifier) RegisterConf(txid *chainhash.Hash, pkScript []byte, + numConfs, heightHint uint32) (*ConfRegistration, error) { select { case <-n.quit: - return nil, 0, ErrTxNotifierExiting + return nil, ErrTxNotifierExiting default: } - // Enforce that we will not dispatch confirmations beyond the reorg - // safety limit. - if ntfn.NumConfirmations > n.reorgSafetyLimit { - return nil, 0, ErrTxMaxConfs + // We'll start by performing a series of validation checks. + ntfn, err := n.newConfNtfn(txid, pkScript, numConfs, heightHint) + if err != nil { + return nil, err } + Log.Infof("New confirmation subscription: %v, num_confs=%v ", + ntfn.ConfRequest, numConfs) + // Before proceeding to register the notification, we'll query our // height hint cache to determine whether a better one exists. // @@ -557,9 +605,16 @@ func (n *TxNotifier) RegisterConf(ntfn *ConfNtfn) (*HistoricalConfDispatch, "registration since rescan has finished", ntfn.ConfRequest) - return nil, n.currentHeight, n.dispatchConfDetails( - ntfn, confSet.details, - ) + err := n.dispatchConfDetails(ntfn, confSet.details) + if err != nil { + return nil, err + } + + return &ConfRegistration{ + Event: ntfn.Event, + HistoricalDispatch: nil, + Height: n.currentHeight, + }, nil // A rescan is already in progress, return here to prevent dispatching // another. When the rescan returns, this notification's details will be @@ -568,7 +623,11 @@ func (n *TxNotifier) RegisterConf(ntfn *ConfNtfn) (*HistoricalConfDispatch, Log.Debugf("Waiting for pending rescan to finish before "+ "notifying %v at tip", ntfn.ConfRequest) - return nil, n.currentHeight, nil + return &ConfRegistration{ + Event: ntfn.Event, + HistoricalDispatch: nil, + Height: n.currentHeight, + }, nil // If no rescan has been dispatched, attempt to do so now. case rescanNotStarted: @@ -587,7 +646,11 @@ func (n *TxNotifier) RegisterConf(ntfn *ConfNtfn) (*HistoricalConfDispatch, // notifier to start delivering messages for this set // immediately. confSet.rescanStatus = rescanComplete - return nil, n.currentHeight, nil + return &ConfRegistration{ + Event: ntfn.Event, + HistoricalDispatch: nil, + Height: n.currentHeight, + }, nil } Log.Debugf("Dispatching historical confirmation rescan for %v", @@ -607,7 +670,11 @@ func (n *TxNotifier) RegisterConf(ntfn *ConfNtfn) (*HistoricalConfDispatch, // registrations don't also attempt a dispatch. confSet.rescanStatus = rescanPending - return dispatch, n.currentHeight, nil + return &ConfRegistration{ + Event: ntfn.Event, + HistoricalDispatch: dispatch, + Height: n.currentHeight, + }, nil } // CancelConf cancels an existing request for a spend notification of an diff --git a/chainntnfs/txnotifier_test.go b/chainntnfs/txnotifier_test.go index 0023e3b0..ecfc327f 100644 --- a/chainntnfs/txnotifier_test.go +++ b/chainntnfs/txnotifier_test.go @@ -136,22 +136,17 @@ func TestTxNotifierMaxConfs(t *testing.T) { // Registering one confirmation above the maximum should fail with // ErrTxMaxConfs. - ntfn := &chainntnfs.ConfNtfn{ - ConfRequest: chainntnfs.ConfRequest{ - TxID: chainntnfs.ZeroHash, - PkScript: testScript, - }, - NumConfirmations: chainntnfs.MaxNumConfs + 1, - Event: chainntnfs.NewConfirmationEvent( - chainntnfs.MaxNumConfs, nil, - ), - } - if _, _, err := n.RegisterConf(ntfn); err != chainntnfs.ErrTxMaxConfs { + _, err := n.RegisterConf( + &chainntnfs.ZeroHash, testRawScript, chainntnfs.MaxNumConfs+1, 1, + ) + if err != chainntnfs.ErrTxMaxConfs { t.Fatalf("expected chainntnfs.ErrTxMaxConfs, got %v", err) } - ntfn.NumConfirmations-- - if _, _, err := n.RegisterConf(ntfn); err != nil { + _, err = n.RegisterConf( + &chainntnfs.ZeroHash, testRawScript, chainntnfs.MaxNumConfs, 1, + ) + if err != nil { t.Fatalf("unable to register conf ntfn: %v", err) } } @@ -176,29 +171,17 @@ func TestTxNotifierFutureConfDispatch(t *testing.T) { // notifications. tx1 := wire.MsgTx{Version: 1} tx1.AddTxOut(&wire.TxOut{PkScript: testRawScript}) - ntfn1 := chainntnfs.ConfNtfn{ - ConfRequest: chainntnfs.ConfRequest{ - TxID: tx1.TxHash(), - PkScript: testScript, - }, - NumConfirmations: tx1NumConfs, - Event: chainntnfs.NewConfirmationEvent(tx1NumConfs, nil), - } - if _, _, err := n.RegisterConf(&ntfn1); err != nil { + tx1Hash := tx1.TxHash() + ntfn1, err := n.RegisterConf(&tx1Hash, testRawScript, tx1NumConfs, 1) + if err != nil { t.Fatalf("unable to register ntfn: %v", err) } tx2 := wire.MsgTx{Version: 2} tx2.AddTxOut(&wire.TxOut{PkScript: testRawScript}) - ntfn2 := chainntnfs.ConfNtfn{ - ConfRequest: chainntnfs.ConfRequest{ - TxID: tx2.TxHash(), - PkScript: testScript, - }, - NumConfirmations: tx2NumConfs, - Event: chainntnfs.NewConfirmationEvent(tx2NumConfs, nil), - } - if _, _, err := n.RegisterConf(&ntfn2); err != nil { + tx2Hash := tx2.TxHash() + ntfn2, err := n.RegisterConf(&tx2Hash, testRawScript, tx2NumConfs, 1) + if err != nil { t.Fatalf("unable to register ntfn: %v", err) } @@ -226,7 +209,7 @@ func TestTxNotifierFutureConfDispatch(t *testing.T) { Transactions: []*wire.MsgTx{&tx1, &tx2}, }) - err := n.ConnectTip(block1.Hash(), 11, block1.Transactions()) + err = n.ConnectTip(block1.Hash(), 11, block1.Transactions()) if err != nil { t.Fatalf("Failed to connect block: %v", err) } @@ -361,24 +344,14 @@ func TestTxNotifierHistoricalConfDispatch(t *testing.T) { // Create the test transactions at a height before the TxNotifier's // starting height so that they are confirmed once registering them. tx1Hash := tx1.TxHash() - ntfn1 := chainntnfs.ConfNtfn{ - ConfID: 0, - ConfRequest: chainntnfs.ConfRequest{TxID: tx1Hash}, - NumConfirmations: tx1NumConfs, - Event: chainntnfs.NewConfirmationEvent(tx1NumConfs, nil), - } - if _, _, err := n.RegisterConf(&ntfn1); err != nil { + ntfn1, err := n.RegisterConf(&tx1Hash, testRawScript, tx1NumConfs, 1) + if err != nil { t.Fatalf("unable to register ntfn: %v", err) } tx2Hash := tx2.TxHash() - ntfn2 := chainntnfs.ConfNtfn{ - ConfID: 1, - ConfRequest: chainntnfs.ConfRequest{TxID: tx2Hash}, - NumConfirmations: tx2NumConfs, - Event: chainntnfs.NewConfirmationEvent(tx2NumConfs, nil), - } - if _, _, err := n.RegisterConf(&ntfn2); err != nil { + ntfn2, err := n.RegisterConf(&tx2Hash, testRawScript, tx2NumConfs, 1) + if err != nil { t.Fatalf("unable to register ntfn: %v", err) } @@ -390,7 +363,7 @@ func TestTxNotifierHistoricalConfDispatch(t *testing.T) { TxIndex: 1, Tx: &tx1, } - err := n.UpdateConfDetails(ntfn1.ConfRequest, &txConf1) + err = n.UpdateConfDetails(ntfn1.HistoricalDispatch.ConfRequest, &txConf1) if err != nil { t.Fatalf("unable to update conf details: %v", err) } @@ -424,7 +397,7 @@ func TestTxNotifierHistoricalConfDispatch(t *testing.T) { TxIndex: 2, Tx: &tx2, } - err = n.UpdateConfDetails(ntfn2.ConfRequest, &txConf2) + err = n.UpdateConfDetails(ntfn2.HistoricalDispatch.ConfRequest, &txConf2) if err != nil { t.Fatalf("unable to update conf details: %v", err) } @@ -693,34 +666,22 @@ func TestTxNotifierMultipleHistoricalConfRescans(t *testing.T) { // The first registration for a transaction in the notifier should // request a historical confirmation rescan as it does not have a // historical view of the chain. - confNtfn1 := &chainntnfs.ConfNtfn{ - ConfID: 0, - // TODO(wilmer): set pkScript. - ConfRequest: chainntnfs.ConfRequest{TxID: chainntnfs.ZeroHash}, - Event: chainntnfs.NewConfirmationEvent(1, nil), - } - historicalConfDispatch1, _, err := n.RegisterConf(confNtfn1) + ntfn1, err := n.RegisterConf(&chainntnfs.ZeroHash, testRawScript, 1, 1) if err != nil { t.Fatalf("unable to register spend ntfn: %v", err) } - if historicalConfDispatch1 == nil { + if ntfn1.HistoricalDispatch == nil { t.Fatal("expected to receive historical dispatch request") } // We'll register another confirmation notification for the same // transaction. This should not request a historical confirmation rescan // since the first one is still pending. - confNtfn2 := &chainntnfs.ConfNtfn{ - ConfID: 1, - // TODO(wilmer): set pkScript. - ConfRequest: chainntnfs.ConfRequest{TxID: chainntnfs.ZeroHash}, - Event: chainntnfs.NewConfirmationEvent(1, nil), - } - historicalConfDispatch2, _, err := n.RegisterConf(confNtfn2) + ntfn2, err := n.RegisterConf(&chainntnfs.ZeroHash, testRawScript, 1, 1) if err != nil { t.Fatalf("unable to register spend ntfn: %v", err) } - if historicalConfDispatch2 != nil { + if ntfn2.HistoricalDispatch != nil { t.Fatal("received unexpected historical rescan request") } @@ -731,21 +692,16 @@ func TestTxNotifierMultipleHistoricalConfRescans(t *testing.T) { confDetails := &chainntnfs.TxConfirmation{ BlockHeight: startingHeight - 1, } - err = n.UpdateConfDetails(confNtfn2.ConfRequest, confDetails) + err = n.UpdateConfDetails(ntfn1.HistoricalDispatch.ConfRequest, confDetails) if err != nil { t.Fatalf("unable to update conf details: %v", err) } - confNtfn3 := &chainntnfs.ConfNtfn{ - ConfID: 2, - ConfRequest: chainntnfs.ConfRequest{TxID: chainntnfs.ZeroHash}, - Event: chainntnfs.NewConfirmationEvent(1, nil), - } - historicalConfDispatch3, _, err := n.RegisterConf(confNtfn3) + ntfn3, err := n.RegisterConf(&chainntnfs.ZeroHash, testRawScript, 1, 1) if err != nil { t.Fatalf("unable to register spend ntfn: %v", err) } - if historicalConfDispatch3 != nil { + if ntfn3.HistoricalDispatch != nil { t.Fatal("received unexpected historical rescan request") } } @@ -848,23 +804,16 @@ func TestTxNotifierMultipleHistoricalNtfns(t *testing.T) { var txid chainhash.Hash copy(txid[:], bytes.Repeat([]byte{0x01}, 32)) - confRequest := chainntnfs.ConfRequest{ - // TODO(wilmer): set pkScript. - TxID: txid, - } // We'll start off by registered 5 clients for a confirmation // notification on the same transaction. - confNtfns := make([]*chainntnfs.ConfNtfn, numNtfns) + confNtfns := make([]*chainntnfs.ConfRegistration, numNtfns) for i := uint64(0); i < numNtfns; i++ { - confNtfns[i] = &chainntnfs.ConfNtfn{ - ConfID: i, - ConfRequest: confRequest, - Event: chainntnfs.NewConfirmationEvent(1, nil), - } - if _, _, err := n.RegisterConf(confNtfns[i]); err != nil { + ntfn, err := n.RegisterConf(&txid, testRawScript, 1, 1) + if err != nil { t.Fatalf("unable to register conf ntfn #%d: %v", i, err) } + confNtfns[i] = ntfn } // Ensure none of them have received the confirmation details. @@ -884,7 +833,9 @@ func TestTxNotifierMultipleHistoricalNtfns(t *testing.T) { BlockHeight: startingHeight - 1, Tx: wire.NewMsgTx(1), } - err := n.UpdateConfDetails(confNtfns[0].ConfRequest, expectedConfDetails) + err := n.UpdateConfDetails( + confNtfns[0].HistoricalDispatch.ConfRequest, expectedConfDetails, + ) if err != nil { t.Fatalf("unable to update conf details: %v", err) } @@ -905,16 +856,11 @@ func TestTxNotifierMultipleHistoricalNtfns(t *testing.T) { // we'll register another client for the same transaction. We should not // see a historical rescan request and the confirmation notification // should come through immediately. - extraConfNtfn := &chainntnfs.ConfNtfn{ - ConfID: numNtfns + 1, - ConfRequest: confRequest, - Event: chainntnfs.NewConfirmationEvent(1, nil), - } - historicalConfRescan, _, err := n.RegisterConf(extraConfNtfn) + extraConfNtfn, err := n.RegisterConf(&txid, testRawScript, 1, 1) if err != nil { t.Fatalf("unable to register conf ntfn: %v", err) } - if historicalConfRescan != nil { + if extraConfNtfn.HistoricalDispatch != nil { t.Fatal("received unexpected historical rescan request") } @@ -1016,31 +962,17 @@ func TestTxNotifierCancelConf(t *testing.T) { // canceled. tx1 := wire.NewMsgTx(1) tx1.AddTxOut(&wire.TxOut{PkScript: testRawScript}) - ntfn1 := &chainntnfs.ConfNtfn{ - ConfID: 1, - ConfRequest: chainntnfs.ConfRequest{ - TxID: tx1.TxHash(), - PkScript: testScript, - }, - NumConfirmations: 1, - Event: chainntnfs.NewConfirmationEvent(1, nil), - } - if _, _, err := n.RegisterConf(ntfn1); err != nil { + tx1Hash := tx1.TxHash() + ntfn1, err := n.RegisterConf(&tx1Hash, testRawScript, 1, 1) + if err != nil { t.Fatalf("unable to register spend ntfn: %v", err) } tx2 := wire.NewMsgTx(2) tx2.AddTxOut(&wire.TxOut{PkScript: testRawScript}) - ntfn2 := &chainntnfs.ConfNtfn{ - ConfID: 2, - ConfRequest: chainntnfs.ConfRequest{ - TxID: tx2.TxHash(), - PkScript: testScript, - }, - NumConfirmations: 1, - Event: chainntnfs.NewConfirmationEvent(1, nil), - } - if _, _, err := n.RegisterConf(ntfn2); err != nil { + tx2Hash := tx2.TxHash() + ntfn2, err := n.RegisterConf(&tx2Hash, testRawScript, 1, 1) + if err != nil { t.Fatalf("unable to register spend ntfn: %v", err) } @@ -1057,9 +989,9 @@ func TestTxNotifierCancelConf(t *testing.T) { // Before extending the notifier's tip with the block above, we'll // cancel the second request. - n.CancelConf(ntfn2.ConfRequest, ntfn2.ConfID) + n.CancelConf(ntfn2.HistoricalDispatch.ConfRequest, 2) - err := n.ConnectTip(block.Hash(), startingHeight+1, block.Transactions()) + err = n.ConnectTip(block.Hash(), startingHeight+1, block.Transactions()) if err != nil { t.Fatalf("unable to connect block: %v", err) } @@ -1200,60 +1132,42 @@ func TestTxNotifierConfReorg(t *testing.T) { // Tx 1 will be confirmed in block 9 and requires 2 confs. tx1 := wire.MsgTx{Version: 1} tx1.AddTxOut(&wire.TxOut{PkScript: testRawScript}) - ntfn1 := chainntnfs.ConfNtfn{ - ConfID: 1, - ConfRequest: chainntnfs.ConfRequest{ - TxID: tx1.TxHash(), - PkScript: testScript, - }, - NumConfirmations: tx1NumConfs, - Event: chainntnfs.NewConfirmationEvent(tx1NumConfs, nil), - } - if _, _, err := n.RegisterConf(&ntfn1); err != nil { + tx1Hash := tx1.TxHash() + ntfn1, err := n.RegisterConf(&tx1Hash, testRawScript, tx1NumConfs, 1) + if err != nil { t.Fatalf("unable to register ntfn: %v", err) } - if err := n.UpdateConfDetails(ntfn1.ConfRequest, nil); err != nil { + err = n.UpdateConfDetails(ntfn1.HistoricalDispatch.ConfRequest, nil) + if err != nil { t.Fatalf("unable to deliver conf details: %v", err) } // Tx 2 will be confirmed in block 10 and requires 1 conf. tx2 := wire.MsgTx{Version: 2} tx2.AddTxOut(&wire.TxOut{PkScript: testRawScript}) - ntfn2 := chainntnfs.ConfNtfn{ - ConfID: 2, - ConfRequest: chainntnfs.ConfRequest{ - TxID: tx2.TxHash(), - PkScript: testScript, - }, - NumConfirmations: tx2NumConfs, - Event: chainntnfs.NewConfirmationEvent(tx2NumConfs, nil), - } - if _, _, err := n.RegisterConf(&ntfn2); err != nil { + tx2Hash := tx2.TxHash() + ntfn2, err := n.RegisterConf(&tx2Hash, testRawScript, tx2NumConfs, 1) + if err != nil { t.Fatalf("unable to register ntfn: %v", err) } - if err := n.UpdateConfDetails(ntfn2.ConfRequest, nil); err != nil { + err = n.UpdateConfDetails(ntfn2.HistoricalDispatch.ConfRequest, nil) + if err != nil { t.Fatalf("unable to deliver conf details: %v", err) } // Tx 3 will be confirmed in block 10 and requires 2 confs. tx3 := wire.MsgTx{Version: 3} tx3.AddTxOut(&wire.TxOut{PkScript: testRawScript}) - ntfn3 := chainntnfs.ConfNtfn{ - ConfID: 3, - ConfRequest: chainntnfs.ConfRequest{ - TxID: tx3.TxHash(), - PkScript: testScript, - }, - NumConfirmations: tx3NumConfs, - Event: chainntnfs.NewConfirmationEvent(tx3NumConfs, nil), - } - if _, _, err := n.RegisterConf(&ntfn3); err != nil { + tx3Hash := tx3.TxHash() + ntfn3, err := n.RegisterConf(&tx3Hash, testRawScript, tx3NumConfs, 1) + if err != nil { t.Fatalf("unable to register ntfn: %v", err) } - if err := n.UpdateConfDetails(ntfn3.ConfRequest, nil); err != nil { + err = n.UpdateConfDetails(ntfn3.HistoricalDispatch.ConfRequest, nil) + if err != nil { t.Fatalf("unable to deliver conf details: %v", err) } @@ -1397,7 +1311,7 @@ func TestTxNotifierConfReorg(t *testing.T) { }) block4 := btcutil.NewBlock(&wire.MsgBlock{}) - err := n.ConnectTip(block3.Hash(), 12, block3.Transactions()) + err = n.ConnectTip(block3.Hash(), 12, block3.Transactions()) if err != nil { t.Fatalf("Failed to connect block: %v", err) } @@ -1726,45 +1640,30 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { // Create two test transactions and register them for notifications. tx1 := wire.MsgTx{Version: 1} tx1.AddTxOut(&wire.TxOut{PkScript: testRawScript}) - ntfn1 := &chainntnfs.ConfNtfn{ - ConfID: 1, - ConfRequest: chainntnfs.ConfRequest{ - TxID: tx1.TxHash(), - PkScript: testScript, - }, - NumConfirmations: 1, - Event: chainntnfs.NewConfirmationEvent(1, nil), + tx1Hash := tx1.TxHash() + ntfn1, err := n.RegisterConf(&tx1Hash, testRawScript, 1, 1) + if err != nil { + t.Fatalf("unable to register tx1: %v", err) } tx2 := wire.MsgTx{Version: 2} tx2.AddTxOut(&wire.TxOut{PkScript: testRawScript}) - ntfn2 := &chainntnfs.ConfNtfn{ - ConfID: 2, - ConfRequest: chainntnfs.ConfRequest{ - TxID: tx2.TxHash(), - PkScript: testScript, - }, - NumConfirmations: 2, - Event: chainntnfs.NewConfirmationEvent(2, nil), - } - - if _, _, err := n.RegisterConf(ntfn1); err != nil { - t.Fatalf("unable to register tx1: %v", err) - } - if _, _, err := n.RegisterConf(ntfn2); err != nil { + tx2Hash := tx2.TxHash() + ntfn2, err := n.RegisterConf(&tx2Hash, testRawScript, 2, 1) + if err != nil { t.Fatalf("unable to register tx2: %v", err) } // Both transactions should not have a height hint set, as RegisterConf // should not alter the cache state. - _, err := hintCache.QueryConfirmHint(ntfn1.ConfRequest) + _, err = hintCache.QueryConfirmHint(ntfn1.HistoricalDispatch.ConfRequest) if err != chainntnfs.ErrConfirmHintNotFound { t.Fatalf("unexpected error when querying for height hint "+ "want: %v, got %v", chainntnfs.ErrConfirmHintNotFound, err) } - _, err = hintCache.QueryConfirmHint(ntfn2.ConfRequest) + _, err = hintCache.QueryConfirmHint(ntfn2.HistoricalDispatch.ConfRequest) if err != chainntnfs.ErrConfirmHintNotFound { t.Fatalf("unexpected error when querying for height hint "+ "want: %v, got %v", @@ -1790,14 +1689,14 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { // the height hints should remain unchanged. This simulates blocks // confirming while the historical dispatch is processing the // registration. - hint, err := hintCache.QueryConfirmHint(ntfn1.ConfRequest) + hint, err := hintCache.QueryConfirmHint(ntfn1.HistoricalDispatch.ConfRequest) if err != chainntnfs.ErrConfirmHintNotFound { t.Fatalf("unexpected error when querying for height hint "+ "want: %v, got %v", chainntnfs.ErrConfirmHintNotFound, err) } - hint, err = hintCache.QueryConfirmHint(ntfn2.ConfRequest) + hint, err = hintCache.QueryConfirmHint(ntfn2.HistoricalDispatch.ConfRequest) if err != chainntnfs.ErrConfirmHintNotFound { t.Fatalf("unexpected error when querying for height hint "+ "want: %v, got %v", @@ -1806,10 +1705,12 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { // Now, update the conf details reporting that the neither txn was found // in the historical dispatch. - if err := n.UpdateConfDetails(ntfn1.ConfRequest, nil); err != nil { + err = n.UpdateConfDetails(ntfn1.HistoricalDispatch.ConfRequest, nil) + if err != nil { t.Fatalf("unable to update conf details: %v", err) } - if err := n.UpdateConfDetails(ntfn2.ConfRequest, nil); err != nil { + err = n.UpdateConfDetails(ntfn2.HistoricalDispatch.ConfRequest, nil) + if err != nil { t.Fatalf("unable to update conf details: %v", err) } @@ -1830,7 +1731,7 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { // Now that both notifications are waiting at tip for confirmations, // they should have their height hints updated to the latest block // height. - hint, err = hintCache.QueryConfirmHint(ntfn1.ConfRequest) + hint, err = hintCache.QueryConfirmHint(ntfn1.HistoricalDispatch.ConfRequest) if err != nil { t.Fatalf("unable to query for hint: %v", err) } @@ -1839,7 +1740,7 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { tx1Height, hint) } - hint, err = hintCache.QueryConfirmHint(ntfn2.ConfRequest) + hint, err = hintCache.QueryConfirmHint(ntfn2.HistoricalDispatch.ConfRequest) if err != nil { t.Fatalf("unable to query for hint: %v", err) } @@ -1863,7 +1764,7 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { } // The height hint for the first transaction should remain the same. - hint, err = hintCache.QueryConfirmHint(ntfn1.ConfRequest) + hint, err = hintCache.QueryConfirmHint(ntfn1.HistoricalDispatch.ConfRequest) if err != nil { t.Fatalf("unable to query for hint: %v", err) } @@ -1874,7 +1775,7 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { // The height hint for the second transaction should now be updated to // reflect its confirmation. - hint, err = hintCache.QueryConfirmHint(ntfn2.ConfRequest) + hint, err = hintCache.QueryConfirmHint(ntfn2.HistoricalDispatch.ConfRequest) if err != nil { t.Fatalf("unable to query for hint: %v", err) } @@ -1891,7 +1792,7 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { // This should update the second transaction's height hint within the // cache to the previous height. - hint, err = hintCache.QueryConfirmHint(ntfn2.ConfRequest) + hint, err = hintCache.QueryConfirmHint(ntfn2.HistoricalDispatch.ConfRequest) if err != nil { t.Fatalf("unable to query for hint: %v", err) } @@ -1902,7 +1803,7 @@ func TestTxNotifierConfirmHintCache(t *testing.T) { // The first transaction's height hint should remain at the original // confirmation height. - hint, err = hintCache.QueryConfirmHint(ntfn2.ConfRequest) + hint, err = hintCache.QueryConfirmHint(ntfn2.HistoricalDispatch.ConfRequest) if err != nil { t.Fatalf("unable to query for hint: %v", err) } @@ -2122,16 +2023,8 @@ func TestTxNotifierNtfnDone(t *testing.T) { // We'll start by creating two notification requests: one confirmation // and one spend. - confNtfn := &chainntnfs.ConfNtfn{ - ConfID: 1, - ConfRequest: chainntnfs.ConfRequest{ - TxID: chainntnfs.ZeroHash, - PkScript: testScript, - }, - NumConfirmations: 1, - Event: chainntnfs.NewConfirmationEvent(1, nil), - } - if _, _, err := n.RegisterConf(confNtfn); err != nil { + confNtfn, err := n.RegisterConf(&chainntnfs.ZeroHash, testRawScript, 1, 1) + if err != nil { t.Fatalf("unable to register conf ntfn: %v", err) } @@ -2160,7 +2053,7 @@ func TestTxNotifierNtfnDone(t *testing.T) { Transactions: []*wire.MsgTx{tx, spendTx}, }) - err := n.ConnectTip(block.Hash(), 11, block.Transactions()) + err = n.ConnectTip(block.Hash(), 11, block.Transactions()) if err != nil { t.Fatalf("unable to connect block: %v", err) } @@ -2268,13 +2161,8 @@ func TestTxNotifierTearDown(t *testing.T) { // To begin the test, we'll register for a confirmation and spend // notification. - confNtfn := &chainntnfs.ConfNtfn{ - ConfID: 1, - ConfRequest: chainntnfs.ConfRequest{TxID: chainntnfs.ZeroHash}, - NumConfirmations: 1, - Event: chainntnfs.NewConfirmationEvent(1, nil), - } - if _, _, err := n.RegisterConf(confNtfn); err != nil { + confNtfn, err := n.RegisterConf(&chainntnfs.ZeroHash, testRawScript, 1, 1) + if err != nil { t.Fatalf("unable to register conf ntfn: %v", err) } @@ -2320,7 +2208,8 @@ func TestTxNotifierTearDown(t *testing.T) { // Now that the notifier is torn down, we should no longer be able to // register notification requests. - if _, _, err := n.RegisterConf(confNtfn); err == nil { + _, err = n.RegisterConf(&chainntnfs.ZeroHash, testRawScript, 1, 1) + if err == nil { t.Fatal("expected confirmation registration to fail") } if _, _, err := n.RegisterSpend(spendNtfn); err == nil {