From 6e5cca0292c6be797bea4dea0a074504c90a3608 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Wed, 7 Oct 2026 10:49:54 +0300 Subject: [PATCH 1/4] kad: Add `global_addresses_only` option --- src/protocol/libp2p/kademlia/config.rs | 22 +++++ src/protocol/libp2p/kademlia/message.rs | 81 ++++++++++++++++++ src/protocol/libp2p/kademlia/mod.rs | 107 +++++++++++++++++++++++- src/protocol/libp2p/kademlia/types.rs | 7 +- src/transport/manager/address.rs | 2 +- 5 files changed, 214 insertions(+), 5 deletions(-) diff --git a/src/protocol/libp2p/kademlia/config.rs b/src/protocol/libp2p/kademlia/config.rs index a6827b253..324feb1bb 100644 --- a/src/protocol/libp2p/kademlia/config.rs +++ b/src/protocol/libp2p/kademlia/config.rs @@ -102,6 +102,9 @@ pub struct Config { /// Default record TTL. pub(super) record_ttl: Duration, + /// Drop non-global addresses received from remote peers. + pub(super) global_addresses_only: bool, + /// Provider record TTL. pub(super) memory_store_config: MemoryStoreConfig, @@ -134,6 +137,7 @@ impl Config { mode: KademliaMode, validation_mode: IncomingRecordValidationMode, record_ttl: Duration, + global_addresses_only: bool, memory_store_config: MemoryStoreConfig, max_message_size: usize, ) -> (Self, KademliaHandle) { @@ -153,6 +157,7 @@ impl Config { mode, validation_mode, record_ttl, + global_addresses_only, memory_store_config, codec: ProtocolCodec::UnsignedVarint(Some(max_message_size)), replication_factor, @@ -175,6 +180,7 @@ impl Config { KademliaMode::Server, IncomingRecordValidationMode::Automatic, DEFAULT_TTL, + false, Default::default(), DEFAULT_MAX_MESSAGE_SIZE, ) @@ -205,6 +211,9 @@ pub struct ConfigBuilder { /// Default TTL for the records. pub(super) record_ttl: Duration, + /// Drop non-global addresses received from remote peers. + pub(super) global_addresses_only: bool, + /// Memory store configuration. pub(super) memory_store_config: MemoryStoreConfig, @@ -229,6 +238,7 @@ impl ConfigBuilder { mode: KademliaMode::Server, validation_mode: IncomingRecordValidationMode::Automatic, record_ttl: DEFAULT_TTL, + global_addresses_only: false, memory_store_config: Default::default(), max_message_size: DEFAULT_MAX_MESSAGE_SIZE, } @@ -294,6 +304,17 @@ impl ConfigBuilder { self } + /// Drop non-global IP addresses of peers and providers received from remote peers, so + /// Kademlia neither dials nor stores them. Peers left without addresses are not used as + /// query candidates. DNS addresses are kept. + /// + /// Locally supplied addresses (known peers, [`KademliaHandle::add_known_peer`]) are not + /// affected. Disabled by default. + pub fn with_global_addresses_only(mut self, global_addresses_only: bool) -> Self { + self.global_addresses_only = global_addresses_only; + self + } + /// Set maximum number of records in the memory store. /// /// If unspecified, the default maximum number of records is 1024. @@ -372,6 +393,7 @@ impl ConfigBuilder { self.mode, self.validation_mode, self.record_ttl, + self.global_addresses_only, self.memory_store_config, self.max_message_size, ) diff --git a/src/protocol/libp2p/kademlia/message.rs b/src/protocol/libp2p/kademlia/message.rs index ad1b4d546..60a472e32 100644 --- a/src/protocol/libp2p/kademlia/message.rs +++ b/src/protocol/libp2p/kademlia/message.rs @@ -357,6 +357,36 @@ impl KademliaMessage { } } } + + /// Remove non-global addresses of the peers carried in the message. + /// + /// Closer peers left without addresses are dropped, as they are unreachable. Providers are + /// kept: the provider identity is the payload and can be resolved with `FIND_NODE`. + pub fn retain_global_addresses(&mut self) { + fn retain_closer_peers(peers: &mut Vec) { + peers.retain_mut(|peer| { + if peer.address_store.is_empty() { + return true; + } + peer.retain_global_addresses(); + !peer.address_store.is_empty() + }); + } + + match self { + Self::FindNode { peers, .. } | Self::GetRecord { peers, .. } => + retain_closer_peers(peers), + Self::GetProviders { + peers, providers, .. + } => { + retain_closer_peers(peers); + providers.iter_mut().for_each(KademliaPeer::retain_global_addresses); + } + Self::AddProvider { providers, .. } => + providers.iter_mut().for_each(KademliaPeer::retain_global_addresses), + Self::PutValue { .. } => {} + } + } } fn record_to_schema(record: Record) -> schema::kademlia::Record { @@ -399,6 +429,7 @@ fn record_from_schema(record: schema::kademlia::Record) -> Option { #[cfg(test)] mod tests { use super::*; + use multiaddr::Multiaddr; #[test] fn non_empty_publisher_and_ttl_are_preserved() { @@ -436,4 +467,54 @@ mod tests { assert_eq!(got_record, record); } + + #[test] + fn retain_global_addresses() { + let peer = |addresses: &[&str]| { + KademliaPeer::new( + PeerId::random(), + addresses.iter().map(|address| address.parse().unwrap()).collect(), + ConnectionType::NotConnected, + ) + }; + let private_only = peer(&["/ip4/10.0.0.1/tcp/30333", "/ip6/fd00::1/tcp/30333"]); + let mixed = peer(&["/ip4/192.168.1.1/tcp/30333", "/ip4/8.8.8.8/tcp/30333"]); + let dns = peer(&["/dns/example.com/tcp/30333"]); + let no_addresses = peer(&[]); + + let mut message = KademliaMessage::GetProviders { + key: None, + peers: vec![ + private_only.clone(), + mixed.clone(), + dns.clone(), + no_addresses.clone(), + ], + providers: vec![private_only.clone(), mixed.clone()], + }; + message.retain_global_addresses(); + + let KademliaMessage::GetProviders { + peers, providers, .. + } = message + else { + panic!("message type changed"); + }; + + // Closer peers left without addresses are dropped. + assert_eq!( + peers.iter().map(|peer| peer.peer).collect::>(), + vec![mixed.peer, dns.peer, no_addresses.peer], + ); + assert_eq!( + peers[0].addresses(), + vec!["/ip4/8.8.8.8/tcp/30333".parse::().unwrap()], + ); + assert_eq!(peers[1].addresses(), dns.addresses()); + + // Providers are kept even if left without addresses. + assert_eq!(providers[0].peer, private_only.peer); + assert!(providers[0].addresses().is_empty()); + assert_eq!(providers[1].addresses(), peers[0].addresses()); + } } diff --git a/src/protocol/libp2p/kademlia/mod.rs b/src/protocol/libp2p/kademlia/mod.rs index fa63fb2c3..8a475ca96 100644 --- a/src/protocol/libp2p/kademlia/mod.rs +++ b/src/protocol/libp2p/kademlia/mod.rs @@ -178,6 +178,9 @@ pub(crate) struct Kademlia { /// Default record TTL. record_ttl: Duration, + /// Drop non-global addresses received from remote peers. + global_addresses_only: bool, + /// Query engine. engine: QueryEngine, @@ -217,6 +220,7 @@ impl Kademlia { mode: config.mode, validation_mode: config.validation_mode, record_ttl: config.record_ttl, + global_addresses_only: config.global_addresses_only, replication_factor: config.replication_factor, engine: QueryEngine::new(local_peer_id, config.replication_factor, PARALLELISM_FACTOR), } @@ -485,9 +489,13 @@ impl Kademlia { ) -> crate::Result<()> { tracing::trace!(target: LOG_TARGET, ?peer, query = ?query_id, "handle message from peer"); - match KademliaMessage::from_bytes(message, self.replication_factor) - .ok_or(Error::InvalidData)? - { + let mut message = KademliaMessage::from_bytes(message, self.replication_factor) + .ok_or(Error::InvalidData)?; + if self.global_addresses_only { + message.retain_global_addresses(); + } + + match message { KademliaMessage::FindNode { target, peers } => { match query_id { Some(query_id) => { @@ -1470,6 +1478,13 @@ mod tests { } fn make_kademlia_with_mode(mode: KademliaMode) -> (Kademlia, Context, TransportManager) { + make_kademlia_with(mode, false) + } + + fn make_kademlia_with( + mode: KademliaMode, + global_addresses_only: bool, + ) -> (Kademlia, Context, TransportManager) { let manager = TransportManagerBuilder::new().build(); let peer = PeerId::random(); @@ -1495,6 +1510,7 @@ mod tests { mode, validation_mode: IncomingRecordValidationMode::Automatic, record_ttl: Duration::from_secs(36 * 60 * 60), + global_addresses_only, memory_store_config: Default::default(), event_tx, cmd_rx, @@ -1867,4 +1883,89 @@ mod tests { ) .is_none()); } + + #[tokio::test] + async fn non_global_addresses_dropped_from_responses() { + let (mut kademlia, mut context, _manager) = make_kademlia_with(KademliaMode::Server, true); + + let private_peer = PeerId::random(); + let private = KademliaPeer::new( + private_peer, + vec![Multiaddr::from_str("/ip4/10.0.0.1/tcp/30333").unwrap()], + ConnectionType::NotConnected, + ); + let public_peer = PeerId::random(); + let public = KademliaPeer::new( + public_peer, + vec![ + Multiaddr::from_str("/ip4/10.0.0.2/tcp/30333").unwrap(), + Multiaddr::from_str("/ip4/8.8.8.8/tcp/30333").unwrap(), + ], + ConnectionType::NotConnected, + ); + + let responder = PeerId::random(); + let mut substream = MockSubstream::new(); + substream.expect_poll_close().times(1).return_once(|_| Poll::Ready(Ok(()))); + let message = + KademliaMessage::find_node_response(PeerId::random().to_bytes(), vec![private, public]); + kademlia + .on_message_received( + responder, + Some(QueryId(0)), + BytesMut::from(&message[..]), + Substream::new_mock(responder, SubstreamId::from(0usize), Box::new(substream)), + ) + .await + .unwrap(); + + // The peer left without addresses is not discovered. + match context.event_rx.try_recv() { + Ok(KademliaEvent::PeersDiscovered { peers }) => assert_eq!(peers, vec![public_peer]), + event => panic!("unexpected event: {event:?}"), + } + } + + #[tokio::test] + async fn non_global_addresses_dropped_from_incoming_provider() { + let (mut kademlia, mut context, _manager) = make_kademlia_with(KademliaMode::Server, true); + + let key = RecordKey::from(vec![1, 2, 3]); + let provider = PeerId::random(); + let message = KademliaMessage::add_provider( + key.clone(), + ContentProvider { + peer: provider, + addresses: vec![ + Multiaddr::from_str("/ip4/10.0.0.1/tcp/30333").unwrap(), + Multiaddr::from_str("/ip4/8.8.8.8/tcp/30333").unwrap(), + ], + }, + ); + kademlia + .on_message_received( + provider, + None, + BytesMut::from(&message[..]), + Substream::new_mock( + provider, + SubstreamId::from(0usize), + Box::new(MockSubstream::new()), + ), + ) + .await + .unwrap(); + + let global = vec![Multiaddr::from_str("/ip4/8.8.8.8/tcp/30333").unwrap()]; + let providers = kademlia.store.get_providers(&key); + assert_eq!(providers.len(), 1); + assert_eq!(providers[0].addresses, global); + match context.event_rx.try_recv() { + Ok(KademliaEvent::IncomingProvider { provider: p, .. }) => { + assert_eq!(p.peer, provider); + assert_eq!(p.addresses, global); + } + event => panic!("unexpected event: {event:?}"), + } + } } diff --git a/src/protocol/libp2p/kademlia/types.rs b/src/protocol/libp2p/kademlia/types.rs index d0d930dd6..a567e7c50 100644 --- a/src/protocol/libp2p/kademlia/types.rs +++ b/src/protocol/libp2p/kademlia/types.rs @@ -26,7 +26,7 @@ use crate::{ protocol::libp2p::kademlia::schema, - transport::manager::address::{AddressRecord, AddressStore}, + transport::manager::address::{is_global_multiaddr, AddressRecord, AddressStore}, PeerId, }; @@ -288,6 +288,11 @@ impl KademliaPeer { pub fn addresses(&self) -> Vec { self.address_store.addresses(MAX_ADDRESSES) } + + /// Remove non-global addresses of the peer. + pub(super) fn retain_global_addresses(&mut self) { + self.address_store.addresses.retain(|address, _| is_global_multiaddr(address)); + } } impl TryFrom<&schema::kademlia::Peer> for KademliaPeer { diff --git a/src/transport/manager/address.rs b/src/transport/manager/address.rs index 38dd6a34e..0fb2ceb7b 100644 --- a/src/transport/manager/address.rs +++ b/src/transport/manager/address.rs @@ -127,7 +127,7 @@ impl AddressRecord { /// Check if a multiaddr represents a global/public address. /// /// DNS addresses are considered potentially public. -fn is_global_multiaddr(address: &Multiaddr) -> bool { +pub(crate) fn is_global_multiaddr(address: &Multiaddr) -> bool { for protocol in address.iter() { match protocol { Protocol::Ip4(ip) => return IpNetwork::from(ip).is_global(), From b2be709a1af5afbd71dde4581d101948811feb18 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Wed, 7 Oct 2026 10:53:53 +0300 Subject: [PATCH 2/4] Use an enum instead of a boolean flag --- src/protocol/libp2p/kademlia/config.rs | 31 ++++++++++++-------------- src/protocol/libp2p/kademlia/handle.rs | 14 ++++++++++++ src/protocol/libp2p/kademlia/mod.rs | 29 ++++++++++++------------ 3 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/protocol/libp2p/kademlia/config.rs b/src/protocol/libp2p/kademlia/config.rs index 324feb1bb..6f91949b5 100644 --- a/src/protocol/libp2p/kademlia/config.rs +++ b/src/protocol/libp2p/kademlia/config.rs @@ -23,7 +23,7 @@ use crate::{ protocol::libp2p::kademlia::{ handle::{ IncomingRecordValidationMode, KademliaCommand, KademliaEvent, KademliaHandle, - RoutingTableUpdateMode, + RemoteAddressMode, RoutingTableUpdateMode, }, store::MemoryStoreConfig, }, @@ -102,8 +102,8 @@ pub struct Config { /// Default record TTL. pub(super) record_ttl: Duration, - /// Drop non-global addresses received from remote peers. - pub(super) global_addresses_only: bool, + /// Remote address mode. + pub(super) remote_address_mode: RemoteAddressMode, /// Provider record TTL. pub(super) memory_store_config: MemoryStoreConfig, @@ -137,7 +137,7 @@ impl Config { mode: KademliaMode, validation_mode: IncomingRecordValidationMode, record_ttl: Duration, - global_addresses_only: bool, + remote_address_mode: RemoteAddressMode, memory_store_config: MemoryStoreConfig, max_message_size: usize, ) -> (Self, KademliaHandle) { @@ -157,7 +157,7 @@ impl Config { mode, validation_mode, record_ttl, - global_addresses_only, + remote_address_mode, memory_store_config, codec: ProtocolCodec::UnsignedVarint(Some(max_message_size)), replication_factor, @@ -180,7 +180,7 @@ impl Config { KademliaMode::Server, IncomingRecordValidationMode::Automatic, DEFAULT_TTL, - false, + RemoteAddressMode::All, Default::default(), DEFAULT_MAX_MESSAGE_SIZE, ) @@ -211,8 +211,8 @@ pub struct ConfigBuilder { /// Default TTL for the records. pub(super) record_ttl: Duration, - /// Drop non-global addresses received from remote peers. - pub(super) global_addresses_only: bool, + /// Remote address mode. + pub(super) remote_address_mode: RemoteAddressMode, /// Memory store configuration. pub(super) memory_store_config: MemoryStoreConfig, @@ -238,7 +238,7 @@ impl ConfigBuilder { mode: KademliaMode::Server, validation_mode: IncomingRecordValidationMode::Automatic, record_ttl: DEFAULT_TTL, - global_addresses_only: false, + remote_address_mode: RemoteAddressMode::All, memory_store_config: Default::default(), max_message_size: DEFAULT_MAX_MESSAGE_SIZE, } @@ -304,14 +304,11 @@ impl ConfigBuilder { self } - /// Drop non-global IP addresses of peers and providers received from remote peers, so - /// Kademlia neither dials nor stores them. Peers left without addresses are not used as - /// query candidates. DNS addresses are kept. + /// Set which addresses received from remote peers are accepted. /// - /// Locally supplied addresses (known peers, [`KademliaHandle::add_known_peer`]) are not - /// affected. Disabled by default. - pub fn with_global_addresses_only(mut self, global_addresses_only: bool) -> Self { - self.global_addresses_only = global_addresses_only; + /// If unspecified, all addresses are accepted ([`RemoteAddressMode::All`]). + pub fn with_remote_address_mode(mut self, mode: RemoteAddressMode) -> Self { + self.remote_address_mode = mode; self } @@ -393,7 +390,7 @@ impl ConfigBuilder { self.mode, self.validation_mode, self.record_ttl, - self.global_addresses_only, + self.remote_address_mode, self.memory_store_config, self.max_message_size, ) diff --git a/src/protocol/libp2p/kademlia/handle.rs b/src/protocol/libp2p/kademlia/handle.rs index 9021a7b97..72f181306 100644 --- a/src/protocol/libp2p/kademlia/handle.rs +++ b/src/protocol/libp2p/kademlia/handle.rs @@ -76,6 +76,20 @@ pub enum IncomingRecordValidationMode { Automatic, } +/// Which addresses received from remote peers are accepted. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum RemoteAddressMode { + /// Accept all addresses. + All, + + /// Drop non-global IP addresses, so Kademlia neither dials nor stores them. Peers left + /// without addresses are not used as query candidates. DNS addresses are kept. + /// + /// Locally supplied addresses (known peers, [`KademliaHandle::add_known_peer()`]) are not + /// affected. + GlobalOnly, +} + /// Kademlia commands. #[derive(Debug)] #[cfg_attr(feature = "fuzz", derive(serde::Serialize, serde::Deserialize))] diff --git a/src/protocol/libp2p/kademlia/mod.rs b/src/protocol/libp2p/kademlia/mod.rs index 8a475ca96..3a2d8a8f3 100644 --- a/src/protocol/libp2p/kademlia/mod.rs +++ b/src/protocol/libp2p/kademlia/mod.rs @@ -57,7 +57,7 @@ use std::{ pub use config::{Config, ConfigBuilder, KademliaMode}; pub use handle::{ IncomingRecordValidationMode, KademliaCommand, KademliaEvent, KademliaHandle, Quorum, - RoutingTableUpdateMode, + RemoteAddressMode, RoutingTableUpdateMode, }; pub use query::QueryId; pub use record::{ContentProvider, Key as RecordKey, PeerRecord, Record}; @@ -178,8 +178,8 @@ pub(crate) struct Kademlia { /// Default record TTL. record_ttl: Duration, - /// Drop non-global addresses received from remote peers. - global_addresses_only: bool, + /// Remote address mode. + remote_address_mode: RemoteAddressMode, /// Query engine. engine: QueryEngine, @@ -220,7 +220,7 @@ impl Kademlia { mode: config.mode, validation_mode: config.validation_mode, record_ttl: config.record_ttl, - global_addresses_only: config.global_addresses_only, + remote_address_mode: config.remote_address_mode, replication_factor: config.replication_factor, engine: QueryEngine::new(local_peer_id, config.replication_factor, PARALLELISM_FACTOR), } @@ -491,7 +491,7 @@ impl Kademlia { let mut message = KademliaMessage::from_bytes(message, self.replication_factor) .ok_or(Error::InvalidData)?; - if self.global_addresses_only { + if self.remote_address_mode == RemoteAddressMode::GlobalOnly { message.retain_global_addresses(); } @@ -1474,16 +1474,12 @@ mod tests { } fn make_kademlia() -> (Kademlia, Context, TransportManager) { - make_kademlia_with_mode(KademliaMode::Server) - } - - fn make_kademlia_with_mode(mode: KademliaMode) -> (Kademlia, Context, TransportManager) { - make_kademlia_with(mode, false) + make_kademlia_with(KademliaMode::Server, RemoteAddressMode::All) } fn make_kademlia_with( mode: KademliaMode, - global_addresses_only: bool, + remote_address_mode: RemoteAddressMode, ) -> (Kademlia, Context, TransportManager) { let manager = TransportManagerBuilder::new().build(); @@ -1510,7 +1506,7 @@ mod tests { mode, validation_mode: IncomingRecordValidationMode::Automatic, record_ttl: Duration::from_secs(36 * 60 * 60), - global_addresses_only, + remote_address_mode, memory_store_config: Default::default(), event_tx, cmd_rx, @@ -1700,7 +1696,8 @@ mod tests { #[tokio::test] async fn client_mode_ignores_inbound_substreams() { - let (mut kademlia, _context, _manager) = make_kademlia_with_mode(KademliaMode::Client); + let (mut kademlia, _context, _manager) = + make_kademlia_with(KademliaMode::Client, RemoteAddressMode::All); let peer = PeerId::random(); let mut substream = MockSubstream::new(); @@ -1886,7 +1883,8 @@ mod tests { #[tokio::test] async fn non_global_addresses_dropped_from_responses() { - let (mut kademlia, mut context, _manager) = make_kademlia_with(KademliaMode::Server, true); + let (mut kademlia, mut context, _manager) = + make_kademlia_with(KademliaMode::Server, RemoteAddressMode::GlobalOnly); let private_peer = PeerId::random(); let private = KademliaPeer::new( @@ -1928,7 +1926,8 @@ mod tests { #[tokio::test] async fn non_global_addresses_dropped_from_incoming_provider() { - let (mut kademlia, mut context, _manager) = make_kademlia_with(KademliaMode::Server, true); + let (mut kademlia, mut context, _manager) = + make_kademlia_with(KademliaMode::Server, RemoteAddressMode::GlobalOnly); let key = RecordKey::from(vec![1, 2, 3]); let provider = PeerId::random(); From 2a7a1f9b68586e42f6962eb0593ba375207baebe Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Wed, 7 Oct 2026 11:05:20 +0300 Subject: [PATCH 3/4] Review and fixes --- src/protocol/libp2p/kademlia/handle.rs | 8 ++++---- src/protocol/libp2p/kademlia/message.rs | 5 +---- src/protocol/libp2p/kademlia/types.rs | 2 +- src/transport/manager/address.rs | 5 +++++ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/protocol/libp2p/kademlia/handle.rs b/src/protocol/libp2p/kademlia/handle.rs index 72f181306..57a04da93 100644 --- a/src/protocol/libp2p/kademlia/handle.rs +++ b/src/protocol/libp2p/kademlia/handle.rs @@ -82,11 +82,11 @@ pub enum RemoteAddressMode { /// Accept all addresses. All, - /// Drop non-global IP addresses, so Kademlia neither dials nor stores them. Peers left - /// without addresses are not used as query candidates. DNS addresses are kept. + /// Drop non-global IP addresses of peers and providers received from remote peers. Closer + /// peers left without addresses are not used as query candidates. DNS addresses are kept. /// - /// Locally supplied addresses (known peers, [`KademliaHandle::add_known_peer()`]) are not - /// affected. + /// Locally supplied addresses (known peers, [`KademliaHandle::add_known_peer()`], addresses + /// of connections we dialed) are not affected. GlobalOnly, } diff --git a/src/protocol/libp2p/kademlia/message.rs b/src/protocol/libp2p/kademlia/message.rs index 60a472e32..1b2f509e5 100644 --- a/src/protocol/libp2p/kademlia/message.rs +++ b/src/protocol/libp2p/kademlia/message.rs @@ -365,9 +365,6 @@ impl KademliaMessage { pub fn retain_global_addresses(&mut self) { fn retain_closer_peers(peers: &mut Vec) { peers.retain_mut(|peer| { - if peer.address_store.is_empty() { - return true; - } peer.retain_global_addresses(); !peer.address_store.is_empty() }); @@ -504,7 +501,7 @@ mod tests { // Closer peers left without addresses are dropped. assert_eq!( peers.iter().map(|peer| peer.peer).collect::>(), - vec![mixed.peer, dns.peer, no_addresses.peer], + vec![mixed.peer, dns.peer], ); assert_eq!( peers[0].addresses(), diff --git a/src/protocol/libp2p/kademlia/types.rs b/src/protocol/libp2p/kademlia/types.rs index a567e7c50..2012f9b90 100644 --- a/src/protocol/libp2p/kademlia/types.rs +++ b/src/protocol/libp2p/kademlia/types.rs @@ -291,7 +291,7 @@ impl KademliaPeer { /// Remove non-global addresses of the peer. pub(super) fn retain_global_addresses(&mut self) { - self.address_store.addresses.retain(|address, _| is_global_multiaddr(address)); + self.address_store.retain(is_global_multiaddr); } } diff --git a/src/transport/manager/address.rs b/src/transport/manager/address.rs index 0fb2ceb7b..a03b2f949 100644 --- a/src/transport/manager/address.rs +++ b/src/transport/manager/address.rs @@ -289,6 +289,11 @@ impl AddressStore { self.addresses.insert(record.address.clone(), record); } + /// Retain only the addresses matching `predicate`. + pub fn retain(&mut self, mut predicate: impl FnMut(&Multiaddr) -> bool) { + self.addresses.retain(|address, _| predicate(address)); + } + /// Return the available addresses sorted by score. pub fn addresses(&self, limit: usize) -> Vec { let mut records = self.addresses.values().cloned().collect::>(); From 608fb6a42f07247e0e87f0bfc6bb171e2fac1e17 Mon Sep 17 00:00:00 2001 From: Dmitry Markin Date: Wed, 7 Oct 2026 11:12:54 +0300 Subject: [PATCH 4/4] minor: comments --- src/protocol/libp2p/kademlia/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocol/libp2p/kademlia/config.rs b/src/protocol/libp2p/kademlia/config.rs index 6f91949b5..e9cb25037 100644 --- a/src/protocol/libp2p/kademlia/config.rs +++ b/src/protocol/libp2p/kademlia/config.rs @@ -102,7 +102,7 @@ pub struct Config { /// Default record TTL. pub(super) record_ttl: Duration, - /// Remote address mode. + /// Whether to accept non-global addresses from remote peers. pub(super) remote_address_mode: RemoteAddressMode, /// Provider record TTL. @@ -211,7 +211,7 @@ pub struct ConfigBuilder { /// Default TTL for the records. pub(super) record_ttl: Duration, - /// Remote address mode. + /// Whether to accept non-global addresses from remote peers. pub(super) remote_address_mode: RemoteAddressMode, /// Memory store configuration. @@ -304,7 +304,7 @@ impl ConfigBuilder { self } - /// Set which addresses received from remote peers are accepted. + /// Set whether non-global addresses received from remote peers are accepted. /// /// If unspecified, all addresses are accepted ([`RemoteAddressMode::All`]). pub fn with_remote_address_mode(mut self, mode: RemoteAddressMode) -> Self {