Skip to content

Commit

Permalink
feat(kad): report automatic changes to kad mode
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dhuseby authored Oct 20, 2023
1 parent eb8fffa commit d26e04a
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 4 deletions.
2 changes: 2 additions & 0 deletions protocols/kad/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
15 changes: 15 additions & 0 deletions protocols/kad/src/behaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions protocols/kad/src/behaviour/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:?}"),
_ => {}
}
Expand Down Expand Up @@ -1382,6 +1383,7 @@ fn get_providers_single() {
result: QueryResult::StartProviding(Ok(_)),
..
}) => {}
SwarmEvent::Behaviour(Event::ModeChanged { .. }) => {}
SwarmEvent::Behaviour(e) => panic!("Unexpected event: {e:?}"),
_ => {}
}
Expand Down
11 changes: 7 additions & 4 deletions protocols/kad/tests/client_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:?}"),
Expand Down

0 comments on commit d26e04a

Please sign in to comment.