Skip to content

feat(pipelining): complete attestations by build-slot end#22735

Draft
spalladino wants to merge 2 commits intomerge-train/spartanfrom
spl/early-pipelining-attestations
Draft

feat(pipelining): complete attestations by build-slot end#22735
spalladino wants to merge 2 commits intomerge-train/spartanfrom
spl/early-pipelining-attestations

Conversation

@spalladino
Copy link
Copy Markdown
Contributor

@spalladino spalladino commented Apr 22, 2026

Motivation

Under today's pipelining schedule, attestations for slot N's checkpoint trail into slot N+1 by blockDuration + p2pPropagationTime (~8s with defaults), which delays the L1 propose tx and pushes it toward the 3rd L1 block of the target slot. Shifting the broadcast ~8s earlier lets attestations finish by the build-slot boundary so the proposer can submit to L1 immediately at the target-slot start.

Approach

Updates the pipelined timing model to reserve assembly, round-trip p2p, and last-block re-execution at the end of the build slot (rather than leaking into the target slot). Proposal broadcast now fires at ~T = slotDuration − timeReservedAtEnd inside the build slot, so attestations arrive before the boundary. Receiver acceptance windows are tightened accordingly: proposalWindowIntoTargetSlot drops from p2pPropagationTime to 0 (only clock-disparity grace remains) and attestationWindowIntoTargetSlot shrinks from slotDuration − l1PublishingTime (60s at defaults) to 2·p2pPropagationTime (4s).

No new p2p validation path is needed: the main messageSlot === targetSlot || messageSlot === nextSlot check already covers the steady state under pipelining.

Changes

  • stdlib (timetable): PipelinedCheckpointTimingModel.timeReservedAtEnd is now checkpointAssembleTime + 2·p2pPropagationTime + blockDuration; pipeliningAttestationGracePeriod drops to 0 under pipelining. proposalWindowIntoTargetSlot drops to 0 and attestationWindowIntoTargetSlot shrinks to 2·p2pPropagationTime.
  • p2p (msg_validators): Tightens PipeliningWindow.acceptsProposal / acceptsAttestation via the new timing-model values; isWithinPipeliningWindow JSDoc is refreshed to describe the straggler-acceptance role explicitly.
  • sequencer-client (README): Rewrites the pipelining section to describe the new schedule (broadcast inside build slot, attestations in hand by slot boundary, L1 submission at target-slot boundary) and refreshes the worked example.
  • tests (stdlib, p2p, sequencer-client): Updates pipelined timing / window-size assertions and tightens acceptance tests for the shorter straggler windows.

Rollout notes

The tightened straggler windows mean a receiver running this change will reject stale-schedule proposals that arrive more than 500ms into the target slot and stale-schedule attestations that arrive more than 4.5s into the target slot. Expect to roll this out across validators together (the merge-train/spartan flow already batches validator upgrades) rather than mixing old and new schedules on a live network.

Shifts the pipelining schedule so that proposal broadcast and
attestation collection happen inside the build slot, letting the
L1 submission fire at the target-slot boundary instead of trailing
into it.

- stdlib: PipelinedCheckpointTimingModel reserves assemble + round-trip
  p2p + last-block re-execution at end of slot, drops attestation
  grace into target slot to zero, and adds explicit early-acceptance
  windows for proposals and attestations.
- p2p: PipeliningWindow now accepts next-slot proposals/attestations
  during the final seconds of the current slot (new isWithinEarly
  PipeliningWindow check) and pipes blockDurationMs through the
  libp2p validators.
- Updates sequencer README and affected unit tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@spalladino spalladino added ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure ci-draft Run CI on draft PRs. labels Apr 22, 2026
Drops the isWithinEarlyPipeliningWindow path (and its proposalEarlyWindow /
attestationEarlyWindow getters and blockDurationMs plumbing): the existing
main-path check `messageSlot === targetSlot || messageSlot === nextSlot`
already accepts next-slot messages under both pipelining-on and
pipelining-off receivers, so the early window was dead code in every
realistic scenario.

- Remove isWithinEarlyPipeliningWindow and the early-window interface fields.
- Update JSDoc on isWithinPipeliningWindow to describe what the function
  actually guards (straggler messages for the previous target slot after
  slot rollover), now that windows are tight.
- Revert blockDurationMs plumbing through ProposalValidator /
  CheckpointAttestationValidator / libp2p_service (no longer needed, and
  avoids the foot-gun where an omitted blockDurationMs silently shrank the
  window).
- Fix README broadcast time: with assemble=1s the last block ends at
  T=61s and broadcast happens at T=62s, not T=61s.

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

ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant