From 9a70883002e1fee76c24810808af4fb43f2c8cf5 Mon Sep 17 00:00:00 2001 From: Martin Zumsande Date: Mon, 25 Nov 2024 17:07:53 -0500 Subject: [PATCH] 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 --- src/validation.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 941e433f008..6e6de0ea6e4 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -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; }