diff --git a/Cargo.lock b/Cargo.lock index 421ae65f53f..198dd4706b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2643,7 +2643,7 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.47.0" +version = "0.48.0" dependencies = [ "asynchronous-codec", "either", @@ -3068,7 +3068,7 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.47.0" +version = "0.47.1" dependencies = [ "criterion", "either", diff --git a/Cargo.toml b/Cargo.toml index 36c148cffee..451b2809b35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,7 @@ libp2p-dcutr = { version = "0.14.0", path = "protocols/dcutr" } libp2p-dns = { version = "0.44.0", path = "transports/dns" } libp2p-floodsub = { version = "0.47.0", path = "protocols/floodsub" } libp2p-gossipsub = { version = "0.50.0", path = "protocols/gossipsub" } -libp2p-identify = { version = "0.47.0", path = "protocols/identify" } +libp2p-identify = { version = "0.48.0", path = "protocols/identify" } libp2p-identity = { version = "0.2.12" } libp2p-kad = { version = "0.49.0", path = "protocols/kad" } libp2p-mdns = { version = "0.48.0", path = "protocols/mdns" } @@ -102,7 +102,7 @@ libp2p-rendezvous = { version = "0.17.0", path = "protocols/rendezvous" } libp2p-request-response = { version = "0.29.0", path = "protocols/request-response" } libp2p-server = { version = "0.12.7", path = "misc/server" } libp2p-stream = { version = "0.4.0-alpha", path = "protocols/stream" } -libp2p-swarm = { version = "0.47.0", path = "swarm" } +libp2p-swarm = { version = "0.47.1", path = "swarm" } libp2p-swarm-derive = { version = "=0.35.1", path = "swarm-derive" } # `libp2p-swarm-derive` may not be compatible with different `libp2p-swarm` non-breaking releases. E.g. `libp2p-swarm` might introduce a new enum variant `FromSwarm` (which is `#[non-exhaustive]`) in a non-breaking release. Older versions of `libp2p-swarm-derive` would not forward this enum variant within the `NetworkBehaviour` hierarchy. Thus the version pinning is required. libp2p-swarm-test = { version = "0.6.0", path = "swarm-test" } libp2p-tcp = { version = "0.44.0", path = "transports/tcp" } diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 85a5beb0209..1755476b215 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.48.0 + +- Replace `with_cache_size` by `with_cache_config` to fully configure the identify cache using `PeerAddressesConfig`. + See [PR 5574](https://github.com/libp2p/rust-libp2p/pull/5574). + ## 0.47.0 - Implement optional `signedPeerRecord` support for identify messages. diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index 2132b0b2435..bf05bec81fe 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-identify" edition.workspace = true rust-version = { workspace = true } description = "Nodes identification protocol for libp2p" -version = "0.47.0" +version = "0.48.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" diff --git a/protocols/identify/src/behaviour.rs b/protocols/identify/src/behaviour.rs index a50e8e64cbd..6202a49424a 100644 --- a/protocols/identify/src/behaviour.rs +++ b/protocols/identify/src/behaviour.rs @@ -20,7 +20,6 @@ use std::{ collections::{hash_map::Entry, HashMap, HashSet, VecDeque}, - num::NonZeroUsize, sync::Arc, task::{Context, Poll}, time::Duration, @@ -35,8 +34,8 @@ use libp2p_identity::{Keypair, PeerId, PublicKey}; use libp2p_swarm::{ behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm}, ConnectionDenied, ConnectionId, DialError, ExternalAddresses, ListenAddresses, - NetworkBehaviour, NotifyHandler, PeerAddresses, StreamUpgradeError, THandler, THandlerInEvent, - THandlerOutEvent, ToSwarm, _address_translation, + NetworkBehaviour, NotifyHandler, PeerAddresses, PeerAddressesConfig, StreamUpgradeError, + THandler, THandlerInEvent, THandlerOutEvent, ToSwarm, _address_translation, }; use crate::{ @@ -145,11 +144,8 @@ pub struct Config { /// Disabled by default. push_listen_addr_updates: bool, - /// How many entries of discovered peers to keep before we discard - /// the least-recently used one. - /// - /// Defaults to 100 - cache_size: usize, + /// Configuration for the LRU cache of discovered peers. + cache_config: Option, /// Whether to include our listen addresses in our responses. If enabled, /// we will effectively only share our external addresses. @@ -182,7 +178,7 @@ impl Config { local_key: Arc::new(key.into()), interval: Duration::from_secs(5 * 60), push_listen_addr_updates: false, - cache_size: 100, + cache_config: Some(Default::default()), hide_listen_addrs: false, } } @@ -208,9 +204,11 @@ impl Config { self } - /// Configures the size of the LRU cache, caching addresses of discovered peers. - pub fn with_cache_size(mut self, cache_size: usize) -> Self { - self.cache_size = cache_size; + /// Configures the LRU cache responsible for caching addresses of discovered peers. + /// + /// If set to [`None`], caching is disabled. + pub fn with_cache_config(mut self, cache_config: Option) -> Self { + self.cache_config = cache_config; self } @@ -245,9 +243,9 @@ impl Config { self.push_listen_addr_updates } - /// Get the cache size of the Config. - pub fn cache_size(&self) -> usize { - self.cache_size + /// Get the config of the LRU cache responsible for caching addresses of discovered peers. + pub fn cache_config(&self) -> &Option { + &self.cache_config } /// Get the hide listen address boolean value of the Config. @@ -259,10 +257,7 @@ impl Config { impl Behaviour { /// Creates a new identify [`Behaviour`]. pub fn new(config: Config) -> Self { - let discovered_peers = match NonZeroUsize::new(config.cache_size) { - None => PeerCache::disabled(), - Some(size) => PeerCache::enabled(size), - }; + let discovered_peers = PeerCache::new(config.cache_config.clone()); Self { config, @@ -681,12 +676,8 @@ fn multiaddr_matches_peer_id(addr: &Multiaddr, peer_id: &PeerId) -> bool { struct PeerCache(Option); impl PeerCache { - fn disabled() -> Self { - Self(None) - } - - fn enabled(size: NonZeroUsize) -> Self { - Self(Some(PeerAddresses::new(size))) + fn new(cache_config: Option) -> Self { + Self(cache_config.map(PeerAddresses::new)) } fn get(&mut self, peer: &PeerId) -> Vec { diff --git a/protocols/identify/tests/smoke.rs b/protocols/identify/tests/smoke.rs index 70d864037b1..c548769011d 100644 --- a/protocols/identify/tests/smoke.rs +++ b/protocols/identify/tests/smoke.rs @@ -1,13 +1,14 @@ use std::{ collections::HashSet, iter, + num::NonZeroUsize, time::{Duration, Instant}, }; use futures::StreamExt; use libp2p_identify as identify; use libp2p_identity::Keypair; -use libp2p_swarm::{Swarm, SwarmEvent}; +use libp2p_swarm::{PeerAddressesConfig, Swarm, SwarmEvent}; use libp2p_swarm_test::SwarmExt; use tracing_subscriber::EnvFilter; @@ -165,7 +166,10 @@ async fn emits_unique_listen_addresses() { identify::Config::new("a".to_string(), identity.public()) .with_agent_version("b".to_string()) .with_interval(Duration::from_secs(1)) - .with_cache_size(10), + .with_cache_config(Some( + PeerAddressesConfig::default() + .with_number_of_peers(NonZeroUsize::new(10).expect("10 != 0")), + )), ) }); let mut swarm2 = Swarm::new_ephemeral_tokio(|identity| { @@ -237,7 +241,10 @@ async fn hides_listen_addresses() { identify::Config::new("a".to_string(), identity.public()) .with_agent_version("b".to_string()) .with_interval(Duration::from_secs(1)) - .with_cache_size(10), + .with_cache_config(Some( + PeerAddressesConfig::default() + .with_number_of_peers(NonZeroUsize::new(10).expect("10 != 0")), + )), ) }); let mut swarm2 = Swarm::new_ephemeral_tokio(|identity| { diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 90d104156f6..ef6a6ecf86e 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.47.1 + +- Add `PeerAddressesConfig` and the possibility to configure the number of addresses cached per peer. + See [PR 5574](https://github.com/libp2p/rust-libp2p/pull/5574). + ## 0.47.0 - Remove `async-std` support. diff --git a/swarm/Cargo.toml b/swarm/Cargo.toml index 81d03ca9559..29b3ccc60ed 100644 --- a/swarm/Cargo.toml +++ b/swarm/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-swarm" edition.workspace = true rust-version = { workspace = true } description = "The libp2p swarm" -version = "0.47.0" +version = "0.47.1" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index 8c8c5998f67..9e709cfa775 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -33,7 +33,7 @@ use libp2p_core::{ }; use libp2p_identity::PeerId; pub use listen_addresses::ListenAddresses; -pub use peer_addresses::PeerAddresses; +pub use peer_addresses::{PeerAddresses, PeerAddressesConfig}; use crate::{ connection::ConnectionId, dial_opts::DialOpts, listen_opts::ListenOpts, ConnectionDenied, diff --git a/swarm/src/behaviour/peer_addresses.rs b/swarm/src/behaviour/peer_addresses.rs index d6aff6e8c42..c9e6f941585 100644 --- a/swarm/src/behaviour/peer_addresses.rs +++ b/swarm/src/behaviour/peer_addresses.rs @@ -6,16 +6,58 @@ use libp2p_identity::PeerId; use crate::{behaviour::FromSwarm, DialError, DialFailure, NewExternalAddrOfPeer}; +#[derive(Debug, Clone)] +/// Configuration of a [`PeerAddresses`] instance. +pub struct PeerAddressesConfig { + /// Capacity of the [`PeerAddresses`] cache. + number_of_peers: NonZeroUsize, + + /// Maximum number of cached addresses per peer. + number_of_addresses_per_peer: NonZeroUsize, +} + +impl PeerAddressesConfig { + /// Configure the capacity of the [`PeerAddresses`] cache. + /// The default capacity is 100. + pub fn with_number_of_peers(mut self, number_of_peers: NonZeroUsize) -> Self { + self.number_of_peers = number_of_peers; + self + } + + /// Configure the maximum number of cached addresses per peer. + /// The default number is 10. + pub fn with_number_of_addresses_per_peer( + mut self, + number_of_addresses_per_peer: NonZeroUsize, + ) -> Self { + self.number_of_addresses_per_peer = number_of_addresses_per_peer; + self + } +} + +impl Default for PeerAddressesConfig { + fn default() -> Self { + Self { + number_of_peers: NonZeroUsize::new(100).expect("100 != 0"), + number_of_addresses_per_peer: NonZeroUsize::new(10).expect("10 != 0"), + } + } +} + /// Struct for tracking peers' external addresses of the [`Swarm`](crate::Swarm). #[derive(Debug)] -pub struct PeerAddresses(LruCache>); +pub struct PeerAddresses { + config: PeerAddressesConfig, + inner: LruCache>, +} impl PeerAddresses { /// Creates a [`PeerAddresses`] cache with capacity for the given number of peers. /// - /// For each peer, we will at most store 10 addresses. - pub fn new(number_of_peers: NonZeroUsize) -> Self { - Self(LruCache::new(number_of_peers.get())) + /// For each peer, we will at most store `config.number_of_addresses_per_peer` addresses. + pub fn new(config: PeerAddressesConfig) -> Self { + let inner = LruCache::new(config.number_of_peers.get()); + Self { config, inner } } /// Feed a [`FromSwarm`] event to this struct. @@ -47,12 +89,12 @@ impl PeerAddresses { pub fn add(&mut self, peer: PeerId, address: Multiaddr) -> bool { match prepare_addr(&peer, &address) { Ok(address) => { - if let Some(cached) = self.0.get_mut(&peer) { + if let Some(cached) = self.inner.get_mut(&peer) { cached.insert(address, ()).is_none() } else { - let mut set = LruCache::new(10); + let mut set = LruCache::new(self.config.number_of_addresses_per_peer.get()); set.insert(address, ()); - self.0.insert(peer, set); + self.inner.insert(peer, set); true } @@ -63,7 +105,7 @@ impl PeerAddresses { /// Returns peer's external addresses. pub fn get(&mut self, peer: &PeerId) -> impl Iterator + '_ { - self.0 + self.inner .get(peer) .into_iter() .flat_map(|c| c.iter().map(|(m, ())| m)) @@ -73,7 +115,7 @@ impl PeerAddresses { /// Removes address from peer addresses cache. /// Returns true if the address was removed. pub fn remove(&mut self, peer: &PeerId, address: &Multiaddr) -> bool { - match self.0.get_mut(peer) { + match self.inner.get_mut(peer) { Some(addrs) => match prepare_addr(peer, address) { Ok(address) => addrs.remove(&address).is_some(), Err(_) => false, @@ -89,7 +131,7 @@ fn prepare_addr(peer: &PeerId, addr: &Multiaddr) -> Result impl Default for PeerAddresses { fn default() -> Self { - Self(LruCache::new(100)) + Self::new(Default::default()) } } diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index d0ae6118190..ac436ea639f 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -105,7 +105,8 @@ pub use behaviour::{ AddressChange, CloseConnection, ConnectionClosed, DialFailure, ExpiredListenAddr, ExternalAddrExpired, ExternalAddresses, FromSwarm, ListenAddresses, ListenFailure, ListenerClosed, ListenerError, NetworkBehaviour, NewExternalAddrCandidate, - NewExternalAddrOfPeer, NewListenAddr, NotifyHandler, PeerAddresses, ToSwarm, + NewExternalAddrOfPeer, NewListenAddr, NotifyHandler, PeerAddresses, PeerAddressesConfig, + ToSwarm, }; pub use connection::{pool::ConnectionCounters, ConnectionError, ConnectionId, SupportedProtocols}; use connection::{