diff options
author | MarcoFalke <falke.marco@gmail.com> | 2021-12-13 13:37:55 +0100 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2021-12-13 13:38:02 +0100 |
commit | bf66e258a84e18935fde3ebb9a4b0392bf883222 (patch) | |
tree | 2e0eac49f1f05889ac6b9644f185c1398ef3235b /test | |
parent | eb63b8fab91c3aec46ef4ae66e6241ed5de49bbd (diff) | |
parent | 9600ea01450b0d39be90eb2971c1ac5c9b69a66e (diff) |
Merge bitcoin/bitcoin#23365: index: Fix backwards search for bestblock
9600ea01450b0d39be90eb2971c1ac5c9b69a66e test: Add edge case of pruning up to index height (Martin Zumsande)
698c524698c33595a4d555eaa9e21bc19b4d3e93 index: Fix backwards search for bestblock (Martin Zumsande)
Pull request description:
This PR attempts to fix an intermittent Init issue encountered during the stress testing of #23289, which relates to the pruning-compatible filter reconstruction logic introduced in #15946.
The problem would occur when the node starts with `-txindex=1` but `ThreadSync` is interrupted after it sets `m_best_block_index` to Genesis, and before it gets do any further work.
In that case, during the next restart of the node, an Init error would be thrown because `BaseIndex::Init()` tries to backtrack from the tip to the last block which has been successfully indexed (here: Genesis), but the backtracking logic didn't work properly in this case:
The loop
`while (block_to_test && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA))` checks if a predecessor exists **before** performing the check `block_to_test == block` and then possbily setting `prune_violation = false`
If `block_to_test` and `block` are the Genesis block this check will not be reached because `block->pprev` does not exist.
To reproduce this bug on regtest:
1) start a node with a fresh datadir using `-txindex=1` (or any other index)
2) stop and restart without any index
3) mine a block
3) stop and restart again with the index enabled
->InitError `Error: txindex best block of the index goes beyond pruned data. (...)`
Fix this by requiring that we have the data for the block of the current iteration `block` (instead of requiring it for the predecessor `block->pprev`)
That way, the check for `block_to_test == block` is also reached when `block_to_test` is the Genesis block.
No longer requiring the data of `block->pprev` also means that we can now prune up to `m_best_block_index` height without requiring a reindex (one block more than before). I added this edge case to `feature_blockfilterindex_prune.py`, the new version should fail on master.
ACKs for top commit:
ryanofsky:
Partial code review ACK 9600ea01450b0d39be90eb2971c1ac5c9b69a66e for the code change, not the test changes. (Test changes are indirect and little over my head.) It seems obvious that previous code `prune_violation = true, while (block->pprev)` would incorrectly detect a prune violation at the genesis block, and the fix here make sense and looks correct.
Tree-SHA512: c717f372cee8fd49718b1b18bfe237aa6ba3ff4468588c10e1272d7a2ef3981d10af4e57de51dec295e2ca72d441bc6c2812f7990011a94d7f818775e3ff1a38
Diffstat (limited to 'test')
-rwxr-xr-x | test/functional/feature_blockfilterindex_prune.py | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/test/functional/feature_blockfilterindex_prune.py b/test/functional/feature_blockfilterindex_prune.py index 39eb700b4f..83a50c504e 100755 --- a/test/functional/feature_blockfilterindex_prune.py +++ b/test/functional/feature_blockfilterindex_prune.py @@ -24,9 +24,7 @@ class FeatureBlockfilterindexPruneTest(BitcoinTestFramework): self.log.info("check if we can access a blockfilter when pruning is enabled but no blocks are actually pruned") self.sync_index(height=200) assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getbestblockhash())['filter']), 0) - # Mine two batches of blocks to avoid hitting NODE_NETWORK_LIMITED_MIN_BLOCKS disconnection - self.generate(self.nodes[0], 250) - self.generate(self.nodes[0], 250) + self.generate(self.nodes[0], 500) self.sync_index(height=700) self.log.info("prune some blocks") @@ -39,16 +37,29 @@ class FeatureBlockfilterindexPruneTest(BitcoinTestFramework): self.log.info("check if we can access the blockfilter of a pruned block") assert_greater_than(len(self.nodes[0].getblockfilter(self.nodes[0].getblockhash(2))['filter']), 0) + # mine and sync index up to a height that will later be the pruneheight + self.generate(self.nodes[0], 298) + self.sync_index(height=998) + self.log.info("start node without blockfilterindex") self.restart_node(0, extra_args=["-fastprune", "-prune=1"]) self.log.info("make sure accessing the blockfilters throws an error") assert_raises_rpc_error(-1, "Index is not enabled for filtertype basic", self.nodes[0].getblockfilter, self.nodes[0].getblockhash(2)) - self.generate(self.nodes[0], 1000) + self.generate(self.nodes[0], 502) + + self.log.info("prune exactly up to the blockfilterindexes best block while blockfilters are disabled") + pruneheight_2 = self.nodes[0].pruneblockchain(1000) + assert_equal(pruneheight_2, 998) + self.restart_node(0, extra_args=["-fastprune", "-prune=1", "-blockfilterindex=1"]) + self.log.info("make sure that we can continue with the partially synced index after having pruned up to the index height") + self.sync_index(height=1500) self.log.info("prune below the blockfilterindexes best block while blockfilters are disabled") - pruneheight_new = self.nodes[0].pruneblockchain(1000) - assert_greater_than(pruneheight_new, pruneheight) + self.restart_node(0, extra_args=["-fastprune", "-prune=1"]) + self.generate(self.nodes[0], 1000) + pruneheight_3 = self.nodes[0].pruneblockchain(2000) + assert_greater_than(pruneheight_3, pruneheight_2) self.stop_node(0) self.log.info("make sure we get an init error when starting the node again with block filters") |