Skip to content

feat: tiered attestation scoring#791

Draft
MegaRedHand wants to merge 15 commits into
leanEthereum:mainfrom
lambdaclass:feat/tiered-attestation-scoring
Draft

feat: tiered attestation scoring#791
MegaRedHand wants to merge 15 commits into
leanEthereum:mainfrom
lambdaclass:feat/tiered-attestation-scoring

Conversation

@MegaRedHand
Copy link
Copy Markdown
Contributor

🗒️ Description

Previously, we relaxed the block building algorithm to also take into account attestations with an older source. This fixed a devnet breaking bug but also made block building much less efficient, with useless attestations now being packed in blocks.

This PR changes the block building algorithm to order attestations by usefulness, with attestations that finalize a slot being included before any that only justify a slot, and those being preferred before attestations that only add weight. This is implemented by grouping attestations by tiers (Finalize, Justify, Build), and scoring them by coverage.

✅ Checklist

  • Ran local quality checks to avoid unnecessary CI fails:
    just check
  • Considered adding appropriate tests for the changes.
  • Considered updating the online docs in the ./docs/ directory.

Adds three integration tests that build real block chains and verify
the core behaviors of _select_attestations: cascading projected
justification across rounds, accepting a gap-closing attestation with
an older-but-valid source, and enforcing the MAX_ATTESTATIONS_DATA cap.
An older-source candidate (source.slot < projected_finalized_slot), reachable
after a finalize-tier pick advances the finalized boundary or on an
already-finalized head, made the finalize predicate call is_justifiable_after
with a slot behind the finalized boundary, which asserts. Clamp the scan to
start above the finalized slot: such slots are finalized, not pending, so they
never block finalization. Add regression tests for the finalize tier and the
older-source path.
- Require source.slot >= projected_finalized_slot before classifying an entry
  as FINALIZE tier. Finalization is monotonic, so an entry whose source is
  behind the projected boundary cannot advance it. The previous scan_start
  clamp avoided the is_justifiable_after assertion but still allowed FINALIZE
  to fire with a vacuously-empty range, which then dropped the projected
  finalized_slot below its current value and corrupted subsequent
  is_slot_justified lookups (silent wrong answer or IndexError).
- Add precondition assert on slot > parent_slot so a same-slot misuse fails
  fast instead of underflowing Uint64 into a 2^64-element list allocation.
- Extract _is_genesis_self_vote helper to dedupe the predicate across the
  scorer and the filter.
- Add a focused regression test for the boundary-regression scenario.
Collapse the three genesis-self-vote exemption guards in the entry
filter into a single branch, hash each candidate's data root once up
front instead of re-hashing every round, and accumulate running votes
only for BUILD-tier targets since justify and finalize discard them
immediately.
The per-round re-hashing it avoided is not worth the extra parameter
and map allocation; restore the inline data-root hash at the tiebreak
site.
…on-scoring

# Conflicts:
#	src/lean_spec/spec/forks/lstar/spec.py
The tiered greedy scorer changes which attestations a block carries
relative to the old fixed-point builder, so two fork-choice fixtures
needed updating.

Divergence self-healing: the produced block carries only the
divergence-closing vote. The other pool entry's voters are already
recorded on-chain for that target, so it adds no new voters and the
scorer omits it rather than re-stating a vote the post-state holds.

Attestation-data cap: gossip one more than the limit using the first
justifiable target slots, one voter each so no entry justifies. The cap
is then exercised by entry count alone, with the justifiability filter
and justification dynamics held out of the candidate set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant