Merge bitcoin/bitcoin#33251: [29.x] backport #33212

fcac8022d8 test: index with an unclean restart after a reorg (Martin Zumsande)
16b1710d97 index: don't commit state in BaseIndex::Rewind (Martin Zumsande)

Pull request description:

  Backports #33212 to 29.x

ACKs for top commit:
  achow101:
    ACK fcac8022d8
  stickies-v:
    ACK fcac8022d8
  mzumsande:
    Code Review ACK fcac8022d8

Tree-SHA512: eeb9213f03bbb1d48c3ccb12121a6e475f436895d314b5171007e7e4ee457c74b312fa7f0d1808d6221dc22b192700a93ea21c4e9e04689da7dde7e1f79e9569
This commit is contained in:
merge-script
2025-08-27 09:46:59 +01:00
2 changed files with 17 additions and 7 deletions

View File

@@ -253,18 +253,13 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
return false; return false;
} }
// In the case of a reorg, ensure persisted block locator is not stale. // Don't commit here - the committed index state must never be ahead of the
// flushed chainstate, otherwise unclean restarts would lead to index corruption.
// Pruning has a minimum of 288 blocks-to-keep and getting the index // Pruning has a minimum of 288 blocks-to-keep and getting the index
// out of sync may be possible but a users fault. // out of sync may be possible but a users fault.
// In case we reorg beyond the pruned depth, ReadBlock would // In case we reorg beyond the pruned depth, ReadBlock would
// throw and lead to a graceful shutdown // throw and lead to a graceful shutdown
SetBestBlockIndex(new_tip); SetBestBlockIndex(new_tip);
if (!Commit()) {
// If commit fails, revert the best block index to avoid corruption.
SetBestBlockIndex(current_tip);
return false;
}
return true; return true;
} }

View File

@@ -322,6 +322,21 @@ class CoinStatsIndexTest(BitcoinTestFramework):
res1 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=None, use_index=True) res1 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=None, use_index=True)
assert_equal(res["muhash"], res1["muhash"]) assert_equal(res["muhash"], res1["muhash"])
self.log.info("Test index with an unclean restart after a reorg")
self.restart_node(1, extra_args=self.extra_args[1])
committed_height = index_node.getblockcount()
self.generate(index_node, 2, sync_fun=self.no_op)
self.sync_index_node()
block2 = index_node.getbestblockhash()
index_node.invalidateblock(block2)
self.generatetoaddress(index_node, 1, getnewdestination()[2], sync_fun=self.no_op)
self.sync_index_node()
index_node.kill_process()
self.start_node(1, extra_args=self.extra_args[1])
self.sync_index_node()
# Because of the unclean shutdown above, indexes reset to the point we last committed them to disk.
assert_equal(index_node.getindexinfo()['coinstatsindex']['best_block_height'], committed_height)
if __name__ == '__main__': if __name__ == '__main__':
CoinStatsIndexTest(__file__).main() CoinStatsIndexTest(__file__).main()