refactor(blockchain): move projection and scoring onto ProjectedState#525
Conversation
2bb7ac7 to
0277f5c
Compare
Pull the round-by-round projection and candidate scoring out of select_attestations into ProjectedState methods: from_head_state() seeds it, advance() folds a selected entry's voters and moves justification/finalization forward, and score_entry() scores a candidate from its realized `coverage` against the projection (reading current_votes and finalized_slot from &self rather than as parameters). Widen ProjectedState with its methods, entry_passes_filters, Tier, EntryScore, OrderingKey, and EntryScore::ordering_key to pub(crate). Block-building behavior is unchanged: the method bodies are the former inline logic (advance()'s current_votes update simply moves after the trace it never fed), and pick_best_candidate now unions proof participants into `coverage` before scoring, the exact set the old score_entry derived internally. This exposes the projection and scoring primitives so interval-2 aggregation can reuse them instead of duplicating the logic.
0277f5c to
607d19f
Compare
Move entry_passes_filters onto ProjectedState alongside score_entry: it reads justified_slots and finalized_slot from &self and still takes the chain view (known_block_roots, extended_historical_block_hashes) as arguments. Callers become projected.entry_passes_filters(att_data, known_roots, hist). Behavior-preserving.
🤖 Kimi Code ReviewThe PR refactors attestation selection logic by extracting High-level assessment: Correct and well-structured refactoring. No security issues detected. Specific observations:
Minor suggestions:
No changes required – the PR is ready to merge. Automated review by Kimi (Moonshot AI) · kimi-k2.5 · custom prompt |
🤖 Codex Code Review
No consensus-correctness or security regression stood out from the refactor itself. The extracted I couldn’t run Automated review by OpenAI Codex · gpt-5.4 · custom prompt |
Greptile SummaryThis PR moves attestation projection and scoring into a reusable
Confidence Score: 5/5This looks safe to merge.
|
| Filename | Overview |
|---|---|
| crates/blockchain/src/block_builder.rs | Extracts the existing projection, filtering, and scoring flow into crate-visible types and methods without changing the current block-builder behavior. |
Reviews (1): Last reviewed commit: "Merge branch 'main' into refactor/block-..." | Re-trigger Greptile
🤖 Claude Code ReviewReview: PR 525 — refactor(blockchain): move projection and scoring onto ProjectedStateSummaryThis is a clean, mechanical extraction. Two minor items worth a look before merge — neither blocks the refactor, both are cheap to fix. Findings1. let coverage: HashSet<u64> = proofs
.iter()
.flat_map(|proof| proof.participant_indices())
.collect();
let Some((score, new_voters)) =
projected.score_entry(att_data, &coverage, chain.validator_count)The old This tradeoff is presumably intentional — the doc comment on 2. Doc comments describe the aggregator integration as already wired up, but it isn't yet ( /// Shared by `select_attestations` (block proposal) and
/// `aggregation::snapshot_aggregation_inputs` (interval-2 aggregation) so the
/// two selectors project justification/finalization identically.
and /// The caller resolves `coverage` and passes it in: block building unions a
/// data's proof participants (see `pick_best_candidate`); committee-signature
/// aggregation passes a job's realized raw + child participants.
I checked Non-findings (things that look right)
Automated review by Claude (Anthropic) · sonnet · custom prompt |
## What Rework `snapshot_aggregation_inputs` into a tiered greedy selector modeled on the block builder's `select_attestations`: an up-front store pass resolves each candidate's aggregation material once (raw-first + trim), then a loop scores candidates by (current-slot-first, Finalize > Justify > Build) against an optimistically-projected state, emitting at most `MAX_AGGREGATION_JOBS` jobs. ## Why The interval-2 session aggregated current-slot gossip groups in arbitrary order and ignored existing proofs, so it could not prioritize the groups whose aggregation most advances consensus. ## How - Candidates are filtered by the block builder's `entry_passes_filters` against a chain view covering `[0, head_slot]` (the head root is pushed onto the state's `historical_block_hashes`, which omits the head's own root), so prover time is spent only on aggregations a block could actually pack. - Reuses the shared `ProjectedState` (`from_head_state` + `advance`) and `Tier`/`EntryScore`/`entry_passes_filters` via a coverage-based `score_from_coverage` core, so proposer and aggregator can never drift on either the justify/finalize projection or the tiering. - Deletes `snapshot_current_slot_aggregation_inputs` and `build_raw_signature_job` (subsumed). ## Stacking Stacked on #525 (the block builder refactor). Review/merge that first; GitHub retargets this PR to `main` once it lands. ## Checks - `cargo fmt` clean - `cargo clippy --all-targets -- -D warnings` clean - `cargo test -p ethlambda-blockchain --lib` green (incl. resolve_job / pick_best_candidate / snapshot tests)
What
Pure, behavior-preserving refactor of the block builder: pull the round-by-round
justification/finalization projection out of
select_attestationsinto areusable
ProjectedStatewithfrom_head_state()andadvance(), and widenentry_passes_filters,Tier,EntryScore,OrderingKey, andEntryScore::ordering_keytopub(crate).Why
The interval-2 aggregation selector duplicates the block builder's
justify/finalize projection verbatim. This PR extracts that projection so a
follow-up can reuse it instead of copy-pasting the round-by-round logic, keeping
proposer and aggregator from ever drifting on how they project the post-state.
Behavior
Block building is unchanged:
advance()'s body is the former inline projection.current_votesupdate simply moves after thetrace!it never fed.Notes
score_entryis intentionally left as-is (proofs-based).Checks
cargo fmtcleancargo clippy --all-targets -- -D warningscleancargo test -p ethlambda-blockchain --libgreen (incl. projection-cascade tests)