Skip to content

Commit 0391458

Browse files
ryanofskyMarcoFalke
andcommitted
test: assumeutxo stale block CheckBlockIndex crash test
Add a test for a CheckBlockIndex crash that would happen before previous "assumeutxo: Get rid of faked nTx and nChainTx values" commit. The crash was an assert failure in the (pindex->nChainTx == pindex->nTx + prev_chain_tx) check that would previously happen if a snapshot was loaded, and a block was submitted which forked from the chain before the snapshot block and after the last downloaded background chain block. This block would not be marked assumed-valid because it would not be an ancestor of the snapshot, and it would have nTx set, nChainTx unset, and prev->nChainTx set with a fake value, so the assert would fail. After the fix, prev->nChainTx is unset instead of being set to a fake value, so the assert succeeds. This test was originally posted by maflcko in bitcoin/bitcoin#29261 (comment) Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
1 parent ef29c8b commit 0391458

File tree

1 file changed

+17
-0
lines changed

1 file changed

+17
-0
lines changed

test/functional/feature_assumeutxo.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,14 @@ def run_test(self):
186186
height = n0.getblockcount()
187187
hash = n0.getbestblockhash()
188188
blocks[height] = Block(hash, block_tx, blocks[height-1].chain_tx + block_tx)
189+
if i == 4:
190+
# Create a stale block that forks off the main chain before the snapshot.
191+
temp_invalid = n0.getbestblockhash()
192+
n0.invalidateblock(temp_invalid)
193+
stale_hash = self.generateblock(n0, output="raw(aaaa)", transactions=[], sync_fun=self.no_op)["hash"]
194+
n0.invalidateblock(stale_hash)
195+
n0.reconsiderblock(temp_invalid)
196+
stale_block = n0.getblock(stale_hash, 0)
189197

190198

191199
self.log.info("-- Testing assumeutxo + some indexes + pruning")
@@ -270,6 +278,15 @@ def check_tx_counts(final: bool) -> None:
270278

271279
assert_equal(n1.getblockchaininfo()["blocks"], SNAPSHOT_BASE_HEIGHT)
272280

281+
self.log.info("Submit a stale block that forked off the chain before the snapshot")
282+
# Normally a block like this would not be downloaded, but if it is
283+
# submitted early before the background chain catches up to the fork
284+
# point, it winds up in m_blocks_unlinked and triggers a corner case
285+
# that previously crashed CheckBlockIndex.
286+
n1.submitblock(stale_block)
287+
n1.getchaintips()
288+
n1.getblock(stale_hash)
289+
273290
self.log.info("Submit a spending transaction for a snapshot chainstate coin to the mempool")
274291
# spend the coinbase output of the first block that is not available on node1
275292
spend_coin_blockhash = n1.getblockhash(START_HEIGHT + 1)

0 commit comments

Comments
 (0)