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:?}"),