'verifychain 4 0' result in "const CChainParams&, bool): Assertion `hashPrevBlock == view.GetBestBlock()' failed" #15316

issue ehoffman2 opened this issue on February 1, 2019
  1. ehoffman2 commented at 3:03 PM on February 1, 2019: none

    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

  2. MarcoFalke added the label Data corruption on Feb 1, 2019
  3. MarcoFalke added the label Validation on Feb 1, 2019
  4. MarcoFalke removed the label Data corruption on Feb 1, 2019
  5. MarcoFalke commented at 3:28 PM on April 26, 2020: member

    Yes, you will have to add more memory for the operation to succeed. Is there anything that can be done in Bitcoin Core?

  6. MarcoFalke closed this on Apr 26, 2020

  7. MarcoFalke locked this on Feb 15, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-15 18:15 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me