diff --git a/sips/early_randao_preconsensus.md b/sips/early_randao_preconsensus.md new file mode 100644 index 0000000..2c9d243 --- /dev/null +++ b/sips/early_randao_preconsensus.md @@ -0,0 +1,137 @@ +| Author | Title | Category | Status | Dependency SIP | Date | +| ------ | ----- | -------- | ------ | -------------- | ---- | +| Shane Moore | Early RANDAO Pre-Consensus Emission | Core | draft | [ePBS (EIP-7732) Support (#94)](https://github.com/ssvlabs/SIPs/pull/94) | 2026-07-23 | + +[Discussion](https://github.com/ssvlabs/SIPs/discussions/100) + +Depends on the ePBS SIP (currently [PR #94](https://github.com/ssvlabs/SIPs/pull/94)); per [SIP-0](sip0.md), this SIP cannot move to last-call before that SIP is approved, and is rejected if it is rejected (unless changed to remove the dependency). + +**Summary** + +Operators may emit their existing block-proposal RANDAO partial signature up to 2 slots before the proposal slot, so the cluster reconstructs `randao_reveal` before the slot starts instead of inside the post-Gloas ~3s block-production budget. No new duty, role, message kind, domain, topic, or container: the existing Proposer-duty `RandaoPartialSig` message is emitted earlier, stamped with the proposal slot as today. Protocol changes are confined to message-validation timing, ordering, and duty-handling rules; receivers may additionally retain Unknown-duty candidates locally for later revalidation. The rules activate by target proposal slot `S`: they apply when `epoch(S) >= GLOAS_FORK_EPOCH`, even if the permitted emission window for `S` begins before the fork in wall-clock time. The dependency on the ePBS SIP is activation coupling only. + +**Motivation** + +Gloas moves the attestation deadline to 1/4 slot. RANDAO pre-consensus (sign, gossip, collect 2f+1, reconstruct) is the first serial step of block production and costs a gossip round trip at slot start. The signed object, `SSZUint64(epoch)` under `DOMAIN_RANDAO`, is a pure function of the proposal slot's epoch, so it can be signed and exchanged at any time and a re-org can never invalidate it. Failure modes fall back to today's in-slot exchange, except at a receiver that already IGNOREd the early copy and did not retain it: gossip duplicate caching may suppress the byte-identical in-slot copy for the remainder of the useful duty window (see *Duty assignment* and *Optional Unknown-duty retention*). Addresses [ssv-spec#373](https://github.com/ssvlabs/ssv-spec/issues/373). + +**Rationale & Design Goals** + +- No new duty: RANDAO always has an in-slot consumer (the Proposer duty), and a separate duty would still need the in-slot pre-consensus as its fallback. This differs from `ProposerPreferences` (defined in the ePBS SIP, [#94](https://github.com/ssvlabs/SIPs/pull/94)), which must reconstruct before the slot and is mutable. +- The 2-slot value is the maximum earliness receivers MUST support, not a gossip-latency requirement. Producers may emit later within that window, and operators need not emit simultaneously. At a participating receiver, the reveal becomes available once it has collected `2f+1` valid shares, so the latest share needed for quorum determines reconstruction time. Different producer schedules remain interoperable, but later schedules reduce the time saved before block proposal. The window also permits a simple slot-driven producer to make an initial attempt in the `S - 2` slot and retry in `S - 1` if the earlier local publication attempt fails. It does not guarantee a second network delivery after successful publication because byte-identical re-publications are gossip-deduplicated. A longer receiver window would widen reveal and stale-duty exposure without an identified need and would require protocol coordination. +- The per-(signer, slot) duplicate limit stays 1. Each logical partial has exactly one valid byte encoding, gossip message identifiers are content-derived, and gossip layers deduplicate before validation, so a second copy either never reaches validation or is the receiver's first copy. +- Because gossip duplicate-cache lifetimes can exceed the entire useful Early RANDAO window, a receiver that IGNOREs an early partial cannot rely on a byte-identical in-slot re-emission to recover that share. The dedicated clock tolerance narrows timing-induced loss, and optional Unknown-duty retention can recover some missing-view cases. Remaining losses are bounded by the existing round-change path. + +**Specification** + +Notation: `S` is a proposal slot; `slot_start(s)` and `epoch(s)` as usual; for a non-genesis Gloas activation, `F` is the first slot of `GLOAS_FORK_EPOCH`; `SLOT_DURATION` is the network's beacon-chain seconds-per-slot (unchanged at Gloas, which alters only intra-slot timing). REJECT penalizes the delivering peer; IGNORE drops without forwarding or penalty. + +| Constant | Value | +| -------- | ----- | +| `EARLY_RANDAO_LEAD` | 2 slots | +| `EARLY_RANDAO_CLOCK_TOLERANCE` | 1000 ms | + +**Qualifying message** + +A qualifying randao partial MUST satisfy all of: + +- Proposer-role `MessageID`; type `RandaoPartialSig`; exactly one `PartialSignatureMessage` entry; +- `slot` = the proposal slot `S`; signed object `SSZUint64(epoch(S))` under `DOMAIN_RANDAO`, domain epoch `epoch(S)`; +- canonical SSZ; deterministic BLS share signature; deterministic RSA (PKCS#1 v1.5) operator signature; exactly one outer signer, equal to the embedded operator ID; +- eligibility predicate: `S >= EARLY_RANDAO_LEAD` and `epoch(S) >= GLOAS_FORK_EPOCH` (the Ethereum Gloas fork epoch, as used by the ePBS SIP, [#94](https://github.com/ssvlabs/SIPs/pull/94)). + +The predicate is a pure function of `S`, evaluated identically by producers and receivers. It is not gated by the receiver's current epoch or by whether wall-clock time has reached the Gloas fork. The `S >= EARLY_RANDAO_LEAD` conjunct only keeps the producer's emission window well defined and excludes the first `EARLY_RANDAO_LEAD` slots at genesis. + +For a non-genesis activation, `F` and `F + 1` are eligible target slots. Their producer windows begin, by the producer's clock, at `slot_start(F - 2)` and `slot_start(F - 1)`, respectively. There is no activation warm-up: the first Gloas target slot receives the full early window. Because receiver timing includes `EARLY_RANDAO_CLOCK_TOLERANCE`, implementations MUST enable the receiver rules no later than `slot_start(F - 2) - EARLY_RANDAO_CLOCK_TOLERANCE` by the receiver's clock. This is the earliest receiver-local time at which a conforming partial for `F` can pass timing validation. + +The SSV fork schedule plays no part, and an emission window that spans an SSV fork activation is fine: every fork-sensitive artifact of a partial signature (gossip topic, domain, role gating) is derived from the message's stamped slot rather than from the moment it was emitted, so such a message is published, validated, and consumed entirely under the fork active at `S`. The same holds for a window spanning the Ethereum fork boundary. Containers violating the canonical form fall to existing structural rules (REJECT); BLS-share validity is not evaluated during message validation (see Message validation). Messages failing the predicate, and all non-randao messages, keep today's validation unchanged. + +**Producer behavior** + +For a locally known proposer duty at eligible slot `S`, an operator: + +- MAY broadcast its qualifying randao partial at any wall-clock time in `[slot_start(S - EARLY_RANDAO_LEAD), slot_start(S))`; +- MUST NOT broadcast it before `slot_start(S - EARLY_RANDAO_LEAD)` by its own clock; +- SHOULD delay emission at least 500 ms past `slot_start(S - EARLY_RANDAO_LEAD)` (assumed maximum pairwise honest clock disparity: 1 s); +- SHOULD still execute the existing in-slot emission at `S` unconditionally; a running origin's identical re-publish is absorbed by its own gossip layer (expected, not an error), and a restarted origin's re-publish aids recovery; +- MAY emit immediately for a duty discovered inside the window; SHOULD emit multiple eligible duties in ascending slot order (correctness does not depend on it). + +For `S = F`, the interval begins at `slot_start(F - EARLY_RANDAO_LEAD)`, before wall-clock Gloas activation. Producer scheduling therefore needs to run before `F` to use the full window, but early emission itself remains optional. + +Operators that never emit early remain fully conformant. + +**Message validation** + +Validation of a potential Early RANDAO message begins with the structural and canonical-form checks, which MUST run first; a structurally and canonically valid randao container satisfying the eligibility predicate is an Early RANDAO candidate, and the rules below apply to candidates only (all other messages keep today's validation unchanged). For a candidate, implementations MAY order operator-signature verification and the non-mutating contextual checks below (timing, slot ordering, duty assignment, duplicate limits) according to local denial-of-service policy, and MAY short-circuit on a contextual verdict that neither retains nor accepts the message. Any outcome that retains, accepts, forwards, feeds signature collection, or mutates ordinary validation state MUST first pass operator-signature verification. If a candidate fails both operator-signature verification and a non-retaining contextual check, either the contextual verdict or the signature-verification REJECT is conformant, but the candidate is never retained. Ordinary validation state (duplicate counts, signer state, slot high-water marks, and epoch counters) mutates only on acceptance or successful promotion, never on IGNORE or initial retention. + +Candidate classification depends on message structure and the stamped target slot, not on whether a copy arrived before `slot_start(S)`. Consequently, the duty tri-state replaces existing RANDAO duty handling for every eligible target slot, including ordinary in-slot copies and later copies still within the existing Proposer lateness window. + +Checks are staged: operator-signature verification gates retention, acceptance, forwarding, and state mutation; BLS-share validity gates consumption. A candidate is fully qualifying only once every applicable check has passed; honest producers emit qualifying messages by construction. + +*Earliness.* A receiver MUST accept a candidate's timing iff + +```text +slot_start(msg.slot) - local_now <= EARLY_RANDAO_LEAD * SLOT_DURATION + EARLY_RANDAO_CLOCK_TOLERANCE +``` + +inclusive on the accept side; strictly greater is IGNORE. This replaces the generic clock tolerance for this rule only. Lateness is unchanged (existing Proposer-role TTL against `msg.slot`). All other message classes keep their existing allowances. + +*Slot ordering.* Candidate randao partials are exempt from the per-(operator, `MessageID`) highest-seen-slot rule in both directions: they MUST NOT be rejected for a slot below the high-water mark, and they MUST NOT advance the high-water mark applied to other message classes on the same `MessageID` (randao shares its `MessageID` with the proposal's consensus and post-consensus traffic). Final acceptance still requires the remaining qualifying-message checks; earliness, lateness, the duplicate limit of 1, and canonical form bound these messages instead. + +*Duty assignment.* Tri-state, evaluated per candidate against the receiver's proposer-duty view for `epoch(msg.slot)` and the message's validator: + +- Known (a retained view is authoritative for the candidate; see below) and assigned at exactly `msg.slot`: the duty-assignment check passes. +- Known and not assigned: the duty-assignment verdict is IGNORE, never REJECT (receiver views can be stale or re-orged); an independently failing rule may still determine the final verdict under the ordering allowance above. +- Unknown (otherwise): IGNORE. A receiver MAY additionally retain the candidate locally under the optional rules below. + +A proposer-duty view is authoritative for an epoch iff the receiver retains a complete schedule containing exactly `SLOTS_PER_EPOCH` duties, one for every distinct slot in that epoch. Such a view is authoritative for every validator in the epoch, independent of the receiver's local SSV registry. A schedule that fails this shape establishes no new view. A newly retained complete schedule replaces the prior view; a failed or malformed refresh and a local validator-set change do not invalidate a previously retained authoritative view. A reorg likewise does not revoke authority until a replacement complete schedule is retained, so a stale view remains Known with the loss class described below. + +Receivers SHOULD hold next-epoch proposer duties by the tail of each epoch. + +A retained complete schedule can become stale after a boundary-adjacent reorg while remaining Known. It can therefore yield Known-and-not-assigned and IGNORE an honest early share. This is an intentional residual: the original gossip verdict cannot be retroactively changed, a byte-identical in-slot re-emission may be duplicate-suppressed, and the cost is bounded by the existing round-change path. Receivers SHOULD refresh proposer duties promptly after detecting a change, but this SIP does not require recovery from a stale Known view. + +**Optional Unknown-duty retention** + +A receiver MAY retain an Early RANDAO candidate whose proposer-duty view is Unknown for possible later promotion. Retention is local implementation policy and does not change the gossip verdict, which remains IGNORE. A receiver that does not retain the candidate remains conformant. + +Before retention, the candidate MUST pass operator-signature verification and every applicable message-validation rule other than duty assignment. Initial retention MUST NOT forward the original message, penalize the delivering peer, feed the candidate to signature collection or any downstream reconstruction cache, or mutate ordinary validation state. + +If a retained candidate is later considered for promotion, it MUST be reprocessed as if newly received under the receiver's then-current duty view, with every stateful rule applied at that time. It may be accepted and consumed only if full revalidation succeeds; otherwise it MUST be discarded. Promotion MUST NOT retroactively forward the original message or change its original gossip verdict. An implementation may attempt promotion before or after `S`; the ordinary lateness rule determines whether the candidate can still be accepted. Capacity, keying, duplicate handling within the retention store, eviction, expiry, persistence, and earlier discard are implementation-specific. + +Shares that are neither promoted nor normally accepted MUST NOT be fed to signature collection or any downstream reconstruction cache. + +**Reconstruction and consumption** + +Unchanged. The reconstructed reveal is a per-epoch value: an implementation MAY serve a proposal at slot `Y` from a reconstruction built via shares stamped for slot `X` of the same epoch, provided every contributing share was promoted or normally accepted. Wire messages remain per-slot-stamped. + +"Promoted or normally accepted" is evaluated at receipt or promotion time against the receiver's then-current duty view and is never re-evaluated at consumption. The cross-slot case is reachable two ways: a validator with two proposals in the same epoch, and a reorg that moves a proposal from `X` to `Y` after `X`-stamped shares were accepted under the pre-reorg view; the allowance exists so a completed early collection survives the shift. The signed object is identical for `X` and `Y` (`SSZUint64(epoch)`), so reuse has no cryptographic effect; implementations that key collection by signing root exercise it naturally, and implementations that require exact-slot consumption remain conformant. + +**Test expectations** + +Cross-client vectors MUST cover: + +- earliness boundary at exactly `EARLY_RANDAO_LEAD * SLOT_DURATION + EARLY_RANDAO_CLOCK_TOLERANCE` (accept) and beyond (IGNORE); +- candidate scope: an eligible in-slot `RandaoPartialSig` under an Unknown duty view produces the same initial IGNORE verdict as an otherwise-identical early copy; +- message-kind scoping: a non-RANDAO Proposer-role message two slots early remains outside the candidate path and receives the existing timing IGNORE without the Early RANDAO ordering exemption; +- Known-assigned pass, Known-unassigned IGNORE, and an otherwise-valid Unknown candidate producing the same initial IGNORE gossip verdict whether optional retention is enabled or not; +- the stale-Known reorg path: an honest share is IGNOREd as Known-and-not-assigned under a stale complete schedule, and a later replacement schedule does not retroactively change the original gossip verdict; +- same-epoch duty move: shares stamped `X` accepted under a duty-at-`X` view, the duty moves to `Y` in the same epoch, and the proposal at `Y` completes (served from the `X` reconstruction where the implementation reuses; via the in-slot exchange otherwise); +- the two-direction ordering exemption with proposals at consecutive slots for one validator; +- Known authority: a retained schedule with exactly `SLOTS_PER_EPOCH` duties over distinct in-epoch slots is authoritative for every validator; a missing, duplicate-slot, or out-of-epoch entry establishes no new view; local validator-set changes and failed or malformed refreshes do not invalidate a prior authoritative view; +- an operator-authenticated share whose BLS signature is invalid is discarded at consumption and contributes to no reconstructed reveal; reconstruction still succeeds from a valid threshold of honest shares; +- the eligibility predicate at genesis: slots below `EARLY_RANDAO_LEAD` are ineligible even when `GLOAS_FORK_EPOCH` is 0; +- activation gating: `epoch(S)` immediately before `GLOAS_FORK_EPOCH` is ineligible; for a non-genesis `F`, an otherwise qualifying `msg.slot = F` received at receiver-local time `slot_start(F - 2) - EARLY_RANDAO_CLOCK_TOLERANCE` and `msg.slot = F + 1` received at `slot_start(F - 1) - EARLY_RANDAO_CLOCK_TOLERANCE` enter the Early RANDAO validation path even though local wall-clock time is before the fork; an SSV fork scheduled anywhere does not change that; +- multi-fault precedence: a structurally valid message failing both operator-signature verification and a non-retaining contextual check (e.g. invalid signature plus Known-unassigned, or invalid signature plus too-early) may produce either the contextual verdict or REJECT, but is never retained, accepted, forwarded, collected, or state-mutating; +- late mesh join and cross-epoch stamps. + +Implementations that provide optional retention SHOULD additionally test that initial retention leaves the gossip verdict and ordinary validation state unchanged, candidates with invalid operator signatures are never retained, unpromoted candidates never reach signature collection, promotion performs full revalidation, and candidates that fail revalidation are discarded. + +Before mainnet activation guidance, testnet measurement MUST quantify early-share miss incidence at duty start (stratified by emission lead, receiver restarts, partition duration, leader round, and whether receiver retention was enabled), record promotion timing and outcome where retention is enabled, and MUST demonstrate round-2 viability under Gloas timing, meaning block publication before the post-Gloas useful-block deadline. + +**Security Considerations** + +- Deliberately ineligible early emission only starves the attacker's own share (only the signer can produce the bytes). The clock tolerance and IGNORE-not-REJECT choices narrow the permanent-loss class for honest shares, and optional retention can further narrow Unknown-view losses. Stale Known views and Unknown candidates that are not retained or are discarded before promotion remain residual loss cases. +- Gossip duplicate-cache lifetimes can exceed the entire useful Early RANDAO window, so a receiver that has already seen and IGNOREd an early share cannot rely on byte-identical re-emission for recovery. A receiver restart can both clear its seen state and drop any in-memory retained candidates; restarts and partitions are correlated events. Residual: a live round-1 leader without a reconstruction forces a round change. Mitigations: later emission inside the window, unconditional in-slot emission where duplicate state does not suppress it, optional retention, and the mandatory testnet measurement above. +- Early reconstruction widens the third-party reaction window between reveal knowability and block publication from roughly 2-4 s to up to 25 s, enabling adaptive bribery, censorship, or targeted DoS when withholding the proposal favors an adversary (one randao bit per affected slot, compounding across slots). Bounded by the existing single-proposal grinding bound; narrowable operationally via later emission, without a protocol change. +- Optional retention exposes local memory and revalidation work to operator-authenticated candidates. Implementations that enable it are responsible for bounding local resource use and MAY scope retention to committees they participate in. Capacity, eviction, and persistence choices do not affect wire conformance. +- No unauthenticated retention amplification: messages failing operator-signature verification are never forwarded or retained. An operator-authenticated share whose BLS signature proves invalid at consumption is attributable and MUST be discarded without contributing to a reconstructed reveal. A signer emitting two distinct containers for one (signer, slot) is provably misbehaving and attributable via its operator signature. +- No slashing surface: the randao object is not slashable and is a pure function of public data; early signing changes when it is signed, not what.