test: verify that ancestors of a reconsidered block can become the chain tip

when we reconsiderblock, previously only block and it's
descendants were considered as chain tip candidates/inserted into
setBlockIndexCandidates

ex: on this chain, with block 4 invalidated
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> header 7
blocks 4, 5, 6, header 7 have BLOCK_FAILED_* flags set

previously:
- if we reconsiderblock header 7, the chain would have all the
BLOCK_FAILED_* flags cleared but would report chain tip as block 3.
- after restart, it reports correct chain tip block 6.

now:
- if we reconsiderblock header 7, the correct chain tip block 6 is
reported since ancestors are also considered as chain tip
candidates/inserted into setBlockIndexCandidates.

Co-authored-by: Martin Zumsande <mzumsande@gmail.com>
This commit is contained in:
stratospher
2025-02-28 23:45:53 +05:30
committed by Martin Zumsande
parent 3c39a55e64
commit 86d98b94e5

View File

@@ -85,6 +85,23 @@ class InvalidateTest(BitcoinTestFramework):
self.wait_until(lambda: self.nodes[0].getblockcount() == 4, timeout=5)
self.wait_until(lambda: self.nodes[1].getblockcount() == 4, timeout=5)
self.log.info("Verify that ancestors can become chain tip candidates when we reconsider blocks")
# Invalidate node0's current chain (1' -> 2' -> 3' -> 4') so that we don't reorg back to it in this test
badhash = self.nodes[0].getblockhash(1)
self.nodes[0].invalidateblock(badhash)
# Reconsider the tip so that node0's chain becomes this chain again : 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> header 7
self.nodes[0].reconsiderblock(tip)
blockhash_3 = self.nodes[0].getblockhash(3)
blockhash_4 = self.nodes[0].getblockhash(4)
blockhash_6 = self.nodes[0].getblockhash(6)
assert_equal(self.nodes[0].getbestblockhash(), blockhash_6)
# Invalidate block 4 so that chain becomes : 1 -> 2 -> 3
self.nodes[0].invalidateblock(blockhash_4)
assert_equal(self.nodes[0].getbestblockhash(), blockhash_3)
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 3)
assert_equal(self.nodes[0].getblockchaininfo()['headers'], 3)
self.log.info("Verify that we reconsider all ancestors as well")
blocks = self.generatetodescriptor(self.nodes[1], 10, ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR, sync_fun=self.no_op)
assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])
@@ -111,6 +128,14 @@ class InvalidateTest(BitcoinTestFramework):
# Should report consistent blockchain info
assert_equal(self.nodes[1].getblockchaininfo()["headers"], self.nodes[1].getblockchaininfo()["blocks"])
# Reconsider the header
self.nodes[0].reconsiderblock(block.hash)
# Since header doesn't have block data, it can't be chain tip
# Check if it's possible for an ancestor (with block data) to be the chain tip
assert_equal(self.nodes[0].getbestblockhash(), blockhash_6)
assert_equal(self.nodes[0].getblockchaininfo()['blocks'], 6)
assert_equal(self.nodes[0].getblockchaininfo()['headers'], 7)
self.log.info("Verify that invalidating an unknown block throws an error")
assert_raises_rpc_error(-5, "Block not found", self.nodes[1].invalidateblock, "00" * 32)
assert_equal(self.nodes[1].getbestblockhash(), blocks[-1])