From be31d423c61a00e41d927dd83a928713f388da92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20RIBEAU?= Date: Wed, 28 Aug 2024 16:23:19 +0200 Subject: [PATCH] feat(swarm): improve `PeerAddresses` configurability --- Cargo.lock | 4 +-- Cargo.toml | 2 +- protocols/identify/CHANGELOG.md | 5 ++++ protocols/identify/Cargo.toml | 2 +- protocols/identify/src/behaviour.rs | 35 ++++++++-------------- protocols/identify/tests/smoke.rs | 8 +++-- swarm/CHANGELOG.md | 5 ++++ swarm/Cargo.toml | 2 +- swarm/src/behaviour.rs | 2 +- swarm/src/behaviour/peer_addresses.rs | 43 ++++++++++++++++++++------- swarm/src/lib.rs | 3 +- 11 files changed, 70 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f37b652c30..0741177a6bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2875,7 +2875,7 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.45.0" +version = "0.46.0" dependencies = [ "async-std", "asynchronous-codec", @@ -3330,7 +3330,7 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.45.1" +version = "0.45.2" dependencies = [ "async-std", "criterion", diff --git a/Cargo.toml b/Cargo.toml index 8d63ac3ee1e..8783b4890bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,7 @@ libp2p-dcutr = { version = "0.12.0", path = "protocols/dcutr" } libp2p-dns = { version = "0.42.0", path = "transports/dns" } libp2p-floodsub = { version = "0.45.0", path = "protocols/floodsub" } libp2p-gossipsub = { version = "0.47.0", path = "protocols/gossipsub" } -libp2p-identify = { version = "0.45.0", path = "protocols/identify" } +libp2p-identify = { version = "0.46.0", path = "protocols/identify" } libp2p-identity = { version = "0.2.9" } libp2p-kad = { version = "0.47.0", path = "protocols/kad" } libp2p-mdns = { version = "0.46.0", path = "protocols/mdns" } diff --git a/protocols/identify/CHANGELOG.md b/protocols/identify/CHANGELOG.md index 275f7114b28..481c05c8a05 100644 --- a/protocols/identify/CHANGELOG.md +++ b/protocols/identify/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.46.0 + +- Update to the new `PeerAddresses` API with `PeerAddressesConfig`, changing `with_cache_size` to `with_cache_config`. + See [PR 5574](https://github.com/libp2p/rust-libp2p/pull/5574). + ## 0.45.0 - Address translation is moved here from `libp2p-core`. diff --git a/protocols/identify/Cargo.toml b/protocols/identify/Cargo.toml index cdc5ce587de..13c43b6a71f 100644 --- a/protocols/identify/Cargo.toml +++ b/protocols/identify/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-identify" edition = "2021" rust-version = { workspace = true } description = "Nodes identification protocol for libp2p" -version = "0.45.0" +version = "0.46.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 6590ccd6588..79ed2b9c07d 100644 --- a/protocols/identify/src/behaviour.rs +++ b/protocols/identify/src/behaviour.rs @@ -28,13 +28,12 @@ use libp2p_identity::PublicKey; use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm}; use libp2p_swarm::{ ConnectionDenied, DialError, ExternalAddresses, ListenAddresses, NetworkBehaviour, - NotifyHandler, PeerAddresses, StreamUpgradeError, THandlerInEvent, ToSwarm, - _address_translation, + NotifyHandler, PeerAddresses, PeerAddressesConfig, StreamUpgradeError, THandlerInEvent, + ToSwarm, _address_translation, }; use libp2p_swarm::{ConnectionId, THandler, THandlerOutEvent}; use std::collections::hash_map::Entry; -use std::num::NonZeroUsize; use std::{ collections::{HashMap, HashSet, VecDeque}, task::Context, @@ -142,11 +141,8 @@ pub struct Config { /// Disabled by default. pub push_listen_addr_updates: bool, - /// How many entries of discovered peers to keep before we discard - /// the least-recently used one. - /// - /// Disabled by default. - pub cache_size: usize, + /// Configuration for the LRU cache of discovered peers. + pub cache_config: Option, } impl Config { @@ -159,7 +155,7 @@ impl Config { local_public_key, interval: Duration::from_secs(5 * 60), push_listen_addr_updates: false, - cache_size: 100, + cache_config: Some(Default::default()), } } @@ -184,9 +180,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; + /// Configuration for 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 } } @@ -194,10 +192,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, @@ -602,12 +597,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 49ae9f0726f..3a791d69f94 100644 --- a/protocols/identify/tests/smoke.rs +++ b/protocols/identify/tests/smoke.rs @@ -1,9 +1,10 @@ use futures::StreamExt; use libp2p_identify as identify; -use libp2p_swarm::{Swarm, SwarmEvent}; +use libp2p_swarm::{PeerAddressesConfig, Swarm, SwarmEvent}; use libp2p_swarm_test::SwarmExt; use std::collections::HashSet; use std::iter; +use std::num::NonZeroUsize; use std::time::{Duration, Instant}; use tracing_subscriber::EnvFilter; @@ -161,7 +162,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 { + number_of_peers: NonZeroUsize::new(10).expect("10 != 0"), + ..Default::default() + })), ) }); let mut swarm2 = Swarm::new_ephemeral(|identity| { diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index e7931a60de2..1bf4c1f4cbb 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.45.2 + +- 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.45.1 - Update `libp2p-swarm-derive` to version `0.35.0`, see [PR 5545] diff --git a/swarm/Cargo.toml b/swarm/Cargo.toml index 3d0b1a84eee..cdee67f3fb3 100644 --- a/swarm/Cargo.toml +++ b/swarm/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-swarm" edition = "2021" rust-version = { workspace = true } description = "The libp2p swarm" -version = "0.45.1" +version = "0.45.2" 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 35aed12fba5..1e0f2354c9b 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -26,7 +26,7 @@ pub mod toggle; pub use external_addresses::ExternalAddresses; pub use listen_addresses::ListenAddresses; -pub use peer_addresses::PeerAddresses; +pub use peer_addresses::{PeerAddresses, PeerAddressesConfig}; use crate::connection::ConnectionId; use crate::dial_opts::DialOpts; diff --git a/swarm/src/behaviour/peer_addresses.rs b/swarm/src/behaviour/peer_addresses.rs index 1eeead56ca1..226e0914c1c 100644 --- a/swarm/src/behaviour/peer_addresses.rs +++ b/swarm/src/behaviour/peer_addresses.rs @@ -8,16 +8,39 @@ use lru::LruCache; use std::num::NonZeroUsize; +#[derive(Debug, Clone)] +/// Configuration of a [`PeerAddresses`] instance. +pub struct PeerAddressesConfig { + /// Capacity of the [`PeerAddresses`] cache. + pub number_of_peers: NonZeroUsize, + + /// Maximum number of cached addresses per peer. + pub number_of_addresses_by_peer: NonZeroUsize, +} + +impl Default for PeerAddressesConfig { + fn default() -> Self { + Self { + number_of_peers: NonZeroUsize::new(100).expect("100 != 0"), + number_of_addresses_by_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)) + /// For each peer, we will at most store `config.number_of_addresses_by_peer` addresses. + pub fn new(config: PeerAddressesConfig) -> Self { + let inner = LruCache::new(config.number_of_peers); + Self { config, inner } } /// Feed a [`FromSwarm`] event to this struct. @@ -50,12 +73,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.put(address, ()).is_none() } else { - let mut set = LruCache::new(NonZeroUsize::new(10).expect("10 > 0")); + let mut set = LruCache::new(self.config.number_of_addresses_by_peer); set.put(address, ()); - self.0.put(peer, set); + self.inner.put(peer, set); true } @@ -66,7 +89,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)) @@ -76,7 +99,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.pop(&address).is_some(), Err(_) => false, @@ -92,7 +115,7 @@ fn prepare_addr(peer: &PeerId, addr: &Multiaddr) -> Result impl Default for PeerAddresses { fn default() -> Self { - Self(LruCache::new(NonZeroUsize::new(100).unwrap())) + Self::new(Default::default()) } } diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 81b1ca1a68d..360e71ebf71 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -111,7 +111,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; pub use connection::{ConnectionError, ConnectionId, SupportedProtocols};