From ef09472c0f4c96c40fcbc6f368cc9b7f61a31a7b Mon Sep 17 00:00:00 2001 From: Darius Date: Wed, 28 Jun 2023 21:31:21 -0400 Subject: [PATCH 01/24] feat: Add Kademlia::set_explicit_mode --- protocols/kad/src/behaviour.rs | 125 ++++++++++++++++++++++----------- protocols/kad/src/lib.rs | 2 +- 2 files changed, 86 insertions(+), 41 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 7df17c91e1a..bb96f673d9e 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -115,6 +115,8 @@ pub struct Kademlia { mode: Mode, + explicit_mode: ExplicitMode, + /// The record storage. store: TStore, } @@ -456,6 +458,7 @@ where local_peer_id: id, connections: Default::default(), mode: Mode::Client, + explicit_mode: ExplicitMode::Auto, } } @@ -990,6 +993,31 @@ where id } + pub fn set_explicit_mode(&mut self, mode: ExplicitMode) { + self.explicit_mode = mode; + + match self.explicit_mode { + ExplicitMode::Client => self.mode = Mode::Client, + ExplicitMode::Server => self.mode = Mode::Server, + ExplicitMode::Auto => {} + } + + if !self.connections.is_empty() { + self.queued_events + .extend( + self.connections + .iter() + .map(|(conn_id, peer_id)| ToSwarm::NotifyHandler { + peer_id: *peer_id, + handler: NotifyHandler::One(*conn_id), + event: KademliaHandlerIn::ReconfigureMode { + new_mode: self.mode, + }, + }), + ); + } + } + /// Processes discovered peers from a successful request in an iterative `Query`. fn discovered<'a, I>(&'a mut self, query_id: &QueryId, source: &PeerId, peers: I) where @@ -2437,60 +2465,60 @@ where self.listen_addresses.on_swarm_event(&event); let external_addresses_changed = self.external_addresses.on_swarm_event(&event); - self.mode = match (self.external_addresses.as_slice(), self.mode) { - ([], Mode::Server) => { - log::debug!("Switching to client-mode because we no longer have any confirmed external addresses"); - - Mode::Client - } - ([], Mode::Client) => { - // Previously client-mode, now also client-mode because no external addresses. + if matches!(self.explicit_mode, ExplicitMode::Auto) { + self.mode = match (self.external_addresses.as_slice(), self.mode) { + ([], Mode::Server) => { + log::debug!("Switching to client-mode because we no longer have any confirmed external addresses"); - Mode::Client - } - (confirmed_external_addresses, Mode::Client) => { - if log::log_enabled!(log::Level::Debug) { - let confirmed_external_addresses = - to_comma_separated_list(confirmed_external_addresses); + Mode::Client + } + ([], Mode::Client) => { + // Previously client-mode, now also client-mode because no external addresses. - log::debug!("Switching to server-mode assuming that one of [{confirmed_external_addresses}] is externally reachable"); + Mode::Client } + (confirmed_external_addresses, Mode::Client) => { + if log::log_enabled!(log::Level::Debug) { + let confirmed_external_addresses = + to_comma_separated_list(confirmed_external_addresses); - Mode::Server - } - (confirmed_external_addresses, Mode::Server) => { - debug_assert!( - !confirmed_external_addresses.is_empty(), - "Previous match arm handled empty list" - ); + log::debug!("Switching to server-mode assuming that one of [{confirmed_external_addresses}] is externally reachable"); + } - // Previously, server-mode, now also server-mode because > 1 external address. Don't log anything to avoid spam. + Mode::Server + } + (confirmed_external_addresses, Mode::Server) => { + debug_assert!( + !confirmed_external_addresses.is_empty(), + "Previous match arm handled empty list" + ); - Mode::Server - } - }; + // Previously, server-mode, now also server-mode because > 1 external address. Don't log anything to avoid spam. - if external_addresses_changed && !self.connections.is_empty() { - let num_connections = self.connections.len(); + Mode::Server + } + }; - log::debug!( - "External addresses changed, re-configuring {} established connection{}", - num_connections, - if num_connections > 1 { "s" } else { "" } - ); + if external_addresses_changed && !self.connections.is_empty() { + let num_connections = self.connections.len(); - self.queued_events - .extend( - self.connections - .iter() - .map(|(conn_id, peer_id)| ToSwarm::NotifyHandler { + log::debug!( + "External addresses changed, re-configuring {} established connection{}", + num_connections, + if num_connections > 1 { "s" } else { "" } + ); + + self.queued_events + .extend(self.connections.iter().map(|(conn_id, peer_id)| { + ToSwarm::NotifyHandler { peer_id: *peer_id, handler: NotifyHandler::One(*conn_id), event: KademliaHandlerIn::ReconfigureMode { new_mode: self.mode, }, - }), - ); + } + })); + } } match event { @@ -3275,6 +3303,23 @@ impl fmt::Display for Mode { } } +#[derive(PartialEq, Copy, Clone, Debug)] +pub enum ExplicitMode { + Auto, + Client, + Server, +} + +impl fmt::Display for ExplicitMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ExplicitMode::Auto => write!(f, "auto"), + ExplicitMode::Client => write!(f, "client"), + ExplicitMode::Server => write!(f, "server"), + } + } +} + fn to_comma_separated_list(confirmed_external_addresses: &[T]) -> String where T: ToString, diff --git a/protocols/kad/src/lib.rs b/protocols/kad/src/lib.rs index fbf8a0b0e12..56b02bdab34 100644 --- a/protocols/kad/src/lib.rs +++ b/protocols/kad/src/lib.rs @@ -67,7 +67,7 @@ pub use addresses::Addresses; pub use behaviour::{ AddProviderContext, AddProviderError, AddProviderOk, AddProviderPhase, AddProviderResult, BootstrapError, BootstrapOk, BootstrapResult, GetClosestPeersError, GetClosestPeersOk, - GetClosestPeersResult, GetProvidersError, GetProvidersOk, GetProvidersResult, GetRecordError, + GetClosestPeersResult, GetProvidersError, GetProvidersOk, ExplicitMode, GetProvidersResult, GetRecordError, GetRecordOk, GetRecordResult, InboundRequest, NoKnownPeers, PeerRecord, PutRecordContext, PutRecordError, PutRecordOk, PutRecordPhase, PutRecordResult, QueryInfo, QueryMut, QueryRef, QueryResult, QueryStats, RoutingUpdate, From a62fa23fc66d22e38656b11bf8aa53fc5a55b101 Mon Sep 17 00:00:00 2001 From: Darius Date: Wed, 28 Jun 2023 22:22:12 -0400 Subject: [PATCH 02/24] chore: Return on ExplicitMode::Auto --- protocols/kad/src/behaviour.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index bb96f673d9e..563228835fb 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -999,7 +999,9 @@ where match self.explicit_mode { ExplicitMode::Client => self.mode = Mode::Client, ExplicitMode::Server => self.mode = Mode::Server, - ExplicitMode::Auto => {} + ExplicitMode::Auto => { + return; + } } if !self.connections.is_empty() { From 94e8ddfc9eddba3988f3e389ec0f1699ef1cea7a Mon Sep 17 00:00:00 2001 From: Darius Date: Wed, 28 Jun 2023 22:34:51 -0400 Subject: [PATCH 03/24] chore: Formatted code --- protocols/kad/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/protocols/kad/src/lib.rs b/protocols/kad/src/lib.rs index 56b02bdab34..1aa7de09687 100644 --- a/protocols/kad/src/lib.rs +++ b/protocols/kad/src/lib.rs @@ -66,11 +66,11 @@ mod proto { pub use addresses::Addresses; pub use behaviour::{ AddProviderContext, AddProviderError, AddProviderOk, AddProviderPhase, AddProviderResult, - BootstrapError, BootstrapOk, BootstrapResult, GetClosestPeersError, GetClosestPeersOk, - GetClosestPeersResult, GetProvidersError, GetProvidersOk, ExplicitMode, GetProvidersResult, GetRecordError, - GetRecordOk, GetRecordResult, InboundRequest, NoKnownPeers, PeerRecord, PutRecordContext, - PutRecordError, PutRecordOk, PutRecordPhase, PutRecordResult, QueryInfo, QueryMut, QueryRef, - QueryResult, QueryStats, RoutingUpdate, + BootstrapError, BootstrapOk, BootstrapResult, ExplicitMode, GetClosestPeersError, + GetClosestPeersOk, GetClosestPeersResult, GetProvidersError, GetProvidersOk, + GetProvidersResult, GetRecordError, GetRecordOk, GetRecordResult, InboundRequest, NoKnownPeers, + PeerRecord, PutRecordContext, PutRecordError, PutRecordOk, PutRecordPhase, PutRecordResult, + QueryInfo, QueryMut, QueryRef, QueryResult, QueryStats, RoutingUpdate, }; pub use behaviour::{ Kademlia, KademliaBucketInserts, KademliaCaching, KademliaConfig, KademliaEvent, From d9f7ab82d44ea3563efe244e4b1d32c0fbf94b20 Mon Sep 17 00:00:00 2001 From: Darius Date: Fri, 30 Jun 2023 08:42:59 -0400 Subject: [PATCH 04/24] chore: Remove ExplicitMode and add auto_mode and waker field --- protocols/kad/src/behaviour.rs | 57 +++++++++++++++++++--------------- protocols/kad/src/lib.rs | 10 +++--- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 563228835fb..ab5883763d1 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -52,7 +52,7 @@ use smallvec::SmallVec; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::fmt; use std::num::NonZeroUsize; -use std::task::{Context, Poll}; +use std::task::{Context, Poll, Waker}; use std::time::Duration; use std::vec; use thiserror::Error; @@ -115,7 +115,9 @@ pub struct Kademlia { mode: Mode, - explicit_mode: ExplicitMode, + auto_mode: bool, + + waker: Option, /// The record storage. store: TStore, @@ -458,7 +460,8 @@ where local_peer_id: id, connections: Default::default(), mode: Mode::Client, - explicit_mode: ExplicitMode::Auto, + auto_mode: true, + waker: None, } } @@ -993,30 +996,32 @@ where id } - pub fn set_explicit_mode(&mut self, mode: ExplicitMode) { - self.explicit_mode = mode; - - match self.explicit_mode { - ExplicitMode::Client => self.mode = Mode::Client, - ExplicitMode::Server => self.mode = Mode::Server, - ExplicitMode::Auto => { - return; + pub fn set_explicit_mode(&mut self, mode: Option) { + match mode { + Some(mode) => { + self.mode = mode; + self.auto_mode = false; + + if !self.connections.is_empty() { + self.queued_events + .extend(self.connections.iter().map(|(conn_id, peer_id)| { + ToSwarm::NotifyHandler { + peer_id: *peer_id, + handler: NotifyHandler::One(*conn_id), + event: KademliaHandlerIn::ReconfigureMode { + new_mode: self.mode, + }, + } + })); + } + } + None => { + self.auto_mode = true; } } - if !self.connections.is_empty() { - self.queued_events - .extend( - self.connections - .iter() - .map(|(conn_id, peer_id)| ToSwarm::NotifyHandler { - peer_id: *peer_id, - handler: NotifyHandler::One(*conn_id), - event: KademliaHandlerIn::ReconfigureMode { - new_mode: self.mode, - }, - }), - ); + if let Some(waker) = self.waker.take() { + waker.wake(); } } @@ -2454,6 +2459,8 @@ where } } + self.waker = Some(cx.waker().clone()); + // No immediate event was produced as a result of a finished query. // If no new events have been queued either, signal `NotReady` to // be polled again later. @@ -2467,7 +2474,7 @@ where self.listen_addresses.on_swarm_event(&event); let external_addresses_changed = self.external_addresses.on_swarm_event(&event); - if matches!(self.explicit_mode, ExplicitMode::Auto) { + if self.auto_mode { self.mode = match (self.external_addresses.as_slice(), self.mode) { ([], Mode::Server) => { log::debug!("Switching to client-mode because we no longer have any confirmed external addresses"); diff --git a/protocols/kad/src/lib.rs b/protocols/kad/src/lib.rs index 1aa7de09687..ccdb06b885d 100644 --- a/protocols/kad/src/lib.rs +++ b/protocols/kad/src/lib.rs @@ -66,11 +66,11 @@ mod proto { pub use addresses::Addresses; pub use behaviour::{ AddProviderContext, AddProviderError, AddProviderOk, AddProviderPhase, AddProviderResult, - BootstrapError, BootstrapOk, BootstrapResult, ExplicitMode, GetClosestPeersError, - GetClosestPeersOk, GetClosestPeersResult, GetProvidersError, GetProvidersOk, - GetProvidersResult, GetRecordError, GetRecordOk, GetRecordResult, InboundRequest, NoKnownPeers, - PeerRecord, PutRecordContext, PutRecordError, PutRecordOk, PutRecordPhase, PutRecordResult, - QueryInfo, QueryMut, QueryRef, QueryResult, QueryStats, RoutingUpdate, + BootstrapError, BootstrapOk, BootstrapResult, GetClosestPeersError, GetClosestPeersOk, + GetClosestPeersResult, GetProvidersError, GetProvidersOk, GetProvidersResult, GetRecordError, + GetRecordOk, GetRecordResult, InboundRequest, Mode, NoKnownPeers, PeerRecord, PutRecordContext, + PutRecordError, PutRecordOk, PutRecordPhase, PutRecordResult, QueryInfo, QueryMut, QueryRef, + QueryResult, QueryStats, RoutingUpdate, }; pub use behaviour::{ Kademlia, KademliaBucketInserts, KademliaCaching, KademliaConfig, KademliaEvent, From 048607bc091b47c29e9f0b860f6333d7f96eca2d Mon Sep 17 00:00:00 2001 From: Darius Date: Fri, 30 Jun 2023 09:30:11 -0400 Subject: [PATCH 05/24] chore: Remove ExplicitMode --- protocols/kad/src/behaviour.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index ab5883763d1..a7e5191b3d1 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -3312,23 +3312,6 @@ impl fmt::Display for Mode { } } -#[derive(PartialEq, Copy, Clone, Debug)] -pub enum ExplicitMode { - Auto, - Client, - Server, -} - -impl fmt::Display for ExplicitMode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ExplicitMode::Auto => write!(f, "auto"), - ExplicitMode::Client => write!(f, "client"), - ExplicitMode::Server => write!(f, "server"), - } - } -} - fn to_comma_separated_list(confirmed_external_addresses: &[T]) -> String where T: ToString, From 437be0f48bc15db8acce9cf8b80bb3e9bf443e31 Mon Sep 17 00:00:00 2001 From: Darius Date: Fri, 30 Jun 2023 11:57:17 -0400 Subject: [PATCH 06/24] chore: Move into a single function --- protocols/kad/src/behaviour.rs | 38 +++++++++++++++------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index a7e5191b3d1..549de5164d9 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -1001,18 +1001,8 @@ where Some(mode) => { self.mode = mode; self.auto_mode = false; - if !self.connections.is_empty() { - self.queued_events - .extend(self.connections.iter().map(|(conn_id, peer_id)| { - ToSwarm::NotifyHandler { - peer_id: *peer_id, - handler: NotifyHandler::One(*conn_id), - event: KademliaHandlerIn::ReconfigureMode { - new_mode: self.mode, - }, - } - })); + self.reconfigure_mode(); } } None => { @@ -1025,6 +1015,21 @@ where } } + fn reconfigure_mode(&mut self) { + self.queued_events + .extend( + self.connections + .iter() + .map(|(conn_id, peer_id)| ToSwarm::NotifyHandler { + peer_id: *peer_id, + handler: NotifyHandler::One(*conn_id), + event: KademliaHandlerIn::ReconfigureMode { + new_mode: self.mode, + }, + }), + ); + } + /// Processes discovered peers from a successful request in an iterative `Query`. fn discovered<'a, I>(&'a mut self, query_id: &QueryId, source: &PeerId, peers: I) where @@ -2517,16 +2522,7 @@ where if num_connections > 1 { "s" } else { "" } ); - self.queued_events - .extend(self.connections.iter().map(|(conn_id, peer_id)| { - ToSwarm::NotifyHandler { - peer_id: *peer_id, - handler: NotifyHandler::One(*conn_id), - event: KademliaHandlerIn::ReconfigureMode { - new_mode: self.mode, - }, - } - })); + self.reconfigure_mode(); } } From 884ce0c2a72150d7d062bd9f0100c25d8bb2923e Mon Sep 17 00:00:00 2001 From: Darius Date: Fri, 30 Jun 2023 11:58:28 -0400 Subject: [PATCH 07/24] chore: Group fields together --- protocols/kad/src/behaviour.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 549de5164d9..62c9d1da585 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -114,9 +114,7 @@ pub struct Kademlia { local_peer_id: PeerId, mode: Mode, - auto_mode: bool, - waker: Option, /// The record storage. From 6faeade6afbaf0cded43d30df0bcc77f2d72c5c9 Mon Sep 17 00:00:00 2001 From: Darius Date: Sat, 1 Jul 2023 00:04:05 -0400 Subject: [PATCH 08/24] chore: added test set_client_to_server_mode --- protocols/kad/tests/client_mode.rs | 48 +++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/protocols/kad/tests/client_mode.rs b/protocols/kad/tests/client_mode.rs index afd35ab0686..f81b793b596 100644 --- a/protocols/kad/tests/client_mode.rs +++ b/protocols/kad/tests/client_mode.rs @@ -1,7 +1,7 @@ use libp2p_identify as identify; use libp2p_identity as identity; use libp2p_kad::store::MemoryStore; -use libp2p_kad::{Kademlia, KademliaConfig, KademliaEvent}; +use libp2p_kad::{Kademlia, KademliaConfig, KademliaEvent, Mode}; use libp2p_swarm::Swarm; use libp2p_swarm_test::SwarmExt; @@ -111,6 +111,52 @@ async fn adding_an_external_addresses_activates_server_mode_on_existing_connecti } } +#[async_std::test] +async fn set_client_to_server_mode() { + let _ = env_logger::try_init(); + + let mut client = Swarm::new_ephemeral(MyBehaviour::new); + client + .behaviour_mut() + .kad + .set_explicit_mode(Some(Mode::Client)); + + let mut server = Swarm::new_ephemeral(MyBehaviour::new); + + server.listen().await; + client.connect(&mut server).await; + + let server_peer_id = *server.local_peer_id(); + + match libp2p_swarm_test::drive(&mut client, &mut server).await { + ( + [MyBehaviourEvent::Identify(_), MyBehaviourEvent::Identify(_), MyBehaviourEvent::Kad(KademliaEvent::RoutingUpdated { peer, .. })], + [MyBehaviourEvent::Identify(_), MyBehaviourEvent::Identify(_)], + ) => { + assert_eq!(peer, server_peer_id) + } + other => panic!("Unexpected events: {other:?}"), + } + + client + .behaviour_mut() + .kad + .set_explicit_mode(Some(Mode::Server)); + + match libp2p_swarm_test::drive(&mut client, &mut server).await { + ( + [MyBehaviourEvent::Identify(_)], + [MyBehaviourEvent::Identify(identify::Event::Received { info, .. }), MyBehaviourEvent::Kad(_)], + ) => { + assert!(info + .protocols + .iter() + .any(|proto| libp2p_kad::PROTOCOL_NAME.eq(proto))) + } + other => panic!("Unexpected events: {other:?}"), + } +} + #[derive(libp2p_swarm::NetworkBehaviour)] #[behaviour(prelude = "libp2p_swarm::derive_prelude")] struct MyBehaviour { From ce2bb2a4b7c387949781cab6c0f8c56906a4cd65 Mon Sep 17 00:00:00 2001 From: Darius Date: Sat, 1 Jul 2023 02:19:45 -0400 Subject: [PATCH 09/24] chore: Update test --- protocols/kad/tests/client_mode.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/protocols/kad/tests/client_mode.rs b/protocols/kad/tests/client_mode.rs index f81b793b596..1b3c0ff1250 100644 --- a/protocols/kad/tests/client_mode.rs +++ b/protocols/kad/tests/client_mode.rs @@ -131,9 +131,13 @@ async fn set_client_to_server_mode() { match libp2p_swarm_test::drive(&mut client, &mut server).await { ( [MyBehaviourEvent::Identify(_), MyBehaviourEvent::Identify(_), MyBehaviourEvent::Kad(KademliaEvent::RoutingUpdated { peer, .. })], - [MyBehaviourEvent::Identify(_), MyBehaviourEvent::Identify(_)], + [MyBehaviourEvent::Identify(_), MyBehaviourEvent::Identify(identify::Event::Received { info, .. })], ) => { - assert_eq!(peer, server_peer_id) + assert_eq!(peer, server_peer_id); + assert!(info + .protocols + .iter() + .any(|proto| libp2p_kad::PROTOCOL_NAME.ne(proto))) } other => panic!("Unexpected events: {other:?}"), } From bb42582c4f6d1e48a1c8bac70d7c2517b1c57c8a Mon Sep 17 00:00:00 2001 From: Darius Date: Sat, 1 Jul 2023 02:44:15 -0400 Subject: [PATCH 10/24] chore: Update CHANGELOG.md --- protocols/kad/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 899f2519a98..420e2b72f73 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.44.2 - unreleased + +- feat(kad): allow to explicitly set Mode::{Client,Server} + See [PR 4132] + +[PR 4132]: https://github.com/libp2p/rust-libp2p/pull/4132 + ## 0.44.1 - Expose `KBucketDistance`. From 0423bcb831e1eaf03189b7103281ad8221a23be6 Mon Sep 17 00:00:00 2001 From: Darius Date: Sat, 1 Jul 2023 23:04:37 -0400 Subject: [PATCH 11/24] chore: Redetermine mode when setting mode to None --- protocols/kad/src/behaviour.rs | 91 ++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 62c9d1da585..b689395e5b2 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -1005,6 +1005,7 @@ where } None => { self.auto_mode = true; + self.determine_mode(); } } @@ -1028,6 +1029,45 @@ where ); } + fn determine_mode(&mut self) { + self.mode = match (self.external_addresses.as_slice(), self.mode) { + ([], Mode::Server) => { + log::debug!("Switching to client-mode because we no longer have any confirmed external addresses"); + + Mode::Client + } + ([], Mode::Client) => { + // Previously client-mode, now also client-mode because no external addresses. + + Mode::Client + } + (confirmed_external_addresses, Mode::Client) => { + if log::log_enabled!(log::Level::Debug) { + let confirmed_external_addresses = + to_comma_separated_list(confirmed_external_addresses); + + log::debug!("Switching to server-mode assuming that one of [{confirmed_external_addresses}] is externally reachable"); + } + + Mode::Server + } + (confirmed_external_addresses, Mode::Server) => { + debug_assert!( + !confirmed_external_addresses.is_empty(), + "Previous match arm handled empty list" + ); + + // Previously, server-mode, now also server-mode because > 1 external address. Don't log anything to avoid spam. + + Mode::Server + } + }; + + if !self.connections.is_empty() { + self.reconfigure_mode(); + } + } + /// Processes discovered peers from a successful request in an iterative `Query`. fn discovered<'a, I>(&'a mut self, query_id: &QueryId, source: &PeerId, peers: I) where @@ -2477,51 +2517,16 @@ where self.listen_addresses.on_swarm_event(&event); let external_addresses_changed = self.external_addresses.on_swarm_event(&event); - if self.auto_mode { - self.mode = match (self.external_addresses.as_slice(), self.mode) { - ([], Mode::Server) => { - log::debug!("Switching to client-mode because we no longer have any confirmed external addresses"); + if self.auto_mode && external_addresses_changed { + let num_connections = self.connections.len(); - Mode::Client - } - ([], Mode::Client) => { - // Previously client-mode, now also client-mode because no external addresses. - - Mode::Client - } - (confirmed_external_addresses, Mode::Client) => { - if log::log_enabled!(log::Level::Debug) { - let confirmed_external_addresses = - to_comma_separated_list(confirmed_external_addresses); - - log::debug!("Switching to server-mode assuming that one of [{confirmed_external_addresses}] is externally reachable"); - } - - Mode::Server - } - (confirmed_external_addresses, Mode::Server) => { - debug_assert!( - !confirmed_external_addresses.is_empty(), - "Previous match arm handled empty list" - ); - - // Previously, server-mode, now also server-mode because > 1 external address. Don't log anything to avoid spam. - - Mode::Server - } - }; - - if external_addresses_changed && !self.connections.is_empty() { - let num_connections = self.connections.len(); - - log::debug!( - "External addresses changed, re-configuring {} established connection{}", - num_connections, - if num_connections > 1 { "s" } else { "" } - ); + log::debug!( + "External addresses changed, re-configuring {} established connection{}", + num_connections, + if num_connections > 1 { "s" } else { "" } + ); - self.reconfigure_mode(); - } + self.determine_mode(); } match event { From a3f43ce7f9d3120349fed1473dc65c51bc422bba Mon Sep 17 00:00:00 2001 From: Darius Clark Date: Sun, 2 Jul 2023 03:04:42 -0400 Subject: [PATCH 12/24] Update protocols/kad/tests/client_mode.rs Co-authored-by: Max Inden --- protocols/kad/tests/client_mode.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/kad/tests/client_mode.rs b/protocols/kad/tests/client_mode.rs index 1b3c0ff1250..22be54e6185 100644 --- a/protocols/kad/tests/client_mode.rs +++ b/protocols/kad/tests/client_mode.rs @@ -137,7 +137,7 @@ async fn set_client_to_server_mode() { assert!(info .protocols .iter() - .any(|proto| libp2p_kad::PROTOCOL_NAME.ne(proto))) + .all(|proto| libp2p_kad::PROTOCOL_NAME.ne(proto))) } other => panic!("Unexpected events: {other:?}"), } From 7974cefe64e09987338dcede560264f72eaf490f Mon Sep 17 00:00:00 2001 From: Darius Clark Date: Sun, 2 Jul 2023 03:28:11 -0400 Subject: [PATCH 13/24] Update protocols/kad/src/behaviour.rs Co-authored-by: Max Inden --- protocols/kad/src/behaviour.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 62c9d1da585..8b7d2ac2e8f 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -994,7 +994,8 @@ where id } - pub fn set_explicit_mode(&mut self, mode: Option) { + /// Either set Kademlia [`Mode`] explicitly via `Some(_)` or enable automatic configuration of the Kademlia [`Mode`] based on the external addresses available via `None`. + pub fn set_mode(&mut self, mode: Option) { match mode { Some(mode) => { self.mode = mode; From bc260c7db065b36b0f423d0cda858542ef50ee53 Mon Sep 17 00:00:00 2001 From: Darius Date: Sun, 2 Jul 2023 11:11:41 -0400 Subject: [PATCH 14/24] fix: Correct test --- protocols/kad/tests/client_mode.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocols/kad/tests/client_mode.rs b/protocols/kad/tests/client_mode.rs index 22be54e6185..7062c44173c 100644 --- a/protocols/kad/tests/client_mode.rs +++ b/protocols/kad/tests/client_mode.rs @@ -119,7 +119,7 @@ async fn set_client_to_server_mode() { client .behaviour_mut() .kad - .set_explicit_mode(Some(Mode::Client)); + .set_mode(Some(Mode::Client)); let mut server = Swarm::new_ephemeral(MyBehaviour::new); @@ -145,7 +145,7 @@ async fn set_client_to_server_mode() { client .behaviour_mut() .kad - .set_explicit_mode(Some(Mode::Server)); + .set_mode(Some(Mode::Server)); match libp2p_swarm_test::drive(&mut client, &mut server).await { ( From f23a7f9fd02681d3bf8c25120befe08161f48f0f Mon Sep 17 00:00:00 2001 From: Darius Date: Sun, 2 Jul 2023 11:52:11 -0400 Subject: [PATCH 15/24] chore: Format code --- protocols/kad/tests/client_mode.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/protocols/kad/tests/client_mode.rs b/protocols/kad/tests/client_mode.rs index 7062c44173c..b2530569518 100644 --- a/protocols/kad/tests/client_mode.rs +++ b/protocols/kad/tests/client_mode.rs @@ -116,10 +116,7 @@ async fn set_client_to_server_mode() { let _ = env_logger::try_init(); let mut client = Swarm::new_ephemeral(MyBehaviour::new); - client - .behaviour_mut() - .kad - .set_mode(Some(Mode::Client)); + client.behaviour_mut().kad.set_mode(Some(Mode::Client)); let mut server = Swarm::new_ephemeral(MyBehaviour::new); @@ -142,10 +139,7 @@ async fn set_client_to_server_mode() { other => panic!("Unexpected events: {other:?}"), } - client - .behaviour_mut() - .kad - .set_mode(Some(Mode::Server)); + client.behaviour_mut().kad.set_mode(Some(Mode::Server)); match libp2p_swarm_test::drive(&mut client, &mut server).await { ( From 82be8cd913770ceff79a69a5108e9895b2923dc7 Mon Sep 17 00:00:00 2001 From: Darius Clark Date: Mon, 3 Jul 2023 11:28:25 -0400 Subject: [PATCH 16/24] Update protocols/kad/CHANGELOG.md Co-authored-by: Thomas Eizinger --- protocols/kad/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 420e2b72f73..35cc73e14b0 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.44.2 - unreleased -- feat(kad): allow to explicitly set Mode::{Client,Server} +- Allow to explicitly set `Mode::{Client,Server}`. See [PR 4132] [PR 4132]: https://github.com/libp2p/rust-libp2p/pull/4132 From 9af4772f51a441f42d9d35789a5712952f14b2db Mon Sep 17 00:00:00 2001 From: Darius Date: Mon, 3 Jul 2023 11:34:15 -0400 Subject: [PATCH 17/24] chore: if statement into reconfigure_mode --- protocols/kad/src/behaviour.rs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index a1b0a28f749..56373471941 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -1000,9 +1000,7 @@ where Some(mode) => { self.mode = mode; self.auto_mode = false; - if !self.connections.is_empty() { - self.reconfigure_mode(); - } + self.reconfigure_mode(); } None => { self.auto_mode = true; @@ -1016,18 +1014,20 @@ where } fn reconfigure_mode(&mut self) { - self.queued_events - .extend( - self.connections - .iter() - .map(|(conn_id, peer_id)| ToSwarm::NotifyHandler { - peer_id: *peer_id, - handler: NotifyHandler::One(*conn_id), - event: KademliaHandlerIn::ReconfigureMode { - new_mode: self.mode, - }, - }), - ); + if !self.connections.is_empty() { + self.queued_events + .extend( + self.connections + .iter() + .map(|(conn_id, peer_id)| ToSwarm::NotifyHandler { + peer_id: *peer_id, + handler: NotifyHandler::One(*conn_id), + event: KademliaHandlerIn::ReconfigureMode { + new_mode: self.mode, + }, + }), + ); + } } fn determine_mode(&mut self) { @@ -1064,9 +1064,7 @@ where } }; - if !self.connections.is_empty() { - self.reconfigure_mode(); - } + self.reconfigure_mode(); } /// Processes discovered peers from a successful request in an iterative `Query`. From bb18f70664d48f15a259cc93d051d00a20974a89 Mon Sep 17 00:00:00 2001 From: Darius Date: Mon, 3 Jul 2023 11:46:06 -0400 Subject: [PATCH 18/24] chore: Move log into reconfigure_mode --- protocols/kad/src/behaviour.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 56373471941..05c1015eea7 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -1015,6 +1015,14 @@ where fn reconfigure_mode(&mut self) { if !self.connections.is_empty() { + let num_connections = self.connections.len(); + + log::debug!( + "Re-configuring {} established connection{}", + num_connections, + if num_connections > 1 { "s" } else { "" } + ); + self.queued_events .extend( self.connections @@ -2517,14 +2525,6 @@ where let external_addresses_changed = self.external_addresses.on_swarm_event(&event); if self.auto_mode && external_addresses_changed { - let num_connections = self.connections.len(); - - log::debug!( - "External addresses changed, re-configuring {} established connection{}", - num_connections, - if num_connections > 1 { "s" } else { "" } - ); - self.determine_mode(); } From 5613545231233fc2157a4393ecd1261e7376852b Mon Sep 17 00:00:00 2001 From: Darius Clark Date: Mon, 3 Jul 2023 11:47:05 -0400 Subject: [PATCH 19/24] Update protocols/kad/src/behaviour.rs Co-authored-by: Thomas Eizinger --- protocols/kad/src/behaviour.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 05c1015eea7..88a530887d1 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -1038,7 +1038,7 @@ where } } - fn determine_mode(&mut self) { + fn determine_mode_from_external_addresses(&mut self) { self.mode = match (self.external_addresses.as_slice(), self.mode) { ([], Mode::Server) => { log::debug!("Switching to client-mode because we no longer have any confirmed external addresses"); From 39481febcfaa2b234ce10111f4571b7bb281761c Mon Sep 17 00:00:00 2001 From: Darius Date: Mon, 3 Jul 2023 11:55:19 -0400 Subject: [PATCH 20/24] chore: Rename method --- protocols/kad/src/behaviour.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 88a530887d1..ef0b0de2fae 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -1004,7 +1004,7 @@ where } None => { self.auto_mode = true; - self.determine_mode(); + self.determine_mode_from_external_addresses(); } } @@ -2525,7 +2525,7 @@ where let external_addresses_changed = self.external_addresses.on_swarm_event(&event); if self.auto_mode && external_addresses_changed { - self.determine_mode(); + self.determine_mode_from_external_addresses(); } match event { From 6e37c3c32c87131e2977fae498f503fccae262c0 Mon Sep 17 00:00:00 2001 From: Darius Date: Mon, 3 Jul 2023 14:59:59 -0400 Subject: [PATCH 21/24] chore: Return early and minor cleanup --- protocols/kad/src/behaviour.rs | 52 ++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index ef0b0de2fae..c70348d0df5 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -115,7 +115,7 @@ pub struct Kademlia { mode: Mode, auto_mode: bool, - waker: Option, + no_events_waker: Option, /// The record storage. store: TStore, @@ -459,7 +459,7 @@ where connections: Default::default(), mode: Mode::Client, auto_mode: true, - waker: None, + no_events_waker: None, } } @@ -1008,34 +1008,36 @@ where } } - if let Some(waker) = self.waker.take() { + if let Some(waker) = self.no_events_waker.take() { waker.wake(); } } fn reconfigure_mode(&mut self) { - if !self.connections.is_empty() { - let num_connections = self.connections.len(); + if self.connections.is_empty() { + return; + } - log::debug!( - "Re-configuring {} established connection{}", - num_connections, - if num_connections > 1 { "s" } else { "" } - ); + let num_connections = self.connections.len(); - self.queued_events - .extend( - self.connections - .iter() - .map(|(conn_id, peer_id)| ToSwarm::NotifyHandler { - peer_id: *peer_id, - handler: NotifyHandler::One(*conn_id), - event: KademliaHandlerIn::ReconfigureMode { - new_mode: self.mode, - }, - }), - ); - } + log::debug!( + "Re-configuring {} established connection{}", + num_connections, + if num_connections > 1 { "s" } else { "" } + ); + + self.queued_events + .extend( + self.connections + .iter() + .map(|(conn_id, peer_id)| ToSwarm::NotifyHandler { + peer_id: *peer_id, + handler: NotifyHandler::One(*conn_id), + event: KademliaHandlerIn::ReconfigureMode { + new_mode: self.mode, + }, + }), + ); } fn determine_mode_from_external_addresses(&mut self) { @@ -2509,12 +2511,12 @@ where } } - self.waker = Some(cx.waker().clone()); - // No immediate event was produced as a result of a finished query. // If no new events have been queued either, signal `NotReady` to // be polled again later. if self.queued_events.is_empty() { + self.no_events_waker = Some(cx.waker().clone()); + return Poll::Pending; } } From aed03b7f9d649a41c59a7cfee4921cc936fa166f Mon Sep 17 00:00:00 2001 From: Darius Clark Date: Mon, 3 Jul 2023 15:00:34 -0400 Subject: [PATCH 22/24] Update protocols/kad/src/behaviour.rs Co-authored-by: Thomas Eizinger --- protocols/kad/src/behaviour.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index ef0b0de2fae..855ba66217f 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -994,7 +994,12 @@ where id } - /// Either set Kademlia [`Mode`] explicitly via `Some(_)` or enable automatic configuration of the Kademlia [`Mode`] based on the external addresses available via `None`. + /// Set the [`Mode`] in which we should operate. + /// + /// By default, we are in [`Mode::Client`] and will swap into [`Mode::Server`] as soon as we have a confirmed, external address via [`FromSwarm::ExternalAddrConfirmed`]. + /// + /// Setting a mode via this function disables this automatic behaviour and unconditionally operates in the specified mode. + /// To reactivate the automatic configuration, pass [`None`] instead. pub fn set_mode(&mut self, mode: Option) { match mode { Some(mode) => { From 365b3c5c80a983c2d105745447b28e78eb8945e5 Mon Sep 17 00:00:00 2001 From: Darius Date: Mon, 3 Jul 2023 16:30:55 -0400 Subject: [PATCH 23/24] chore: Update version --- Cargo.lock | 2 +- protocols/kad/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0007a601858..b28954b8c4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2768,7 +2768,7 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.44.1" +version = "0.44.2" dependencies = [ "arrayvec", "async-std", diff --git a/protocols/kad/Cargo.toml b/protocols/kad/Cargo.toml index 72a90fbdb6c..5b71b384283 100644 --- a/protocols/kad/Cargo.toml +++ b/protocols/kad/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-kad" edition = "2021" rust-version = "1.65.0" description = "Kademlia protocol for libp2p" -version = "0.44.1" +version = "0.44.2" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" From 25921779389c23fe85d132646a8683ec5c9f4e1f Mon Sep 17 00:00:00 2001 From: Darius Date: Mon, 3 Jul 2023 16:46:05 -0400 Subject: [PATCH 24/24] chore: Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 321e81a24a1..db54152709f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,7 +73,7 @@ libp2p-floodsub = { version = "0.43.0", path = "protocols/floodsub" } libp2p-gossipsub = { version = "0.45.0", path = "protocols/gossipsub" } libp2p-identify = { version = "0.43.0", path = "protocols/identify" } libp2p-identity = { version = "0.2.1" } -libp2p-kad = { version = "0.44.1", path = "protocols/kad" } +libp2p-kad = { version = "0.44.2", path = "protocols/kad" } libp2p-mdns = { version = "0.44.0", path = "protocols/mdns" } libp2p-metrics = { version = "0.13.0", path = "misc/metrics" } libp2p-mplex = { version = "0.40.0", path = "muxers/mplex" }