ChainSafe / ChainSafe/lodestar
getPoolAttestationsV2 omits unaggregated attestations — only exposes aggregatedAttestationPool
- Dominant language
- TypeScript
- Stars
- 1.4k
- Forks
- 483
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 150
Description
Spun out from #9669 (per @markolazic01's [suggestion](https://github.com/ChainSafe/lodestar/issues/9669#issuecomment-5008095649)) so it isn't overlooked when the 500-vs-empty-array fix there lands.
## Summary
`GET /eth/v2/beacon/pool/attestations` only exposes `chain.aggregatedAttestationPool`, never `chain.attestationPool`. Aggregates are populated from `beacon_aggregate_and_proof` gossip at ~2/3 into the slot (~8s), so the endpoint reports an empty list for the first ~8s of every slot — even for slots the node has already seen unaggregated attestations for.
## Detail
The spec describes the endpoint as *"Retrieves attestations known by the node but not necessarily incorporated into any block."*
- The GET handler reads only the aggregated pool: `chain.aggregatedAttestationPool.getAll(slot)` — `packages/beacon-node/src/api/impl/beacon/pool/index.ts:41`.
- Unaggregated attestations arriving on `beacon_attestation_{subnet}` at ~4s go to a separate pool, `chain.attestationPool` (`chain/interface.ts:122`), which has its own `getAll(bySlot)` (`chain/opPools/attestationPool.ts:200`) that the API never calls.
- That pool is itself gated on `aggregatorTracker.shouldAggregate(subnet, slot)` before insert — on the gossip path (`network/processor/gossipHandlers.ts:1343`) and on the API submit path (`api/impl/beacon/pool/index.ts:102`). So it is a pre-aggregation buffer, not a general "everything the node has seen" pool.
## Consequence
Fixing the 500 in #9669 removes the error, but the endpoint still returns `data: []` for the first ~8s of every slot. This is the underlying reason the Vouch hot-standby use case described in #9669 fails — its primary-detection check at +5s lands inside the empty window — rather than the 500 itself.
## Decision needed
Whether returning only aggregated attestations matches the intended semantics of *"attestations known by the node"*. If not, options include surfacing `chain.attestationPool` alongside the aggregated pool and/or documenting the aggregated-only behavior explicitly.
Note: because of the `shouldAggregate` gating, even exposing `attestationPool` would surface only attestations in subnets the node is aggregating for that slot — not *every* seen attestation — so fully satisfying "known by the node" may need a broader buffer. Worth settling the intended contract first.
Related: #9669 (the 500-vs-empty-array bug this was split from).
🤖 Generated with AI assistance
Contributor guide
Research direction
Read packages/beacon-node/src/api/impl/beacon/pool/index.ts, chain/interface.ts, chain/opPools/attestationPool.ts, and network/processor/gossipHandlers.ts to trace the endpoint and pool behavior. Review related issue #9669 and settle the intended contract for “attestations known by the node.” Done means the chosen behavior is implemented or the aggregated-only behavior is explicitly documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100