Skip to content

Build at each configured offset and resubmit only on a higher value - #559

Open
0w3n-d wants to merge 1 commit into
od/builder-submit-step4from
od/builder-slot-loop-step5
Open

Build at each configured offset and resubmit only on a higher value#559
0w3n-d wants to merge 1 commit into
od/builder-submit-step4from
od/builder-slot-loop-step5

Conversation

@0w3n-d

@0w3n-d 0w3n-d commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Issue: #550 (step 5 of 6)

What this PR does

Builds at each configured offset into the slot instead of once when the event
arrives, and submits only when the value beats what was already sent for that
slot and parent.

Two pieces are kept pure so the timing is testable without sleeping:
schedule::delays decides when to build, and BestBid::improves decides
whether to send.

Scope change

self_validate is dropped, as agreed. The config field and its example
entry are removed rather than left unread.

Re-simulating a block we just built is duplicated work: assembly already
executes every transaction and computes the state root. Paying for a second
full validation inside the slot would cost latency for nothing. Correctness
here is the job of the tests and of running on a testnet before deploying.

What this PR deliberately does not do

No bidding strategy — the bid is always the full block value, never held back.
No cancellations. No multi-relay fan-out. A slot's attempts run in sequence, so
a context arriving mid-slot waits for the previous slot's last attempt; with
12s slots and the default offsets this cannot bite, but it is a real bound.

Tests

8 new, written before the implementation and signed off first.

  • Scheduling (4): offsets become delays from the slot start; an unsorted list
    is ordered, since nothing else sorts it; an offset already past is skipped;
    and a late event still gets one immediate attempt — otherwise a late
    payload_attributes means no bid at all for that slot.
  • The improvement gate (4): a higher value is sent; an equal or lower one is
    not, because the relay treats each submission as a new bid and a worse one
    would replace a better; a new slot resets; and a new parent for the same
    slot resets
    , because after a re-org the earlier bid sits on a dead parent.
    That last one pairs with step 2's rule that a new parent is not a duplicate.

147 pass in the crate.

A bug these tests did not catch

Wiring the loop, I first slept the delays end to end, which puts the second
attempt at 2500ms rather than 2000ms. delays is correct and its tests pass
either way — the fault was in the caller. It now sleeps to an absolute deadline
from a single base instant, and the doc comment says why. The loop's own timing
remains untested; only the schedule it consumes is.

Reviewer checklist

  • CI (lint, unit-test) is green
  • Matches the linked issue/step
  • No unexplained scope creep or unrelated files touched

Sleep to an absolute deadline. The offsets share one origin, so sleeping
them end to end would land every attempt after the last.

Key the best bid by slot and parent. After a re-org the earlier bid sits
on a dead parent, so a lower value must still go out.

Drop `self_validate`.

Co-Authored-By: Claude Opus 5 (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