feat(state): verify supplied commitment roots against header commitments#411
Conversation
Analyzed four files, diff |
| // Validate this block's header commitment against the current (parent) tree, | ||
| // i.e. against every root already folded in. | ||
| if !skip_parent_check { |
There was a problem hiding this comment.
Note to reviewer why this is needed
There was a problem hiding this comment.
The skip is only a dedup for the VCT one-block look-ahead, not a trust shortcut.
When committing fast block H, we first check H’s header against T(H-1), then push H’s supplied roots into a candidate T(H). If H+1 is buffered, we immediately check H+1’s header against T(H), which authenticates H’s supplied roots before they are persisted.
When H+1 later becomes the block being committed, its parent-tree check is the exact same H+1 header against T(H) check that already succeeded as H’s look-ahead. skip_parent_check only fires when the cached prevalidation matches the exact (height, hash), so it just avoids repeating that same computation. The current block’s supplied roots are still pushed and authenticated by the successor check.
There was a problem hiding this comment.
711c2ad to
c293612
Compare
|
@v12-auditor review |
|
Note Complete: Audit complete. No review-worthy issues remain after automatic triage. Three findings were auto-invalidated. Open the full results here. Analyzed four files, diff |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit cc199db. Configure here.
| /// Verify this block's parent-history commitment, then fold the supplied | ||
| /// per-block roots into the running history tree for the next block. | ||
| pub(crate) fn with_roots( | ||
| block: Arc<Block>, |
There was a problem hiding this comment.
Later on this will no longer require block correct?
Motivation
Next slice of the verified-commitment-trees (VCT) split series (#402 merged, #410 open, #408 draft/reference). This is the verification core — the single invariant the whole design rests on: no peer-supplied root influences consensus state until it has been authenticated against a header commitment. Landing it alone, with its own tests, lets that consensus-critical logic be reviewed without the ~5k lines of plumbing around it.
Stacked on #410 (
split/vct-root-serving); the diff collapses to this slice once #410 merges.Solution
Add
commitment_aux_verify.rs, read-only verification of supplied per-block Sapling/Orchard roots against the node's own checkpoint-committed block headers:verify_commitment_roots: for each block, validate its header commitment against the running ZIP-221 ChainHistory MMR (i.e. against every root already folded in — the one-block-lag check), then fold the block's supplied roots into the MMR viaHistoryTree::push. Returns the candidate tree only if every step verifies; any failure reports the failing height and leaves no state touched.verify_supplied_sapling_root_below_heartwood/verify_supplied_orchard_root_below_nu5: direct checks where the MMR does not constrain a pool's root — below Heartwood the header'shashFinalSaplingRootpins the Sapling root; below NU5 the Orchard root must be the empty-tree root (newCommitmentError::InvalidPreNu5OrchardRootinzebra-chain).CommitmentRootVerificationitems carry an optional precomputed ZIP-244 auth-data root (byte-identical to recomputing; see the new comment incheck.rs) and aheader_onlyform for confirming a predecessor's roots from the successor header.There is no new crypto: the module reuses the existing consensus check
block_commitment_is_valid_for_chain_historyandHistoryTree::push, which build the V1/V2 leaf from the block body and the supplied roots.