feat(validator_store): implement sign_payload_attestation - #1082
Conversation
…dator partial-sig) Replace the Unsupported stub with a SingleValidator partial-signature collection over the PayloadAttestationData Lighthouse passes in, signed under Domain::PTCAttester. No beacon node fetch, no slashing protection, no QBFT: LH fetches the data at the 75% slot cutoff and abstains on no-block, and payload attestations carry no slashable offense. Collection failures are classified for telemetry before the error is surfaced: no-threshold misses (QueueClosedError via collector eviction) warn and increment anchor_ptc_reconstruction_failures_total with reason=no_signature, an upper bound on PTC observation divergence; local faults count as reason=infra. LH crit-logs the returned error either way, so the metric is the measurement channel. Addresses sigp#1077
|
@claude, please take a look |
|
Claude finished @shane-moore's task in 7m 42s —— View job Review of PR #1082 —
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## epbs #1082 +/- ##
=======================================
Coverage ? 62.89%
=======================================
Files ? 157
Lines ? 26787
Branches ? 0
=======================================
Hits ? 16848
Misses ? 9939
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:
|
Review feedback on sigp#1082: the Infra classification arm was uncovered, and an infra CollectionError variant drifting into the no_signature bucket would silently inflate the SIP-94 divergence upper bound. The new test injects EmptySignature and asserts the infra label increments while no_signature stays at zero delta. The two metric tests now serialize via a shared tokio mutex: the zero-delta read crosses a label the other test writes, so the prior sole-writer-per-label safety argument no longer held.
|
@claude, went through each review item: 1 (Infra arm coverage): Added 2 (double index resolution): Leaving as is. Resolving 3 ( 4 (metric delta race): Resolved alongside item 1. The new zero-delta read crosses a label the existing test writes, so the sole-writer argument no longer held; both metric tests now serialize via a shared lock, which also closes the symmetric race on the existing delta assertion. 5 (description vs behavior): Description updated. Behavior is per #1077's spec (non-collection errors from |
|
Claude finished @shane-moore's task in 1m 18s —— View job Follow-up reviewThanks — verified the responses against the diff and updated description.
No further requests. LGTM modulo the usual CI confirmation of |
jnhsigmap
left a comment
There was a problem hiding this comment.
The observation divergence property looks like it's going to occur more frequently than what could be considered 'exceptional' as it looks more like 1. an artefact of Lighthouse's architecture and 2. an artefact of how the network behaves. The scope of this PR is just to ensure metrics attempt to capture? is this something we can try to resolve in Lighthouse?
Merge Queue Status
This pull request spent 20 minutes 45 seconds in the queue, including 18 minutes 18 seconds running CI. Required conditions to merge
|
|
agreed it won't be exceptional, but that's the expected design, not a defect: On "resolve in LH": no. It isn't an LH bug (any client observes independently), and the only LH-touchable part is the The one real follow-up is Anchor-side and measurement-only, tracked in #1079 (research): make |
Wire Lighthouse's PayloadAttestationService into client startup so locally assigned validators sign and publish PTC payload attestations. Gate the start on spec.is_gloas_scheduled() to mirror LH's validator client and avoid a perpetual idle task on networks where Gloas is not scheduled. PTC duties are already populated by the Gloas-gated poll_beacon_ptc_attesters inside the existing duties service, and sign_payload_attestation landed in sigp#1082, so this is the final wiring step. Closes sigp#1078
…ions epbs (sigp#1082/sigp#1103/sigp#1128) added `spec` and `forced_gloas_index` to the shared test HarnessOptions. Append `..Default::default()` to the two ProposerPreferences failure-test constructions, matching the sibling payload_attestation tests, so the suite compiles on the rebased base. Part of sigp#1063.
Problem, Evidence, and Context
Under Gloas/ePBS, PTC validators must sign payload attestations (SSV-side section 3 of SIP-94). Lighthouse's
PayloadAttestationServicecallssign_payload_attestation(pubkey, data)per validator, but Anchor's implementation is anUnsupportedstub, so the duty cannot run. Both dependencies are merged toepbs: #1076 (PTC value object removal) and #1080 (Role::PTCAttester+PartialSignatureKind::PTCAttester).Addresses #1077.
Change Overview
The method runs a SingleValidator partial-signature collection over the
PayloadAttestationDataLH passes in, signed underDomain::PTCAttester, mirroring the voluntary-exit flow (the one merged SingleValidator single-signature precedent). LH fetches the data once at the 75% slot cutoff and abstains on no-block, so the method only signs what it is handed.Collection failures are classified for telemetry before the error is surfaced, because LH crit-logs whatever we return and the trait has no abstain path: a no-threshold miss (surfacing as
QueueClosedErrorvia collector eviction) warns and incrementsanchor_ptc_reconstruction_failures_total{reason="no_signature"}; local faults count asreason="infra". Errors from the method's own validator/cluster/index resolution propagate untouched; non-collection errors raised insidecollect_signature(share lookup, key decryption, threshold arithmetic) are error-logged for context but emit no metric.Suggested reading order:
lib.rs:sign_payload_attestation(the duty) andreport_ptc_collection_failure(the effects)instrumentation.rs: pure failure classifier, next to the existingfailure_reasonmappermetrics.rs: the new countertesting/: harness extensions (failure injection, slashing flag, richer call capture) and the 5 new testsIntentionally unchanged:
PayloadAttestationServicespawning (feat(client): spawn LH PayloadAttestationService with AnchorValidatorStore backend #1078)signature_collectorchanges; at current collector granularity a no-threshold miss and a genuine channel close are bothQueueClosedError, soreason="no_signature"is an upper bound on true observation divergence. Clean measurement needs a collector change (separate follow-up issue).is_syncedgating: LH only schedules duties when synced. Flagging for reviewer confirmation.Risks, Trade-offs, and Mitigations
collect_signatureshared by all duties, not introduced here.crit!; unavoidable Anchor-side given the trait shape. The metric, not the log, is the measurement channel.Validation
cargo test -p anchor_validator_store: 44 passed (5 new). The new tests lock:Domain::PTCAttesterchoice, epoch derivation, and signed object), plus kind/role/slot wiring into the collectorMissingIndexfails before any collection attemptQueueClosedErrorreturns the original error and increments{reason="no_signature"}EmptySignatureincrements{reason="infra"}and leaves{reason="no_signature"}at zero delta, pinning that infra faults cannot leak into the divergence bucketmake cargo-fmtandmake lintclean.Rollback
Revert the commit; the method returns to the
Unsupportedstub. No config, data, or operational impact (no caller yet; the metric simply disappears).Blockers / Dependencies
None for merge. Follow-ups: #1078 (spawn the LH service) and a research issue for clean divergence measurement in
signature_collector.