From d26e04a2edb1b028ea3a1f402732d311f246ddd5 Mon Sep 17 00:00:00 2001 From: Dave Huseby Date: Fri, 20 Oct 2023 00:53:37 -0600 Subject: [PATCH] feat(kad): report automatic changes to kad mode Previously, the kademlia protocol would only log changes to the internal mode. With this patch, we now also emit an event which allows users to code against the internal state of the kademlia protocol. Fixes #4310. Pull-Request: #4503. --- protocols/kad/CHANGELOG.md | 2 ++ protocols/kad/src/behaviour.rs | 15 +++++++++++++++ protocols/kad/src/behaviour/test.rs | 2 ++ protocols/kad/tests/client_mode.rs | 11 +++++++---- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/protocols/kad/CHANGELOG.md b/protocols/kad/CHANGELOG.md index 5a9c0974652..f7ee68f46b5 100644 --- a/protocols/kad/CHANGELOG.md +++ b/protocols/kad/CHANGELOG.md @@ -1,5 +1,7 @@ ## 0.45.0 - unreleased +- Emit `ModeChanged` event whenever we automatically reconfigure the mode. + See [PR 4503](https://github.com/libp2p/rust-libp2p/pull/4503). ## 0.44.6 diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index bf0cfdd4cea..b92ff1c03b3 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -1048,6 +1048,8 @@ where } fn determine_mode_from_external_addresses(&mut self) { + let old_mode = self.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"); @@ -1082,6 +1084,13 @@ where }; self.reconfigure_mode(); + + if old_mode != self.mode { + self.queued_events + .push_back(ToSwarm::GenerateEvent(Event::ModeChanged { + new_mode: self.mode, + })); + } } /// Processes discovered peers from a successful request in an iterative `Query`. @@ -2673,6 +2682,12 @@ pub enum Event { /// See [`Behaviour::kbucket`] for insight into the contents of /// the k-bucket of `peer`. PendingRoutablePeer { peer: PeerId, address: Multiaddr }, + + /// This peer's mode has been updated automatically. + /// + /// This happens in response to an external + /// address being added or removed. + ModeChanged { new_mode: Mode }, } /// Information about progress events. diff --git a/protocols/kad/src/behaviour/test.rs b/protocols/kad/src/behaviour/test.rs index 79826d2653b..bb96a2f04ec 100644 --- a/protocols/kad/src/behaviour/test.rs +++ b/protocols/kad/src/behaviour/test.rs @@ -1059,6 +1059,7 @@ fn exceed_jobs_max_queries() { result: QueryResult::GetClosestPeers(Ok(r)), .. }) => break assert!(r.peers.is_empty()), + SwarmEvent::Behaviour(Event::ModeChanged { .. }) => {} SwarmEvent::Behaviour(e) => panic!("Unexpected event: {e:?}"), _ => {} } @@ -1382,6 +1383,7 @@ fn get_providers_single() { result: QueryResult::StartProviding(Ok(_)), .. }) => {} + SwarmEvent::Behaviour(Event::ModeChanged { .. }) => {} SwarmEvent::Behaviour(e) => panic!("Unexpected event: {e:?}"), _ => {} } diff --git a/protocols/kad/tests/client_mode.rs b/protocols/kad/tests/client_mode.rs index ff91dec082b..13bf08bd288 100644 --- a/protocols/kad/tests/client_mode.rs +++ b/protocols/kad/tests/client_mode.rs @@ -82,21 +82,24 @@ async fn adding_an_external_addresses_activates_server_mode_on_existing_connecti // Remove memory address to simulate a server that doesn't know its external address. server.remove_external_address(&memory_addr); client.dial(memory_addr.clone()).unwrap(); - // Do the usual identify send/receive dance. + // Do the usual identify send/receive dance. This triggers a mode change to Mode::Client. match libp2p_swarm_test::drive(&mut client, &mut server).await { - ([Identify(_), Identify(_)], [Identify(_), Identify(_)]) => {} + ([Identify(_), Identify(_)], [Kad(ModeChanged { new_mode }), Identify(_), Identify(_)]) => { + assert_eq!(new_mode, Mode::Client); + } other => panic!("Unexpected events: {other:?}"), } // Server learns its external address (this could be through AutoNAT or some other mechanism). server.add_external_address(memory_addr); - // The server reconfigured its connection to the client to be in server mode, pushes that information to client which as a result updates its routing table. + // The server reconfigured its connection to the client to be in server mode, pushes that information to client which as a result updates its routing table and triggers a mode change to Mode::Server. match libp2p_swarm_test::drive(&mut client, &mut server).await { ( [Identify(identify::Event::Received { .. }), Kad(RoutingUpdated { peer: peer1, .. })], - [Identify(identify::Event::Pushed { .. })], + [Kad(ModeChanged { new_mode }), Identify(identify::Event::Pushed { .. })], ) => { + assert_eq!(new_mode, Mode::Server); assert_eq!(peer1, server_peer_id); } other => panic!("Unexpected events: {other:?}"),