| 4231 | } |
| 4232 | |
| 4233 | bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) |
| 4234 | { |
| 4235 | LOCK(cs_main); |
| 4236 | if (chainActive.Tip() == nullptr || chainActive.Tip()->pprev == nullptr) |
| 4237 | return true; |
| 4238 | |
| 4239 | // Verify blocks in the best chain |
| 4240 | if (nCheckDepth <= 0 || nCheckDepth > chainActive.Height()) |
| 4241 | nCheckDepth = chainActive.Height(); |
| 4242 | nCheckLevel = std::max(0, std::min(4, nCheckLevel)); |
| 4243 | LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); |
| 4244 | CCoinsViewCache coins(coinsview); |
| 4245 | CBlockIndex* pindex; |
| 4246 | CBlockIndex* pindexFailure = nullptr; |
| 4247 | int nGoodTransactions = 0; |
| 4248 | CValidationState state; |
| 4249 | int reportDone = 0; |
| 4250 | LogPrintf("[0%%]..."); /* Continued */ |
| 4251 | for (pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) { |
| 4252 | boost::this_thread::interruption_point(); |
| 4253 | int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100)))); |
| 4254 | if (reportDone < percentageDone/10) { |
| 4255 | // report every 10% step |
| 4256 | LogPrintf("[%d%%]...", percentageDone); /* Continued */ |
| 4257 | reportDone = percentageDone/10; |
| 4258 | } |
| 4259 | uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false); |
| 4260 | if (pindex->nHeight <= chainActive.Height()-nCheckDepth) |
| 4261 | break; |
| 4262 | if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) { |
| 4263 | // If pruning, only go back as far as we have data. |
| 4264 | LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight); |
| 4265 | break; |
| 4266 | } |
| 4267 | CBlock block; |
| 4268 | // check level 0: read from disk |
| 4269 | if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) |
| 4270 | return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); |
| 4271 | // check level 1: verify block validity |
| 4272 | if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams.GetConsensus())) |
| 4273 | return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__, |
| 4274 | pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state)); |
| 4275 | // check level 2: verify undo validity |
| 4276 | if (nCheckLevel >= 2 && pindex) { |
| 4277 | CBlockUndo undo; |
| 4278 | if (!pindex->GetUndoPos().IsNull()) { |
| 4279 | if (!UndoReadFromDisk(undo, pindex)) { |
| 4280 | return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); |
| 4281 | } |
| 4282 | } |
| 4283 | } |
| 4284 | // check level 3: check for inconsistencies during memory-only disconnect of tip blocks |
| 4285 | if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { |
| 4286 | assert(coins.GetBestBlock() == pindex->GetBlockHash()); |
| 4287 | DisconnectResult res = g_chainstate.DisconnectBlock(block, pindex, coins); |
| 4288 | if (res == DISCONNECT_FAILED) { |
| 4289 | return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); |
| 4290 | } |
no test coverage detected