feat(network): verify Zakura header-sync commitment roots before persisting#62
Draft
p0mvn wants to merge 13 commits into
Draft
feat(network): verify Zakura header-sync commitment roots before persisting#62p0mvn wants to merge 13 commits into
p0mvn wants to merge 13 commits into
Conversation
p0mvn
marked this pull request as draft
July 9, 2026 23:33
Robustness fixes to the below-checkpoint header-sync history-tree reconstruction/rebuild path, from a self-audit: - Arm the rebuild in-flight guard only when the QueryBestHeaderHistoryTree action is actually queued. dispatch_action is a non-blocking try_send that drops on a full/closed channel; arming the guard on a dropped send would suppress every future rebuild permanently (the guard clears only when the reload completes). A dropped send now leaves the guard clear so the next range retry re-dispatches. - Re-base the reconstruction at the current snapshot tip when the caller's cached verified_block_tip has no stored tree. The finalized history tree is tip-only, so a concurrent checkpoint/legacy commit advancing the finalized tip during the round-trip made read::tree::history_tree return None, then Err, then a network-paced no-progress rebuild loop. Reading the tip from the same snapshot is atomic and is the correct committed base below the checkpoint. - Clamp finalized_height with max() in handle_state_frontiers_changed so a stale or out-of-order frontier update cannot move the root-regime floor backward. verified_block_tip is left free (it can reorg above the checkpoint). Adds failed_rebuild_clears_guard_and_retriggers, and updates docs/design/verified-commitment-trees.md (6.4 robustness details, 13 the sync.header.history_tree.rebuild counter).
…w it
The runtime header-frontier history-tree lazy rebuild discarded the frontier
that `ReadResponse::BestHeaderHistoryTree` returns, keeping only the tree
(`{ tree, .. }`) and echoing the requested `best_header_tip` back to the
reactor. When durable roots have a gap — a non-Zakura path (checkpoint/legacy
sync) committed below the checkpoint without persisting header-commit roots —
the fold stops below `best_header_tip - 1`, so the rebuilt tree never reaches
the current tip's parent. The reactor installed the low tree but left the tip
high, so every forward range re-detected the behind tree and re-triggered the
identical deterministic rebuild forever (a network-paced no-progress loop that
also re-ran the O(gap) durable-root fold each retry).
The startup path already honors the frontier contract (resume from
`frontier + 1`, anchor on the frontier hash); the runtime path did not. This
threads the frontier from where it is known (the zebrad driver, which owns the
state read) to where it is actionable (the reactor, which owns the tip):
- Add `HeaderFrontierReanchor` and carry it on `BestHeaderHistoryTreeLoaded`.
- Driver `header_frontier_reanchor` resolves the resume anchor on a gap
(mirroring the startup resume), `None` in the common no-gap case.
- Reactor `reanchor_header_frontier` drops the tip onto the rebuilt tree,
clearing the stranded forward schedule and repositioning tip/parent-hash,
then reschedules so the resumed range verifies against the reinstalled tree.
- Generalize `publish_best_tip_reanchored` to take the overlap parent hash.
Adds `lazy_rebuild_reanchors_tip_onto_lower_frontier_tree` (verified to fail
without the reanchor) and the `sync.header.history_tree.reanchor` counter;
documents both in docs/design/verified-commitment-trees.md (6.4, 13).
p0mvn
force-pushed
the
port/zakura-header-anchor-root-validation
branch
from
July 11, 2026 06:04
78e9647 to
68efc3d
Compare
Use the migrated Zakura crate names so header-sync state and tests compile, and apply rustfmt to the affected reactor helper.
Teach the throughput mock about the finalized and verified tip reads performed after local block application.
This was referenced Jul 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
This ports valargroup/zebra#458 onto the migrated
zakura-core/zakurarepository. In the header-sync network layer, Zakura must authenticate peer-supplied note-commitment / auth-data roots against block header commitments before writing anything unvalidated to the database.A block header commits to the history tree as of its parent, so the root for height
His only confirmed once headerH + 1validates against the tree that includesH. A contiguous delivery[start..=end]therefore confirms roots only for[start..=end - 1]; the tip's root stays unconfirmed and is re-delivered by the next overlapping range. This makes the trust boundary a persisted-state invariant: the commit path accepts only the header-authenticated confirmed prefix (exactly one root shorter than the headers, or an empty vector for checkpoint backfill), so the unconfirmed tip root can never reach disk.Solution
The change is the upstream PR#458 diff, rebased first onto
valargroup/zebraironwood-main(to resolve the semantic conflicts against the intervening zakura header-store work) and then replayed ontozakuramain:roots.is_empty() || roots.len() + 1 == headers.len(), aligns each present root to its header height, and — on any overlap with a committed body — keeps the verified row (committed roots win).[X-3999, X],[X, X+3999], …) so each range's tip root is confirmed by the successor header in the next range.frontier + 1.Conflict resolution notes (port-specific)
The two-step rebase isolated the semantic conflicts (all in the zakura header-store area that landed on both repos) from the mechanical rename/CI conflicts. Beyond the upstream diff, three integration fixes were needed because the target already contained header-store work authored after PR#458's base:
commit_header_rangewriter: kept ironwood'sUnlinkedRangelinkage check while adopting the PR's optional-tip-root (.get(index)) semantics.header_store_coherenceharness (ops.rs): now delivers the confirmed prefix (tip root omitted) so it exercises the shape the production commit path enforces.block_reorg_drops_conflicting_provisional_roots_before_reconstruction: the conflicting height-1 reorg block now links to genesis (differing by nonce) instead of using a bogus parent hash, so the header-store linkage guard admits the reorg instead of refusing it as a non-linking no-op.Tests
All automated, on the ported branch against
zakuramain:cargo fmt --all -- --check— cleancargo clippy --workspace --all-targets -- -D warnings— cleancargo check --workspace --all-targets— cleancargo test -p zebra-state --lib— 347 passed (incl.header_store_coherencescenarios + property test, and the reorg/root-drop test)cargo test -p zebra-network --lib— 912 passed (108zakura::header_synctests incl. the new root-verification, overlap, lazy-rebuild, and duplicate-disconnect cases). One fuzz test (fuzz_reliability_discounts_dropping_carrier) is load-sensitive and passes reliably in isolation (3/3); it is pre-existing flakiness the PR base commit#475already targeted.cargo test -p zebrad --lib commands::start/datadir— 63 + 14 passedcargo test -p zebra-chain --lib commitment_aux— 9 passedSpecifications & References
docs/design/verified-commitment-trees.mdAI Disclosure