chain/bitcoind_client: extend filterTx with script spend support

In this commit, we extend the BitcoindClient to properly detect the
spend of an arbitrary script on-chain. This is possible by looking at a
transaction's input and re-deriving the PkScript, from its signature
script/witness, of the output it's attempting to spend. Upon detecting
the spend, a chain.RelevantTx will be dispatched.
This commit is contained in:
Wilmer Paulino 2019-01-14 18:38:45 -08:00 committed by Conner Fromknecht
parent cf8553756b
commit ec210ad79c
No known key found for this signature in database
GPG key ID: E7D737B67FA592C7

View file

@ -1205,16 +1205,47 @@ func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
// to determine if this transaction is somehow relevant to the caller.
var isRelevant bool
// We'll start by cycling through its outputs to determine if it pays to
// any of the currently watched addresses. If an output matches, we'll
// add it to our watch list.
for i, out := range tx.TxOut {
_, addrs, _, err := txscript.ExtractPkScriptAddrs(
out.PkScript, c.chainParams,
// We'll start by checking all inputs and determining whether it spends
// an existing outpoint or a pkScript encoded as an address in our watch
// list.
for _, txIn := range tx.TxIn {
// If it matches an outpoint in our watch list, we can exit our
// loop early.
if _, ok := c.watchedOutPoints[txIn.PreviousOutPoint]; ok {
isRelevant = true
break
}
// Otherwise, we'll check whether it matches a pkScript in our
// watch list encoded as an address. To do so, we'll re-derive
// the pkScript of the output the input is attempting to spend.
pkScript, err := txscript.ComputePkScript(
txIn.SignatureScript, txIn.Witness,
)
if err != nil {
log.Debugf("Unable to parse output script in %s:%d: %v",
tx.TxHash(), i, err)
// Non-standard outputs can be safely skipped.
continue
}
addr, err := pkScript.Address(c.chainParams)
if err != nil {
// Non-standard outputs can be safely skipped.
continue
}
if _, ok := c.watchedAddresses[addr.String()]; ok {
isRelevant = true
break
}
}
// We'll also cycle through its outputs to determine if it pays to
// any of the currently watched addresses. If an output matches, we'll
// add it to our watch list.
for i, txOut := range tx.TxOut {
_, addrs, _, err := txscript.ExtractPkScriptAddrs(
txOut.PkScript, c.chainParams,
)
if err != nil {
// Non-standard outputs can be safely skipped.
continue
}
@ -1238,17 +1269,6 @@ func (c *BitcoindClient) filterTx(tx *wire.MsgTx,
}
}
// If the transaction didn't pay to any of our watched hashes, we'll
// check if it spends any of our watched outpoints.
if !isRelevant {
for _, in := range tx.TxIn {
if _, ok := c.watchedOutPoints[in.PreviousOutPoint]; ok {
isRelevant = true
break
}
}
}
// If the transaction is not relevant to us, we can simply exit.
if !isRelevant {
return false, rec, nil