Skip to content

feat(state): activate VCT fast checkpoint sync in the committer#416

Merged
p0mvn merged 4 commits into
ironwood-mainfrom
split/vct-committer
Jul 3, 2026
Merged

feat(state): activate VCT fast checkpoint sync in the committer#416
p0mvn merged 4 commits into
ironwood-mainfrom
split/vct-committer

Conversation

@p0mvn

@p0mvn p0mvn commented Jul 2, 2026

Copy link
Copy Markdown

Motivation

Next slice of the verified-commitment-trees (VCT) fast-sync split series, stacked on #414 (split/vct-runtime). It makes the runtime live: the committer fast path, the fail-closed reopen, and the property-test suite. This is the slice that removes the #[allow(dead_code)] from mod vct;, so the compiler proves the whole state layer is wired.

Extracted from the #408 reference draft / #409, adapted to #414's final APIs (DB-only PeerSource, mandatory handoff frontier, no eviction seam).

Solution

  • Committer fast path (finalized_state.rs): below the checkpoint, when the source has a block's roots, the committer verifies them against the node's own header commitments (via feat(state): verify supplied commitment roots against header commitments #411's verify-core), folds them into the anchor set and history leaf, and skips the per-block note-commitment frontier recompute. At the handoff height the embedded final frontier is verified against that block's proven root and written as the tip treestate. Untrusted peer roots at or above Heartwood are only committed once a buffered successor confirms them; the write loop keeps a one-block look-ahead for this.
  • Retryable stall handling (write.rs): a missing/rejected root or an absent successor parks and retries the same block in place (with the feat(state): add VCT runtime, embedded frontier, and commitment-root source seam #414 error variants) instead of resetting the checkpoint queue; a stall persisting past 30s escalates to an error log and a state.vct.root.stalled.height gauge, since a node that can't obtain a verifiable root will not — by design — recompute against the frozen frontier.
  • Fail-closed reopen: a fast-synced database records the handoff in VCT_SYNC_METADATA; reopening one below the handoff refuses to run in configurations that would misuse the frozen frontier, and the genesis-root cache upgrade treats an absent genesis tree as a mid-flight fast sync instead of panicking.
  • DB plumbing (zebra_db/*, disk_format/*): fast-anchor-root writes, the fast-sync marker, staged-root rollback, and retention interaction with pruning.
  • Prop tests (tests/prop.rs, ~1,800 lines): legacy-vs-fast consensus-state equivalence (anchors + history root digests), producer→consumer round-trip from a real DB through produce_block_roots, poisoned-root rejection + refetch un-poisoning, await-successor deferral, frozen-frontier restart safety, and handoff treestate writes. Peer-source tests fill roots through the same insert_zakura_header_commitment_roots write path production header sync uses, against the fast state's own database.

Activation note

State config defaults (checkpoint_sync = true, vct_fast_sync = true, both serde-skipped mirrors) mean the fast path is active by default on Mainnet once this merges. The user-facing consensus.vct_fast_sync opt-out and zebrad plumbing land in the next slice — if the series should stay dormant until then, flip the state-config defaults here and restore them in that PR.

@v12-auditor

v12-auditor Bot commented Jul 2, 2026

Copy link
Copy Markdown

Note

Complete: Audit complete. V12 found two issues worth reviewing.

Open the full results here.

FindingSeverityDetails
F-95299 🟠 High
Evicted roots are never refetched

A bad VCT tree_aux root is evicted from the provisional root store, but the finalized writer has no live path that causes header sync to request a replacement. During fast sync, verify_commitment_roots rejects forged roots and vct_reject_supplied_root deletes the height through the VCT source, then returns VctSuppliedRootUnavailable. After at least one fast block has frozen the frontier, retrying the same block with the now-missing root refuses legacy recomputation and returns the same retryable error, so the write loop only parks and retries in place. Header sync has already committed and marked the header/root range covered once the original CommitHeaderRange state request succeeded, cancels covered outstanding requests, drops late covered responses, and its scheduler refuses retries for covered ranges. A malicious peer that wins a header-range response with a forged commitment root can therefore leave the node waiting for a replacement root that the covered-range machinery will not request.

F-95300 🟡 Medium
Repair probe panics early

The new open-time history-tree compatibility probe can still panic before the repair fallback runs. ZebraDb::new calls run_blocking_format_repairs on writable opens, which calls repair_tip_history_tree_if_incompatible and uses db.check_tip_history_tree_decodes().is_ok() to decide whether to rebuild. That probe deserializes raw HistoryTreeParts and then calls parts.with_network(&self.db.network()).map_err(...), treating network validation as a fallible result. HistoryTreeParts::with_network first performs an assert_eq! on the stored network_kind, so a bincode-decodable but wrong-network or similarly corrupted history-tree row panics before map_err can produce the intended Err. The rebuild and safe warning paths in repair_tip_history_tree_if_incompatible are therefore bypassed by exactly the kind of incompatible state the new probe is meant to handle safely.

And one more auto-invalidated finding.

Analyzed 13 files, diff 3264de3...e86497c.

@p0mvn
p0mvn marked this pull request as draft July 2, 2026 21:22
@p0mvn
p0mvn force-pushed the split/vct-runtime branch from 3264de3 to cf0d4aa Compare July 2, 2026 21:40
@p0mvn
p0mvn force-pushed the split/vct-committer branch 2 times, most recently from 56b5162 to 60b8ca4 Compare July 2, 2026 21:59
@p0mvn
p0mvn changed the base branch from split/vct-runtime to ironwood-main July 2, 2026 21:59
@p0mvn
p0mvn force-pushed the split/vct-committer branch from 60b8ca4 to 806321d Compare July 3, 2026 01:00
@p0mvn

p0mvn commented Jul 3, 2026

Copy link
Copy Markdown
Author

F-95300 is obsolete, no probe anymore

@p0mvn

p0mvn commented Jul 3, 2026

Copy link
Copy Markdown
Author

F-95299 I believe that our goal is to solve this in a subsequent iteration via #366 and #355

@p0mvn
p0mvn force-pushed the split/vct-committer branch from 806321d to 4df6516 Compare July 3, 2026 01:05
@p0mvn
p0mvn marked this pull request as ready for review July 3, 2026 01:13
Comment thread zebra-state/src/service/finalized_state/disk_format/chain.rs
Comment thread zebra-state/src/service/finalized_state/zebra_db/block.rs
Comment thread zebra-state/src/service/finalized_state/zebra_db/block.rs
Comment thread zebra-state/src/service/finalized_state/zebra_db/shielded.rs Outdated
Comment thread zebra-state/src/service/finalized_state/zebra_db/shielded.rs Outdated
Comment thread zebra-state/src/service/finalized_state/vct.rs
Comment thread zebra-state/src/service/finalized_state/vct.rs Outdated

@ValarDragon ValarDragon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took me awhile! Thank you, this looks good to me!

We still need to validate the full header before persisting later, which removes a lot more risk frontier/complexity as well.

Longer term we should think through more type safety here as well.

Great work here!

@p0mvn
p0mvn merged commit c17d606 into ironwood-main Jul 3, 2026
51 checks passed
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.

2 participants