I was issuing the command 'verifyblock 4 0', that is, highest level, all blocks, and then after level 3 verification, when core is performing level 4 verification, it crashes:
bitcoin-qt: [...]/src/validation.cpp:1838: bool CChainState::ConnectBlock(const CBlock&, CValidationState&, CBlockIndex*, CCoinsViewCache&, const CChainParams&, bool): Assertion `hashPrevBlock == view.GetBestBlock()' failed.
Aborted (core dumped)
I did trace the code, and I found out that actually, verifychain (level 4) with any block count higher than the coin cache will result in assertion failure.
If you take a look at CVerifyDB::VerifyDB() in validation.cpp, there's an issue, as follow:
When you specify level 3 or 4, the level 3 verification process will try to disconnect all the blocks, from the tip, down to the depth you specified. It does this on a copy of the coinsview, that is, on a cached view:
CCoinsViewCache coins(coinsview);
Also, the level 3 verification will only disconnect blocks from this cached view that are in memory
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
assert(coins.GetBestBlock() == pindex->GetBlockHash());
DisconnectResult res = g_chainstate.DisconnectBlock(block, pindex, coins);
[...]
}
On my system, with approx 405MB left for coin cache (value I get in nCoinCacheUsage), this gives about 1600 blocks worth of chainstate data.
So, if you specify for example a depth of 2000 blocks, and the coin cache only have 1600 blocks worth of chainstate data, then this inner loop will effectively disconnect only 1600 blocks. The main outer loop will continue to perform level 1 and 2 verification, and just skip verifying undo data on the coin cache (since we do not wish to modify on-disk chainstate data).
Moving out of the main loop (which verify 2000 blocks in the example above), the pindex will have stepped back 2000 blocks.
However, at level 4 verification, the level 4 loop will try to re-connect all the 2000 blocks. It will call ConnectBlock() successively with index (active chain height - 1999) up to (active chain height), providing the coin cache view on which to reconnect the blocks.
However, there is now a de-synchronization, between the block to reconnect (pindex is 2000 blocks away from tip), and the coin cached view (1600 blocks from tip).
So, when ConnectBlock() verify that the provided block's previous block hash is the coin view best block hash, poof!
Eric