Skip to content

Commit

Permalink
feat(rendezous): refresh registration on change to external addresses
Browse files Browse the repository at this point in the history
Resolves #4627.

Pull-Request: #4629.
  • Loading branch information
dariusc93 authored Oct 15, 2023
1 parent d72c67d commit 4686ce8
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ libp2p-plaintext = { version = "0.40.1", path = "transports/plaintext" }
libp2p-pnet = { version = "0.23.0", path = "transports/pnet" }
libp2p-quic = { version = "0.9.3", path = "transports/quic" }
libp2p-relay = { version = "0.16.1", path = "protocols/relay" }
libp2p-rendezvous = { version = "0.13.0", path = "protocols/rendezvous" }
libp2p-rendezvous = { version = "0.13.1", path = "protocols/rendezvous" }
libp2p-upnp = { version = "0.1.1", path = "protocols/upnp" }
libp2p-request-response = { version = "0.25.1", path = "protocols/request-response" }
libp2p-server = { version = "0.12.3", path = "misc/server" }
Expand Down
6 changes: 6 additions & 0 deletions protocols/rendezvous/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.13.1 - unreleased
- Refresh registration upon a change in external addresses.
See [PR 4629].

[PR 4629]: https://github.com/libp2p/rust-libp2p/pull/4629

## 0.13.0

- Changed the signature of the function `client::Behavior::register()`,
Expand Down
2 changes: 1 addition & 1 deletion protocols/rendezvous/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "libp2p-rendezvous"
edition = "2021"
rust-version = { workspace = true }
description = "Rendezvous protocol for libp2p"
version = "0.13.0"
version = "0.13.1"
authors = ["The COMIT guys <hello@comit.network>"]
license = "MIT"
repository = "https://github.com/libp2p/rust-libp2p"
Expand Down
20 changes: 19 additions & 1 deletion protocols/rendezvous/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub struct Behaviour {
/// Storing these internally allows us to assist the [`libp2p_swarm::Swarm`] in dialing by returning addresses from [`NetworkBehaviour::handle_pending_outbound_connection`].
discovered_peers: HashMap<(PeerId, Namespace), Vec<Multiaddr>>,

registered_namespaces: HashMap<(PeerId, Namespace), Ttl>,

/// Tracks the expiry of registrations that we have discovered and stored in `discovered_peers` otherwise we have a memory leak.
expiring_registrations: FuturesUnordered<BoxFuture<'static, (PeerId, Namespace)>>,

Expand All @@ -68,6 +70,7 @@ impl Behaviour {
waiting_for_register: Default::default(),
waiting_for_discovery: Default::default(),
discovered_peers: Default::default(),
registered_namespaces: Default::default(),
expiring_registrations: FuturesUnordered::from_iter(vec![
futures::future::pending().boxed()
]),
Expand Down Expand Up @@ -103,6 +106,9 @@ impl Behaviour {

/// Unregister ourselves from the given namespace with the given rendezvous peer.
pub fn unregister(&mut self, namespace: Namespace, rendezvous_node: PeerId) {
self.registered_namespaces
.retain(|(rz_node, ns), _| rz_node.ne(&rendezvous_node) && ns.ne(&namespace));

self.inner
.send_request(&rendezvous_node, Unregister(namespace));
}
Expand Down Expand Up @@ -218,9 +224,18 @@ impl NetworkBehaviour for Behaviour {
}

fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
self.external_addresses.on_swarm_event(&event);
let changed = self.external_addresses.on_swarm_event(&event);

self.inner.on_swarm_event(event);

if changed && self.external_addresses.iter().count() > 0 {
let registered = self.registered_namespaces.clone();
for ((rz_node, ns), ttl) in registered {
if let Err(e) = self.register(ns, rz_node, Some(ttl)) {
log::warn!("refreshing registration failed: {e}")
}
}
}
}

fn poll(
Expand Down Expand Up @@ -348,6 +363,9 @@ impl Behaviour {
if let Some((rendezvous_node, namespace)) =
self.waiting_for_register.remove(request_id)
{
self.registered_namespaces
.insert((rendezvous_node, namespace.clone()), ttl);

return Some(Event::Registered {
rendezvous_node,
ttl,
Expand Down
53 changes: 53 additions & 0 deletions protocols/rendezvous/tests/rendezvous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

use futures::stream::FuturesUnordered;
use futures::StreamExt;
use libp2p_core::multiaddr::Protocol;
use libp2p_core::Multiaddr;
use libp2p_identity as identity;
use libp2p_rendezvous as rendezvous;
use libp2p_rendezvous::client::RegisterError;
Expand Down Expand Up @@ -162,6 +164,57 @@ async fn given_successful_registration_then_refresh_ttl() {
}
}

#[tokio::test]
async fn given_successful_registration_then_refresh_external_addrs() {
let _ = env_logger::try_init();
let namespace = rendezvous::Namespace::from_static("some-namespace");
let ([mut alice], mut robert) =
new_server_with_connected_clients(rendezvous::server::Config::default()).await;

let roberts_peer_id = *robert.local_peer_id();

alice
.behaviour_mut()
.register(namespace.clone(), roberts_peer_id, None)
.unwrap();

match libp2p_swarm_test::drive(&mut alice, &mut robert).await {
(
[rendezvous::client::Event::Registered { .. }],
[rendezvous::server::Event::PeerRegistered { .. }],
) => {}
events => panic!("Unexpected events: {events:?}"),
}

let external_addr = Multiaddr::empty().with(Protocol::Memory(0));

alice.add_external_address(external_addr.clone());

match libp2p_swarm_test::drive(&mut alice, &mut robert).await {
(
[rendezvous::client::Event::Registered { .. }],
[rendezvous::server::Event::PeerRegistered { registration, .. }],
) => {
let record = registration.record;
assert!(record.addresses().contains(&external_addr));
}
events => panic!("Unexpected events: {events:?}"),
}

alice.remove_external_address(&external_addr);

match libp2p_swarm_test::drive(&mut alice, &mut robert).await {
(
[rendezvous::client::Event::Registered { .. }],
[rendezvous::server::Event::PeerRegistered { registration, .. }],
) => {
let record = registration.record;
assert!(!record.addresses().contains(&external_addr));
}
events => panic!("Unexpected events: {events:?}"),
}
}

#[tokio::test]
async fn given_invalid_ttl_then_unsuccessful_registration() {
let _ = env_logger::try_init();
Expand Down

0 comments on commit 4686ce8

Please sign in to comment.