Skip to content

p2p/sentry: fix shared PeerStore version filter in findBestPeers, findPeerByMinBlock, PeerEvents#21394

Merged
anacrolix merged 1 commit into
mainfrom
alex/p2p_shared_store_fixes
May 25, 2026
Merged

p2p/sentry: fix shared PeerStore version filter in findBestPeers, findPeerByMinBlock, PeerEvents#21394
anacrolix merged 1 commit into
mainfrom
alex/p2p_shared_store_fixes

Conversation

@AskAlexSharov

Copy link
Copy Markdown
Collaborator

Follow-up fixes for #21335 (merged).

Bugs fixed

With the shared PeerStore introduced in #21335, every GrpcServer can
see all peers regardless of which eth protocol version they negotiated.
Three rangePeers loops were missing the per-sentry version filter that
Peers() and SimplePeerCount() already apply correctly:

1. findBestPeersWithPermit / findPeerByMinBlock

Used by SendMessageByMinBlock to select target peers. Without the
filter, an eth/71 sentry could pick an eth/69 peer:

  • messageCode encodes the request with eth/71 wire codes.
  • writePeer sends it over the eth/69 peer's ethRw.
  • The remote eth/69 peer receives an unrecognised (or misinterpreted)
    code and disconnects.

Contrast: SendMessageToRandomPeers and SendMessageToAll already
filter with protocolVersions.Contains(peerInfo.EthProtocol()).

2. PeerEvents replay

The replay pass at the start of PeerEvents iterated the entire shared
store and emitted a Connect event for every peer. Subscribers for
eth/68 would receive Connect events for eth/69 and eth/71 peers.
Those peers never generate a Disconnect on the eth/68 sentry's
peersStreams, so the subscriber accumulates ghost peers that are never
cleaned up.

Fix

Apply the same two-condition guard already used by Peers() and
SimplePeerCount():

if pv := peerInfo.EthProtocol(); pv == 0 || pv != ss.ethVersion {
    return true
}

Tests

Three new tests added to sentry_grpc_server_test.go:

  • TestGrpcServer_FindBestPeersWithPermit_FiltersVersion
  • TestGrpcServer_FindPeerByMinBlock_FiltersVersion
  • TestGrpcServer_PeerEvents_ReplayFiltersByVersion

All existing tests pass. make lint clean ×2.

…findPeerByMinBlock, PeerEvents

With the shared PeerStore introduced in #21335, all GrpcServers see every
peer regardless of which eth protocol version they negotiated. Three
rangePeers loops were missing the per-sentry version filter that Peers()
and SimplePeerCount() already apply:

- findBestPeersWithPermit: used by SendMessageByMinBlock to pick target
  peers. Without the filter an eth/71 sentry could select an eth/69 peer,
  encode the request with eth/71 wire codes, and send it over the eth/69
  peer's rw — the remote peer would receive an unknown code and disconnect.

- findPeerByMinBlock: same path, single-peer variant.

- PeerEvents replay: emitted Connect events for every peer in the shared
  store, including peers owned by other-version sentries. Those peers
  never generate a Disconnect on this sentry's peersStreams, leaving the
  subscriber with ghost peers that are never cleaned up.

Fix: apply the same `pv == 0 || pv != ss.ethVersion` guard used by
Peers() and SimplePeerCount() to all three loops.

Three new tests cover the fixed behaviour.
@anacrolix anacrolix added this pull request to the merge queue May 25, 2026
Merged via the queue into main with commit b15bb0d May 25, 2026
71 checks passed
@anacrolix anacrolix deleted the alex/p2p_shared_store_fixes branch May 25, 2026 05:15
@AskAlexSharov AskAlexSharov changed the title [wip] p2p/sentry: fix shared PeerStore version filter in findBestPeers, findPeerByMinBlock, PeerEvents p2p/sentry: fix shared PeerStore version filter in findBestPeers, findPeerByMinBlock, PeerEvents May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants