Skip to content

Add early RANDAO pre-consensus emission SIP - #101

Open
shane-moore wants to merge 14 commits into
ssvlabs:mainfrom
shane-moore:feat/early-randao-preconsensus
Open

Add early RANDAO pre-consensus emission SIP#101
shane-moore wants to merge 14 commits into
ssvlabs:mainfrom
shane-moore:feat/early-randao-preconsensus

Conversation

@shane-moore

Copy link
Copy Markdown
Collaborator

Operators may emit the existing Proposer-duty RANDAO partial signature up to 2 slots before the proposal slot, so clusters reconstruct 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; changes are confined to message-validation timing rules plus a bounded receive-side buffer. Activates at the Gloas-aligned SSV fork.

Rationale and design discussion: #100
Addresses: ssvlabs/ssv-spec#373

iurii-ssv
iurii-ssv previously approved these changes Jul 24, 2026

@iurii-ssv iurii-ssv left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM overall, the suggestions below are mostly minor clarifications.

Comment thread sips/early_randao_preconsensus.md Outdated
Comment thread sips/early_randao_preconsensus.md Outdated
Comment thread sips/early_randao_preconsensus.md Outdated
Comment thread sips/early_randao_preconsensus.md Outdated
Comment thread sips/early_randao_preconsensus.md
iurii-ssv
iurii-ssv previously approved these changes Jul 25, 2026

@iurii-ssv iurii-ssv left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just two non-blocking nits.

Comment thread sips/early_randao_preconsensus.md Outdated
Comment thread sips/early_randao_preconsensus.md Outdated
iurii-ssv
iurii-ssv previously approved these changes Jul 27, 2026

@iurii-ssv iurii-ssv left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Found while implementing the receiver rules in Anchor: existing client
pipelines run contextual checks before signature verification, and a strict
signatures-first order would drop the duplicate-count shield in front of RSA.
Structural and canonical-form checks now run first and define the Early
RANDAO candidate; for candidates the signature-vs-contextual order is
implementation-defined, short-circuiting only on non-retaining verdicts, and
any outcome that retains, accepts, forwards, or mutates state requires a
valid operator signature (invalid signature plus Unknown duty is a pinned
REJECT). Checks are staged: RSA gates retention and forwarding, BLS gates
consumption. Vectors added for the pinned and flexible cases.
Pins receiver-divergence points found while mapping the rules onto Anchor's
duty tracker and quarantine design. Known now requires the epoch's complete
fetched proposer schedule (a locally filtered subset is not Known, so an
honest share cannot be IGNOREd as Known-unassigned by a partial view).
Retention is admission-conditioned rather than unconditional; the
byte-identical occupied-key case keeps the original entry, full-capacity
eviction has the incoming candidate compete under an exact total order (the
unreachable fourth tiebreak is dropped), and promotion is restated via
promotion candidates so an entry cannot both promote and fail revalidation.
Vectors added for each case.
The summary said the SIP activates at the Gloas-aligned SSV fork, but the
ePBS SIP (ssvlabs#94, checked at d5197bc) defines no SSV-network fork; its
validation rules gate on epoch(msg.slot) >= GLOAS_FORK_EPOCH. This SIP now
matches that model explicitly: activation is Ethereum-gated by the
epoch(S) >= GLOAS_FORK_EPOCH conjunct, the SSV fork-equality conjunct is
window-boundary protection only (it keeps the 2-slot emission window from
spanning any scheduled SSV fork), and a new S >= EARLY_RANDAO_LEAD conjunct
resolves the genesis underflow normatively, surfaced by the slot-zero unit
test in the Anchor implementation. Vectors spell out the boundary outcomes.
@shane-moore

shane-moore commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator Author

Pushed some commits tightening the validation contract, from some findings while implementing the receiver rules in anchor:

  1. 0affc08 Pin validation ordering and stage authentication checks. The previous text required signatures strictly before the contextual rules. Anchor's pipeline (and, from our reading, go-ssv's) runs the cheap contextual checks first, and reordering would cost the duplicate-count shield in front of RSA verification. Now: structural and canonical-form checks MUST run first and define an "Early RANDAO candidate"; for candidates the signature-vs-contextual order is implementation-defined, short-circuiting only on non-retaining verdicts; any outcome that retains, accepts, forwards, or mutates state MUST first pass operator-signature verification (invalid signature plus Unknown duty is a pinned REJECT, never retained). Staging is explicit: RSA gates retention and forwarding, BLS gates consumption.

  2. 60d143e Make duty-view and retention behavior deterministic. Pins points where two conformant receivers could diverge: Known requires the epoch's complete fetched proposer schedule (Anchor's duty tracker holds a locally filtered subset, which must not count as Known); retention is admission-conditioned; a byte-identical occupied-key duplicate keeps the original entry; full-capacity eviction has the incoming candidate compete under an exact total order; promotion is restated via promotion candidates (revalidate, promote only on success).

Test vectors added for each change.

The predicate required the SSV fork at S - EARLY_RANDAO_LEAD to equal the SSV
fork at S, making the first two slots of every SSV fork activation epoch
ineligible. It protects against nothing. Every fork-sensitive artifact of a
partial signature (gossip topic, domain, role gating) is derived from the
message's stamped slot rather than from emission time, so a message emitted
inside a window that spans a fork activation is published, validated, and
consumed entirely under the fork active at S. The SIP already relied on this
for the Ethereum boundary, where the first slot of GLOAS_FORK_EPOCH is
eligible and its window starts pre-fork; forbidding the same thing for SSV
forks was inconsistent.

Eligibility is now S >= EARLY_RANDAO_LEAD and epoch(S) >= GLOAS_FORK_EPOCH,
a pure function of the slot and the Ethereum fork schedule.
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.

2 participants