Skip to content

forkchoice: tighten validate_attestation future-slot bound#682

Open
tcoratger wants to merge 1 commit intoleanEthereum:mainfrom
tcoratger:forkchoice-tighten-attestation-future-slot-bound
Open

forkchoice: tighten validate_attestation future-slot bound#682
tcoratger wants to merge 1 commit intoleanEthereum:mainfrom
tcoratger:forkchoice-tighten-attestation-future-slot-bound

Conversation

@tcoratger
Copy link
Copy Markdown
Collaborator

Summary

  • The time check in Store.validate_attestation accepted votes up to a full slot ahead of the local clock. With 4 s slots that is ~800 ms of free pre-positioning room — an adversary can publish next-slot aggregates before any honest validator could produce them, and the next proposer happily includes them.
  • The bound is now expressed in interval units against Store.time and gated by a new GOSSIP_DISPARITY_INTERVALS = 1 constant in chain/config.py (the lean analogue of mainnet's MAXIMUM_GOSSIP_CLOCK_DISPARITY).
  • Several existing spec tests gossiped attestations whose data.slot was one slot in the future to compress their timeline. They have been restructured to follow the natural Lean flow (gossip during the producer's own slot, then tick to migrate). Three new boundary regressions are added to both gossip validation files, plus a unit-level TestValidateAttestationTimeCheck class. Tests reference the constant rather than hardcoded numbers, so future tweaks propagate.

Test plan

  • uvx tox -e all-checks
  • uv run pytest tests/lean_spec/subspecs/forkchoice/ (86 passed)
  • uv run fill --fork=devnet --clean -n auto tests/consensus/devnet/fc/ (81 passed)

Notes for reviewers / Zeam

  • Zeam's data.slot <= current_slot was strictly correct for the producer/receiver alignment but did not leave room for clock skew. The new rule allows exactly one interval (~800 ms), so a Zeam node and a leanSpec node tolerate each other under normal NTP drift.
  • The framework now ticks the local store to the block's slot before build_signed_block_with_store gossips in-body attestations, so block-included votes still validate cleanly under the tighter rule.

🤖 Generated with Claude Code

The time check used to admit any vote within one full slot of the local
clock. That window let an adversary pre-publish next-slot aggregates
~800 ms before any honest validator could produce them, with the next
proposer happily including them.

The bound is now expressed in interval units against `Store.time` and
gated by a new `GOSSIP_DISPARITY_INTERVALS` constant (one interval, the
lean analogue of mainnet's `MAXIMUM_GOSSIP_CLOCK_DISPARITY`). Tests
reference the constant rather than hardcoding numbers, so future
changes propagate automatically.

Several existing spec tests gossiped attestations carrying a future
data.slot to compress timelines; they have been restructured to follow
the natural Lean flow (gossip during the producer's own slot, then
tick to migrate). Three new boundary regressions are added to both
gossip validation files plus a unit-level `TestValidateAttestationTimeCheck`
class.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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