Skip to content

bug(core): signing-domain resolution performs live, uncached BN config fetches on every duty-critical operation #563

Description

@iamquang95

Summary

Every signature verification resolves the eth2 signing domain by fetching BN config endpoints
at call time, with no caching: an attester partial-sig verification costs 4 sequential HTTP
calls
(spec ×2 + genesis + fork_schedule — crates/eth2util/src/signing.rs:105-117,
crates/eth2api/src/extensions.rs:287,352,411); the aggregator fetch path adds another spec lookup.

On a non-local BN link this eats the 4s duty budget, and a single stalled request fails the
operation. Worse, the failure is misreported as a signature failure — the VC gets HTTP 400
partial signature verification failed when no signature was ever checked.

Charon has the same call shape but its go-eth2-client fork caches
Spec /
Genesis /
ForkSchedule
— on identical infra (BN behind a ~670ms tunnel), charon ran a clean 14-epoch hoodi window while
pluto missed 3/14.

Evidence (hoodi, 2026-07-22/23, 2×pluto+2×charon, validator 1454246)

Transport failures confirmed live in three verification paths (sigagg 4×, parsigex external store
2×, vapi 400 1×); likely contributed to ≥1 attester miss and to aggregator starvation (2/22
aggregator duties succeeded; direct log: fetch aggregator data → GetSpec(… operation timed out)).

ERROR … pluto_core::sigagg: verify failed error=aggregate signature verification failed:
  Request error: error sending request for url (…/eth/v1/beacon/genesis)
lodestar VC: submitPoolAttestationsV2 failed with status 400: partial signature verification failed

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions