Skip to content

feat(validator_store): early RANDAO pre-sign service behind --early-randao #1179

Description

@shane-moore

Blocked by: #1177, #1184, #933, and #1192

Anchor rollout companion: #1178

Goal

Add a flag-gated producer service that starts RANDAO partial-signature collection at the recommended time before a locally known eligible proposal slot, so Lighthouse's unchanged in-slot randao_reveal call can reuse an already completed reconstruction.

Early emission is optional under SIP-101 at 8279853. An implementation that never emits early remains conformant. Anchor chooses to implement the recommended S - 1 policy and keep the existing in-slot path as the fallback.

Protocol classification

For a locally known proposer duty at eligible target slot S:

  • The producer MAY emit at any time in [slot_start(S - 2), slot_start(S)).
  • If it emits early, it MUST NOT emit before slot_start(S - 2) by its own clock.
  • If it elects to emit early and knows the duty by the recommended time, it SHOULD make its first local publication attempt at exact slot_start(S - 1).
  • It SHOULD still invoke the existing in-slot emission path at S regardless of its locally recorded early outcome.
  • It MAY serve an already reconstructed reveal to the in-slot consumer without waiting for repeated local-share signing, envelope signing, or publication.
  • It MAY emit immediately for a duty first discovered after the recommended time and SHOULD process multiple eligible duties in ascending slot order.

The two-slot value is the maximum receiver window, not the normal Anchor producer schedule. The 1000ms clock tolerance is receiver-side headroom and does not shift the recommended producer time. The SIP does not coordinate a second pre-slot attempt. Anchor adopts one normal attempt at S - 1, followed by the existing in-slot path at S.

Different producer schedules remain interoperable, but the common policies used by a cluster determine when a valid threshold becomes available and when the reveal becomes knowable.

Eligibility uses the stamped target slot: S >= EARLY_RANDAO_LEAD and epoch(S) >= GLOAS_FORK_EPOCH. For the first non-genesis Gloas slot F, the legal window begins at slot_start(F - 2), while Anchor's recommended attempt is at slot_start(F - 1). The service must not add a current-epoch, current-fork, or SSV-fork gate.

Dependencies and rollout

Neither #1192 nor unconditional in-slot emission guarantees a second network delivery after an earlier successful publish. Gossip duplicate caches may absorb the byte-identical message for the useful duty window. The in-slot path remains valuable for restarted origins and receivers that did not see the early copy.

Current implementation shape

At upstream/epbs 7bad23f, RANDAO reconstruction is cached by signing root and validator, while the signing root is epoch-derived. A completed collector returns its cached signature to a newly registered requester.

The current sign_and_collect path registers for the cached result, then attempts to enqueue repeated local-share signing before awaiting that result. A full or closed urgent queue can therefore fail the request even when a completed reconstruction exists. The Early RANDAO path should separate the cached consumer result from the best-effort in-slot signing and publication attempt.

Suggested approach

  • Add early_randao_reveal(&self, pubkey, proposal_slot) to AnchorValidatorStore, using the ordinary randao_reveal signing logic but deriving the epoch and stamped SSV message slot from proposal_slot.
  • Drive one scheduler from both slot ticks and fix(duties_tracker): authoritative complete-schedule transitions for proposer assignment verdicts #1184's complete-schedule watch. At tick slot s, the normal Anchor policy targets locally owned duty S = s + 1, including cross-epoch targets. Do not schedule the ordinary first attempt for s + 2.
  • When fix(duties_tracker): authoritative complete-schedule transitions for proposer assignment verdicts #1184 installs or replaces a complete schedule, inspect the newly visible view for locally owned eligible duties in ascending slot order:
    • before slot_start(S - 1), leave the duty for the normal S - 1 tick;
    • at or after slot_start(S - 1) and before slot_start(S), request at most one immediate best-effort early attempt;
    • at or after slot_start(S), do not start an early attempt, and leave the existing in-slot path in control.
  • Route tick-driven and watch-driven requests through the same bounded, slot-pruned attempt state. Mark a duty in flight before spawning so a concurrent tick and duty-install notification produce one pre-slot attempt. Do not schedule a second pre-slot retry after failure. Treat completed reconstruction as a cache-warming result, not proof that gossip publication succeeded.
  • Keep the ordinary in-slot randao_reveal path invoked regardless of whether the early attempt completed, failed, was duplicate-suppressed, or never ran.
  • When a completed reconstruction is already cached, return it to the in-slot consumer without waiting for repeated local-share signing, envelope signing, publication, or successful enqueue of that best-effort work. Attempt the in-slot emission independently, and report any scheduling or publication failure without converting the cached consumer result into an error.
  • Put the service behind --early-randao. The flag default and rollout schedule are Anchor policy, not SIP conformance. The service may be configured before wall-clock Gloas, but it emits only when the target-slot predicate is true.
  • Record low-cardinality metrics for initiated, completed, failed, and skipped early attempts, plus the ordinary in-slot completion timing and best-effort in-slot emission failures.

Acceptance criteria

  • Anchor never emits before slot_start(S - 2) and never emits early for an ineligible target slot.
  • Anchor's normal first attempt occurs at exact slot_start(S - 1), with no 500ms offset. EARLY_RANDAO_CLOCK_TOLERANCE does not shift it.
  • Anchor makes no normal S - 2 attempt and schedules no second pre-slot retry.
  • The first eligible Gloas target F is selected from the F - 1 tick while target F - 1 remains ineligible.
  • A duty installed before the recommended time waits for the normal S - 1 tick.
  • A duty first installed after the recommended time and before S receives at most one immediate early attempt without waiting for another slot tick.
  • A concurrent S - 1 tick and duty-install notification produce exactly one pre-slot attempt.
  • A duty first installed at or after S does not start an early attempt and falls through to the ordinary in-slot path.
  • Different producer emission moments require no receiver or wire-format change.
  • A failed early attempt falls through to the existing in-slot path rather than a coordinated second pre-slot attempt.
  • A completed reconstruction is returned promptly to the in-slot randao_reveal consumer without waiting for repeated signing or publication.
  • Failure to enqueue or publish the best-effort in-slot emission does not turn an available cached reconstruction into a consumer error.
  • The ordinary in-slot path is invoked whether the early attempt succeeded, failed, was duplicate-suppressed, or was disabled.
  • With the feature disabled, Anchor does not emit early and remains SIP-conformant.
  • The implementation does not claim that fix(message_sender): outbound validation commits state before network enqueue #1192 or the in-slot fallback guarantees network redelivery.

Tests

Cover target-slot activation at F, genesis slots below the lead, cross-epoch target selection, the SSV-fork non-input, the two-slot legal floor, the exact S - 1 Anchor policy without a 500ms offset, no normal S - 2 attempt, duty install before S - 1 deferring to the tick, duty install between S - 1 and S triggering without another tick, duty install at or after S leaving the in-slot path in control, a simultaneous tick and watch notification, feature disabled, attempt deduplication, failed early attempt followed by the in-slot path, unconditional in-slot invocation with and without a completed reconstruction, proposal-slot stamping, cache reuse, a same-epoch duty move from X to Y where the reveal at Y is served from the valid epoch reconstruction when available or completed by the ordinary in-slot exchange otherwise, cached completion when repeated signing or publication enqueue fails, and the invalid-BLS-share path once #933 lands.

Notes

Issues are directionally correct, not prescriptive. Verify symbols and the rollout default at PR time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    epbsePBS / EIP-7732 / Gloas implementation

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions