| 2287 | } |
| 2288 | |
| 2289 | bool VerifyDB(int32_t nCheckLevel, int32_t nCheckDepth) { |
| 2290 | LOCK(cs_main); |
| 2291 | if (chainActive.Tip() == nullptr || chainActive.Tip()->pprev == nullptr) |
| 2292 | return true; |
| 2293 | |
| 2294 | // Verify blocks in the best chain |
| 2295 | if (nCheckDepth <= 0) |
| 2296 | nCheckDepth = 1000000000; // suffices until the year 19000 |
| 2297 | |
| 2298 | if (nCheckDepth > chainActive.Height()) |
| 2299 | nCheckDepth = chainActive.Height(); |
| 2300 | |
| 2301 | nCheckLevel = max(0, min(4, nCheckLevel)); |
| 2302 | LogPrint(BCLog::INFO, "Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); |
| 2303 | |
| 2304 | auto spCW = std::make_shared<CCacheWrapper>(pCdMan); |
| 2305 | |
| 2306 | CBlockIndex *pIndexState = chainActive.Tip(); |
| 2307 | CBlockIndex *pIndexFailure = nullptr; |
| 2308 | int32_t nGoodTransactions = 0; |
| 2309 | CValidationState state; |
| 2310 | |
| 2311 | for (CBlockIndex *pIndex = chainActive.Tip(); pIndex && pIndex->pprev; pIndex = pIndex->pprev) { |
| 2312 | boost::this_thread::interruption_point(); |
| 2313 | if (pIndex->height < chainActive.Height() - nCheckDepth) |
| 2314 | break; |
| 2315 | |
| 2316 | CBlock block; |
| 2317 | // check level 0: read from disk |
| 2318 | if (!ReadBlockFromDisk(pIndex, block)) |
| 2319 | return ERRORMSG("*** ReadBlockFromDisk failed at %d, hash=%s", |
| 2320 | pIndex->height, pIndex->GetBlockHash().ToString()); |
| 2321 | |
| 2322 | // check level 1: verify block validity |
| 2323 | if (nCheckLevel >= 1 && !CheckBlock(block, state, *spCW, false)) |
| 2324 | return ERRORMSG("*** found bad block at %d, hash=%s\n", |
| 2325 | pIndex->height, pIndex->GetBlockHash().ToString()); |
| 2326 | |
| 2327 | // check level 2: verify undo validity |
| 2328 | if (nCheckLevel >= 2 && pIndex) { |
| 2329 | CBlockUndo undo; |
| 2330 | CDiskBlockPos pos = pIndex->GetUndoPos(); |
| 2331 | if (!pos.IsNull()) { |
| 2332 | if (!undo.ReadFromDisk(pos, pIndex->pprev->GetBlockHash())) |
| 2333 | return ERRORMSG("*** found bad undo data at %d, hash=%s\n", |
| 2334 | pIndex->height, pIndex->GetBlockHash().ToString()); |
| 2335 | } |
| 2336 | } |
| 2337 | // check level 3: check for inconsistencies during memory-only disconnect of tip blocks |
| 2338 | if (nCheckLevel >= 3 && pIndex == pIndexState) { |
| 2339 | bool fClean = true; |
| 2340 | if (!DisconnectBlock(block, *spCW, pIndex, state, &fClean)) |
| 2341 | return ERRORMSG("*** irrecoverable inconsistency in block data at %d, hash=%s", |
| 2342 | pIndex->height, pIndex->GetBlockHash().ToString()); |
| 2343 | |
| 2344 | pIndexState = pIndex->pprev; |
| 2345 | if (!fClean) { |
| 2346 | nGoodTransactions = 0; |
no test coverage detected