You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Next slice of the verified-commitment-trees (VCT). It lands the VCT runtime and its inputs — everything about where the fast path's data comes from — while staying fully dormant: the committer fast path that consumes it arrives in the next increment, so there is no behavior change in this PR.
finalized_state/vct.rs (new): the VctState runtime — source-mode selection (checkpoint_sync × vct_fast_sync × embedded-frontier presence), the embedded Mainnet handoff frontier (vct/mainnet-frontier.bin, parsed and height-validated at startup), the Regtest VCT_REGTEST_FRONTIER fixture loader, per-height root lookup bounded by the handoff height, the successor-verification policy, invalidate/evict hooks, and run counters. Declared #[allow(dead_code)] at the module level; the committer slice removes the allow.
commitment_aux.rs: the CommitmentRootSource seam the committer will read through — one trait, two sources: the production PeerSource (backed purely by the provisional header-ahead roots the DB already stores, with invalidate un-poisoning a rejected root so a different peer can supply a replacement) and a test-only FixtureSource. There is deliberately no in-memory root cache: tests fill roots through the same insert_zakura_header_commitment_roots write path header sync uses, so the tested read path is the production read path. Committed rows are cleaned up by the database's own retention, not through the seam. The handoff frontier is mandatory on every source (final_frontiers() -> &FinalFrontiers, with vct_last_checkpoint_height derived from it as a default method): the fast path only runs on networks with an embedded frontier, so the type encodes that invariant instead of threading an Option that is always Some in production. Also removes the #[allow(dead_code)] on FinalFrontiers::from_bytes, now consumed by the frontier loader.
error.rs: the two retryable commit-stall errors the fast path will raise — VctSuppliedRootUnavailable (peer refetch needed) and VctSuppliedRootAwaitingSuccessor (root present, successor not yet buffered) — with vct_retryable_height / vct_supplied_root_unavailable_height accessors distinguishing the two on the commit error types. Nothing constructs these yet.
lib.rs: exports validate_final_frontiers_bytes / FinalFrontiersValidationError (used by the frontier-generation tooling in a later PR).
Public frontier validator panics on malformed input
The newly added, crate-root-exported validate_final_frontiers_bytes(bytes, expected_height) -> Result<(), FinalFrontiersValidationError> is documented as a Result-returning validator for serialized checkpoint-handoff frontier bytes, but it aborts the thread with a panic on a large class of malformed inputs. It delegates to parse_final_frontiers_bytes and FinalFrontiers::from_bytes, which carefully bounds-check the outer framing (4-byte height plus three u32-length-prefixed blobs, with typed FinalFrontiersParseError variants for overflow/missing-length/truncation/trailing bytes). However, once each blob is extracted as an in-bounds slice, from_bytes constructs the trees via <sapling|orchard|sprout::tree::NoteCommitmentTree as FromDisk>::from_bytes(blob), and those FromDisk impls call bincode::DefaultOptions::new().deserialize(...).expect("deserialization format should match the serialization format used by IntoDisk"). Because that .expect() panics inside from_bytes before it returns, the .map_err(...) that would produce FinalFrontiersValidationError::InvalidBytes never runs. A minimal input such as [0u8; 16] with expected_height = 0 passes all framing checks (height 0, three zero-length blobs, no trailing bytes) yet panics when the empty sapling blob is handed to bincode; an invalid Option/enum discriminant byte behaves identically.
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
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
Next slice of the verified-commitment-trees (VCT). It lands the VCT runtime and its inputs — everything about where the fast path's data comes from — while staying fully dormant: the committer fast path that consumes it arrives in the next increment, so there is no behavior change in this PR.
Extracted from the #408 reference draft / #409.
Solution
finalized_state/vct.rs(new): theVctStateruntime — source-mode selection (checkpoint_sync×vct_fast_sync× embedded-frontier presence), the embedded Mainnet handoff frontier (vct/mainnet-frontier.bin, parsed and height-validated at startup), the RegtestVCT_REGTEST_FRONTIERfixture loader, per-height root lookup bounded by the handoff height, the successor-verification policy, invalidate/evict hooks, and run counters. Declared#[allow(dead_code)]at the module level; the committer slice removes the allow.commitment_aux.rs: theCommitmentRootSourceseam the committer will read through — one trait, two sources: the productionPeerSource(backed purely by the provisional header-ahead roots the DB already stores, withinvalidateun-poisoning a rejected root so a different peer can supply a replacement) and a test-onlyFixtureSource. There is deliberately no in-memory root cache: tests fill roots through the sameinsert_zakura_header_commitment_rootswrite path header sync uses, so the tested read path is the production read path. Committed rows are cleaned up by the database's own retention, not through the seam. The handoff frontier is mandatory on every source (final_frontiers() -> &FinalFrontiers, withvct_last_checkpoint_heightderived from it as a default method): the fast path only runs on networks with an embedded frontier, so the type encodes that invariant instead of threading anOptionthat is alwaysSomein production. Also removes the#[allow(dead_code)]onFinalFrontiers::from_bytes, now consumed by the frontier loader.error.rs: the two retryable commit-stall errors the fast path will raise —VctSuppliedRootUnavailable(peer refetch needed) andVctSuppliedRootAwaitingSuccessor(root present, successor not yet buffered) — withvct_retryable_height/vct_supplied_root_unavailable_heightaccessors distinguishing the two on the commit error types. Nothing constructs these yet.lib.rs: exportsvalidate_final_frontiers_bytes/FinalFrontiersValidationError(used by the frontier-generation tooling in a later PR).