feat(state): verified commitment trees fast checkpoint sync (state layer)#408
feat(state): verified commitment trees fast checkpoint sync (state layer)#408p0mvn wants to merge 1 commit into
Conversation
And one more auto-invalidated finding. Analyzed 20 files, diff |
| let (Some(sapling), Some(orchard)) = ( | ||
| db.sapling_tree_by_height(&height), | ||
| db.orchard_tree_by_height(&height), |
There was a problem hiding this comment.
Note: have a task tracking Ironwood
Motivation
Below the last checkpoint, the dominant checkpoint-sync CPU cost is recomputing the per-block Sapling/Orchard note-commitment frontier for every block. This PR adds the zebra-state fast-path logic for verified commitment trees (VCT) checkpoint sync: instead of recomputing the frontier, the node folds peer-supplied, header-verified per-block commitment roots into the anchor set and history tree, and only materializes the real frontier once, at the checkpoint handoff. See
docs/design/verified-commitment-trees.md(merged in #402) for the full design.This is the follow-up slice to #402 (VCT docs, config, and DB storage) and replaces the closed #391: it carries the remaining state-layer logic, without the note-commitment precompute dependency (#387, closed) — the committer uses the existing tree-update path.
Solution
commitment_aux_verify.rs). A root that cannot be obtained or verified is rejected — never recomputed against the stale frozen frontier — so no untrusted data can affect consensus state (fail-closed / frozen-frontier policy).vct/mainnet-frontier.bin), verified against that block's proven root, is written as the tip treestate, and normal per-block recompute resumes above the checkpoint. The resulting consensus state is byte-identical to the legacy recompute.serve_block_rootsstitches theCommitmentRootsByHeightserving index (at/above the upgrade heightU) with per-height trees (belowU) into one gap-freetree_auxBlockRootsresponse, so fast-synced nodes keep the root-serving fleet alive.#[should_panic]).repair_tip_history_tree_if_incompatiblerebuilds an undecodable stored tip history tree from finalized blocks plus commitment roots (index first, per-height trees as fallback) before the background format-validity check reads it.VctDataadaptation:write_blockkeeps theVctDatabundle introduced by feat(state): add VCT docs config and DB storage #402, with both fields now optional to express the full feature's cases: the checkpoint-handoff block writes the real frontier through the legacy path while still setting the sync marker (anchor_roots: None), and a non-persistent fast sync folds roots without marking the database (sync_below: None).Dormant feature: the
checkpoint_sync/vct_fast_syncconfig fields are mirrors that zebrad sets at startup. This PR does not include the zebra-consensusvct_fast_syncknob or the zebrad startup wiring, so the fast path is not yet reachable in a running node — a follow-up PR activates it. The state tests exercise the path directly.Tests
Observed locally on this branch (base
origin/ironwood-main):cargo fmt --all -- --check— clean.cargo clippy --workspace --all-targets -- -D warnings— clean.cargo build --workspace— builds (all consumer crates compile).cargo test -p zebra-state—270 passed; 0 failed; 2 ignored(lib, incl. the large VCTfinalized_state/tests/prop.rsproptests),2 passed(tests/basic.rs).Specifications & References
docs/design/verified-commitment-trees.md(merged in feat(state): add VCT docs config and DB storage #402)Follow-up Work
vct_fast_syncknob and the zebrad startup wiring that set the mirror config fields and make the fast path reachable at runtime..github/workflows/checkpoint-update.yml, and the committer-threadwrite_blockchange (perf(state): run write_block on the committer thread instead of the commit-compute pool #247).AI Disclosure
feat/vct-statebranch ontoironwood-main, adapt theVctDataplumbing from feat(state): add VCT docs config and DB storage #402, and verify (fmt/clippy/build/tests).PR Checklist
type(scope): description