@@ -4208,77 +4208,89 @@ void CChainState::EraseBlockData(CBlockIndex* index)
42084208
42094209bool CChainState::RewindBlockIndex (const CChainParams& params)
42104210{
4211- LOCK (cs_main);
42124211 // Note that during -reindex-chainstate we are called with an empty chainActive!
42134212
42144213 // First erase all post-segwit blocks without witness not in the main chain,
42154214 // as this can we done without costly DisconnectTip calls. Active
4216- // blocks will be dealt with below.
4217- for (const auto & entry : mapBlockIndex) {
4218- if (IsWitnessEnabled (entry.second ->pprev , params.GetConsensus ()) && !(entry.second ->nStatus & BLOCK_OPT_WITNESS) && !chainActive.Contains (entry.second )) {
4219- EraseBlockData (entry.second );
4215+ // blocks will be dealt with below (releasing cs_main in between).
4216+ {
4217+ LOCK (cs_main);
4218+ for (const auto & entry : mapBlockIndex) {
4219+ if (IsWitnessEnabled (entry.second ->pprev , params.GetConsensus ()) && !(entry.second ->nStatus & BLOCK_OPT_WITNESS) && !chainActive.Contains (entry.second )) {
4220+ EraseBlockData (entry.second );
4221+ }
42204222 }
42214223 }
42224224
42234225 // Find what height we need to reorganize to.
4226+ CBlockIndex *tip;
42244227 int nHeight = 1 ;
4225- while (nHeight <= chainActive.Height ()) {
4226- // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all
4227- // blocks in ConnectBlock, we don't need to go back and
4228- // re-download/re-verify blocks from before segwit actually activated.
4229- if (IsWitnessEnabled (chainActive[nHeight - 1 ], params.GetConsensus ()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
4230- break ;
4228+ {
4229+ LOCK (cs_main);
4230+ while (nHeight <= chainActive.Height ()) {
4231+ // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all
4232+ // blocks in ConnectBlock, we don't need to go back and
4233+ // re-download/re-verify blocks from before segwit actually activated.
4234+ if (IsWitnessEnabled (chainActive[nHeight - 1 ], params.GetConsensus ()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
4235+ break ;
4236+ }
4237+ nHeight++;
42314238 }
4232- nHeight++;
4233- }
42344239
4240+ tip = chainActive.Tip ();
4241+ }
42354242 // nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
4243+
42364244 CValidationState state;
4237- CBlockIndex* tip = chainActive.Tip ();
42384245 // Loop until the tip is below nHeight, or we reach a pruned block.
42394246 while (true ) {
4240- // Make sure nothing changed from under us (this won't happen because RewindBlockIndex runs before importing/network are active)
4241- assert (tip == chainActive.Tip ());
4242- if (tip == nullptr || tip->nHeight < nHeight) break ;
4243- if (fPruneMode && !(tip->nStatus & BLOCK_HAVE_DATA)) {
4244- // If pruning, don't try rewinding past the HAVE_DATA point;
4245- // since older blocks can't be served anyway, there's
4246- // no need to walk further, and trying to DisconnectTip()
4247- // will fail (and require a needless reindex/redownload
4248- // of the blockchain).
4249- break ;
4250- }
4251-
4252- // Disconnect block
4253- if (!DisconnectTip (state, params, nullptr )) {
4254- return error (" RewindBlockIndex: unable to disconnect block at height %i (%s)" , tip->nHeight , FormatStateMessage (state));
4255- }
4247+ {
4248+ LOCK (cs_main);
4249+ // Make sure nothing changed from under us (this won't happen because RewindBlockIndex runs before importing/network are active)
4250+ assert (tip == chainActive.Tip ());
4251+ if (tip == nullptr || tip->nHeight < nHeight) break ;
4252+ if (fPruneMode && !(tip->nStatus & BLOCK_HAVE_DATA)) {
4253+ // If pruning, don't try rewinding past the HAVE_DATA point;
4254+ // since older blocks can't be served anyway, there's
4255+ // no need to walk further, and trying to DisconnectTip()
4256+ // will fail (and require a needless reindex/redownload
4257+ // of the blockchain).
4258+ break ;
4259+ }
42564260
4257- // Reduce validity flag and have-data flags.
4258- // We do this after actual disconnecting, otherwise we'll end up writing the lack of data
4259- // to disk before writing the chainstate, resulting in a failure to continue if interrupted.
4260- // Note: If we encounter an insufficiently validated block that
4261- // is on chainActive, it must be because we are a pruning node, and
4262- // this block or some successor doesn't HAVE_DATA, so we were unable to
4263- // rewind all the way. Blocks remaining on chainActive at this point
4264- // must not have their validity reduced.
4265- EraseBlockData (tip);
4261+ // Disconnect block
4262+ if (!DisconnectTip (state, params, nullptr )) {
4263+ return error (" RewindBlockIndex: unable to disconnect block at height %i (%s)" , tip->nHeight , FormatStateMessage (state));
4264+ }
42664265
4267- tip = tip->pprev ;
4266+ // Reduce validity flag and have-data flags.
4267+ // We do this after actual disconnecting, otherwise we'll end up writing the lack of data
4268+ // to disk before writing the chainstate, resulting in a failure to continue if interrupted.
4269+ // Note: If we encounter an insufficiently validated block that
4270+ // is on chainActive, it must be because we are a pruning node, and
4271+ // this block or some successor doesn't HAVE_DATA, so we were unable to
4272+ // rewind all the way. Blocks remaining on chainActive at this point
4273+ // must not have their validity reduced.
4274+ EraseBlockData (tip);
42684275
4276+ tip = tip->pprev ;
4277+ }
42694278 // Occasionally flush state to disk.
42704279 if (!FlushStateToDisk (params, state, FlushStateMode::PERIODIC)) {
42714280 LogPrintf (" RewindBlockIndex: unable to flush state to disk (%s)\n " , FormatStateMessage (state));
42724281 return false ;
42734282 }
42744283 }
42754284
4276- if (chainActive.Tip () != nullptr ) {
4277- // We can't prune block index candidates based on our tip if we have
4278- // no tip due to chainActive being empty!
4279- PruneBlockIndexCandidates ();
4285+ {
4286+ LOCK (cs_main);
4287+ if (chainActive.Tip () != nullptr ) {
4288+ // We can't prune block index candidates based on our tip if we have
4289+ // no tip due to chainActive being empty!
4290+ PruneBlockIndexCandidates ();
42804291
4281- CheckBlockIndex (params.GetConsensus ());
4292+ CheckBlockIndex (params.GetConsensus ());
4293+ }
42824294 }
42834295
42844296 return true ;
0 commit comments