rpc: fix dumptxoutset rollback crash after loadtxoutset on pruned node #36351

pull FlashWayne wants to merge 2 commits into bitcoin:master from FlashWayne:fix-dumptxoutset-rollback-snapshot-tip changing 2 files +9 −0
  1. FlashWayne commented at 10:33 PM on September 26, 2026: none

    On a pruned node, dumptxoutset with rollback checks that the blocks it needs haven't been pruned by calling GetFirstBlock(*current_tip, BLOCK_HAVE_MASK) (blockchain.cpp:3194). GetFirstBlock asserts that the block it starts from has both block and undo data (blockstorage.cpp:638).

    Right after loadtxoutset, the active tip is the snapshot base block, and that has neither until it's downloaded. So on a -prune node:

    loadtxoutset <snapshot>
    dumptxoutset <path> rollback=<height>
    

    aborts bitcoind:

    Assertion failed: ((last_block->nStatus & status_mask) == status_mask), function GetFirstBlock, file blockstorage.cpp, line 638.
    

    The GetPruneHeight helper already guards against a tip without data (blockchain.cpp:934), this call site doesn't.

    This returns the existing "Could not roll back to requested height since necessary block data is already pruned." error when the tip itself has no data, before calling GetFirstBlock.

    The test goes in feature_assumeutxo.py, right after the snapshot is loaded on the pruned node (node 1): dumptxoutset with a rollback to the start height must return that error. On master the RPC times out because the node aborted. With the fix feature_assumeutxo.py and rpc_dumptxoutset.py pass.

  2. rpc: fix dumptxoutset rollback crash after loadtxoutset on pruned node
    On a pruned node, dumptxoutset with rollback calls GetFirstBlock on the
    active chain tip to check that the needed block data hasn't been
    pruned. GetFirstBlock asserts that the block it starts from has block
    and undo data. Right after loadtxoutset the active tip is the snapshot
    base block, which has neither until it is downloaded, so the call
    aborts bitcoind:
    
      Assertion failed: ((last_block->nStatus & status_mask) == status_mask),
      function GetFirstBlock, file blockstorage.cpp
    
    Return the existing "necessary block data is already pruned" error when
    the tip itself has no data.
    a9e79810b2
  3. DrahtBot added the label RPC/REST/ZMQ on Sep 26, 2026
  4. DrahtBot commented at 10:33 PM on September 26, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/36351.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

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

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  5. in test/functional/feature_assumeutxo.py:532 in a9e79810b2
     527 | @@ -528,6 +528,10 @@ def check_dump_output(output):
     528 |          assert_equal(loaded['coins_loaded'], SNAPSHOT_BASE_HEIGHT)
     529 |          assert_equal(loaded['base_height'], SNAPSHOT_BASE_HEIGHT)
     530 |  
     531 | +        self.log.info("Check that dumptxoutset rollback fails cleanly on a pruned node without the snapshot base block")
     532 | +        assert_raises_rpc_error(-1, "Could not roll back to requested height since necessary block data is already pruned.",
    


    fjahr commented at 11:31 PM on September 26, 2026:

    This error message is not reporting the actual reason for the failure


    FlashWayne commented at 7:31 AM on September 27, 2026:

    Right, nothing was pruned in that case, the base block just hasn't been downloaded yet. Added a separate error for it in 8fa8ed0111: "Could not roll back to requested height since block data for the current tip is not available." The "already pruned" message is now only returned when GetFirstBlock actually finds a gap.

  6. fjahr commented at 11:33 PM on September 26, 2026: contributor

    Concept ~0

    This is such a esoteric edge case that I don't really think a user could ever realistically hit it.

  7. rpc: use a dedicated error when the tip has no block data
    The "already pruned" error is misleading when the tip is the snapshot
    base block right after loadtxoutset: nothing was pruned, the block just
    has not been downloaded yet.
    8fa8ed0111
  8. FlashWayne commented at 7:31 AM on September 27, 2026: none

    Agreed it's unlikely to be hit in practice. The reason I still think it's worth fixing is that it's an RPC call aborting the node instead of returning an error, and the fix is just a status check before GetFirstBlock. If you think it's not worth the review time I'm fine closing it.


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-09-28 10:51 UTC

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