Skip to content

feat(message_validator): admit batched builder request auth partial signatures - #1302

Merged
shane-moore merged 1 commit into
sigp:epbsfrom
shane-moore:feat/request-auth-batch-receive
Sep 22, 2026
Merged

shane-moore merged 1 commit into
sigp:epbsfrom
shane-moore:feat/request-auth-batch-receive

Conversation

@shane-moore

Copy link
Copy Markdown
Member

Problem, Evidence, and Context (Required)

  • SIP-94 §5/§7 currently require every RequestAuthPartialSig packet to carry exactly one entry. Matheus proposed relaxing this on the SIP thread so an operator can gossip all of its builder auth shares for a proposal slot in one bounded packet, with per-builder isolation enforced by the receiving runner instead of by packet shape: ePBS (EIP-7732) Support ssvlabs/SIPs#94 (comment)
  • ssv-spec already emits and admits such batches (types: ePBS (Gloas / SIP-94) reference implementation — WIP ssvlabs/ssv-spec#633). Old singleton-only receivers REJECT them, which penalizes the forwarding peer, so receive support has to propagate before any client emits batches.
  • This PR is the receive side only. It evaluates the proposed amendment; the SIP text has not been updated yet.

Change Overview (Required)

  • Message validation admits RequestAuth packets on Role::ProposerPreferences with 1 to 8 entries. Above 8 is a Reject, empty is still a Reject.
  • Every entry of such a packet must carry the same signer and validator index. A packet naming two validator indices is a new Reject-class failure, checked before the local-metadata membership check so it cannot be downgraded to an Ignore.
  • The per-kind distinct-signing-root budget is now set-based: a packet adding no new root is an Ignore, a packet whose new roots would overflow the budget is an Ignore that records nothing, and otherwise all of its new roots are recorded together. For single-entry packets this is exactly the previous behavior, so ProposerPreferences packets need no special case and there is still one enforcement site.
  • Read the diff as: one new error variant, one role arm split out of the one-entry rule, one budget site generalized from a root to a set.
  • Intentionally unchanged: ProposerPreferences packets stay at one entry, every other role's packet rules, the sender (Anchor still emits one singleton packet per auth root), the signature collector, duty counting, and state retention. Configured-root matching stays in local collection, which already requests specific roots; gossip validation does not filter on private builder configuration.

Risks, Trade-offs, and Mitigations (Required)

  • Blast radius is limited to RequestAuth packets on role 8. The risk is a classification slip (Accept/Ignore/Reject) or a budget slip on the batched path.
  • Trade-off: the raw entry bound and the distinct-root budget share one constant (8), the SIP §5 configured-entry cap. Repeated roots inside a packet count as raw entries but only once toward the budget.
  • Mitigation: the tests below pin every classification boundary, the exact budget fit, that an over-budget or forged packet records nothing, and that the preferences budget is untouched by a full auth batch.

Validation (Required)

  • cargo test -p message_validator: 161 passed (20 new). New tests cover singleton, two, and eight entry acceptance, empty and nine entry rejection, nine raw entries with repeated roots, two ProposerPreferences entries still rejected, inner signer drift and inner-vs-outer disagreement, mixed validator indices with metadata present, with an unknown index, and with empty local metadata, all-known versus mixed known/new packets, repeated in-packet roots counted once, exact budget fit, over-budget recording nothing, forged outer signature recording nothing, independent kind budgets, one duty slot for a batch plus a preferences packet, and the pre-Gloas fork gate.
  • cargo test -p signature_collector: 35 passed (1 new). The new test feeds three-entry auth packets for roots A, B, C from each remote operator and registers local collection for A and B only. Both reconstruct; C keeps a share-only collector and no local partial is published for it. This is the concrete case from the SIP thread: configuration agrees on A and B, differs on C, and C must not block A and B.
  • make cargo-fmt-check and make lint pass.

Rollback (Required for behavior or runtime changes; optional otherwise)

  • Revert the commit. No config, database, or wire-format impact. Reverting only restores the singleton-only rule, so it must not happen once any peer emits batches.

Blockers / Dependencies (Optional)

Additional Info / Next Steps (Optional)

  • Once feat(validator_store): sign builder request auth #1282 lands, an end-to-end check through sign_request_auth_v1 is worth adding: with local entries for A and B only, both resolve while peer packets also carry C; with a local C entry whose data differs, only that local root fails to reach threshold.

🤖 Generated with Claude Code

Allow a RequestAuth packet on Role::ProposerPreferences to carry 1 to 8
entries so a peer can gossip all of its builder auth shares for a
proposal slot at once, as proposed for SIP-94 §5/§7 and already emitted
by ssv-spec. Entries must share one signer and validator index; a packet
naming two validators is a new Reject-class failure checked before the
local-metadata membership rule. The distinct-root budget becomes
set-based so a packet is admitted or ignored whole and an over-budget
packet records nothing. Single-entry packets keep their exact previous
classification, ProposerPreferences packets stay at one entry, and the
sender still emits singletons.
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.24812% with 4 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (epbs@cc5c414). Learn more about missing BASE report.

Files with missing lines Patch % Lines
anchor/message_validator/src/partial_signature.rs 99.41% 3 Missing ⚠️
anchor/message_validator/src/duty_state.rs 94.11% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             epbs    #1302   +/-   ##
=======================================
  Coverage        ?   80.22%           
=======================================
  Files           ?      179           
  Lines           ?    40595           
  Branches        ?        0           
=======================================
  Hits            ?    32567           
  Misses          ?     8028           
  Partials        ?        0           
Flag Coverage Δ
rust 80.22% <99.24%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@shane-moore

Copy link
Copy Markdown
Member Author

Reviewed b54c2c9f. No blocking findings.

The receive-side change matches the current SIP-94 §5/§7 text: 1 to 8 auth entries, consistent signer and validator index, atomic distinct-root accounting, and independent preference/auth budgets. The collector test verifies that unmatched root C does not prevent A and B reconstructing.

Checked the hosted CI logs: 986 debug and 986 release tests passed on the merge with current epbs, with the reviewed source files unchanged. Current lint, formatting and audit checks also pass.

Two nonblocking notes: the PR description still says the SIP amendment is unwritten, but it is now in the linked text. Receiver support must also reach the whole network before batch sending is enabled; the current go-ssv ePBS branch still rejects multi-entry auth packets. This review establishes receive-side compliance, not mixed-client rollout readiness.

Reviewed by GPT-6 Astra on high

@shane-moore
shane-moore merged commit 8ea165f into sigp:epbs Sep 22, 2026
63 of 66 checks passed
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