validation: in invalidateblock, calculate m_best_header right away

Before, m_best_header would be calculated only after disconnecting
multiple blocks, letting go of cs_main in the meantime.
This is in preparation for adding checks to CheckBlockIndex()
requiring that m_best_header is the most-work header not known to be invalid.

Co-authored-by: stringintech <stringintech@gmail.com>
This commit is contained in:
Martin Zumsande
2024-11-25 17:07:53 -05:00
parent 8e39f2d20d
commit 9a70883002

View File

@@ -3756,7 +3756,15 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
// Mark out-of-chain descendants of the invalidated block as invalid
// (possibly replacing a pre-existing BLOCK_FAILED_VALID with BLOCK_FAILED_CHILD)
// Add any equal or more work headers that are not invalidated to setBlockIndexCandidates
// Recalculate m_best_header if it became invalid.
auto candidate_it = highpow_outofchain_headers.lower_bound(invalid_walk_tip->pprev->nChainWork);
const bool best_header_needs_update{m_chainman.m_best_header->GetAncestor(invalid_walk_tip->nHeight) == invalid_walk_tip};
if (best_header_needs_update) {
// pprev is definitely still valid at this point, but there may be better ones
m_chainman.m_best_header = invalid_walk_tip->pprev;
}
while (candidate_it != highpow_outofchain_headers.end()) {
CBlockIndex* candidate{candidate_it->second};
if (candidate->GetAncestor(invalid_walk_tip->nHeight) == invalid_walk_tip) {
@@ -3765,7 +3773,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
candidate->nStatus |= BLOCK_FAILED_CHILD;
m_blockman.m_dirty_blockindex.insert(candidate);
// If invalidated, the block is irrelevant for setBlockIndexCandidates
// and can be removed from the cache.
// and for m_best_header and can be removed from the cache.
candidate_it = highpow_outofchain_headers.erase(candidate_it);
continue;
}
@@ -3776,6 +3784,10 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
// Do not remove candidate from the highpow_outofchain_headers cache, because it might be a descendant of the block being invalidated
// which needs to be marked failed later.
}
if (best_header_needs_update &&
m_chainman.m_best_header->nChainWork < candidate->nChainWork) {
m_chainman.m_best_header = candidate;
}
++candidate_it;
}