Skip to content

Commit 3178fda

Browse files
authored
fix missing attestations by using GossipSub for subnet peer coverage (#19523)
## Summary - Fix intermittent missing attestations caused by inaccurate subnet peer coverage calculation. The previous ENR-based approach counted peers that *claimed* to support subnets, while GossipSub mesh often had far fewer actual subscribers (e.g., ENR showed 3 peers but GossipSub only had 1). - Add proactive subnet peer search that runs every slot (12s) to find and connect peers for underserved subnets (< 4 peers). - Add subnet-aware peer pruning that avoids disconnecting peers covering critical subnets. - Allow subnet-useful peers past the peer limit in `onConnection` so proactive search results are not immediately rejected. ## Root Cause Attestations were published with only 1-2 peers on the GossipSub topic, causing them to not propagate. The Sentinel used ENR `attnets` to estimate subnet coverage, but ENR represents *capability* (what a peer claims to support), not *actual GossipSub subscriptions*. This led to the system believing it had sufficient peers when it didn't, skipping peer search for those subnets. ## Changes - **`cl/sentinel/discovery.go`**: Replace ENR-based `getSubnetCoverage()` with GossipSub `ListPeers()` for accurate coverage; add `proactiveSubnetPeerSearch()`, `findPeersForSubnets()`, `pruneExcessPeers()`; subnet-aware `onConnection` handler - **`cl/sentinel/sentinel.go`**: Store `*enode.Node` in `pidToEnr` (was `string`) for ENR data access in `onConnection` - **`cl/phase1/network/gossip/gossip_manager.go`**: Log peer count when publishing attestations; remove `MinTopicSize(1)` to avoid publish failures on empty topics - **`cl/beacon/handler/block_production.go`**: Add subnet info to "Produced Attestation" debug log https://beaconcha.in/validator/1667009#charts <img width="937" height="636" alt="截圖 2026-02-27 晚上7 48 54" src="https://github.com/user-attachments/assets/e435b9ac-3ee3-444f-a4c1-fb1891d381b7" />
1 parent 307b6ce commit 3178fda

File tree

6 files changed

+443
-14
lines changed

6 files changed

+443
-14
lines changed

cl/beacon/handler/block_production.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import (
4747
"github.com/erigontech/erigon/cl/gossip"
4848
"github.com/erigontech/erigon/cl/persistence/beacon_indicies"
4949
"github.com/erigontech/erigon/cl/phase1/core/state"
50+
"github.com/erigontech/erigon/cl/phase1/network/subnets"
5051
"github.com/erigontech/erigon/cl/transition"
5152
"github.com/erigontech/erigon/cl/transition/impl/eth2"
5253
"github.com/erigontech/erigon/cl/transition/machine"
@@ -143,8 +144,13 @@ func (a *ApiHandler) GetEthV1ValidatorAttestationData(
143144
}
144145

145146
defer func() {
147+
epoch := *slot / a.beaconChainCfg.SlotsPerEpoch
148+
committeesPerSlot := a.syncedData.CommitteeCount(epoch)
149+
subnet := subnets.ComputeSubnetForAttestation(
150+
committeesPerSlot, *slot, *committeeIndex,
151+
a.beaconChainCfg.SlotsPerEpoch, 64)
146152
a.logger.Debug("Produced Attestation", "slot", *slot,
147-
"committee_index", *committeeIndex, "cached", ok, "beacon_block_root",
153+
"committee_index", *committeeIndex, "subnet", subnet, "cached", ok, "beacon_block_root",
148154
attestationData.BeaconBlockRoot, "duration", time.Since(start))
149155
}()
150156

cl/p2p/mock_services/p2p_manager_mock.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cl/phase1/network/gossip/gossip_manager.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,18 @@ func (g *GossipManager) Publish(ctx context.Context, name string, data []byte) e
261261
if topicHandle == nil {
262262
return fmt.Errorf("topic not found: %s", topic)
263263
}
264+
// Log peer count for attestation topics to help diagnose propagation issues
265+
if gossip.IsTopicBeaconAttestation(name) {
266+
peerCount := len(g.p2p.Pubsub().ListPeers(topic))
267+
if peerCount == 0 {
268+
log.Warn("[Gossip] Publishing attestation with NO peers on subnet", "topic", name, "peerCount", peerCount)
269+
} else if peerCount < 3 {
270+
log.Debug("[Gossip] Publishing attestation with low peer count", "topic", name, "peerCount", peerCount)
271+
}
272+
}
264273
// Note: before publishing the message to the network, Publish() internally runs the validator function.
265-
return topicHandle.topic.Publish(ctx, compressedData, pubsub.WithReadiness(pubsub.MinTopicSize(1)))
274+
// Removed MinTopicSize(1) - don't fail if no peers on subnet, message will propagate when peers join
275+
return topicHandle.topic.Publish(ctx, compressedData)
266276
}
267277

268278
func (g *GossipManager) goCheckForkAndResubscribe(ctx context.Context) {

0 commit comments

Comments
 (0)