diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4986,60 +4986,70 @@ } bool CChainState::RewindBlockIndex(const Config &config) { - LOCK(cs_main); + const CChainParams ¶ms = config.GetChainParams(); + + int nHeight = 1; + CBlockIndex *tip; // Reduce validity flag and have-data flags. // We do this after actual disconnecting, otherwise we'll end up writing the // lack of data to disk before writing the chainstate, resulting in a // failure to continue if interrupted. - for (const auto &entry : mapBlockIndex) { - CBlockIndex *pindexIter = entry.second; - if (pindexIter->IsValid(BlockValidity::TRANSACTIONS) && - pindexIter->HaveTxsDownloaded()) { - setBlockIndexCandidates.insert(pindexIter); + { + LOCK(cs_main); + for (const auto &entry : mapBlockIndex) { + CBlockIndex *pindexIter = entry.second; + if (pindexIter->IsValid(BlockValidity::TRANSACTIONS) && + pindexIter->HaveTxsDownloaded()) { + setBlockIndexCandidates.insert(pindexIter); + } } - } - const CChainParams ¶ms = config.GetChainParams(); - int nHeight = chainActive.Height() + 1; + nHeight = chainActive.Height() + 1; + // nHeight is now the height of the first insufficiently-validated + // block, or tipheight + 1 + + tip = chainActive.Tip(); + } - // nHeight is now the height of the first insufficiently-validated block, or - // tipheight + 1 CValidationState state; - CBlockIndex *tip = chainActive.Tip(); // Loop until the tip is below nHeight, or we reach a pruned block. while (true) { - // Make sure nothing changed from under us (this won't happen because - // RewindBlockIndex runs before importing/network are active) - assert(tip == chainActive.Tip()); - if (tip == nullptr || tip->nHeight < nHeight) break; - if (fPruneMode && !chainActive.Tip()->nStatus.hasData()) { - // If pruning, don't try rewinding past the HAVE_DATA point; since - // older blocks can't be served anyway, there's no need to walk - // further, and trying to DisconnectTip() will fail (and require a - // needless reindex/redownload of the blockchain). - break; - } + { + LOCK(cs_main); - // Disconnect block - if (!DisconnectTip(config, state, nullptr)) { - return error("RewindBlockIndex: unable to disconnect block at " - "height %i (%s)", - tip->nHeight, FormatStateMessage(state)); - } + // Make sure nothing changed from under us (this won't happen + // because RewindBlockIndex runs before importing/network are + // active) + assert(tip == chainActive.Tip()); + if (tip == nullptr || tip->nHeight < nHeight) break; + if (fPruneMode && !chainActive.Tip()->nStatus.hasData()) { + // If pruning, don't try rewinding past the HAVE_DATA point; + // since older blocks can't be served anyway, there's no need to + // walk further, and trying to DisconnectTip() will fail (and + // require a needless reindex/redownload of the blockchain). + break; + } - // Reduce validity flag and have-data flags. - // We do this after actual disconnecting, otherwise we'll end up writing - // the lack of data to disk before writing the chainstate, resulting in - // a failure to continue if interrupted. Note: If we encounter an - // insufficiently validated block that is on chainActive, it must be - // because we are a pruning node, and this block or some successor - // doesn't HAVE_DATA, so we were unable to rewind all the way. Blocks - // remaining on chainActive at this point must not have their validity - // reduced. - EraseBlockData(tip); + // Disconnect block + if (!DisconnectTip(config, state, nullptr)) { + return error("RewindBlockIndex: unable to disconnect block at " + "height %i (%s)", + tip->nHeight, FormatStateMessage(state)); + } - tip = tip->pprev; + // Reduce validity flag and have-data flags. + // We do this after actual disconnecting, otherwise we'll end up + // writing the lack of data to disk before writing the chainstate, + // resulting in a failure to continue if interrupted. Note: If we + // encounter an insufficiently validated block that is on + // chainActive, it must be because we are a pruning node, and this + // block or some successor doesn't HAVE_DATA, so we were unable to + // rewind all the way. Blocks remaining on chainActive at this + // point must not have their validity reduced. + EraseBlockData(tip); + tip = tip->pprev; + } // Occasionally flush state to disk. if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) { @@ -5049,12 +5059,15 @@ } } - if (chainActive.Tip() != nullptr) { - // We can't prune block index candidates based on our tip if we have - // no tip due to chainActive being empty! - PruneBlockIndexCandidates(); + { + LOCK(cs_main); + if (chainActive.Tip() != nullptr) { + // We can't prune block index candidates based on our tip if we have + // no tip due to chainActive being empty! + PruneBlockIndexCandidates(); - CheckBlockIndex(params.GetConsensus()); + CheckBlockIndex(params.GetConsensus()); + } } return true;