validation: reset BLOCK_FAILED_CHILD to BLOCK_FAILED_VALID when loading from disk
What changed, and why it matters
This Bitcoin Core commit cleans up an old block-status flag when loading the blockchain database from disk. The old flag (BLOCK_FAILED_CHILD) is no longer used by current code, so the patch converts any leftover occurrences into the newer equivalent flag (BLOCK_FAILED_VALID) and marks the index entries as needing to be saved. This is a defensive data-consistency fix rather than a fix for an active exploit.
No immediate action required for operators beyond normal upgrade practices. Developers should verify that BLOCK_FAILED_CHILD is no longer set anywhere else and that the migration covers all on-disk index versions.
Security signals we found
deprecated status flag migration
block index state cleanup on load
defensive consistency fix in consensus-critical storage layer
Evidence from the diff
BlockManager::LoadBlockIndex() now checks every loaded CBlockIndex entry. If the deprecated BLOCK_FAILED_CHILD bit is set in nStatus, it is cleared and replaced with BLOCK_FAILED_VALID, and the index is inserted into m_dirty_blockindex so the corrected state is flushed to disk. The existing descendant-of-invalid logic is preserved and slightly re-commented. The change prevents stale status bits from persisting and ensures downstream logic that tests BLOCK_FAILED_MASK behaves consistently.
Changed components
src/node/blockstorage.cppBlockManager::LoadBlockIndexCBlockIndex status flagsInspect captured patch +8 / −0
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 62abcbc0..a8d5018f 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -487,10 +487,18 @@ bool BlockManager::LoadBlockIndex(const std::optional<uint256>& snapshot_blockha
pindex->m_chain_tx_count = pindex->nTx;
}
}
+
+ if (pindex->nStatus & BLOCK_FAILED_CHILD) {
+ // BLOCK_FAILED_CHILD is deprecated, but may still exist on disk. Replace it with BLOCK_FAILED_VALID.
+ pindex->nStatus = (pindex->nStatus & ~BLOCK_FAILED_CHILD) | BLOCK_FAILED_VALID;
+ m_dirty_blockindex.insert(pindex);
+ }
if (!(pindex->nStatus & BLOCK_FAILED_MASK) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_MASK)) {
+ // All descendants of invalid blocks are invalid too.
pindex->nStatus |= BLOCK_FAILED_VALID;
m_dirty_blockindex.insert(pindex);
}
+
if (pindex->pprev) {
pindex->BuildSkip();
}
Why this scored 44/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.