#36543 validation: check the most recent AssumeUTXO commitment during IBD
| Reviewability | Reviews | Agreement | Size | ||||
|---|---|---|---|---|---|---|---|
| #36543 validation: check the most recent AssumeUTXO commitment during IBD | Waiting on author | 0 | Blocked | 110 + 106 tests | |||
|
|
|
| ||||
Reviewability: ReadyStalePaused Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs. Size: lines added or modified outside tests, then in tests; greener = smaller. | |||||||
Goal
Verifies the hardcoded AssumeUTXO commitment during normal Initial Block Download when block connection reaches the snapshot height and block hash. Pending UTXO modifications are synchronously flushed to disk, the serialized UTXO set is hashed, and a mismatch or failure causes the node to shut down with a fatal error. To prevent repeated multi-minute hashing passes during IBD, chainparams is simplified to store only the single most recent AssumeUTXO commitment per network, deprecating older snapshot activations.
Problem: AssumeUTXO relies on hardcoded snapshot hashes compiled into the node binary. Even though nodes running standard IBD independently reconstruct the exact UTXO set from genesis, they never compare it against the hardcoded commitment, passing up crowd-sourced verification of baked-in snapshot commitments against history (#32377).
Evidence of importance:
- Linked issue #32377 ('AssumeUTXO: crowdsource trust through independent snapshot verification') notes that every syncing full node could automatically audit hardcoded snapshot hashes during standard IBD.
- Commit 36a2a70452 explains: 'This checks the developer-provided commitment against the UTXO set that every node reconstructs during IBD (see #32377).'
Scope: Retaining only the single latest snapshot commitment is a breaking change for loading older AssumeUTXO snapshots or restarting snapshot chainstates built against retired commitments.
Risk of a mistake: medium (validation). It inserts a synchronous disk flush, multi-minute UTXO hashing pass, and potential fatal error exit into ConnectTip during normal block validation.
Changed since the previous assessment: Propagates snapshot verification errors out of ConnectTip as runtime errors instead of reporting success, and refines interruption handling so interrupted hashing during shutdown is not recorded as a validation failure.
Reviewability
Paused · Waiting on author
Open objections from Sjors, ajtowns, fametrano with no author reply for 7 days; review would repeat what has been asked.
Waiting on (from the thread read):
- author: addressing objections and suggestions from Sjors, optout21, ajtowns, and fametrano's assert bug report 2026-10-25
Agreement
Blocked
objection that needs a change, nobody has replied (Sjors, fametrano)
Thread notes: fametrano gave a Concept ACK but reported a concrete correctness objection: an assertion failure occurs when the check fails because coins update before the chain tip, which also allows a restart to skip the check.
Objections, suggestions, and questions:
| Reviewer | Type | Harm, request, or question | Status | Must be | Author replied | Quote |
|---|---|---|---|---|---|---|
| Sjors (member) | objection, safety | Stopping the node on a mismatch risks introducing an effective checkpoint that prevents normal sync if the snapshot commitment is malicious | open | changed | no | 2026-10-17: 'I think this risks introducing a new effective checkpoint. If the snapshot were malicious, normal users couldn't sync' |
| Sjors (member) | suggestion, scope | Limit the scope of the PR by checking the latest hash without deleting the older commitments yet | open | answered | no | 2026-10-17: 'Maybe limit the scope of this PR by only _checking_ the latest hash, but not (yet) deleting the other hashes.' |
| Sjors (member) | suggestion, maintenance | Provide benchmark numbers in the PR description showing minimal performance impact | open | answered | no | 2026-10-17: 'It would be good to provide some numbers in the PR description.' |
| Sjors (member) | question, correctness | How does flushing chainstate to disk before hashing interact with current IBD flush frequency? | open | answered | no | 2026-10-17: '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?' |
| optout21 (contributor) | suggestion, interface | Add a configuration option to bypass or ignore the AssumeUTXO hash check | open | answered | no | 2026-10-17: 'Introduce an option to skip the new AssumeUTXO hash check (may be a hidden option)' |
| optout21 (contributor) | suggestion, scope | Keep non-latest AssumeUTXO commitments in source for visibility instead of dropping them | open | answered | no | 2026-10-17: 'So not checking the non-latest hashes is fine, but it's useful to keep them for visibility.' |
| ajtowns (member) | question, maintenance | What is the performance impact when hitting an AssumeUTXO commitment block during validation? | open | answered | no | 2026-10-24: 'What's the performance impact when hitting such a block?' |
| ajtowns (member) | objection, safety | Crashing an IBD node on snapshot mismatch penalizes nodes with fully verified valid data while failing to protect snapshot users from following an incorrect chain | open | answered | no | 2026-10-24: 'Doesn't this make the result of a release including bad snaphot data worse for everyone -- Alice who does IBD has her node crash despite having good data that she fully verified, and Bob who uses the ' |
| ajtowns (member) | suggestion, approach | Consider predictable snapshot points (e.g. BIP 452) or including the block's muhash in the AssumeUTXO commitment to make verification easier and less disruptive | open | answered | no | 2026-10-24: 'Having predictable snapshot points (every 14112 blocks [per bip452]) would allow every node to calculate the appropriate hash... Including the block's muhash in the assumeutxo set would also probably ' |
| fametrano (contributor) | objection, correctness | A node failing the check aborts on an assertion due to inconsistent chainstate/coins tip, and a plain restart syncs past the commitment without checking it again | open | changed | no | 2026-10-25: 'a node that fails the new check aborts on an assertion, and a plain restart then syncs past the commitment without checking it again' |
Support:
- Sjors (member) (Concept ACK, 2026-10-17): see #32377, with two caveats
- optout21 (contributor) (Concept ACK, 2026-10-17): 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.
- fametrano (contributor) (Concept ACK, 2026-10-25) [both: ConnectTip, ConnectBlock, CheckBlockIndex, feature_assumeutxo.py]: (no reason given) [not substantive]
Participants:
- Sjors (member, objection, 1 statements 2026-10-17 to 2026-10-17): Concept ACK with caveats; objects to stopping on mismatch as an effective checkpoint, suggests keeping older commitments, and asks about flushing
- optout21 (contributor, support, 1 statements 2026-10-17 to 2026-10-17): Concept ACK; suggests an option to skip the check and keeping older commitments for visibility
- ajtowns (member, objection, 1 statements 2026-10-24 to 2026-10-24): objects that crashing IBD on mismatch makes bad snapshot releases worse for everyone, asks about performance impact, and suggests alternative approaches
- fametrano (contributor, objection, 1 statements 2026-10-25 to 2026-10-25): Concept ACK, but objects to assertion failure on mismatch leaving coins cache and chain tip out of sync, allowing restarts to bypass the check
Files
145 lines under test/bench/ci.
- src/kernel/chainparams.cpp +21/-116
- src/validation.cpp +48/-31
- src/test/validation_chainstatemanager_tests.cpp +55/-9
- src/test/validation_tests.cpp +5/-17
- src/test/fuzz/utxo_snapshot.cpp +14/-6
- src/test/util/setup_common.cpp +18/-2
- doc/assumeutxo.md +15/-1
- src/kernel/chainparams.h +3/-11
- src/util/vector.h +0/-12
- test/functional/feature_assumeutxo.py +7/-5
- doc/release-notes-assumeutxo-latest-snapshot.md +11/-0
- src/rpc/blockchain.cpp +2/-5
- src/test/util/setup_common.h +7/-0
- src/validation.h +6/-0
- src/node/blockstorage.cpp +2/-3
- doc/release-process.md +1/-1
- src/external_signer.cpp +1/-1
Card
The short text the ranking pass compares across PRs.
This PR verifies the hardcoded AssumeUTXO snapshot hash during standard Initial Block Download when block connection reaches the commitment height, triggering a fatal error and node shutdown on a mismatch. Full nodes independently rebuild the UTXO set from genesis during IBD, but previously never checked whether their reconstructed UTXO set matched the baked-in commitments (#32377). To avoid multiple expensive UTXO hashing passes during IBD, chainparams is changed to retain only the single latest AssumeUTXO commitment per network, retiring support for loading older snapshots.
Data
thread read through 2026-10-25 (4 statements), head 97b2138e39
labels: Validation
Categories
Validation
P2 · new feature (ranking pass: Moved up: closes a real trust gap in hardcoded snapshot commitments, comparable to other assumeutxo correctness work)
Crowdsources verification of baked-in snapshot commitments against history during standard IBD. As noted in #32377, full nodes currently reconstruct the full UTXO set without auditing hardcoded AssumeUTXO commitments, leaving a trust gap in snapshot validation.
Membership: Has the Validation label and modifies block connection and chainstate flushing logic in src/validation.cpp to audit AssumeUTXO commitments during IBD.
Factors: security/stability 1, bug 0, performance 0, user value 1, leverage 1