feat(validator_store): sign builder request auth - #1282
Conversation
Bump the Lighthouse pin to the Gloas builder-API stack head (sigp/lighthouse#9807) and implement the one new required trait method, sign_request_auth_v1, as a distributed threshold signing round: kind 9 (RequestAuth) riding Role::ProposerPreferences under the fixed builder-specs sigp#165 application domain, with a slot-aware collection bound (future slots 2 slots, current slot 1s fail-fast, elapsed slots declined without broadcast). Wire the BuilderStore and RequestAuthCache the new BlockServiceBuilder requires at startup, decline elapsed-slot proposer-preferences signing after restarts, and migrate the one test broken by the pin (private attestation-due fields).
|
@claude, please take a look |
|
Claude finished @shane-moore's task in 3m 58s —— View job Review:
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## epbs #1282 +/- ##
=======================================
Coverage ? 78.67%
=======================================
Files ? 176
Lines ? 39430
Branches ? 0
=======================================
Hits ? 31020
Misses ? 8410
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
shane-moore
left a comment
There was a problem hiding this comment.
Reviewed at e4f1fea9.
I traced the request-auth domain and root, kind-9 and role-8 wire path, proposal-slot timing, collection mode, BuilderStore and RequestAuthCache wiring, and tests against the current builder spec, SIP-94, ssv-spec, go-ssv, and the pinned Lighthouse stack. I found no correctness, safety, or specification defect in the implementation.
Two follow-ups before this draft is ready:
check-fmtcurrently fails on the new doc comment aroundanchor/validator_store/src/lib.rs:1391.make cargo-fmtapplies the required reflow.- This pin range includes Lighthouse #9869, a lockfile-only update from
blst0.3.16 to 0.3.17 for the Pippenger divide-by-zero fixed in blst #283 and reproduced on a 96-core host. Anchor's downstream lock remains on 0.3.16, so the pin bump does not inherit that hardening. Please carry 0.3.17 during the final repin. I did not establish that a normal Anchor duty reaches the affected large-point branch, so I view this as dependency hardening, not a demonstrated duty-path bug.
The existing draft blocker on Lighthouse #9805 through #9807 landing and the pin being repointed remains valid. At this head, the local testnet and every completed code, test, MSRV, dependency, Docker, and CLI check pass except formatting; the aggregate suite skips because of that failure.
Reviewed by gpt-5.6-sol max.
Review follow-ups: apply the nightly rustfmt reflow check-fmt requires on the request_auth_collection_bound doc comment, and carry the blst 0.3.16 -> 0.3.17 lockfile hardening (Pippenger divide-by-zero, blst sigp#283) that Lighthouse #9869 took upstream but Anchor's lock did not inherit.
|
addressed both in d1a56cd: fmt reflow applied, blst carried to 0.3.17 now rather than at repin (full release suite green on the bump) |
Problem, Evidence, and Context
Anchor pins Lighthouse at
e58ec88fe, which predates the Gloas builder-API stack (sigp/lighthouse#9803/#9804 merged; #9805/#9806/#9807 open, stacked) implementing beacon-APIs #630. At the stack head,ValidatorStoregains exactly one new required method,sign_request_auth_v1, so the pin bump and the implementation must land as one PR to compile. The signing side is the next step of the milestone after #1281 shipped the kind-9 admission rules.Closes #1278. Plan and debate history live with the issue; the receive side is #1281; the config surface and service wiring follow in #1279/#1280.
Change Overview
builder_types/builder_storedeps. Measured migration fallout across the 55 upstream commits: one missing trait method and one test reading fields that Use Gloas timings for aggregate attestations and sync committee messages lighthouse#9823 privatized (rewritten against the public basis-point inputs, which also makes it strictly stronger: it now pins the fork-gate polarity).sign_request_auth_v1mirrorssign_proposer_preferences: resolve validator and cluster, root =request_auth.signing_root(spec.get_request_auth_domain())(fixed application domain, genesis fork version, zeroed genesis-validators-root; fork-epoch invariant, unlike kind 8's epoch-keyed domain), envelope slot = the proposal slot,CollectionMode::SingleValidator, failure classification and metrics siblings.sign_proposer_preferences: after a restart the kind-8 service re-signs every unpublished current-epoch duty including passed slots, each burning the full bound sequentially for an unreachable quorum.BlockServiceBuilder::build()at this pin fails at runtime without aBuilderStoreandRequestAuthCache, so both are constructed. The builder definitions file starts empty, but empty-at-creation is not a gate: an operator who populates<data_dir>/builder_definitions.ymland restarts activates the produce-time direct-builder flow on this branch alone, with an insert-onlyRequestAuthCache(its only prune caller arrives in feat(client): wire builder preferences service and produce-time builder config #1280). Deployment gate: feat(client): wire builder preferences service and produce-time builder config #1280 must merge with or immediately after this PR, and no image or soak may be built from an epbs head containing only this PR.Reading order:
validator_store/src/lib.rs(consts +RequestAuthCollectionBound+ the two sign paths), thenmetrics.rs, thenclient/src/lib.rsanddata_dir.rs(wiring), then the test modules.What did not change: the 23 previously implemented trait methods keep their signatures; kind-8 behavior for current and future slots is untouched; no slashing DB or doppelganger involvement (same class as validator registration); the Lighthouse
[patch.crates-io]mirror is byte-identical between the pins.Risks, Trade-offs, and Mitigations
produceBlockV4with aBuilderConfigin every request body and Eth-Builder-Url publish plumbing; PTC signing is now driven concurrently by the VC (tolerated by Anchor's per-root collectors); attestation/sync timings become fork-aware. Full-network validation of the POST path lands with the milestone's ssv-mini soak.builder_definitions.ymlpast the SSV cap would lose quorum for the excess roots. The startup fail-fast guard ships in feat(client): add builder definitions config for direct builder connections #1279, and this branch merges only after the full stack.RequestAuthCachehas no prune caller until feat(client): wire builder preferences service and produce-time builder config #1280; with the file unpopulated nothing inserts, and the deployment gate above covers the populated case. Merge/deploy order: this PR, then feat(client): wire builder preferences service and produce-time builder config #1280, then feat(client): add builder definitions config for direct builder connections #1279.Validation
cargo check --workspace --all-targets --locked: clean (this catches the test-target fallout a plain check misses).make test(release): 945 passed, 0 failed, including thessv-specfixture suite.testing/request_auth.rs(signing root with a fork-boundary falsifiability guard against regressing to the kind-8 domain, folded slashing-DB non-involvement; table-driven three-case timeout incl. decline with zero collector calls and zero metric delta; failure classification labels; independently derived known-answer signing-root vector with its derivation script in the comment) plus 1 intesting/proposer_preferences.rs(kind-8 elapsed-slot decline).make cargo-fmt-check,make lint,make sort: clean.Rollback
Revert the single commit: the branch is one commit on top of
epbs, no schema or config migration. The only on-disk artifact is an emptybuilder_definitions.ymlin the datadir, which older versions ignore.Blockers / Dependencies
RequestAuthPartialSig = 9in ssv-spec#632).epbs, so peers on the branch accept what this PR emits.