Skip to content

Commit 8e39f2d

Browse files
committed
validation: in invalidateblock, mark children as invalid right away
Before, they would be marked as invalid only after disconnecting multiple blocks, letting go of cs_main in the meantime. This is in preparation for adding a check to CheckBlockIndex() requiring that descendants of invalid block indexes are always marked as invalid. Entries from highpow_outofchain_headers are now only removed if made invalid, no longer after inserting into setBlockIndexCandidates, because they might still become invalid later in the second case. This means that blocks could be inserted multiple times now into setBlockIndexCandidates - this won't have any effect, so behavior isn't changed.
1 parent 4c29326 commit 8e39f2d

File tree

1 file changed

+16
-4
lines changed

1 file changed

+16
-4
lines changed

src/validation.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3753,18 +3753,30 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
37533753
m_blockman.m_dirty_blockindex.insert(to_mark_failed);
37543754
}
37553755

3756-
// Add any equal or more work headers to setBlockIndexCandidates
3756+
// Mark out-of-chain descendants of the invalidated block as invalid
3757+
// (possibly replacing a pre-existing BLOCK_FAILED_VALID with BLOCK_FAILED_CHILD)
3758+
// Add any equal or more work headers that are not invalidated to setBlockIndexCandidates
37573759
auto candidate_it = highpow_outofchain_headers.lower_bound(invalid_walk_tip->pprev->nChainWork);
37583760
while (candidate_it != highpow_outofchain_headers.end()) {
37593761
CBlockIndex* candidate{candidate_it->second};
3762+
if (candidate->GetAncestor(invalid_walk_tip->nHeight) == invalid_walk_tip) {
3763+
// Children of failed blocks should be marked as BLOCK_FAILED_CHILD instead.
3764+
candidate->nStatus &= ~BLOCK_FAILED_VALID;
3765+
candidate->nStatus |= BLOCK_FAILED_CHILD;
3766+
m_blockman.m_dirty_blockindex.insert(candidate);
3767+
// If invalidated, the block is irrelevant for setBlockIndexCandidates
3768+
// and can be removed from the cache.
3769+
candidate_it = highpow_outofchain_headers.erase(candidate_it);
3770+
continue;
3771+
}
37603772
if (!CBlockIndexWorkComparator()(candidate, invalid_walk_tip->pprev) &&
37613773
candidate->IsValid(BLOCK_VALID_TRANSACTIONS) &&
37623774
candidate->HaveNumChainTxs()) {
37633775
setBlockIndexCandidates.insert(candidate);
3764-
candidate_it = highpow_outofchain_headers.erase(candidate_it);
3765-
} else {
3766-
++candidate_it;
3776+
// Do not remove candidate from the highpow_outofchain_headers cache, because it might be a descendant of the block being invalidated
3777+
// which needs to be marked failed later.
37673778
}
3779+
++candidate_it;
37683780
}
37693781

37703782
// Track the last disconnected block, so we can correct its BLOCK_FAILED_CHILD status in future

0 commit comments

Comments
 (0)