Issue Addressed
Follow-up to #806 — the unresolved part of comment-3857920948
(#806 (comment)).
On a closer look the gap is broader than that comment described, so
filing it end-to-end.
This is a research ticket for someone to confirm the gap, validate
feasibility, and either spin out a follow-up implementation issue/PR
or document why we shouldn't do it.
Background
Lighthouse 8.1.0 (sigp/lighthouse#7892)
introduced "earlier attestation broadcasting": the validator
client's AttestationService races a beacon-node SSE head event
against the 1/3-slot timer and calls sign_attestations on
whichever fires first. Anchor's Lighthouse pin (4b3a9d3) includes
this code, but on Anchor it's compiled in and dormant.
Gap
There are three coupled reasons eager attesting doesn't reach the
wire on Anchor today.
First, Anchor never opts into the LH head-monitor wiring. In
anchor/client/src/lib.rs, BeaconNodeFallback is constructed
without set_head_send(...) and AttestationServiceBuilder
without head_monitor_rx(...). Both default to None upstream,
which means the SSE polling task is never spawned and the
eager-attest race in validator_services/src/attestation_service.rs
short-circuits to its timer-only branch. PR #813 was a clean
dependency bump and didn't pick up the small wiring patch LH 8.1.0
added in its own VC binary.
Second, MetadataService's Phase 2 — the step that produces
VotingContext from a fresh attestation_data fetch — runs on a
fixed 1/3-slot timer in anchor/validator_store/src/metadata_service.rs.
There is no head-event subscription anywhere in the metadata service.
Third, the two are intertwined. Even if the LH side were wired,
Anchor's sign_committee_attestations in
anchor/validator_store/src/lib.rs blocks on get_voting_context(slot)
before any signing work, and that watch channel is filled only by
Phase 2 at t ≈ 4 s. Fixing the LH side alone, or the MetadataService
side alone, doesn't move attestation publishing earlier.
Target behaviour
The eager-attest path should be live end-to-end. On a head event at
t < 1/3 slot, the LH AttestationService should fire
sign_attestations early — which means activating the head monitor
in anchor/client/src/lib.rs (mirroring LH's own VC wiring), likely
behind a --disable-beacon-head-monitor flag matching LH 8.1.0. At
the same time, MetadataService Phase 2 should produce VotingContext
from the same head event (falling back to the existing 1/3-slot
timer if no event arrives), so the watch channel is ready when
sign_committee_attestations reaches get_voting_context. With
both in place, Anchor's QBFT consensus and signing begin immediately
on a head event instead of at t = 4 s.
The pattern to mirror lives in LH at
validator_services/src/attestation_service.rs:186-193.
Why it matters
Spec-compliant attestation timing is the benefit LH 8.1.0 already
delivers for solo stakers. On SSV, QBFT round-trips sit on top of
LH's signing path, so any pre-QBFT delay compounds — operator
inclusion-distance scores on ssv.network depend on early publishing.
References
Issue Addressed
Follow-up to #806 — the unresolved part of comment-3857920948
(#806 (comment)).
On a closer look the gap is broader than that comment described, so
filing it end-to-end.
This is a research ticket for someone to confirm the gap, validate
feasibility, and either spin out a follow-up implementation issue/PR
or document why we shouldn't do it.
Background
Lighthouse 8.1.0 (sigp/lighthouse#7892)
introduced "earlier attestation broadcasting": the validator
client's
AttestationServiceraces a beacon-node SSEheadeventagainst the 1/3-slot timer and calls
sign_attestationsonwhichever fires first. Anchor's Lighthouse pin (
4b3a9d3) includesthis code, but on Anchor it's compiled in and dormant.
Gap
There are three coupled reasons eager attesting doesn't reach the
wire on Anchor today.
First, Anchor never opts into the LH head-monitor wiring. In
anchor/client/src/lib.rs,BeaconNodeFallbackis constructedwithout
set_head_send(...)andAttestationServiceBuilderwithout
head_monitor_rx(...). Both default toNoneupstream,which means the SSE polling task is never spawned and the
eager-attest race in
validator_services/src/attestation_service.rsshort-circuits to its timer-only branch. PR #813 was a clean
dependency bump and didn't pick up the small wiring patch LH 8.1.0
added in its own VC binary.
Second, MetadataService's Phase 2 — the step that produces
VotingContextfrom a freshattestation_datafetch — runs on afixed 1/3-slot timer in
anchor/validator_store/src/metadata_service.rs.There is no head-event subscription anywhere in the metadata service.
Third, the two are intertwined. Even if the LH side were wired,
Anchor's
sign_committee_attestationsinanchor/validator_store/src/lib.rsblocks onget_voting_context(slot)before any signing work, and that watch channel is filled only by
Phase 2 at t ≈ 4 s. Fixing the LH side alone, or the MetadataService
side alone, doesn't move attestation publishing earlier.
Target behaviour
The eager-attest path should be live end-to-end. On a head event at
t < 1/3 slot, the LH
AttestationServiceshould firesign_attestationsearly — which means activating the head monitorin
anchor/client/src/lib.rs(mirroring LH's own VC wiring), likelybehind a
--disable-beacon-head-monitorflag matching LH 8.1.0. Atthe same time, MetadataService Phase 2 should produce
VotingContextfrom the same head event (falling back to the existing 1/3-slot
timer if no event arrives), so the watch channel is ready when
sign_committee_attestationsreachesget_voting_context. Withboth in place, Anchor's QBFT consensus and signing begin immediately
on a head event instead of at t = 4 s.
The pattern to mirror lives in LH at
validator_services/src/attestation_service.rs:186-193.Why it matters
Spec-compliant attestation timing is the benefit LH 8.1.0 already
delivers for solo stakers. On SSV, QBFT round-trips sit on top of
LH's signing path, so any pre-QBFT delay compounds — operator
inclusion-distance scores on ssv.network depend on early publishing.
References