chainntnfs: refactor common registration code within RegisterSpendNtfn

This commit is contained in:
Wilmer Paulino 2019-08-16 19:56:26 -07:00
parent 5089311ca1
commit 7821eb6ffb
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F
5 changed files with 240 additions and 287 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/chain"
@ -39,7 +40,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 {
spendClientCounter uint64 // To be used atomically.
epochClientCounter uint64 // To be used atomically.
started int32 // To be used atomically.
@ -615,23 +615,11 @@ func (b *BitcoindNotifier) notifyBlockEpochClient(epochClient *blockEpochRegistr
func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
pkScript []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
// First, we'll construct a spend notification request and hand it off
// to the txNotifier.
spendID := atomic.AddUint64(&b.spendClientCounter, 1)
spendRequest, err := chainntnfs.NewSpendRequest(outpoint, pkScript)
if err != nil {
return nil, err
}
ntfn := &chainntnfs.SpendNtfn{
SpendID: spendID,
SpendRequest: spendRequest,
Event: chainntnfs.NewSpendEvent(func() {
b.txNotifier.CancelSpend(spendRequest, spendID)
}),
HeightHint: heightHint,
}
historicalDispatch, _, err := b.txNotifier.RegisterSpend(ntfn)
// 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.RegisterSpend(outpoint, pkScript, heightHint)
if err != nil {
return nil, err
}
@ -640,17 +628,18 @@ func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// outpoint/output script as spent.
//
// TODO(wilmer): use LoadFilter API instead.
if spendRequest.OutPoint == chainntnfs.ZeroOutPoint {
addr, err := spendRequest.PkScript.Address(b.chainParams)
if outpoint == nil || *outpoint == chainntnfs.ZeroOutPoint {
_, addrs, _, err := txscript.ExtractPkScriptAddrs(
pkScript, b.chainParams,
)
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to parse script: %v", err)
}
addrs := []btcutil.Address{addr}
if err := b.chainConn.NotifyReceived(addrs); err != nil {
return nil, err
}
} else {
ops := []*wire.OutPoint{&spendRequest.OutPoint}
ops := []*wire.OutPoint{outpoint}
if err := b.chainConn.NotifySpent(ops); err != nil {
return nil, err
}
@ -659,7 +648,7 @@ func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// If the txNotifier didn't return any details to perform a historical
// scan of the chain, then we can return early as there's nothing left
// for us to do.
if historicalDispatch == nil {
if ntfn.HistoricalDispatch == nil {
return ntfn.Event, nil
}
@ -669,9 +658,9 @@ func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// We'll short-circuit the path when dispatching the spend of a script,
// rather than an outpoint, as there aren't any additional checks we can
// make for scripts.
if spendRequest.OutPoint == chainntnfs.ZeroOutPoint {
if ntfn.HistoricalDispatch.OutPoint == chainntnfs.ZeroOutPoint {
select {
case b.notificationRegistry <- historicalDispatch:
case b.notificationRegistry <- ntfn.HistoricalDispatch:
case <-b.quit:
return nil, chainntnfs.ErrChainNotifierShuttingDown
}
@ -686,16 +675,16 @@ func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// We'll start by checking the backend's UTXO set to determine whether
// the outpoint has been spent. If it hasn't, we can return to the
// caller as well.
txOut, err := b.chainConn.GetTxOut(
&spendRequest.OutPoint.Hash, spendRequest.OutPoint.Index, true,
)
txOut, err := b.chainConn.GetTxOut(&outpoint.Hash, outpoint.Index, true)
if err != nil {
return nil, err
}
if txOut != nil {
// We'll let the txNotifier know the outpoint is still unspent
// in order to begin updating its spend hint.
err := b.txNotifier.UpdateSpendDetails(spendRequest, nil)
err := b.txNotifier.UpdateSpendDetails(
ntfn.HistoricalDispatch.SpendRequest, nil,
)
if err != nil {
return nil, err
}
@ -710,14 +699,14 @@ func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// index (if enabled) to determine if we have a better rescan starting
// height. We can do this as the GetRawTransaction call will return the
// hash of the block it was included in within the chain.
tx, err := b.chainConn.GetRawTransactionVerbose(&spendRequest.OutPoint.Hash)
tx, err := b.chainConn.GetRawTransactionVerbose(&outpoint.Hash)
if err != nil {
// Avoid returning an error if the transaction was not found to
// proceed with fallback methods.
jsonErr, ok := err.(*btcjson.RPCError)
if !ok || jsonErr.Code != btcjson.ErrRPCNoTxInfo {
return nil, fmt.Errorf("unable to query for txid %v: %v",
spendRequest.OutPoint.Hash, err)
outpoint.Hash, err)
}
}
@ -740,15 +729,15 @@ func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
return nil, err
}
if uint32(blockHeight) > historicalDispatch.StartHeight {
historicalDispatch.StartHeight = uint32(blockHeight)
if uint32(blockHeight) > ntfn.HistoricalDispatch.StartHeight {
ntfn.HistoricalDispatch.StartHeight = uint32(blockHeight)
}
}
// Now that we've determined the starting point of our rescan, we can
// dispatch it and return.
select {
case b.notificationRegistry <- historicalDispatch:
case b.notificationRegistry <- ntfn.HistoricalDispatch:
case <-b.quit:
return nil, chainntnfs.ErrChainNotifierShuttingDown
}

View File

@ -11,6 +11,7 @@ import (
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/chainntnfs"
@ -50,7 +51,6 @@ type txUpdate struct {
// notifications. Multiple concurrent clients are supported. All notifications
// are achieved via non-blocking sends on client channels.
type BtcdNotifier struct {
spendClientCounter uint64 // To be used atomically.
epochClientCounter uint64 // To be used atomically.
started int32 // To be used atomically.
@ -651,23 +651,11 @@ func (b *BtcdNotifier) notifyBlockEpochClient(epochClient *blockEpochRegistratio
func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
pkScript []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
// First, we'll construct a spend notification request and hand it off
// to the txNotifier.
spendID := atomic.AddUint64(&b.spendClientCounter, 1)
spendRequest, err := chainntnfs.NewSpendRequest(outpoint, pkScript)
if err != nil {
return nil, err
}
ntfn := &chainntnfs.SpendNtfn{
SpendID: spendID,
SpendRequest: spendRequest,
Event: chainntnfs.NewSpendEvent(func() {
b.txNotifier.CancelSpend(spendRequest, spendID)
}),
HeightHint: heightHint,
}
historicalDispatch, _, err := b.txNotifier.RegisterSpend(ntfn)
// 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.RegisterSpend(outpoint, pkScript, heightHint)
if err != nil {
return nil, err
}
@ -676,17 +664,18 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// outpoint/output script as spent.
//
// TODO(wilmer): use LoadFilter API instead.
if spendRequest.OutPoint == chainntnfs.ZeroOutPoint {
addr, err := spendRequest.PkScript.Address(b.chainParams)
if outpoint == nil || *outpoint == chainntnfs.ZeroOutPoint {
_, addrs, _, err := txscript.ExtractPkScriptAddrs(
pkScript, b.chainParams,
)
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to parse script: %v", err)
}
addrs := []btcutil.Address{addr}
if err := b.chainConn.NotifyReceived(addrs); err != nil {
return nil, err
}
} else {
ops := []*wire.OutPoint{&spendRequest.OutPoint}
ops := []*wire.OutPoint{outpoint}
if err := b.chainConn.NotifySpent(ops); err != nil {
return nil, err
}
@ -695,7 +684,7 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// If the txNotifier didn't return any details to perform a historical
// scan of the chain, then we can return early as there's nothing left
// for us to do.
if historicalDispatch == nil {
if ntfn.HistoricalDispatch == nil {
return ntfn.Event, nil
}
@ -705,26 +694,29 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// We'll short-circuit the path when dispatching the spend of a script,
// rather than an outpoint, as there aren't any additional checks we can
// make for scripts.
if spendRequest.OutPoint == chainntnfs.ZeroOutPoint {
if outpoint == nil || *outpoint == chainntnfs.ZeroOutPoint {
startHash, err := b.chainConn.GetBlockHash(
int64(historicalDispatch.StartHeight),
int64(ntfn.HistoricalDispatch.StartHeight),
)
if err != nil {
return nil, err
}
// TODO(wilmer): add retry logic if rescan fails?
addr, err := spendRequest.PkScript.Address(b.chainParams)
_, addrs, _, err := txscript.ExtractPkScriptAddrs(
pkScript, b.chainParams,
)
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to parse address: %v", err)
}
addrs := []btcutil.Address{addr}
asyncResult := b.chainConn.RescanAsync(startHash, addrs, nil)
go func() {
if rescanErr := asyncResult.Receive(); rescanErr != nil {
chainntnfs.Log.Errorf("Rescan to determine "+
"the spend details of %v failed: %v",
spendRequest, rescanErr)
ntfn.HistoricalDispatch.SpendRequest,
rescanErr)
}
}()
@ -738,16 +730,16 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// We'll start by checking the backend's UTXO set to determine whether
// the outpoint has been spent. If it hasn't, we can return to the
// caller as well.
txOut, err := b.chainConn.GetTxOut(
&spendRequest.OutPoint.Hash, spendRequest.OutPoint.Index, true,
)
txOut, err := b.chainConn.GetTxOut(&outpoint.Hash, outpoint.Index, true)
if err != nil {
return nil, err
}
if txOut != nil {
// We'll let the txNotifier know the outpoint is still unspent
// in order to begin updating its spend hint.
err := b.txNotifier.UpdateSpendDetails(spendRequest, nil)
err := b.txNotifier.UpdateSpendDetails(
ntfn.HistoricalDispatch.SpendRequest, nil,
)
if err != nil {
return nil, err
}
@ -759,25 +751,25 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// set, we'll determine when it happened by scanning the chain. We'll
// begin by fetching the block hash of our starting height.
startHash, err := b.chainConn.GetBlockHash(
int64(historicalDispatch.StartHeight),
int64(ntfn.HistoricalDispatch.StartHeight),
)
if err != nil {
return nil, fmt.Errorf("unable to get block hash for height "+
"%d: %v", historicalDispatch.StartHeight, err)
"%d: %v", ntfn.HistoricalDispatch.StartHeight, err)
}
// As a minimal optimization, we'll query the backend's transaction
// index (if enabled) to determine if we have a better rescan starting
// height. We can do this as the GetRawTransaction call will return the
// hash of the block it was included in within the chain.
tx, err := b.chainConn.GetRawTransactionVerbose(&spendRequest.OutPoint.Hash)
tx, err := b.chainConn.GetRawTransactionVerbose(&outpoint.Hash)
if err != nil {
// Avoid returning an error if the transaction was not found to
// proceed with fallback methods.
jsonErr, ok := err.(*btcjson.RPCError)
if !ok || jsonErr.Code != btcjson.ErrRPCNoTxInfo {
return nil, fmt.Errorf("unable to query for txid %v: %v",
spendRequest.OutPoint.Hash, err)
outpoint.Hash, err)
}
}
@ -801,7 +793,7 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
"block %v: %v", blockHash, err)
}
if uint32(blockHeader.Height) > historicalDispatch.StartHeight {
if uint32(blockHeader.Height) > ntfn.HistoricalDispatch.StartHeight {
startHash, err = b.chainConn.GetBlockHash(
int64(blockHeader.Height),
)
@ -824,13 +816,12 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
//
// TODO(wilmer): add retry logic if rescan fails?
asyncResult := b.chainConn.RescanAsync(
startHash, nil, []*wire.OutPoint{&spendRequest.OutPoint},
startHash, nil, []*wire.OutPoint{outpoint},
)
go func() {
if rescanErr := asyncResult.Receive(); rescanErr != nil {
chainntnfs.Log.Errorf("Rescan to determine the spend "+
"details of %v failed: %v", spendRequest,
rescanErr)
"details of %v failed: %v", outpoint, rescanErr)
}
}()

View File

@ -37,7 +37,6 @@ const (
// TODO(roasbeef): heavily consolidate with NeutrinoNotifier code
// * maybe combine into single package?
type NeutrinoNotifier struct {
spendClientCounter uint64 // To be used atomically.
epochClientCounter uint64 // To be used atomically.
started int32 // To be used atomically.
@ -662,23 +661,11 @@ func (n *NeutrinoNotifier) notifyBlockEpochClient(epochClient *blockEpochRegistr
func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
pkScript []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
// First, we'll construct a spend notification request and hand it off
// to the txNotifier.
spendID := atomic.AddUint64(&n.spendClientCounter, 1)
spendRequest, err := chainntnfs.NewSpendRequest(outpoint, pkScript)
if err != nil {
return nil, err
}
ntfn := &chainntnfs.SpendNtfn{
SpendID: spendID,
SpendRequest: spendRequest,
Event: chainntnfs.NewSpendEvent(func() {
n.txNotifier.CancelSpend(spendRequest, spendID)
}),
HeightHint: heightHint,
}
historicalDispatch, txNotifierTip, err := n.txNotifier.RegisterSpend(ntfn)
// 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.RegisterSpend(outpoint, pkScript, heightHint)
if err != nil {
return nil, err
}
@ -690,9 +677,12 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
//
// We'll update our filter first to ensure we can immediately detect the
// spend at tip.
if outpoint == nil {
outpoint = &chainntnfs.ZeroOutPoint
}
inputToWatch := neutrino.InputWithScript{
OutPoint: spendRequest.OutPoint,
PkScript: spendRequest.PkScript.Script(),
OutPoint: *outpoint,
PkScript: pkScript,
}
updateOptions := []neutrino.UpdateOption{
neutrino.AddInputs(inputToWatch),
@ -703,10 +693,9 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// update. In the case of an output script spend request, we'll check if
// we should perform a historical rescan and start from there, as we
// cannot do so with GetUtxo since it matches outpoints.
rewindHeight := txNotifierTip
if historicalDispatch != nil &&
spendRequest.OutPoint == chainntnfs.ZeroOutPoint {
rewindHeight = historicalDispatch.StartHeight
rewindHeight := ntfn.Height
if ntfn.HistoricalDispatch != nil && *outpoint == chainntnfs.ZeroOutPoint {
rewindHeight = ntfn.HistoricalDispatch.StartHeight
}
updateOptions = append(updateOptions, neutrino.Rewind(rewindHeight))
@ -733,8 +722,7 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// scan of the chain, or if we already performed one like in the case of
// output script spend requests, then we can return early as there's
// nothing left for us to do.
if historicalDispatch == nil ||
spendRequest.OutPoint == chainntnfs.ZeroOutPoint {
if ntfn.HistoricalDispatch == nil || *outpoint == chainntnfs.ZeroOutPoint {
return ntfn.Event, nil
}
@ -752,7 +740,7 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
currentHeight := uint32(n.bestBlock.Height)
n.bestBlockMtx.RUnlock()
if currentHeight >= historicalDispatch.StartHeight {
if currentHeight >= ntfn.HistoricalDispatch.StartHeight {
break
}
@ -766,10 +754,10 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
spendReport, err := n.p2pNode.GetUtxo(
neutrino.WatchInputs(inputToWatch),
neutrino.StartBlock(&waddrmgr.BlockStamp{
Height: int32(historicalDispatch.StartHeight),
Height: int32(ntfn.HistoricalDispatch.StartHeight),
}),
neutrino.EndBlock(&waddrmgr.BlockStamp{
Height: int32(historicalDispatch.EndHeight),
Height: int32(ntfn.HistoricalDispatch.EndHeight),
}),
neutrino.QuitChan(n.quit),
)
@ -784,7 +772,7 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
if spendReport != nil && spendReport.SpendingTx != nil {
spendingTxHash := spendReport.SpendingTx.TxHash()
spendDetails = &chainntnfs.SpendDetail{
SpentOutPoint: &spendRequest.OutPoint,
SpentOutPoint: outpoint,
SpenderTxHash: &spendingTxHash,
SpendingTx: spendReport.SpendingTx,
SpenderInputIndex: spendReport.SpendingInputIndex,
@ -796,7 +784,9 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
// not, we'll mark our historical rescan as complete to ensure the
// outpoint's spend hint gets updated upon connected/disconnected
// blocks.
err = n.txNotifier.UpdateSpendDetails(spendRequest, spendDetails)
err = n.txNotifier.UpdateSpendDetails(
ntfn.HistoricalDispatch.SpendRequest, spendDetails,
)
if err != nil {
chainntnfs.Log.Errorf("Failed to update spend details: %v", err)
return

View File

@ -415,13 +415,33 @@ type HistoricalSpendDispatch struct {
EndHeight uint32
}
// SpendRegistration encompasses all of the information required for callers to
// retrieve details about a spend event.
type SpendRegistration struct {
// Event contains references to the channels that the notifications are
// to be sent over.
Event *SpendEvent
// 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 *HistoricalSpendDispatch
// Height is the height of the TxNotifier at the time the spend
// notification was registered. This can be used so that backends can
// request to be notified of spends from this point forwards.
Height uint32
}
// TxNotifier is a struct responsible for delivering transaction notifications
// to subscribers. These notifications can be of two different types:
// transaction/output script confirmations and/or outpoint/output script spends.
// 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.
confClientCounter uint64 // To be used atomically.
spendClientCounter 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
@ -885,29 +905,50 @@ func (n *TxNotifier) dispatchConfDetails(
return nil
}
// newSpendNtfn validates all of the parameters required to successfully create
// and register a spend notification.
func (n *TxNotifier) newSpendNtfn(outpoint *wire.OutPoint,
pkScript []byte, heightHint uint32) (*SpendNtfn, error) {
spendRequest, err := NewSpendRequest(outpoint, pkScript)
if err != nil {
return nil, err
}
spendID := atomic.AddUint64(&n.spendClientCounter, 1)
return &SpendNtfn{
SpendID: spendID,
SpendRequest: spendRequest,
Event: NewSpendEvent(func() {
n.CancelSpend(spendRequest, spendID)
}),
HeightHint: heightHint,
}, nil
}
// RegisterSpend handles a new spend notification request. The client will be
// notified once the outpoint/output script is detected as spent within the
// chain.
//
// The registration succeeds if no error is returned. If the returned
// HistoricalSpendDisaptch is non-nil, the caller is responsible for attempting
// to determine whether the outpoint/output script has been spent between the
// start and end heights. The notifier's current height is also returned so that
// backends can request to be notified of spends from this point forwards.
//
// NOTE: If the outpoint/output script has already been spent within the chain
// before the notifier's current tip, the spend details must be provided with
// the UpdateSpendDetails method, otherwise we will wait for the outpoint/output
// script to be spent at tip, even though it already has.
func (n *TxNotifier) RegisterSpend(ntfn *SpendNtfn) (*HistoricalSpendDispatch,
uint32, error) {
func (n *TxNotifier) RegisterSpend(outpoint *wire.OutPoint, pkScript []byte,
heightHint uint32) (*SpendRegistration, error) {
select {
case <-n.quit:
return nil, 0, ErrTxNotifierExiting
return nil, ErrTxNotifierExiting
default:
}
// We'll start by performing a series of validation checks.
ntfn, err := n.newSpendNtfn(outpoint, pkScript, heightHint)
if err != nil {
return nil, err
}
// Before proceeding to register the notification, we'll query our spend
// hint cache to determine whether a better one exists.
startHeight := ntfn.HeightHint
@ -953,9 +994,16 @@ func (n *TxNotifier) RegisterSpend(ntfn *SpendNtfn) (*HistoricalSpendDispatch,
"registration since rescan has finished",
ntfn.SpendRequest)
return nil, n.currentHeight, n.dispatchSpendDetails(
ntfn, spendSet.details,
)
err := n.dispatchSpendDetails(ntfn, spendSet.details)
if err != nil {
return nil, err
}
return &SpendRegistration{
Event: ntfn.Event,
HistoricalDispatch: nil,
Height: n.currentHeight,
}, nil
// If there is an active rescan to determine whether the request has
// been spent, then we won't trigger another one.
@ -963,7 +1011,11 @@ func (n *TxNotifier) RegisterSpend(ntfn *SpendNtfn) (*HistoricalSpendDispatch,
Log.Debugf("Waiting for pending rescan to finish before "+
"notifying %v at tip", ntfn.SpendRequest)
return nil, n.currentHeight, nil
return &SpendRegistration{
Event: ntfn.Event,
HistoricalDispatch: nil,
Height: n.currentHeight,
}, nil
// Otherwise, we'll fall through and let the caller know that a rescan
// should be dispatched to determine whether the request has already
@ -983,7 +1035,11 @@ func (n *TxNotifier) RegisterSpend(ntfn *SpendNtfn) (*HistoricalSpendDispatch,
// spend hints for this request get updated upon
// connected/disconnected blocks.
spendSet.rescanStatus = rescanComplete
return nil, n.currentHeight, nil
return &SpendRegistration{
Event: ntfn.Event,
HistoricalDispatch: nil,
Height: n.currentHeight,
}, nil
}
// We'll set the rescan status to pending to ensure subsequent
@ -993,11 +1049,15 @@ func (n *TxNotifier) RegisterSpend(ntfn *SpendNtfn) (*HistoricalSpendDispatch,
Log.Debugf("Dispatching historical spend rescan for %v",
ntfn.SpendRequest)
return &HistoricalSpendDispatch{
SpendRequest: ntfn.SpendRequest,
StartHeight: startHeight,
EndHeight: n.currentHeight,
}, n.currentHeight, nil
return &SpendRegistration{
Event: ntfn.Event,
HistoricalDispatch: &HistoricalSpendDispatch{
SpendRequest: ntfn.SpendRequest,
StartHeight: startHeight,
EndHeight: n.currentHeight,
},
Height: n.currentHeight,
}, nil
}
// CancelSpend cancels an existing request for a spend notification of an

View File

@ -479,14 +479,9 @@ func TestTxNotifierFutureSpendDispatch(t *testing.T) {
// We'll start off by registering for a spend notification of an
// outpoint.
ntfn := &chainntnfs.SpendNtfn{
SpendRequest: chainntnfs.SpendRequest{
OutPoint: wire.OutPoint{Index: 1},
PkScript: testScript,
},
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(ntfn); err != nil {
op := wire.OutPoint{Index: 1}
ntfn, err := n.RegisterSpend(&op, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
@ -503,14 +498,14 @@ func TestTxNotifierFutureSpendDispatch(t *testing.T) {
// spend notification.
spendTx := wire.NewMsgTx(2)
spendTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: ntfn.OutPoint,
PreviousOutPoint: op,
SignatureScript: testSigScript,
})
spendTxHash := spendTx.TxHash()
block := btcutil.NewBlock(&wire.MsgBlock{
Transactions: []*wire.MsgTx{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)
}
@ -519,7 +514,7 @@ func TestTxNotifierFutureSpendDispatch(t *testing.T) {
}
expectedSpendDetails := &chainntnfs.SpendDetail{
SpentOutPoint: &ntfn.OutPoint,
SpentOutPoint: &op,
SpenderTxHash: &spendTxHash,
SpendingTx: spendTx,
SpenderInputIndex: 0,
@ -593,11 +588,8 @@ func TestTxNotifierHistoricalSpendDispatch(t *testing.T) {
// We'll register for a spend notification of the outpoint and ensure
// that a notification isn't dispatched.
ntfn := &chainntnfs.SpendNtfn{
SpendRequest: chainntnfs.SpendRequest{OutPoint: spentOutpoint},
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(ntfn); err != nil {
ntfn, err := n.RegisterSpend(&spentOutpoint, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
@ -611,7 +603,9 @@ func TestTxNotifierHistoricalSpendDispatch(t *testing.T) {
// we'll hand off the spending details of the outpoint to the notifier
// as it is not possible for it to view historical events in the chain.
// By doing this, we replicate the functionality of the ChainNotifier.
err := n.UpdateSpendDetails(ntfn.SpendRequest, expectedSpendDetails)
err = n.UpdateSpendDetails(
ntfn.HistoricalDispatch.SpendRequest, expectedSpendDetails,
)
if err != nil {
t.Fatalf("unable to update spend details: %v", err)
}
@ -721,35 +715,23 @@ func TestTxNotifierMultipleHistoricalSpendRescans(t *testing.T) {
// The first registration for an outpoint in the notifier should request
// a historical spend rescan as it does not have a historical view of
// the chain.
spendRequest := chainntnfs.SpendRequest{
OutPoint: wire.OutPoint{Index: 1},
}
ntfn1 := &chainntnfs.SpendNtfn{
SpendID: 0,
SpendRequest: spendRequest,
Event: chainntnfs.NewSpendEvent(nil),
}
historicalDispatch1, _, err := n.RegisterSpend(ntfn1)
op := wire.OutPoint{Index: 1}
ntfn1, err := n.RegisterSpend(&op, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
if historicalDispatch1 == nil {
if ntfn1.HistoricalDispatch == nil {
t.Fatal("expected to receive historical dispatch request")
}
// We'll register another spend notification for the same outpoint. This
// should not request a historical spend rescan since the first one is
// still pending.
ntfn2 := &chainntnfs.SpendNtfn{
SpendID: 1,
SpendRequest: spendRequest,
Event: chainntnfs.NewSpendEvent(nil),
}
historicalDispatch2, _, err := n.RegisterSpend(ntfn2)
ntfn2, err := n.RegisterSpend(&op, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
if historicalDispatch2 != nil {
if ntfn2.HistoricalDispatch != nil {
t.Fatal("received unexpected historical rescan request")
}
@ -758,27 +740,24 @@ func TestTxNotifierMultipleHistoricalSpendRescans(t *testing.T) {
// historical rescan request since the confirmation details should be
// cached.
spendDetails := &chainntnfs.SpendDetail{
SpentOutPoint: &ntfn2.OutPoint,
SpentOutPoint: &op,
SpenderTxHash: &chainntnfs.ZeroHash,
SpendingTx: wire.NewMsgTx(2),
SpenderInputIndex: 0,
SpendingHeight: startingHeight - 1,
}
err = n.UpdateSpendDetails(ntfn2.SpendRequest, spendDetails)
err = n.UpdateSpendDetails(
ntfn1.HistoricalDispatch.SpendRequest, spendDetails,
)
if err != nil {
t.Fatalf("unable to update spend details: %v", err)
}
ntfn3 := &chainntnfs.SpendNtfn{
SpendID: 2,
SpendRequest: spendRequest,
Event: chainntnfs.NewSpendEvent(nil),
}
historicalDispatch3, _, err := n.RegisterSpend(ntfn3)
ntfn3, err := n.RegisterSpend(&op, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
if historicalDispatch3 != nil {
if ntfn3.HistoricalDispatch != nil {
t.Fatal("received unexpected historical rescan request")
}
}
@ -872,19 +851,14 @@ func TestTxNotifierMultipleHistoricalNtfns(t *testing.T) {
}
// Similarly, we'll do the same thing but for spend notifications.
spendRequest := chainntnfs.SpendRequest{
OutPoint: wire.OutPoint{Index: 1},
}
spendNtfns := make([]*chainntnfs.SpendNtfn, numNtfns)
op := wire.OutPoint{Index: 1}
spendNtfns := make([]*chainntnfs.SpendRegistration, numNtfns)
for i := uint64(0); i < numNtfns; i++ {
spendNtfns[i] = &chainntnfs.SpendNtfn{
SpendID: i,
SpendRequest: spendRequest,
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(spendNtfns[i]); err != nil {
ntfn, err := n.RegisterSpend(&op, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn #%d: %v", i, err)
}
spendNtfns[i] = ntfn
}
// Ensure none of them have received the spend details.
@ -901,13 +875,15 @@ func TestTxNotifierMultipleHistoricalNtfns(t *testing.T) {
// following spend details. We'll let the notifier know so that it can
// stop watching at tip.
expectedSpendDetails := &chainntnfs.SpendDetail{
SpentOutPoint: &spendNtfns[0].OutPoint,
SpentOutPoint: &op,
SpenderTxHash: &chainntnfs.ZeroHash,
SpendingTx: wire.NewMsgTx(2),
SpenderInputIndex: 0,
SpendingHeight: startingHeight - 1,
}
err = n.UpdateSpendDetails(spendNtfns[0].SpendRequest, expectedSpendDetails)
err = n.UpdateSpendDetails(
spendNtfns[0].HistoricalDispatch.SpendRequest, expectedSpendDetails,
)
if err != nil {
t.Fatalf("unable to update spend details: %v", err)
}
@ -928,16 +904,11 @@ func TestTxNotifierMultipleHistoricalNtfns(t *testing.T) {
// cached, we'll register another client for the same outpoint. We
// should not see a historical rescan request and the spend notification
// should come through immediately.
extraSpendNtfn := &chainntnfs.SpendNtfn{
SpendID: numNtfns + 1,
SpendRequest: spendRequest,
Event: chainntnfs.NewSpendEvent(nil),
}
historicalSpendRescan, _, err := n.RegisterSpend(extraSpendNtfn)
extraSpendNtfn, err := n.RegisterSpend(&op, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
if historicalSpendRescan != nil {
if extraSpendNtfn.HistoricalDispatch != nil {
t.Fatal("received unexpected historical rescan request")
}
@ -1035,26 +1006,15 @@ func TestTxNotifierCancelSpend(t *testing.T) {
// We'll register two notification requests. Only the second one will be
// canceled.
ntfn1 := &chainntnfs.SpendNtfn{
SpendID: 0,
SpendRequest: chainntnfs.SpendRequest{
OutPoint: wire.OutPoint{Index: 1},
PkScript: testScript,
},
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(ntfn1); err != nil {
op1 := wire.OutPoint{Index: 1}
ntfn1, err := n.RegisterSpend(&op1, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
ntfn2 := &chainntnfs.SpendNtfn{
SpendID: 1,
SpendRequest: chainntnfs.SpendRequest{
OutPoint: wire.OutPoint{Index: 2},
},
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(ntfn2); err != nil {
op2 := wire.OutPoint{Index: 2}
ntfn2, err := n.RegisterSpend(&op2, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
@ -1062,12 +1022,12 @@ func TestTxNotifierCancelSpend(t *testing.T) {
// block containing it.
spendTx := wire.NewMsgTx(2)
spendTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: ntfn1.OutPoint,
PreviousOutPoint: op1,
SignatureScript: testSigScript,
})
spendTxHash := spendTx.TxHash()
expectedSpendDetails := &chainntnfs.SpendDetail{
SpentOutPoint: &ntfn1.OutPoint,
SpentOutPoint: &op1,
SpenderTxHash: &spendTxHash,
SpendingTx: spendTx,
SpenderInputIndex: 0,
@ -1080,9 +1040,9 @@ func TestTxNotifierCancelSpend(t *testing.T) {
// Before extending the notifier's tip with the dummy block above, we'll
// cancel the second request.
n.CancelSpend(ntfn2.SpendRequest, ntfn2.SpendID)
n.CancelSpend(ntfn2.HistoricalDispatch.SpendRequest, 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)
}
@ -1404,35 +1364,29 @@ func TestTxNotifierSpendReorg(t *testing.T) {
// We'll have two outpoints that will be spent throughout the test. The
// first will be spent and will not experience a reorg, while the second
// one will.
spendRequest1 := chainntnfs.SpendRequest{
OutPoint: wire.OutPoint{Index: 1},
PkScript: testScript,
}
op1 := wire.OutPoint{Index: 1}
spendTx1 := wire.NewMsgTx(2)
spendTx1.AddTxIn(&wire.TxIn{
PreviousOutPoint: spendRequest1.OutPoint,
PreviousOutPoint: op1,
SignatureScript: testSigScript,
})
spendTxHash1 := spendTx1.TxHash()
expectedSpendDetails1 := &chainntnfs.SpendDetail{
SpentOutPoint: &spendRequest1.OutPoint,
SpentOutPoint: &op1,
SpenderTxHash: &spendTxHash1,
SpendingTx: spendTx1,
SpenderInputIndex: 0,
SpendingHeight: startingHeight + 1,
}
spendRequest2 := chainntnfs.SpendRequest{
OutPoint: wire.OutPoint{Index: 2},
PkScript: testScript,
}
op2 := wire.OutPoint{Index: 2}
spendTx2 := wire.NewMsgTx(2)
spendTx2.AddTxIn(&wire.TxIn{
PreviousOutPoint: chainntnfs.ZeroOutPoint,
SignatureScript: testSigScript,
})
spendTx2.AddTxIn(&wire.TxIn{
PreviousOutPoint: spendRequest2.OutPoint,
PreviousOutPoint: op2,
SignatureScript: testSigScript,
})
spendTxHash2 := spendTx2.TxHash()
@ -1441,7 +1395,7 @@ func TestTxNotifierSpendReorg(t *testing.T) {
// different height, so we'll need to construct the spend details for
// before and after the reorg.
expectedSpendDetails2BeforeReorg := chainntnfs.SpendDetail{
SpentOutPoint: &spendRequest2.OutPoint,
SpentOutPoint: &op2,
SpenderTxHash: &spendTxHash2,
SpendingTx: spendTx2,
SpenderInputIndex: 1,
@ -1454,21 +1408,13 @@ func TestTxNotifierSpendReorg(t *testing.T) {
expectedSpendDetails2AfterReorg.SpendingHeight++
// We'll register for a spend notification for each outpoint above.
ntfn1 := &chainntnfs.SpendNtfn{
SpendID: 78,
SpendRequest: spendRequest1,
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(ntfn1); err != nil {
ntfn1, err := n.RegisterSpend(&op1, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
ntfn2 := &chainntnfs.SpendNtfn{
SpendID: 21,
SpendRequest: spendRequest2,
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(ntfn2); err != nil {
ntfn2, err := n.RegisterSpend(&op2, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
@ -1477,7 +1423,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.Hash(), startingHeight+1, block1.Transactions())
if err != nil {
t.Fatalf("unable to connect block: %v", err)
}
@ -1836,40 +1782,27 @@ func TestTxNotifierSpendHintCache(t *testing.T) {
)
// Create two test outpoints and register them for spend notifications.
ntfn1 := &chainntnfs.SpendNtfn{
SpendID: 1,
SpendRequest: chainntnfs.SpendRequest{
OutPoint: wire.OutPoint{Index: 1},
PkScript: testScript,
},
Event: chainntnfs.NewSpendEvent(nil),
}
ntfn2 := &chainntnfs.SpendNtfn{
SpendID: 2,
SpendRequest: chainntnfs.SpendRequest{
OutPoint: wire.OutPoint{Index: 2},
PkScript: testScript,
},
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(ntfn1); err != nil {
op1 := wire.OutPoint{Index: 1}
ntfn1, err := n.RegisterSpend(&op1, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend for op1: %v", err)
}
if _, _, err := n.RegisterSpend(ntfn2); err != nil {
op2 := wire.OutPoint{Index: 2}
ntfn2, err := n.RegisterSpend(&op2, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend for op2: %v", err)
}
// Both outpoints should not have a spend hint set upon registration, as
// we must first determine whether they have already been spent in the
// chain.
_, err := hintCache.QuerySpendHint(ntfn1.SpendRequest)
_, err = hintCache.QuerySpendHint(ntfn1.HistoricalDispatch.SpendRequest)
if err != chainntnfs.ErrSpendHintNotFound {
t.Fatalf("unexpected error when querying for height hint "+
"expected: %v, got %v", chainntnfs.ErrSpendHintNotFound,
err)
}
_, err = hintCache.QuerySpendHint(ntfn2.SpendRequest)
_, err = hintCache.QuerySpendHint(ntfn2.HistoricalDispatch.SpendRequest)
if err != chainntnfs.ErrSpendHintNotFound {
t.Fatalf("unexpected error when querying for height hint "+
"expected: %v, got %v", chainntnfs.ErrSpendHintNotFound,
@ -1891,13 +1824,13 @@ func TestTxNotifierSpendHintCache(t *testing.T) {
// Since we haven't called UpdateSpendDetails on any of the test
// outpoints, this implies that there is a still a pending historical
// rescan for them, so their spend hints should not be created/updated.
_, err = hintCache.QuerySpendHint(ntfn1.SpendRequest)
_, err = hintCache.QuerySpendHint(ntfn1.HistoricalDispatch.SpendRequest)
if err != chainntnfs.ErrSpendHintNotFound {
t.Fatalf("unexpected error when querying for height hint "+
"expected: %v, got %v", chainntnfs.ErrSpendHintNotFound,
err)
}
_, err = hintCache.QuerySpendHint(ntfn2.SpendRequest)
_, err = hintCache.QuerySpendHint(ntfn2.HistoricalDispatch.SpendRequest)
if err != chainntnfs.ErrSpendHintNotFound {
t.Fatalf("unexpected error when querying for height hint "+
"expected: %v, got %v", chainntnfs.ErrSpendHintNotFound,
@ -1907,10 +1840,12 @@ func TestTxNotifierSpendHintCache(t *testing.T) {
// Now, we'll simulate that their historical rescans have finished by
// calling UpdateSpendDetails. This should allow their spend hints to be
// updated upon every block connected/disconnected.
if err := n.UpdateSpendDetails(ntfn1.SpendRequest, nil); err != nil {
err = n.UpdateSpendDetails(ntfn1.HistoricalDispatch.SpendRequest, nil)
if err != nil {
t.Fatalf("unable to update spend details: %v", err)
}
if err := n.UpdateSpendDetails(ntfn2.SpendRequest, nil); err != nil {
err = n.UpdateSpendDetails(ntfn2.HistoricalDispatch.SpendRequest, nil)
if err != nil {
t.Fatalf("unable to update spend details: %v", err)
}
@ -1918,7 +1853,7 @@ func TestTxNotifierSpendHintCache(t *testing.T) {
// of the first outpoint.
spendTx1 := wire.NewMsgTx(2)
spendTx1.AddTxIn(&wire.TxIn{
PreviousOutPoint: ntfn1.OutPoint,
PreviousOutPoint: op1,
SignatureScript: testSigScript,
})
block1 := btcutil.NewBlock(&wire.MsgBlock{
@ -1935,14 +1870,14 @@ func TestTxNotifierSpendHintCache(t *testing.T) {
// Both outpoints should have their spend hints reflect the height of
// the new block being connected due to the first outpoint being spent
// at this height, and the second outpoint still being unspent.
op1Hint, err := hintCache.QuerySpendHint(ntfn1.SpendRequest)
op1Hint, err := hintCache.QuerySpendHint(ntfn1.HistoricalDispatch.SpendRequest)
if err != nil {
t.Fatalf("unable to query for spend hint of op1: %v", err)
}
if op1Hint != op1Height {
t.Fatalf("expected hint %d, got %d", op1Height, op1Hint)
}
op2Hint, err := hintCache.QuerySpendHint(ntfn2.SpendRequest)
op2Hint, err := hintCache.QuerySpendHint(ntfn2.HistoricalDispatch.SpendRequest)
if err != nil {
t.Fatalf("unable to query for spend hint of op2: %v", err)
}
@ -1953,7 +1888,7 @@ func TestTxNotifierSpendHintCache(t *testing.T) {
// Then, we'll create another block that spends the second outpoint.
spendTx2 := wire.NewMsgTx(2)
spendTx2.AddTxIn(&wire.TxIn{
PreviousOutPoint: ntfn2.OutPoint,
PreviousOutPoint: op2,
SignatureScript: testSigScript,
})
block2 := btcutil.NewBlock(&wire.MsgBlock{
@ -1970,14 +1905,14 @@ func TestTxNotifierSpendHintCache(t *testing.T) {
// Only the second outpoint should have its spend hint updated due to
// being spent within the new block. The first outpoint's spend hint
// should remain the same as it's already been spent before.
op1Hint, err = hintCache.QuerySpendHint(ntfn1.SpendRequest)
op1Hint, err = hintCache.QuerySpendHint(ntfn1.HistoricalDispatch.SpendRequest)
if err != nil {
t.Fatalf("unable to query for spend hint of op1: %v", err)
}
if op1Hint != op1Height {
t.Fatalf("expected hint %d, got %d", op1Height, op1Hint)
}
op2Hint, err = hintCache.QuerySpendHint(ntfn2.SpendRequest)
op2Hint, err = hintCache.QuerySpendHint(ntfn2.HistoricalDispatch.SpendRequest)
if err != nil {
t.Fatalf("unable to query for spend hint of op2: %v", err)
}
@ -1995,14 +1930,14 @@ func TestTxNotifierSpendHintCache(t *testing.T) {
// to the previous height, as that's where its spending transaction was
// included in within the chain. The first outpoint's spend hint should
// remain the same.
op1Hint, err = hintCache.QuerySpendHint(ntfn1.SpendRequest)
op1Hint, err = hintCache.QuerySpendHint(ntfn1.HistoricalDispatch.SpendRequest)
if err != nil {
t.Fatalf("unable to query for spend hint of op1: %v", err)
}
if op1Hint != op1Height {
t.Fatalf("expected hint %d, got %d", op1Height, op1Hint)
}
op2Hint, err = hintCache.QuerySpendHint(ntfn2.SpendRequest)
op2Hint, err = hintCache.QuerySpendHint(ntfn2.HistoricalDispatch.SpendRequest)
if err != nil {
t.Fatalf("unable to query for spend hint of op2: %v", err)
}
@ -2027,16 +1962,8 @@ func TestTxNotifierNtfnDone(t *testing.T) {
if err != nil {
t.Fatalf("unable to register conf ntfn: %v", err)
}
spendNtfn := &chainntnfs.SpendNtfn{
SpendID: 2,
SpendRequest: chainntnfs.SpendRequest{
OutPoint: chainntnfs.ZeroOutPoint,
PkScript: testScript,
},
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(spendNtfn); err != nil {
spendNtfn, err := n.RegisterSpend(&chainntnfs.ZeroOutPoint, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend: %v", err)
}
@ -2165,13 +2092,8 @@ func TestTxNotifierTearDown(t *testing.T) {
if err != nil {
t.Fatalf("unable to register conf ntfn: %v", err)
}
spendNtfn := &chainntnfs.SpendNtfn{
SpendID: 1,
SpendRequest: chainntnfs.SpendRequest{OutPoint: chainntnfs.ZeroOutPoint},
Event: chainntnfs.NewSpendEvent(nil),
}
if _, _, err := n.RegisterSpend(spendNtfn); err != nil {
spendNtfn, err := n.RegisterSpend(&chainntnfs.ZeroOutPoint, testRawScript, 1)
if err != nil {
t.Fatalf("unable to register spend ntfn: %v", err)
}
@ -2212,7 +2134,8 @@ func TestTxNotifierTearDown(t *testing.T) {
if err == nil {
t.Fatal("expected confirmation registration to fail")
}
if _, _, err := n.RegisterSpend(spendNtfn); err == nil {
_, err = n.RegisterSpend(&chainntnfs.ZeroOutPoint, testRawScript, 1)
if err == nil {
t.Fatal("expected spend registration to fail")
}
}