message: Release cs_main during RewindBlockIndex operation
diff: @@ -4208,20 +4208,25 @@ void CChainState::EraseBlockData(CBlockIndex* index)
  bool CChainState::RewindBlockIndex(const CChainParams& params)
  {
  - LOCK(cs_main);
  // Note that during -reindex-chainstate we are called with an empty chainActive!
  // First erase all post-segwit blocks without witness not in the main chain,
  // as this can we done without costly DisconnectTip calls. Active
  - // blocks will be dealt with below.
  + // blocks will be dealt with below (releasing cs_main in between).
  + {
  + LOCK(cs_main);
  for (const auto& entry : mapBlockIndex) {
  if (IsWitnessEnabled(entry.second->pprev, params.GetConsensus()) && !(entry.second->nStatus & BLOCK_OPT_WITNESS) && !chainActive.Contains(entry.second)) {
  EraseBlockData(entry.second);
  }
  }
  + }
  // Find what height we need to reorganize to.
  + CBlockIndex *tip;
  int nHeight = 1;
  + {
  + LOCK(cs_main);
  while (nHeight <= chainActive.Height()) {
  // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all
  // blocks in ConnectBlock, we don't need to go back and
  @@ -4232,11 +4237,15 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
  nHeight++;
  }
  + 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) {
  + {
  + LOCK(cs_main);
  // 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;
  @@ -4265,7 +4274,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
  EraseBlockData(tip);
  tip = tip->pprev;
  -
  + }
  // Occasionally flush state to disk.
  if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) {
  LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
  @@ -4273,6 +4282,8 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
  }
  }
  + {
  + 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!
  @@ -4280,6 +4291,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
  CheckBlockIndex(params.GetConsensus());
  }
  + }
  return true;
  }
  