| 4626 | } |
| 4627 | |
| 4628 | VerifyDBResult CVerifyDB::VerifyDB( |
| 4629 | Chainstate& chainstate, |
| 4630 | const Consensus::Params& consensus_params, |
| 4631 | CCoinsView& coinsview, |
| 4632 | int nCheckLevel, int nCheckDepth) |
| 4633 | { |
| 4634 | AssertLockHeld(cs_main); |
| 4635 | |
| 4636 | if (chainstate.m_chain.Tip() == nullptr || chainstate.m_chain.Tip()->pprev == nullptr) { |
| 4637 | return VerifyDBResult::SUCCESS; |
| 4638 | } |
| 4639 | |
| 4640 | // Verify blocks in the best chain |
| 4641 | if (nCheckDepth <= 0 || nCheckDepth > chainstate.m_chain.Height()) { |
| 4642 | nCheckDepth = chainstate.m_chain.Height(); |
| 4643 | } |
| 4644 | nCheckLevel = std::max(0, std::min(4, nCheckLevel)); |
| 4645 | LogInfo("Verifying last %i blocks at level %i", nCheckDepth, nCheckLevel); |
| 4646 | CCoinsViewCache coins(&coinsview); |
| 4647 | CBlockIndex* pindex; |
| 4648 | CBlockIndex* pindexFailure = nullptr; |
| 4649 | int nGoodTransactions = 0; |
| 4650 | BlockValidationState state; |
| 4651 | int reportDone = 0; |
| 4652 | bool skipped_no_block_data{false}; |
| 4653 | bool skipped_l3_checks{false}; |
| 4654 | LogInfo("Verification progress: 0%%"); |
| 4655 | |
| 4656 | const bool is_snapshot_cs{chainstate.m_from_snapshot_blockhash}; |
| 4657 | |
| 4658 | for (pindex = chainstate.m_chain.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { |
| 4659 | const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); |
| 4660 | if (reportDone < percentageDone / 10) { |
| 4661 | // report every 10% step |
| 4662 | LogInfo("Verification progress: %d%%", percentageDone); |
| 4663 | reportDone = percentageDone / 10; |
| 4664 | } |
| 4665 | m_notifications.progress(_("Verifying blocks…"), percentageDone, false); |
| 4666 | if (pindex->nHeight <= chainstate.m_chain.Height() - nCheckDepth) { |
| 4667 | break; |
| 4668 | } |
| 4669 | if ((chainstate.m_blockman.IsPruneMode() || is_snapshot_cs) && !(pindex->nStatus & BLOCK_HAVE_DATA)) { |
| 4670 | // If pruning or running under an assumeutxo snapshot, only go |
| 4671 | // back as far as we have data. |
| 4672 | LogInfo("Block verification stopping at height %d (no data). This could be due to pruning or use of an assumeutxo snapshot.", pindex->nHeight); |
| 4673 | skipped_no_block_data = true; |
| 4674 | break; |
| 4675 | } |
| 4676 | CBlock block; |
| 4677 | // check level 0: read from disk |
| 4678 | if (!chainstate.m_blockman.ReadBlock(block, *pindex)) { |
| 4679 | LogError("Verification error: ReadBlock failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); |
| 4680 | return VerifyDBResult::CORRUPTED_BLOCK_DB; |
| 4681 | } |
| 4682 | // check level 1: verify block validity |
| 4683 | if (nCheckLevel >= 1 && !CheckBlock(block, state, consensus_params)) { |
| 4684 | LogError("Verification error: found bad block at %d, hash=%s (%s)", |
| 4685 | pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString()); |
no test coverage detected