Skip to content

Commit 436f7d7

Browse files
committed
Release cs_main during RewindBlockIndex operation
1 parent 1d34287 commit 436f7d7

File tree

1 file changed

+57
-45
lines changed

1 file changed

+57
-45
lines changed

src/validation.cpp

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4208,77 +4208,89 @@ void CChainState::EraseBlockData(CBlockIndex* index)
42084208

42094209
bool 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

Comments
 (0)