Skip to content

feat(state): verify VCT roots during header sync (move verification off the committer)#366

Draft
p0mvn wants to merge 4 commits into
feat/pre-release-mainfrom
roman/vct-hs-verify-core
Draft

feat(state): verify VCT roots during header sync (move verification off the committer)#366
p0mvn wants to merge 4 commits into
feat/pre-release-mainfrom
roman/vct-hs-verify-core

Conversation

@p0mvn

@p0mvn p0mvn commented Jul 1, 2026

Copy link
Copy Markdown

Draft. Stacked PR 2 of 2, on top of #365. This holds the core logic. It is a work in progress — the parts-based leaf foundation is in; the verification move, frontier tree, committer simplification, and peer scoring are being added as follow-up commits.

Goal

Make header-sync commit the single authoritative verify+fold for peer-supplied commitment roots, so a lying peer is caught early and attributably at the network boundary (scored + disconnected), and the finalized committer no longer needs the successor at all (no successor-park, no deadlock). Consumes the fields carried by #365.

Landed so far

  • Parts-based ZIP-221 leaf (zebra-chain): block_to_history_node now delegates to a new parts_to_history_node; parts-based constructors added up to HistoryTree::push_from_parts. Proven byte-identical to the block-based path on real blocks (test). This is the mechanism for rebuilding leaves from header-sync data with no body.

Remaining (in-progress commits)

Test evidence (so far)

AI disclosure

Implemented with Claude Code (Opus); the contributor is the responsible author.

@v12-auditor

v12-auditor Bot commented Jul 1, 2026

Copy link
Copy Markdown

Note

Complete: Audit complete. V12 found one issue worth reviewing.

Open the full results here.

FindingSeverityDetails
F-94840 🟠 High
Empty Ironwood root committed

When an Ironwood-capable network activation is configured, Zebra's history tree switches NU6.3/NU7 blocks to the V3 IronwoodOnward leaf format, which commits both the Ironwood note-commitment root and ironwood_tx. The state update paths still maintain only Sprout, Sapling, and Orchard note-commitment frontiers, so they never compute an Ironwood frontier from ironwood_shielded_data. Both finalized and non-finalized commits push Ironwood-era blocks into HistoryTree::push with &Default::default() as the Ironwood root, while the finalized serving index stores the same empty root together with the block's real ironwood_transactions_count(). For any active Ironwood block containing Ironwood actions, Zebra therefore persists a V3 chain-history leaf and per-height auxiliary roots entry that do not match the consensus Ironwood note-commitment root.

Analyzed two files, diff d8523e7...31204ef.

@p0mvn
p0mvn changed the base branch from roman/vct-hs-network-api to feat/pre-release-main July 1, 2026 07:05
@p0mvn
p0mvn force-pushed the roman/vct-hs-verify-core branch from 31204ef to 1c6305b Compare July 1, 2026 07:05
p0mvn added 4 commits July 1, 2026 02:01
…ody)

Refactor `Version::block_to_history_node` into a default that delegates to a new
required `parts_to_history_node(header, height, roots, tx-counts)`, so the
block-based and parts-based leaves are built by identical code. Add the parts-based
constructors up the stack: `Entry::new_leaf_parts`, `Tree::new_from_parts` /
`append_leaf_parts`, and `NonEmptyHistoryTree` / `HistoryTree`
`from_block_parts` / `push_from_parts`.

This lets a node rebuild each block's MMR leaf and fold it into the chain-history
tree from header-sync data alone — the header plus the per-pool roots and shielded
tx-counts carried on the wire — without downloading the block body, which is what
the upcoming header-sync verification needs (design §6).

A new test proves the parts-built history root is byte-identical to the
block-built one on real blocks (Heartwood + Canopy, mainnet + testnet).

First commit of the core-logic PR; the verification move, frontier tree, committer
simplification, and peer scoring follow.
…R) [wip]

Task #11: authoritative header-sync verification. Extract a header-driven
header_commitment_is_valid_for_chain_history core; add parts-based
verify_supplied_roots_from_parts + the sub-Heartwood/sub-NU5/sub-Nu7 direct
checks; persist a running header-frontier ZIP-221 MMR (new ZAKURA_HEADER_FRONTIER_TREE
CF) that each committed range's roots are folded into and verified against the
header commitments; reject a bad range with CommitHeaderRangeError::InvalidCommitmentRoots.
Committer simplification (#13) and peer scoring (#12) still pending.
…re-verified roots [wip]

Tasks #12/#13 (production): header-sync commit is now the authoritative verify+fold
(#11), so map InvalidCommitmentRoots -> InvalidRange peer scoring, and drop the
committer's successor look-ahead + the write-worker await-successor park. The
committer re-checks its own header commitment and folds the (already header-sync-
verified) roots, without waiting for a buffered successor — removing the deadlock.
Removed next_checkpoint threading from commit_finalized/_direct. VCT prop-test suite
rework still in progress (tests reference the removed successor machinery).
…ad successor machinery

Complete #12/#13: adapt the VCT test suite to the moved verification and drop the
now-dead successor/dedup machinery.

- Remove the successor-look-ahead + dedup machinery: header_only,
  vct_root_needs_successor, vct_fast_needs_successor, record_prevalidated,
  vct_prevalidated_count, and the requires_verified_successor / prevalidated_count
  state; simplify VctState + its test constructor.
- Remove three obsolete prop tests (deferral + two dedup tests) and the
  poisoned-root-refill test that exercised the removed immediate-rejection path.
- Update the wrong-root test: a wrong Sapling MMR root is now rejected at its
  successor's commit (one-block lag); the tip case is header-sync's job.
- Header-range reorg tests: synthetic headers now commit the running MMR root of
  their (zero) roots so they pass header-sync verification; the frontier positioner
  rebuilds from empty on a re-anchor below the frontier.
- Drop next_checkpoint from the replay-bench apply path; regenerate CF snapshots
  (new zakura_header_frontier_tree CF).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant