@@ -4208,77 +4208,89 @@ void CChainState::EraseBlockData(CBlockIndex* index)
4208
4208
4209
4209
bool CChainState::RewindBlockIndex (const CChainParams& params)
4210
4210
{
4211
- LOCK (cs_main);
4212
4211
// Note that during -reindex-chainstate we are called with an empty chainActive!
4213
4212
4214
4213
// First erase all post-segwit blocks without witness not in the main chain,
4215
4214
// 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
+ }
4220
4222
}
4221
4223
}
4222
4224
4223
4225
// Find what height we need to reorganize to.
4226
+ CBlockIndex *tip;
4224
4227
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++;
4231
4238
}
4232
- nHeight++;
4233
- }
4234
4239
4240
+ tip = chainActive.Tip ();
4241
+ }
4235
4242
// nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
4243
+
4236
4244
CValidationState state;
4237
- CBlockIndex* tip = chainActive.Tip ();
4238
4245
// Loop until the tip is below nHeight, or we reach a pruned block.
4239
4246
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
+ }
4256
4260
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
+ }
4266
4265
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);
4268
4275
4276
+ tip = tip->pprev ;
4277
+ }
4269
4278
// Occasionally flush state to disk.
4270
4279
if (!FlushStateToDisk (params, state, FlushStateMode::PERIODIC)) {
4271
4280
LogPrintf (" RewindBlockIndex: unable to flush state to disk (%s)\n " , FormatStateMessage (state));
4272
4281
return false ;
4273
4282
}
4274
4283
}
4275
4284
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 ();
4280
4291
4281
- CheckBlockIndex (params.GetConsensus ());
4292
+ CheckBlockIndex (params.GetConsensus ());
4293
+ }
4282
4294
}
4283
4295
4284
4296
return true ;
0 commit comments