#35187 kernel: Block validation without a complete UTXO set

full analysis

https://github.com/bitcoin/bitcoin/pull/35187 · sedited · +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:

ReviewerKindHarmStatusBlockingAuthor repliedQuote
ajtownsapproachA caller-supplied lookup callback allows non-deterministic lookups across calls and fails to capture the resulting UTXO set changes.openyesno2026-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.'
nervana21correctnessBlocks validated via ValidateBlock that are ancestors of the assumevalid block will omit script checks instead of doing full script validation.opennono2026-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...?'
purpleKarrotapproachflattening into two arrays and rebuilding an ephemeral map requires two full copies of the UTXO set and will not scale to productionresolvednoyes2026-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)

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.

Data

dossier JSON · extract JSON · model openrouter/google/gemini-3.8-flash, generated 2026-09-17T21:29, confidence high, input hash 6882d6f4b46439c0