mirror of
https://github.com/logos-messaging/logos-messaging-go.git
synced 2026-07-17 14:49:30 +00:00
fix(peermanager): prefer connected peers in selection
Filter/lightpush peer selection (Automatic -> SelectRandom, and the service-slot pubsub path) chose uniformly at random among all peers that support the protocol+pubsub topic, with no regard for connectedness. A light node that has learned many peers via discv5/peer-exchange — some of them stale/unreachable (e.g. torn-down nodes whose ENRs a bootstrap node still advertised) — would therefore keep picking dead peers, churning on failed dials and missing messages, even while a perfectly good already- connected service node (e.g. the static fleet node) was available. Add preferConnectedPeers: bias selection toward peers we are currently connected to, falling back to the full candidate set when none are connected (so behavior is unchanged when there is no connected candidate). Relates to status-im/status-go#7513. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d6d39395ac
commit
bca1267b39
@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"go.uber.org/zap"
|
||||
@ -91,6 +92,10 @@ func (pm *PeerManager) SelectRandom(criteria PeerSelectionCriteria) (peer.IDSlic
|
||||
filteredPeers = pm.host.Peerstore().(wps.WakuPeerstore).PeersByPubSubTopics(criteria.PubsubTopics, filteredPeers...)
|
||||
}
|
||||
|
||||
// Prefer peers we are already connected to, so we don't churn on dialing
|
||||
// stale/unreachable peers learned via discovery or peer-exchange.
|
||||
filteredPeers = pm.preferConnectedPeers(filteredPeers)
|
||||
|
||||
//Not passing excludePeers as filterPeers are already considering excluded ones.
|
||||
randomPeers, err := selectRandomPeers(filteredPeers, nil, min(criteria.MaxPeers, len(peerIDs)))
|
||||
if err != nil && len(peerIDs) == 0 {
|
||||
@ -121,6 +126,28 @@ func getRandom(filter PeerSet, count int, excludePeers PeerSet) (PeerSet, error)
|
||||
return selectedPeers, nil
|
||||
}
|
||||
|
||||
// preferConnectedPeers returns the subset of the given peers that we are
|
||||
// currently connected to. If none are connected it returns the input unchanged.
|
||||
//
|
||||
// This biases peer selection toward reachable peers (e.g. an already-connected
|
||||
// fleet/service node) instead of stale or unreachable peers learned via
|
||||
// discv5/peer-exchange. Without this, selection is connectedness-blind and a
|
||||
// light node can repeatedly pick dead peers for filter/lightpush, churning on
|
||||
// failed dials and missing messages while a perfectly good connected peer is
|
||||
// available (see status-im/status-go#7513).
|
||||
func (pm *PeerManager) preferConnectedPeers(peers peer.IDSlice) peer.IDSlice {
|
||||
connected := make(peer.IDSlice, 0, len(peers))
|
||||
for _, p := range peers {
|
||||
if pm.host.Network().Connectedness(p) == network.Connected {
|
||||
connected = append(connected, p)
|
||||
}
|
||||
}
|
||||
if len(connected) > 0 {
|
||||
return connected
|
||||
}
|
||||
return peers
|
||||
}
|
||||
|
||||
// selects count random peers from list of peers
|
||||
func selectRandomPeers(peers peer.IDSlice, excludePeers PeerSet, count int) (PeerSet, error) {
|
||||
filteredPeerMap := PeerSliceToMap(peers)
|
||||
@ -172,6 +199,8 @@ func (pm *PeerManager) selectServicePeer(criteria PeerSelectionCriteria) (PeerSe
|
||||
}
|
||||
slot.mu.RUnlock()
|
||||
selectedPeers := pm.host.Peerstore().(wps.WakuPeerstore).PeersByPubSubTopics(criteria.PubsubTopics, keys...)
|
||||
// Prefer already-connected service peers over stale/unreachable ones.
|
||||
selectedPeers = pm.preferConnectedPeers(selectedPeers)
|
||||
tmpPeers, err := selectRandomPeers(selectedPeers, criteria.ExcludePeers, criteria.MaxPeers)
|
||||
for tmpPeer := range tmpPeers {
|
||||
peers[tmpPeer] = struct{}{}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user