| 3529 | } |
| 3530 | |
| 3531 | bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* const pindex) |
| 3532 | { |
| 3533 | AssertLockNotHeld(m_chainstate_mutex); |
| 3534 | AssertLockNotHeld(::cs_main); |
| 3535 | |
| 3536 | // Genesis block can't be invalidated |
| 3537 | assert(pindex); |
| 3538 | if (pindex->nHeight == 0) return false; |
| 3539 | |
| 3540 | // We do not allow ActivateBestChain() to run while InvalidateBlock() is |
| 3541 | // running, as that could cause the tip to change while we disconnect |
| 3542 | // blocks. |
| 3543 | LOCK(m_chainstate_mutex); |
| 3544 | |
| 3545 | // We'll be acquiring and releasing cs_main below, to allow the validation |
| 3546 | // callbacks to run. However, we should keep the block index in a |
| 3547 | // consistent state as we disconnect blocks -- in particular we need to |
| 3548 | // add equal-work blocks to setBlockIndexCandidates as we disconnect. |
| 3549 | // To avoid walking the block index repeatedly in search of candidates, |
| 3550 | // build a map once so that we can look up candidate blocks by chain |
| 3551 | // work as we go. |
| 3552 | std::multimap<const arith_uint256, CBlockIndex*> highpow_outofchain_headers; |
| 3553 | |
| 3554 | { |
| 3555 | LOCK(cs_main); |
| 3556 | for (auto& entry : m_blockman.m_block_index) { |
| 3557 | CBlockIndex& candidate = entry.second; |
| 3558 | // We don't need to put anything in our active chain into the |
| 3559 | // multimap, because those candidates will be found and considered |
| 3560 | // as we disconnect. |
| 3561 | // Instead, consider only non-active-chain blocks that score |
| 3562 | // at least as good with CBlockIndexWorkComparator as the new tip. |
| 3563 | if (!m_chain.Contains(candidate) && |
| 3564 | !CBlockIndexWorkComparator()(&candidate, pindex->pprev) && |
| 3565 | !(candidate.nStatus & BLOCK_FAILED_VALID)) { |
| 3566 | highpow_outofchain_headers.insert({candidate.nChainWork, &candidate}); |
| 3567 | } |
| 3568 | } |
| 3569 | } |
| 3570 | |
| 3571 | CBlockIndex* to_mark_failed = pindex; |
| 3572 | bool pindex_was_in_chain = false; |
| 3573 | int disconnected = 0; |
| 3574 | |
| 3575 | // Disconnect (descendants of) pindex, and mark them invalid. |
| 3576 | while (true) { |
| 3577 | if (m_chainman.m_interrupt) break; |
| 3578 | |
| 3579 | // Make sure the queue of validation callbacks doesn't grow unboundedly. |
| 3580 | if (m_chainman.m_options.signals) LimitValidationInterfaceQueue(*m_chainman.m_options.signals); |
| 3581 | |
| 3582 | LOCK(cs_main); |
| 3583 | // Lock for as long as disconnectpool is in scope to make sure MaybeUpdateMempoolForReorg is |
| 3584 | // called after DisconnectTip without unlocking in between |
| 3585 | LOCK(MempoolMutex()); |
| 3586 | if (!m_chain.Contains(*pindex)) break; |
| 3587 | pindex_was_in_chain = true; |
| 3588 | CBlockIndex* const disconnected_tip{m_chain.Tip()}; |