chainntnfs: fix spend notification registration race condition

In this commit, we fix a race condition related to the way we attempt
to query to see if an outpoint has already been spent by the time it’s
registered within the ChainNotifier. If the transaction creating the
outpoint hasn’t made it into the mempool by the time we execute the
GetTxOut call, then we’ll attempt to query for the transaction itself.
In this case, if we query for the transaction, then the block hash
field will be empty as it hasn’t yet made it into a block. Under the
previous logic, we’d then attempt to force a rescan. This is an issue
as the forced rescan will fail since it’ll try to fetch the block hash
of all zeroes.

In this commit, we fix this issue by only entering this “fallback to
rescan” logic iff, the transaction has actually been mined.
This commit is contained in:
Olaoluwa Osuntokun 2018-01-28 14:46:54 -08:00
parent 3b4ffbca48
commit bf6001074c
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21
2 changed files with 12 additions and 2 deletions

@ -527,7 +527,12 @@ func (b *BitcoindNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
}
}
if transaction != nil {
// We'll only request a rescan if the transaction has actually
// been included within a block. Otherwise, we'll encounter an
// error when scanning for blocks. This can happens in the case
// of a race condition, wherein the output itself is unspent,
// and only arrives in the mempool after the getxout call.
if transaction != nil && transaction.BlockHash != "" {
blockhash, err := chainhash.NewHashFromStr(transaction.BlockHash)
if err != nil {
return nil, err

@ -547,7 +547,12 @@ func (b *BtcdNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
}
}
if transaction != nil {
// We'll only request a rescan if the transaction has actually
// been included within a block. Otherwise, we'll encounter an
// error when scanning for blocks. This can happens in the case
// of a race condition, wherein the output itself is unspent,
// and only arrives in the mempool after the getxout call.
if transaction != nil && transaction.BlockHash != "" {
blockhash, err := chainhash.NewHashFromStr(transaction.BlockHash)
if err != nil {
return nil, err