chainntnfs/bitcoindnotify: support registration for script spends
In this commit, we extend the BitcoindNotifier to support registering scripts for spends notifications. Once the script has been detected as spent within the chain, a spend notification will be dispatched through the Spend channel of the SpendEvent returned upon registration. For scripts that have been spent in the past, the rescan logic has been modified to match on the script rather than the outpoint. This is done by re-deriving the script of the output a transaction input is spending and checking whether it matches ours. For scripts that are unspent, a request to the backend will be sent to alert the BitcoindNotifier of when the script was spent by a transaction. To make this request we encode the script as an address, as this is what the backend uses to detect the spend. The transaction will then be proxied through the txUpdates concurrent queue, which will hand it off to the underlying txNotifier and dispatch spend notifications to the relevant clients. Along the way, we also address an issue where we'd miss detecting that an outpoint/script has been spent in the future due to not receiving a historical dispatch request from the underlying txNotifier. To fix this, we ensure that we always request the backend to notify us of the spend once it detects it at tip, regardless of whether a historical rescan was detected or not.
This commit is contained in:
2 files changed
+140
-62
No files matched your search
@@ -310,6 +310,42 @@ func (r SpendRequest) SpendHintKey() ([]byte, error) {
|
||||
return outpoint.Bytes(), nil
|
||||
}
|
||||
|
||||
// MatchesTx determines whether the given transaction satisfies the spend
|
||||
// request. If the spend request is for an outpoint, then we'll check all of
|
||||
// the outputs being spent by the inputs of the transaction to determine if it
|
||||
// matches. Otherwise, we'll need to match on the output script being spent, so
|
||||
// we'll recompute it for each input of the transaction to determine if it
|
||||
// matches.
|
||||
func (r SpendRequest) MatchesTx(tx *wire.MsgTx) (bool, uint32, error) {
|
||||
if r.OutPoint != ZeroOutPoint {
|
||||
for i, txIn := range tx.TxIn {
|
||||
if txIn.PreviousOutPoint == r.OutPoint {
|
||||
return true, uint32(i), nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, 0, nil
|
||||
}
|
||||
|
||||
for i, txIn := range tx.TxIn {
|
||||
pkScript, err := txscript.ComputePkScript(
|
||||
txIn.SignatureScript, txIn.Witness,
|
||||
)
|
||||
if err == txscript.ErrUnsupportedScriptType {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
|
||||
if bytes.Equal(pkScript.Script(), r.PkScript.Script()) {
|
||||
return true, uint32(i), nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, 0, nil
|
||||
}
|
||||
|
||||
// SpendNtfn represents a client's request to receive a notification once an
|
||||
// outpoint/output script has been spent on-chain. The client is asynchronously
|
||||
// notified via the SpendEvent channels.
|
||||
|
||||
Reference in new issue
Block a user