validation: check the most recent AssumeUTXO commitment during IBD #36543

pull l0rinc wants to merge 7 commits into bitcoin:master from l0rinc:l0rinc/assumeutxo-latest-snapshot changing 17 files +216 −220
  1. l0rinc commented at 1:40 PM on October 15, 2026: contributor

    Problem: AssumeUTXO verifies imported UTXOs against a hash we bake into the binary. Every node reconstructs the same UTXO set during ordinary IBD, but does not check its hash against the existing AssumeUTXO commitment.

    Fix: During ordinary block validation, verify the provided AssumeUTXO hash when block connection reaches the corresponding block, stopping the node on a mismatch. Flush pending changes to disk before hashing the UTXO set and comparing the result with the commitment.

    Keep only the latest AssumeUTXO commitment per network to limit the extra hashing work during IBD, and update the release process to replace it. Users who need older snapshots for research or other purposes can use a compatible older release or restore the corresponding commitment as m_assumeutxo_data and recompile.

  2. test: move AssumeUTXO commitments into test fixtures
    Move the height-110 and height-200 regtest commitments into their unit and fuzz fixtures.
    Keep the immutable fixture parameters alive across chainstate-manager restarts.
    Leave only the height-299 functional-test commitment in the default regtest parameters.
    Persist block-index test edits before reloading to prepare for the IBD check's forced flush.
    Check that an unrelated chain passes the fixture's commitment height without starting a UTXO scan.
    Check that interrupted snapshot validation leaves the snapshot unvalidated and can be retried.
    1606010c94
  3. chainparams: use the latest AssumeUTXO commitment
    Match AssumeUTXO imports, background validation, and chainstate reloads against the latest commitment.
    Keep the height and block hash mismatch checks, and report the supported height for an unknown snapshot block hash.
    Older AssumeUTXO commitments are no longer recognized.
    All configured commitment lists are nonempty and ordered by increasing height, so the last entry supplies the same height as the previous max_element lookup for rollback exports.
    Use the same accessor for the fixture checks and remove the optional lookup APIs and height list.
    59eeb531b0
  4. refactor: extract AssumeUTXO hash verification
    Extract UTXO hashing, interruption handling, commitment comparison, and result logging from AssumeUTXO background validation.
    Keep snapshot invalidation at the caller so ordinary block validation can reuse the check.
    Use log wording that also fits ordinary block validation.
    9646f56002
  5. DrahtBot added the label Validation on Oct 15, 2026
  6. DrahtBot commented at 1:40 PM on October 15, 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.

    Type Reviewers
    Concept ACK Sjors, optout21

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #36326 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36326.svg"></sub> (kernel: Use typed errors for fatal and flush error notifications by arejula27)
    • #36114 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/36114.svg"></sub> (wallet: harden external signer psbt processing, revamp mock by Sjors)
    • #35642 <sub><img src="https://drahtbot.space/ack_count/bitcoin/bitcoin/35642.svg"></sub> (headersync: do parameter search at runtime by sipa)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

    LLM Linter (✨ experimental)

    Possible places where named args for integral literals may be used (e.g. func(x, /*named_arg=*/0) in C++, and func(x, named_arg=0) in Python):

    • src/test/validation_chainstatemanager_tests.cpp: ProcessNewBlock(std::make_shared<const CBlock>(block), true, true, nullptr)

    <sup>2026-10-15 13:59:52</sup>

  7. refactor: store one AssumeUTXO commitment
    All consumers now use only the latest commitment.
    Retain only that commitment to limit the extra hashing work during IBD.
    Remove the unused older production commitments and replace the vector with one optional `AssumeutxoData`.
    Keep it disengaged until the network constructor assigns the commitment.
    27705e415f
  8. validation: verify the provided AssumeUTXO hash
    Verify the provided AssumeUTXO hash when block connection reaches the corresponding block.
    Skip other chains at the same height.
    This checks the developer-provided commitment against the UTXO set that every node reconstructs during IBD (see #32377).
    Reuse the AssumeUTXO background verifier and its reporting.
    Flush pending UTXO changes to disk before hashing the set.
    Stop on a flush failure before updating the tip or mempool.
    Request shutdown if UTXO statistics cannot be computed or the commitment does not match, preserving normal shutdown interruptions.
    AssumeUTXO import verification and background validation remain mandatory.
    36a2a70452
  9. validation: propagate snapshot verification errors
    `MaybeValidateSnapshot()` already invalidates a failed snapshot and requests shutdown, but `ConnectTip()` reports success to its caller.
    Return a runtime error for snapshot-validation failures without marking the connected block invalid.
    Keep interrupted hashing distinct so normal shutdown does not become a validation failure.
    c296123d4d
  10. doc: describe latest AssumeUTXO commitment checks
    Document hash verification at the corresponding block and shutdown on a mismatch.
    Explain the compatibility change and how to use older snapshots for research.
    Update the release instructions to replace the commitment instead of appending it.
    97b2138e39
  11. l0rinc force-pushed on Oct 15, 2026
  12. DrahtBot added the label CI failed on Oct 15, 2026
  13. DrahtBot commented at 2:01 PM on October 15, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task iwyu: https://github.com/bitcoin/bitcoin/actions/runs/38744710504/job/116455202409</sub> <sub>LLM reason (✨ experimental): CI failed because the IWYU check modified src/kernel/chainparams.cpp by removing an unused cassert include, leaving an uncommitted diff.</sub>

    <details><summary>Hints</summary>

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

    </details>

  14. DrahtBot removed the label CI failed on Oct 15, 2026
  15. Sjors commented at 3:24 AM on October 17, 2026: member

    Concept ACK, see #32377, with two caveats:

    stopping the node on a mismatch

    I think this risks introducing a new effective checkpoint. If the snapshot were malicious, normal users couldn't sync and a subset may decide to restart in AssumeUTXO mode.

    It seems better to emit a warning, severe enough that the GUI shows it, but not aborting. It's a clear sign there's something wrong with the software. Even though it doesn't affect them, they should seek advice, since it's a giant red flag.

    (in such a malicious scenario, developers would presumably change the warning to an error, exactly to achieve this wrong behavior)

    This was already discussed in #32377 (comment), but the implementation doesn't match the conclusion there.

    Keep only the latest AssumeUTXO commitment per network to limit the extra hashing work during IBD

    Maybe limit the scope of this PR by only checking the latest hash, but not (yet) deleting the other hashes.


    You mentioned offline that the performance impact of this extra check is minimal. It would be good to provide some numbers in the PR description.

    I'm not up to speed on how often and when we flush the chainstate to disk during IBD nowadays. How does this interact with that?

  16. optout21 commented at 5:16 AM on October 17, 2026: contributor

    Concept ACK

    As there is a hash provided that requires trust, the more checks the better. It makes sense to use all nodes performing IBD to also perform this check, as it's relatively cheap to do.

    It seems better to emit a warning, severe enough that the GUI shows it, but not aborting.

    Two suggestions:

    • Introduce an option to skip the new AssumeUTXO hash check (may be a hidden option) -- useful in itself.
    • In the unlikely case a hash mismatch is found, abort, and advice the user to shout out and restart with the ignore AssumeUTXO hash check option. That way the effect is hard to ignore by the user, but easy to bypass.

    Maybe limit the scope of this PR by only checking the latest hash, but not (yet) deleting the other hashes.

    For clarity it's worth mentioning that the latest hash a user is checking may not be the same as the latest hash of the latest release, nor the one used by most nodes in the network. (For the sake of example, assuming v35 has been released, and a majority of the network is on v34, when a user is running v33, the checked hash will not match the hash used by many other nodes.) Note that it would be desirable to check the hash of newer versions, but of course it's not possible to hardcode hashes of future releases in the source code. So not checking the non-latest hashes is fine, but it's useful to keep them for visibility.


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-23 11:51 UTC

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