Skip to content

Commit 0ae7281

Browse files
committed
Add a checkfor the previous invalid comparison of invalid_walk_tip
This adds a new test in CheckBlockIndex which tests that any descendants of a block marked BLOCK_FAILED_VALID will not be marked BLOCK_FAILED_VALID as they should never have been connected in the first place. Note that this check requires further changes in InvalidateBlock as if you iteratively call InvalidateBlock to walk the chain backwards (instead of calling InvalidateBlock on an old block and allowing it to do the walking), the later-in-the-chain blocks will violate this.
1 parent f043ca0 commit 0ae7281

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

src/validation.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2792,6 +2792,8 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
27922792
// work as we go.
27932793
std::multimap<const arith_uint256, CBlockIndex *> candidate_blocks_by_work;
27942794

2795+
std::set<CBlockIndex *> failed_valid_descendants;
2796+
27952797
{
27962798
LOCK(cs_main);
27972799
for (const auto& entry : m_blockman.m_block_index) {
@@ -2801,11 +2803,12 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
28012803
// as we disconnect.
28022804
// Instead, consider only non-active-chain blocks that have at
28032805
// least as much work as where we expect the new tip to end up.
2804-
if (!m_chain.Contains(candidate) &&
2805-
!CBlockIndexWorkComparator()(candidate, pindex->pprev) &&
2806-
candidate->IsValid(BLOCK_VALID_TRANSACTIONS) &&
2807-
candidate->HaveTxsDownloaded()) {
2808-
candidate_blocks_by_work.insert(std::make_pair(candidate->nChainWork, candidate));
2806+
if (!m_chain.Contains(candidate) && !CBlockIndexWorkComparator()(candidate, pindex->pprev)) {
2807+
if (candidate->IsValid(BLOCK_VALID_TRANSACTIONS) && candidate->HaveTxsDownloaded()) {
2808+
candidate_blocks_by_work.insert(std::make_pair(candidate->nChainWork, candidate));
2809+
} else if ((candidate->nStatus & BLOCK_FAILED_VALID) && candidate->GetAncestor(pindex->nHeight) == pindex) {
2810+
failed_valid_descendants.insert(candidate);
2811+
}
28092812
}
28102813
}
28112814
}
@@ -2863,6 +2866,15 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
28632866
}
28642867
}
28652868

2869+
for (auto candidate_descendant_it = failed_valid_descendants.begin(); candidate_descendant_it != failed_valid_descendants.end(); ) {
2870+
if ((*candidate_descendant_it)->nHeight > invalid_walk_tip->nHeight && (*candidate_descendant_it)->GetAncestor(invalid_walk_tip->nHeight) == invalid_walk_tip) {
2871+
(*candidate_descendant_it)->nStatus = ((*candidate_descendant_it)->nStatus ^ BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD;
2872+
candidate_descendant_it = failed_valid_descendants.erase(candidate_descendant_it);
2873+
} else {
2874+
++candidate_descendant_it;
2875+
}
2876+
}
2877+
28662878
// Track the last disconnected block, so we can correct its BLOCK_FAILED_CHILD status in future
28672879
// iterations, or, if it's the last one, call InvalidChainFound on it.
28682880
to_mark_failed = invalid_walk_tip;
@@ -4652,6 +4664,11 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
46524664
if (pindexFirstInvalid == nullptr) {
46534665
// Checks for not-invalid blocks.
46544666
assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents.
4667+
} else if (pindexFirstInvalid != pindex) {
4668+
// If a parent is invalid, we may be BLOCK_FAILED_CHILD (though no guarantee thereof),
4669+
// but we must not be BLOCK_FAILED_VALID (as we shouldn't have attempted to connect
4670+
// this block in the first place).
4671+
assert((pindex->nStatus & BLOCK_FAILED_VALID) == 0);
46554672
}
46564673
if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && pindexFirstNeverProcessed == nullptr) {
46574674
if (pindexFirstInvalid == nullptr) {

0 commit comments

Comments
 (0)