Split on_block() and on_gossip_attestation() into verified and unverified variants#157
Split on_block() and on_gossip_attestation() into verified and unverified variants#157pablodeymo wants to merge 5 commits intomainfrom
Conversation
…ified variants, removing the skip-signature-verification compile-time feature flag entirely. on_block() and on_gossip_attestation() now always verify signatures (safe default). on_block_without_verification() and on_gossip_attestation_without_verification() provide explicit opt-outs for tests where signatures are absent. Shared block processing logic is extracted into a private on_block_core() that takes parent_state by value to avoid cloning.
🤖 Kimi Code ReviewReview SummaryThis PR removes the Key Issues Found
Minor Issues
Positive Changes
Recommendations
Automated review by Kimi (Moonshot AI) · custom prompt |
🤖 Codex Code ReviewFindings:
What looks good:
Validation note:
Automated review by OpenAI Codex · custom prompt |
🤖 Claude Code ReviewNow I have a clear picture of all the changes. Let me write up my review. Review: PR #157 — Split
|
Greptile SummaryThis PR successfully eliminates the Key improvements:
Code organization:
Changes include:
Confidence Score: 4/5
|
| Filename | Overview |
|---|---|
| crates/blockchain/src/store.rs | Successfully splits on_block() and on_gossip_attestation() into verified/unverified variants with shared logic, eliminating feature flags. Minor timing change in signature storage warrants verification. |
| crates/blockchain/tests/forkchoice_spectests.rs | Correctly updated to use on_block_without_verification() and fixed pre-existing clippy warnings for collapsible if statements using modern Rust syntax. |
| crates/blockchain/Cargo.toml | Cleanly removes skip-signature-verification feature flag and associated test requirements. No issues found. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Block Received] --> B{Production or Test?}
B -->|Production| C[on_block]
B -->|Fork Choice Tests| D[on_block_without_verification]
C --> E[Check for Duplicate]
D --> F[Check for Duplicate]
E --> G[Get Parent State]
F --> H[Get Parent State]
G --> I[verify_signatures]
I --> J[Store Proposer Signature]
J --> K[on_block_core]
H --> K
K --> L[State Transition]
L --> M[Store Block & State]
M --> N[Process Attestations]
N --> O[Update Fork Choice Head]
O --> P[Process Proposer Attestation]
P --> Q[Complete]
style C fill:#90EE90
style D fill:#FFB6C1
style I fill:#87CEEB
style J fill:#FFD700
style K fill:#DDA0DD
Last reviewed commit: aff6594
Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com>
…on duplication into shared core functions with a runtime verify flag, restore parent-state comment, remove redundant forkchoice test target from Makefile, and add BUILD_PROFILE example to RELEASE.md.
| // Store the proposer's signature for potential future block building | ||
| let proposer_attestation = &signed_block.message.proposer_attestation; | ||
| let proposer_sig = | ||
| ValidatorSignature::from_bytes(&signed_block.signature.proposer_signature) | ||
| .map_err(|_| StoreError::SignatureDecodingFailed)?; | ||
| store.insert_gossip_signature( | ||
| &proposer_attestation.data, | ||
| proposer_attestation.validator_id, | ||
| proposer_sig, | ||
| ); |
There was a problem hiding this comment.
Let's keep this the same as before, but using the new flag. That way, we avoid storing the proposer signature if the block is invalid.
Motivation
PR #113 proposed extracting signature verification out of
on_block()into a separateprecheck_block_signatures()function called by the network layer before processing. Four automated reviewers flagged a critical security flaw: removingverify_signatures()fromon_block()means any caller that forgets to callprecheck_block_signatures()first can import blocks without cryptographic validation. There are 3 call sites foron_block()(productionprocess_block(), and 2 test files), and only 1 would get the precheck.PR #154 responded by taking the conservative approach: keep
on_block()unchanged and document its validate-then-mutate structure. It argued against extraction.This PR is the compromise: instead of removing verification from
on_block(), we keepon_block()as the safe default (always verifies) and addon_block_without_verification()as an explicit opt-out. This follows Zeam's architecture whereForkChoice.onBlock()is signature-agnostic and verification happens at the chain layer, but inverted — verification is the default and opting out requires calling a function whose name makes the risk obvious.This eliminates the
skip-signature-verificationcompile-time feature flag entirely.Description
store.rs— Spliton_block()Three functions replace the old
on_block():on_block()lib.rs),signature_spectestson_block_without_verification()forkchoice_spectestson_block_core()on_block_core()takesparent_stateby value (avoids the previous.clone()— minor perf win). The 4-line dedup + parent-state preamble is duplicated in both public functions to avoid double deserialization (verification needs the state, core needs the state).store.rs— Spliton_gossip_attestation()Same pattern:
on_gossip_attestation()on_gossip_attestation_without_verification()Both share the validation +
on_attestation()+ logging logic. Some duplication is acceptable to keep each function self-contained.Cargo.toml— Remove feature flag[features]section withskip-signature-verificationrequired-features = ["skip-signature-verification"]from forkchoice test entryforkchoice_spectests.rsstore::on_block()→store::on_block_without_verification()collapsible_ifclippy warnings (now surfaced because the test no longer requires a feature flag to compile, soclippy --all-targetssees it)Makefile--features skip-signature-verificationfromtesttargetCLAUDE.mdandRELEASE.mdskip-signature-verificationreferences from test commands, gotchas, and Docker build examplesRelationship to #113 and #78
This PR supersedes #113's approach. Rather than extracting verification to a separate precheck (which creates the "forgotten precheck" security risk flagged by reviewers), it splits the function into safe and unsafe variants. The safe variant (
on_block()) always verifies — callers can't accidentally skip verification. The unsafe variant (on_block_without_verification()) makes the risk explicit in its name. Issue #78's concern about signature verification is fully addressed: production paths always verify, and the compile-time feature flag is eliminated.How to test
Confirm no feature flag remnants:
grep -r "skip-signature-verification" crates/Note:
signature_spectestshave pre-existing failures (fixture deserialization issue withProposerSignature). These failures are identical onmainand are unrelated to this change.