| 4415 | } |
| 4416 | |
| 4417 | bool CChainState::RewindBlockIndex(const CChainParams& params) |
| 4418 | { |
| 4419 | LOCK(cs_main); |
| 4420 | |
| 4421 | // Note that during -reindex-chainstate we are called with an empty chainActive! |
| 4422 | |
| 4423 | int nHeight = 1; |
| 4424 | while (nHeight <= chainActive.Height()) { |
| 4425 | // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all |
| 4426 | // blocks in ConnectBlock, we don't need to go back and |
| 4427 | // re-download/re-verify blocks from before segwit actually activated. |
| 4428 | if (IsWitnessEnabled(chainActive[nHeight - 1], params.GetConsensus()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) { |
| 4429 | break; |
| 4430 | } |
| 4431 | nHeight++; |
| 4432 | } |
| 4433 | |
| 4434 | // nHeight is now the height of the first insufficiently-validated block, or tipheight + 1 |
| 4435 | CValidationState state; |
| 4436 | CBlockIndex* pindex = chainActive.Tip(); |
| 4437 | while (chainActive.Height() >= nHeight) { |
| 4438 | if (fPruneMode && !(chainActive.Tip()->nStatus & BLOCK_HAVE_DATA)) { |
| 4439 | // If pruning, don't try rewinding past the HAVE_DATA point; |
| 4440 | // since older blocks can't be served anyway, there's |
| 4441 | // no need to walk further, and trying to DisconnectTip() |
| 4442 | // will fail (and require a needless reindex/redownload |
| 4443 | // of the blockchain). |
| 4444 | break; |
| 4445 | } |
| 4446 | if (!DisconnectTip(state, params, nullptr)) { |
| 4447 | return error("RewindBlockIndex: unable to disconnect block at height %i (%s)", pindex->nHeight, FormatStateMessage(state)); |
| 4448 | } |
| 4449 | // Occasionally flush state to disk. |
| 4450 | if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) { |
| 4451 | LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state)); |
| 4452 | return false; |
| 4453 | } |
| 4454 | } |
| 4455 | |
| 4456 | // Reduce validity flag and have-data flags. |
| 4457 | // We do this after actual disconnecting, otherwise we'll end up writing the lack of data |
| 4458 | // to disk before writing the chainstate, resulting in a failure to continue if interrupted. |
| 4459 | for (const auto& entry : mapBlockIndex) { |
| 4460 | CBlockIndex* pindexIter = entry.second; |
| 4461 | |
| 4462 | // Note: If we encounter an insufficiently validated block that |
| 4463 | // is on chainActive, it must be because we are a pruning node, and |
| 4464 | // this block or some successor doesn't HAVE_DATA, so we were unable to |
| 4465 | // rewind all the way. Blocks remaining on chainActive at this point |
| 4466 | // must not have their validity reduced. |
| 4467 | if (IsWitnessEnabled(pindexIter->pprev, params.GetConsensus()) && !(pindexIter->nStatus & BLOCK_OPT_WITNESS) && !chainActive.Contains(pindexIter)) { |
| 4468 | // Reduce validity |
| 4469 | pindexIter->nStatus = std::min<unsigned int>(pindexIter->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | (pindexIter->nStatus & ~BLOCK_VALID_MASK); |
| 4470 | // Remove have-data flags. |
| 4471 | pindexIter->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO); |
| 4472 | // Remove storage location. |
| 4473 | pindexIter->nFile = 0; |
| 4474 | pindexIter->nDataPos = 0; |
no test coverage detected