#35187 kernel: Block validation without a complete UTXO set
https://github.com/bitcoin/bitcoin/pull/35187 · · +361/-0 in 6 files, 5 commits · labels: Validation, Needs rebase
Goal
- Allow external library consumers to validate blocks without maintaining a full local UTXO database
- Enables stateless verification for downstream projects like rust-bitcoinkernel
This pull request adds a C API endpoint to libbitcoinkernel for validating blocks without access to a complete UTXO set. It introduces ChainstateManager::ValidateBlock, which executes CheckBlock, ContextualCheckBlock, and ConnectBlock in check-only mode against caller-supplied coins fetched through a callback.
Problem: External applications using libbitcoinkernel currently cannot validate individual blocks without instantiating and maintaining a full internal UTXO set, preventing lightweight or custom UTXO indexing architectures from verifying blocks.
Category: Kernel (libbitcoinkernel) (#2 of 18)
P2 · new feature
- P2 because it expands kernel API completeness for external consumers wanting stateless validation
- Unblocks downstream tools like rust-bitcoinkernel that need to validate blocks on demand
P2 because it adds an important new capability to libbitcoinkernel, allowing downstream applications to validate blocks without requiring a complete local UTXO database. Downstream consumers have already prototyped rust-bitcoinkernel tests on top of it.
Membership: Adds C API endpoints btck_chainstate_manager_validate_block, btck_coin_create, and related wrapper methods.
Factors: security/stability 0, bug 0, performance 0, user value 2, leverage 2
Category: Validation (#29 of 48)
P3 · new feature
- P3 because it exposes a check-only validation helper without altering internal node validation
- Serves primarily as a backing implementation for the kernel API rather than core node logic
P3 because it adds an isolated read-only helper to ChainstateManager that runs standard block checks against an external CCoinsViewCache, without changing consensus rules or node validation workflows.
Membership: Touches src/validation.cpp and src/validation.h to add ChainstateManager::ValidateBlock, and carries the Validation label.
Factors: security/stability 0, bug 0, performance 0, user value 1, leverage 1
Reviewability: Stale: Needs rebase
- Needs rebase against master due to merge conflicts
The branch has merge conflicts with master and carries the 'Needs rebase' label.
Author status: silent since 2026-08-28
Open concerns:
- ajtowns suggested using an explicit in-memory CCoinsView container instead of a callback function to avoid non-deterministic lookups and capture UTXO set deltas.
- nervana21 noted that ConnectBlock will inherit assumevalid logic and potentially skip script checks for blocks under assumevalid, asking if script checking should be forced.
Resolved concerns:
- Initial implementation used block undo data, which tied validation to internal cache structures; resolved by switching to outpoint/coin pairs and ultimately to a callback fetcher.
- Addressed 31-bit integer limit documentation and handling for coin confirmation height.
- Removed redundant intra-block spend filtering in FetchCoinFromBase.
Agreement: Blocked
- Concept approval for stateless block validation (yuvicc, nervana21)
- Verified by implementing a prototype test suite in rust-bitcoinkernel (alexanderwiederin)
- Prefers an in-memory coin container over dynamic callbacks to prevent inconsistent lookups (ajtowns)
- Questioned whether assumevalid logic should bypass script checks during standalone validation (nervana21)
Blocked: blocking objection open with no author reply (ajtowns)
There is broad agreement on the value of the feature, but an architectural dispute from ajtowns regarding callback determinism vs an in-memory coins container remains open alongside an unanswered question on assumevalid handling.
- alexanderwiederin: 'The design holds up well in my opinion.'
- ajtowns: 'ConceptACK, approach = nearly, but not quite?... I think we should control the container ourselves, rather than using a lookup(outpoint) -> coin callback'
- nervana21: 'Should there instead be some logic that forces a script_check_reason when ValidateBlock calls ConnectBlock or is the current logic the desired behavior?'
Objections:
| Reviewer | Kind | Harm | Status | Blocking | Author replied | Quote |
|---|---|---|---|---|---|---|
| ajtowns | approach | A caller-supplied lookup callback allows non-deterministic lookups across calls and fails to capture the resulting UTXO set changes. | open | yes | no | 2026-08-06: 'I think we should control the container ourselves, rather than using a lookup(outpoint) -> coin callback that the caller provides so that we can be sure the lookups are consistent across calls.' |
| nervana21 | correctness | Blocks validated via ValidateBlock that are ancestors of the assumevalid block will omit script checks instead of doing full script validation. | open | no | no | 2026-09-09: 'When we call ConnectBlock on a main chain block that is an ancestor of the assumevalid block... we inherit assumevalid logic and omit script checks. Should there instead be some logic that forces a script_check_reason when ValidateBlock calls ConnectBlock...?' |
| purpleKarrot | approach | flattening into two arrays and rebuilding an ephemeral map requires two full copies of the UTXO set and will not scale to production | resolved | no | yes | 2026-07-21: 'While this approach may serve as a proof-of-concept, it will not scale to a production application. As @alexanderwiederin pointed out, a better approach would be to abstract the lookup function.' Settled: 2026-08-06: sedited '* Switched to callback approach for fetching the coins' |
Support:
- alexanderwiederin: Wrote rust-bitcoinkernel tests against the bindings and found the callback design intuitive and effective.
- ismaelsadeeq: ACKed approach and code review after the removal of the block undo requirement.
- w0xlt: Approach ACK. [not substantive]
- yuvicc: Concept ACK. [not substantive]
- nervana21: Concept ACK [not substantive]
Participants: purpleKarrot (objection), ismaelsadeeq (support), alexanderwiederin (support), w0xlt (support), 17031996 (neutral), yuvicc (support), ajtowns (objection), nervana21 (objection), optout21 (neutral)
State derived from the lists: blocking objection open with no author reply (ajtowns) (model's own read: Mild)
Review verdicts (DrahtBot): 0 (+2)
- Stale ACK: ismaelsadeeq, ajtowns
- Approach ACK: w0xlt
- Concept ACK: yuvicc, nervana21
Dependencies
Enables:
- External block validation workflows without full chainstate in projects like rust-bitcoinkernel
Files
119 lines under test/bench/ci.
- src/test/kernel/test_kernel.cpp +119/-0
- src/kernel/bitcoinkernel.cpp +76/-0
- src/kernel/bitcoinkernel.h +75/-0
- src/kernel/bitcoinkernel_wrapper.h +42/-0
- src/validation.cpp +34/-0
- src/validation.h +15/-0
Card
This PR adds a libbitcoinkernel C API endpoint for validating blocks without a local UTXO set by fetching spent coins via a user-supplied callback. It solves the problem of requiring full node chainstate data for external tools that already track UTXOs independently. Downstream consumers in rust-bitcoinkernel have verified the workflow, but the PR is currently unmergeable due to merge conflicts and has an open design critique from ajtowns over callbacks versus an in-memory UTXO container.