chainntnfs: refactor common registration code within RegisterSpendNtfn
This commit is contained in:
5 files changed
+240
-287
No files matched your search
@@ -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)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
Reference in new issue
Block a user