RequestAuth: new non-QBFT duty for builder auth signing (produceBlockV4 POST + BuilderPreferences) #99
shane-moore
started this conversation in
SIP Discussions
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Durable version of the 2026-07-09 HackMD plus everything settled since on Discord and the upstream PRs. Where they differ, this supersedes.
TLDR
Post-Gloas, the beacon node dials builders directly and needs a validator-key BLS signature (
SignedRequestAuthV1) to authenticate the validator's requests to each builder. That signature is the only part that touches the SSV protocol. Proposal: one new non-QBFT partial-signature duty (RequestAuth), ValidatorRegistration-shaped, one signature per(validator, proposal_slot, builder), signed at duty-discovery time (proposer lookahead gives an epoch-plus of warning), reconstructed and cached, submitted ahead of the slot via #630'ssubmitBuilderPreferences(JIT signing during the produce call stays possible as fallback). Plus cluster-level builder config that must be byte-identical across operators. Nothing protocol-breaking; failure blast radius is yield-only, never liveness.The signed object is
RequestAuthV1 = { data: ByteList[4096], slot }underDOMAIN_REQUEST_AUTH(builder-specs #138 + #165):data= opaque bytes pre-agreed with the builder (default: its URL), signed exactly as serialized, no normalization; routing URL stays unsigned;slot= proposal slot; no pubkey in the message. Deterministic from shared state, which is what makes independent construction by N operators work.Design decisions (from the Discord + PR threads)
Why not QBFT over the builder list? No sound value-check exists: validating the leader's list against local config means divergent configs decide nothing; accepting anything lets a rogue leader direct the cluster's signed auths. A builder list is static config; divergence is a misconfiguration to alert on, not something to consense over. SIP-94 already ships ProposerPreferences non-QBFT under the same reasoning.
Why a new duty instead of proposer pre-consensus? (@GalRogozinski's question) Proposer pre-consensus runs at the proposal-slot tick (ssv-spec#373 is unimplemented), which puts signing inside the ~3s produce window. And mechanically: pre-consensus container validation is all-or-nothing (
verifyExpectedRoot), so adding config-dependent auth roots to the RANDAO container means one divergent builder list rejects the whole container, RANDAO included; a 2-2 config split misses the block. Separate duty = isolated failure domain: divergence costs only the auth.Why not bundle with RANDAO in one container? (Iurii's idea) Same all-or-nothing coupling, plus cardinality/lifecycle mismatch (RANDAO: one config-independent root per epoch; auth: N config-dependent roots per proposal slot). The p2p saving is negligible at proposal-slot frequency. But the good part stands: same trigger (duty discovery), same fork-gated earliness mechanism (SIP-94 §7), separate messages. Early RANDAO pre-signing rides that same mechanism and is proposed separately.
Container shape and divergence. One
PartialSignatureMessagescontainer per proposal slot, one message per builder (mirrors the API: oneSignedRequestAuthV1per builder entry), stock strict validation, no carve-outs. Config is required-identical, so roots never legitimately diverge. Known trade-off: a rolling config change or typo loses all builder auths for that window (yield-only); if that ever matters, per-root acceptance a la the AggregatorCommittee runner is available as a policy choice.Upstream outcomes (all SSV asks resolved)
DOMAIN_REQUEST_AUTH = 0x0B000001datasemanticsdatacheck (confirmed)RequestAuthV1.slotOpen items
PartialSigMsgType+ runner; SIP-94 §7 earliness row; dedup for mid-epoch builder-list re-emission.databytes per builder) + reconstruction-failure alerting.All reactions