Closed kcalvinalvin closed 6 months ago
This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Changes Missing Coverage | Covered Lines | Changed/Added Lines | % | ||
---|---|---|---|---|---|
blockchain/fullblocktests/generate.go | 55 | 57 | 96.49% | ||
blockchain/chain.go | 14 | 18 | 77.78% | ||
<!-- | Total: | 72 | 78 | 92.31% | --> |
Files with Coverage Reduction | New Missed Lines | % | ||
---|---|---|---|---|
blockchain/chainio.go | 2 | 60.99% | ||
connmgr/connmanager.go | 2 | 86.27% | ||
blockchain/utxoviewpoint.go | 9 | 72.54% | ||
peer/peer.go | 9 | 73.94% | ||
<!-- | Total: | 22 | --> |
Totals | |
---|---|
Change from base Build 8117173129: | 0.003% |
Covered Lines: | 29309 |
Relevant Lines: | 51619 |
During reorgs, the assumption being made was that the utxocache is ignored and we're directly accessing the database for utxo set modifications.
However, after a block disconnect, the
BlockChain.chainLock
, the lock that prevents modifications to the utxo set, was being freed for the callback functions for the blockchain notifications. https://github.com/btcsuite/btcd/blob/13152b35e191385a874294a9dbc902e48b1d71b0/blockchain/chain.go#L853-L858If a caller calls either of the two methods below, the utxocache could be loaded with utxos that are fetched from the database:
https://github.com/btcsuite/btcd/blob/13152b35e191385a874294a9dbc902e48b1d71b0/blockchain/utxoviewpoint.go#L687-L693
https://github.com/btcsuite/btcd/blob/13152b35e191385a874294a9dbc902e48b1d71b0/blockchain/utxoviewpoint.go#L722-L732
Since the UTXOs fetched here are considered unmodified and therefore wouldn't be saved in the database when the
utxoCache
is flushed at the end of a reorganization, if a caller makes a call to the above two functions during a reorg, they could be mistakenly think that a utxo exists when it was removed from the utxo set.Example:
There's a chain like so where a utxo created in
b1001
is spent inb1002
. Blocksb1002
andb1001
are being disconnected out by a longer chain.Mempool tries to fetch
b1001.tx[1].out[0]
three times in total.2
,8
and11
. At6
the utxob1001.tx[1].out[0]
get loaded up to the cache. The cache never gets reset and that utxo gets fetched at12
. When the reorg finishes, the mempool can no longer fetchb1001.tx[1].out[0]