validation: don't treat snapshot block as linked on startup #36702

pull shuv-amp wants to merge 1 commits into bitcoin:master from shuv-amp:fix-snapshot-block-unlinked-on-startup changing 3 files +15 −0
  1. shuv-amp commented at 11:23 AM on October 30, 2026: contributor

    Background sync requests blocks up to and including the snapshot block from several peers at once, so the snapshot block can be stored before one of its ancestors. ReceivedBlockTransactions() then keeps it in m_blocks_unlinked, but that isn't persisted. On restart LoadBlockIndex() gives it the hardcoded m_chain_tx_count, PopulateBlockIndexCandidates() makes it a background candidate, and FindMostWorkChain() walks back to its parent, which has no chain tx count:

    Assertion failed: (pindexTest->HaveNumChainTxs() || pindexTest->nHeight == 0), function FindMostWorkChain, file validation.cpp, line 3217.
    

    It needs a restart in that window, so it should be rare, but after that the node aborts on every start. The only ways out I found are -reindex-chainstate or -reindex, and both delete the snapshot chainstate.

    Fix this by adding the snapshot block to m_blocks_unlinked on startup if an ancestor is missing, and not making it a background candidate until then. Both are needed, without the first one background validation stalls. A node that is already stuck starts with the fix and finishes background validation without a reindex.

    The new step in feature_assumeutxo.py restarts the node after the snapshot block is submitted out of order, and fails on master. I also reproduced it over p2p with a test peer that withholds the snapshot block's parent.

    These are the two changes from #35307 (closed, the motivation there was submitblock before loadtxoutset) without its blockfile and VerifyDB changes. cyb3ralbert hit the same assertion while testing #36452 (https://github.com/bitcoin/bitcoin/pull/36452#issuecomment-6464524112), which is still needed when the snapshot tip is at the snapshot block. #36149 drops the BLOCK_HAVE_DATA check in the branch right below, so whichever is merged second should match it.

  2. validation: don't treat snapshot block as linked on startup
    If the snapshot block is received during background sync before some
    of its ancestors, ReceivedBlockTransactions() adds it to
    m_blocks_unlinked and it isn't a background candidate until the
    missing blocks arrive.
    
    LoadBlockIndex() doesn't restore this on restart. The snapshot block
    gets its m_chain_tx_count from the assumeutxo data and is never added
    to m_blocks_unlinked, so PopulateBlockIndexCandidates() makes it a
    background candidate. FindMostWorkChain() then walks back to its
    parent, which has m_chain_tx_count 0, and hits the HaveNumChainTxs()
    assert. This happens on every restart.
    
    Add the block to m_blocks_unlinked on startup if an ancestor is
    missing, and skip it as a background candidate until then. Without
    the m_blocks_unlinked entry the block isn't picked up when the
    missing blocks arrive, and background validation stalls.
    
    Extend feature_assumeutxo.py to restart the node in this state.
    80f6ddd6cb
  3. DrahtBot added the label Validation on Oct 30, 2026
  4. DrahtBot commented at 11:23 AM on October 30, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--006a51241073e994b41acfe9ec718e94-->

    External sites

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process. A summary of reviews will appear here.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->


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-10-30 15:51 UTC

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