test: check LoadBlockIndex correctly recomputes invalidity flags
What changed, and why it matters
This commit only adds a new automated test to Bitcoin Core. It does not change any production code. The test verifies that when the block index database is reloaded, a chain of three blocks with mixed invalidity flags is all correctly marked as permanently invalid. There is no direct security fix here, only a regression test for existing behavior.
No action required. Treat as routine test-coverage improvement. If reviewing for security, confirm the underlying LoadBlockIndex recomputation behavior is already deployed and that this test accurately captures the intended legacy-to-current flag migration.
Security signals we found
Adds regression test for block index invalidity flag recomputation
No production code changes
No network, consensus, or cryptographic logic modified
Evidence from the diff
The diff adds a BOOST_FIXTURE_TEST_CASE named loadblockindex_invalid_descendants in src/test/validation_chainstatemanager_tests.cpp. It constructs a three-block lineage (grand_parent <- parent <- child), manually sets grand_parent to BLOCK_FAILED_VALID, parent to BLOCK_FAILED_CHILD, and child to non-invalid, then calls LoadBlockIndex() and asserts all three end up with BLOCK_FAILED_VALID. This is purely test coverage for the status-recomputation logic in LoadBlockIndex; no consensus or validation code is modified.
Changed components
src/test/validation_chainstatemanager_tests.cppInspect captured patch +25 / −0
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 41dfdcd1..40f99690 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -591,6 +591,31 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup)
BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.size(), num_indexes - last_assumed_valid_idx + 1);
}
+BOOST_FIXTURE_TEST_CASE(loadblockindex_invalid_descendants, TestChain100Setup)
+{
+ LOCK(Assert(m_node.chainman)->GetMutex());
+ // consider the chain of blocks grand_parent <- parent <- child
+ // intentionally mark:
+ // - grand_parent: BLOCK_FAILED_VALID
+ // - parent: BLOCK_FAILED_CHILD
+ // - child: not invalid
+ // Test that when the block index is loaded, all blocks are marked as BLOCK_FAILED_VALID
+ auto* child{m_node.chainman->ActiveChain().Tip()};
+ auto* parent{child->pprev};
+ auto* grand_parent{parent->pprev};
+ grand_parent->nStatus = (grand_parent->nStatus | BLOCK_FAILED_VALID);
+ parent->nStatus = (parent->nStatus & ~BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD;
+ child->nStatus = (child->nStatus & ~BLOCK_FAILED_VALID);
+
+ // Reload block index to recompute block status validity flags.
+ m_node.chainman->LoadBlockIndex();
+
+ // check grand_parent, parent, child is marked as BLOCK_FAILED_VALID after reloading the block index
+ BOOST_CHECK(grand_parent->nStatus & BLOCK_FAILED_VALID);
+ BOOST_CHECK(parent->nStatus & BLOCK_FAILED_VALID);
+ BOOST_CHECK(child->nStatus & BLOCK_FAILED_VALID);
+}
+
//! Ensure that snapshot chainstate can be loaded when found on disk after a
//! restart, and that new blocks can be connected to both chainstates.
BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_init, SnapshotTestSetup)
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.