Skip to content

Commit db05d78

Browse files
fix: tiered attestation scoring for block building (lambdaclass#382)
## Description / Motivation Replaces the `target.slot` ASC sort + STF-advance fixed point in `build_block` with a tiered greedy modeled on Prysm's `sortByProfitability`. The previous loop committed attestations in arbitrary chain order and re-ran the STF after each batch to detect justification advance, which: - Doesn't prioritize attestations that finalize or justify under the `MAX_ATTESTATIONS_DATA = 16` cap. - Pays for a full STF execution every outer iteration. - Has no signal for "this entry adds marginal voters worth packing" — it's all-or-nothing per data entry. The new selection algorithm scores each candidate against a projected post-state and picks the highest-tier entry per round. ## Scoring tiers | Tier | Predicate | Notes | |---|---|---| | 1 | applying the entry finalizes its source | 3SF-mini: no slot in `(source.slot, target.slot)` is still justifiable per `slot_is_justifiable_after`, so source and target are consecutive justified checkpoints in the projected post-state | | 2 | applying the entry justifies its target | total voters (prior + new) crosses ⅔ | | 3 | adds marginal new voters | not enough to cross ⅔, but contributes toward future rounds | Within a tier: more `new_voters` wins, then smaller `target_slot` (older chain progress first), then smaller `att_slot`, then `data_root` for determinism. ## What Changed Three commits on this branch: | Commit | Subject | |---|---| | `6336ce7` | feat(blockchain): tiered attestation scoring for block building | | `5ccc938` | refactor(blockchain): simplify attestation scoring helpers | | `d59d41b` | refactor(blockchain): extract block_builder module | Key code: - New module `crates/blockchain/src/block_builder.rs` containing `build_block`, `select_attestations`, `pick_best_candidate`, `score_entry`, `entry_passes_filters`, the `EntryScore` / `ChainContext` / `ProjectedState` types, plus `compact_attestations` and `extend_proofs_greedily` (moved out of `store.rs`). - `build_running_votes(state)` deserializes the flattened `state.justifications_validators` bitlist into `HashMap<H256, HashSet<u64>>` — the analog of Prysm/Lighthouse's participation flags. Selection seeds from this and updates it incrementally. - Projection of `justified_slots` and `finalized_slot` happens in-loop after each tier 1/2 selection so dependent attestations (whose source is the just-justified slot) become eligible on the next round without running the STF. - The final STF still runs once on the assembled block to seal `state_root` and validate that the proposed block is sound. ## Correctness / Behavior Guarantees - **Final STF unchanged**: `process_slots` + `process_block` still run on the selected attestations before `state_root` is set. Any divergence between projection and the actual STF produces an error here. - **Filter invariants preserved**: `entry_passes_filters` enforces the same predicates the previous loop did (head known, source justified, chain-match, target not already justified) plus the genesis self-vote bypass. - **3SF-mini finalize predicate**: tier 1 elevation requires `(source.slot + 1..target.slot).all(|s| !slot_is_justifiable_after(s, projected_finalized_slot))` — matches `try_finalize` exactly, including the implicit "source and target must be consecutive justified checkpoints" constraint (any already-justified slot between them is by construction still justifiable). - **Cap preserved**: still bounded by `MAX_ATTESTATIONS_DATA = 16` distinct `AttestationData` entries. - **Genesis self-vote handling preserved**: `(source.slot == 0 && target.slot == 0)` entries are scored as tier 3 (fork-choice only) and bypass the "target already justified" filter. ## Tests Added / Run - All existing tests pass: 20 unit tests in `ethlambda-blockchain` (incl. `build_block_caps_attestation_data_entries` and `build_block_absorbs_older_but_justified_source`), 84 fork-choice spec tests, 11 signature spec tests. Full `make test` = 415 passed / 0 failed / 6 ignored. - Tests moved alongside the code into `block_builder::tests`. ## Related Issues / PRs - Modeled after Prysm's `proposerAtts.sortByProfitability` in `beacon-chain/operations/attestations/`. - 3SF-mini reference for justifiability deltas: https://github.com/ethereum/research/blob/c003fe1c1a785797e7b53e3cbf9569b989be6e93/3sf-mini/consensus.py#L52-L54 ## Verification Checklist - [x] Ran `make fmt` — clean - [x] Ran `make lint` (clippy with `-D warnings`) — clean - [x] Ran `cargo test --workspace --release` — all passing --------- Co-authored-by: Pablo Deymonnaz <pdeymon@fi.uba.ar>
1 parent ae6ac42 commit db05d78

3 files changed

Lines changed: 1257 additions & 864 deletions

File tree

0 commit comments

Comments
 (0)