From 7348524430ab2af7ccdcf38bfe76461b476337a5 Mon Sep 17 00:00:00 2001 From: tv Date: Sun, 1 Nov 2026 13:20:08 +0100 Subject: libp2p: revise published address count/selection --- src/transport/identity.rs | 5 +++-- src/transport/libp2p/book.rs | 4 ++-- src/transport/libp2p/mod.rs | 15 ++++++++++++--- src/transport/paths.rs | 21 +++++++++++++++++---- 4 files changed, 34 insertions(+), 11 deletions(-) (limited to 'src/transport') diff --git a/src/transport/identity.rs b/src/transport/identity.rs index a748505..fb1600b 100644 --- a/src/transport/identity.rs +++ b/src/transport/identity.rs @@ -58,8 +58,9 @@ const ASK_INTERVAL: Duration = Duration::from_secs(5); const OTHER_PATHS_ASK_INTERVAL: Duration = Duration::from_secs(60); /// How long resolving a seed waits for its ME. const RESOLVE_TIMEOUT: Duration = Duration::from_secs(10); -/// Addresses kept per node from hints: about one per transport. -const MAX_HINTS: usize = 8; +/// Addresses kept per node from hints: as many as a member lists +/// (`members::MAX_ADDRESSES`). +const MAX_HINTS: usize = 16; /// Addresses with a proven node, nodes with hints, and addresses asked, each at most: /// anyone can send us proofs (keys are free), so the books are bounded. const MAX_ENTRIES: usize = 4096; diff --git a/src/transport/libp2p/book.rs b/src/transport/libp2p/book.rs index b2ce7bb..02a6b49 100644 --- a/src/transport/libp2p/book.rs +++ b/src/transport/libp2p/book.rs @@ -267,8 +267,8 @@ impl Book { let address = without_peer(address.clone()); (!address.is_empty() && !is_relayed(&address)).then_some(address) }); - // First: the member list keeps only so many (`members::MAX_ADDRESSES`), and a - // node listening everywhere has many. + // First: only so many are published (`PUBLISHED_DIRECT`), and a node listening + // everywhere has many. let mut first: Vec = Vec::new(); for address in self.mapped.iter().cloned().chain(confirmed) { if !first.contains(&address) { diff --git a/src/transport/libp2p/mod.rs b/src/transport/libp2p/mod.rs index 6032891..2ad07e5 100644 --- a/src/transport/libp2p/mod.rs +++ b/src/transport/libp2p/mod.rs @@ -145,6 +145,11 @@ const MIN_RATE: u64 = 1 << 20; const READS: usize = 32; /// Addresses kept per peer, and peers with addresses at most. const ADDRESSES_PER_PEER: usize = 8; +/// Of this node's own, the direct ones (the best first) and those through relays it +/// publishes at most (`local_addresses`): a node listening everywhere has many direct +/// ones, and those through a relay are what reaches it from behind a NAT. +const PUBLISHED_DIRECT: usize = 4; +const PUBLISHED_RELAYED: usize = 2; const MAX_PEERS: usize = 4096; /// A relayed connection (circuit) through this node lasts at most this long and carries @@ -363,20 +368,24 @@ impl Transport for Libp2pTransport { } /// Where we can be reached, each with our peer ID: the announced addresses, or else - /// those we listen on (`published`), and those through relays. A relay adds each - /// direct one again, ending in `/p2p-circuit`: where to reserve a slot. + /// those we listen on (`published`), and those through relays; at most + /// `PUBLISHED_DIRECT` and `PUBLISHED_RELAYED` of them, so the direct ones never + /// crowd out the relayed ones. A relay adds each direct one again, ending in + /// `/p2p-circuit`: where to reserve a slot. fn local_addresses(&self) -> Vec { let book = lock(&self.book); let direct: Vec = book .direct() .into_iter() .filter_map(|address| address.with_p2p(self.peer_id).ok()) + .take(PUBLISHED_DIRECT) .collect(); let relayed = book .listening .iter() .filter(|address| is_relayed(address)) - .filter_map(|address| address.clone().with_p2p(self.peer_id).ok()); + .filter_map(|address| address.clone().with_p2p(self.peer_id).ok()) + .take(PUBLISHED_RELAYED); let offers: Vec = if book.serving { direct .iter() diff --git a/src/transport/paths.rs b/src/transport/paths.rs index 658f681..ce19fd4 100644 --- a/src/transport/paths.rs +++ b/src/transport/paths.rs @@ -620,17 +620,30 @@ impl Paths { .unwrap_or_default() } - /// Each transport's (`Transport::local_addresses`), with its scheme. + /// Each transport's (`Transport::local_addresses`), with its scheme: taken in turns, + /// each transport's first in the configured order, then each one's second, and so on, + /// so a list cut short (`members::MAX_ADDRESSES`) still has every transport's best. pub(crate) fn local_addresses(&self) -> Vec { - self.links + let mut each: Vec> = self + .links .iter() - .flat_map(|link| { + .map(|link| { link.inner .local_addresses() .into_iter() .map(|target| link.address(&target)) + .collect::>() + .into_iter() }) - .collect() + .collect(); + let mut addresses = Vec::new(); + loop { + let before = addresses.len(); + addresses.extend(each.iter_mut().filter_map(Iterator::next)); + if addresses.len() == before { + return addresses; + } + } } /// The schemes of the transports, in order of preference. -- cgit v1.3.1