From 73b48b5321df23895e4872df9d5841f85b86ac41 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 16 May 2023 13:40:51 +0200 Subject: [PATCH 01/17] Initial refactoring to new events --- misc/allow-block-list/src/lib.rs | 5 +- misc/connection-limits/src/lib.rs | 5 +- protocols/autonat/src/behaviour.rs | 11 ++- protocols/autonat/src/behaviour/as_client.rs | 20 +--- protocols/dcutr/src/behaviour_impl.rs | 5 +- protocols/floodsub/src/layer.rs | 5 +- protocols/gossipsub/src/behaviour.rs | 5 +- protocols/identify/src/behaviour.rs | 15 ++- protocols/kad/src/behaviour.rs | 5 +- protocols/mdns/src/behaviour.rs | 5 +- protocols/perf/src/client/behaviour.rs | 5 +- protocols/perf/src/server/behaviour.rs | 5 +- protocols/ping/src/lib.rs | 5 +- protocols/relay/src/behaviour.rs | 5 +- protocols/relay/src/priv_client.rs | 5 +- protocols/rendezvous/src/client.rs | 5 +- protocols/rendezvous/src/server.rs | 5 +- protocols/request-response/src/lib.rs | 5 +- swarm-derive/src/lib.rs | 65 +++++++++---- swarm/src/behaviour.rs | 72 +++++++------- swarm/src/behaviour/external_addresses.rs | 10 +- swarm/src/dummy.rs | 5 +- swarm/src/keep_alive.rs | 5 +- swarm/src/lib.rs | 98 ++++++++++++-------- swarm/src/test.rs | 19 ++-- swarm/tests/swarm_derive.rs | 5 +- 26 files changed, 232 insertions(+), 168 deletions(-) diff --git a/misc/allow-block-list/src/lib.rs b/misc/allow-block-list/src/lib.rs index 521aa0026cc..eba747462fe 100644 --- a/misc/allow-block-list/src/lib.rs +++ b/misc/allow-block-list/src/lib.rs @@ -243,8 +243,9 @@ where FromSwarm::ExpiredListenAddr(_) => {} FromSwarm::ListenerError(_) => {} FromSwarm::ListenerClosed(_) => {} - FromSwarm::NewExternalAddr(_) => {} - FromSwarm::ExpiredExternalAddr(_) => {} + FromSwarm::NewExternalAddrCandidate(_) => {} + FromSwarm::ExternalAddrExpired(_) => {} + FromSwarm::ExternalAddrConfirmed(_) => {} } } diff --git a/misc/connection-limits/src/lib.rs b/misc/connection-limits/src/lib.rs index 1a568cb7ab9..52d0aa62c39 100644 --- a/misc/connection-limits/src/lib.rs +++ b/misc/connection-limits/src/lib.rs @@ -337,8 +337,9 @@ impl NetworkBehaviour for Behaviour { FromSwarm::ExpiredListenAddr(_) => {} FromSwarm::ListenerError(_) => {} FromSwarm::ListenerClosed(_) => {} - FromSwarm::NewExternalAddr(_) => {} - FromSwarm::ExpiredExternalAddr(_) => {} + FromSwarm::NewExternalAddrCandidate(_) => {} + FromSwarm::ExternalAddrExpired(_) => {} + FromSwarm::ExternalAddrConfirmed(_) => {} } } diff --git a/protocols/autonat/src/behaviour.rs b/protocols/autonat/src/behaviour.rs index 17681341489..30e70e48768 100644 --- a/protocols/autonat/src/behaviour.rs +++ b/protocols/autonat/src/behaviour.rs @@ -36,8 +36,8 @@ use libp2p_request_response::{ }; use libp2p_swarm::{ behaviour::{ - AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredExternalAddr, - ExpiredListenAddr, FromSwarm, + AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredListenAddr, + ExternalAddrExpired, FromSwarm, }, ConnectionDenied, ConnectionId, ExternalAddresses, ListenAddresses, NetworkBehaviour, PollParameters, THandler, THandlerInEvent, THandlerOutEvent, ToSwarm, @@ -561,12 +561,12 @@ impl NetworkBehaviour for Behaviour { })); self.as_client().on_expired_address(addr); } - FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }) => { + FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr }) => { self.inner - .on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr })); + .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr })); self.as_client().on_expired_address(addr); } - external_addr @ FromSwarm::NewExternalAddr(_) => { + external_addr @ FromSwarm::NewExternalAddrCandidate(_) => { self.inner.on_swarm_event(external_addr); self.as_client().on_new_address(); } @@ -580,6 +580,7 @@ impl NetworkBehaviour for Behaviour { listener_closed @ FromSwarm::ListenerClosed(_) => { self.inner.on_swarm_event(listener_closed) } + confirmed @ FromSwarm::ExternalAddrConfirmed(_) => self.inner.on_swarm_event(confirmed), } } diff --git a/protocols/autonat/src/behaviour/as_client.rs b/protocols/autonat/src/behaviour/as_client.rs index e0c0b2e9e0a..6149a6b35c7 100644 --- a/protocols/autonat/src/behaviour/as_client.rs +++ b/protocols/autonat/src/behaviour/as_client.rs @@ -30,9 +30,7 @@ use instant::Instant; use libp2p_core::Multiaddr; use libp2p_identity::PeerId; use libp2p_request_response::{self as request_response, OutboundFailure, RequestId}; -use libp2p_swarm::{ - AddressScore, ConnectionId, ExternalAddresses, ListenAddresses, PollParameters, ToSwarm, -}; +use libp2p_swarm::{ConnectionId, ExternalAddresses, ListenAddresses, PollParameters, ToSwarm}; use rand::{seq::SliceRandom, thread_rng}; use std::{ collections::{HashMap, HashSet, VecDeque}, @@ -103,7 +101,7 @@ pub(crate) struct AsClient<'a> { impl<'a> HandleInnerEvent for AsClient<'a> { fn handle_event( &mut self, - params: &mut impl PollParameters, + _: &mut impl PollParameters, event: request_response::Event, ) -> VecDeque { match event { @@ -147,19 +145,7 @@ impl<'a> HandleInnerEvent for AsClient<'a> { } if let Ok(address) = response.result { - // Update observed address score if it is finite. - #[allow(deprecated)] - // TODO: Fix once we report `AddressScore` through `FromSwarm` event. - let score = params - .external_addresses() - .find_map(|r| (r.addr == address).then_some(r.score)) - .unwrap_or(AddressScore::Finite(0)); - if let AddressScore::Finite(finite_score) = score { - actions.push_back(ToSwarm::ReportObservedAddr { - address, - score: AddressScore::Finite(finite_score + 1), - }); - } + actions.push_back(ToSwarm::ExternalAddrConfirmed(address)); } actions diff --git a/protocols/dcutr/src/behaviour_impl.rs b/protocols/dcutr/src/behaviour_impl.rs index 5b89f2ef2c2..d47e94e9117 100644 --- a/protocols/dcutr/src/behaviour_impl.rs +++ b/protocols/dcutr/src/behaviour_impl.rs @@ -441,8 +441,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/protocols/floodsub/src/layer.rs b/protocols/floodsub/src/layer.rs index f8a498912d6..29fe8ba250f 100644 --- a/protocols/floodsub/src/layer.rs +++ b/protocols/floodsub/src/layer.rs @@ -494,8 +494,9 @@ impl NetworkBehaviour for Floodsub { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/protocols/gossipsub/src/behaviour.rs b/protocols/gossipsub/src/behaviour.rs index ba0594a9801..f4af1175586 100644 --- a/protocols/gossipsub/src/behaviour.rs +++ b/protocols/gossipsub/src/behaviour.rs @@ -3500,8 +3500,9 @@ where | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/protocols/identify/src/behaviour.rs b/protocols/identify/src/behaviour.rs index 532b86dafa8..ac08a142a24 100644 --- a/protocols/identify/src/behaviour.rs +++ b/protocols/identify/src/behaviour.rs @@ -25,8 +25,8 @@ use libp2p_identity::PeerId; use libp2p_identity::PublicKey; use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm}; use libp2p_swarm::{ - AddressScore, ConnectionDenied, DialError, ExternalAddresses, ListenAddresses, - NetworkBehaviour, NotifyHandler, PollParameters, StreamUpgradeError, THandlerInEvent, ToSwarm, + ConnectionDenied, DialError, ExternalAddresses, ListenAddresses, NetworkBehaviour, + NotifyHandler, PollParameters, StreamUpgradeError, THandlerInEvent, ToSwarm, }; use libp2p_swarm::{ConnectionId, THandler, THandlerOutEvent}; use lru::LruCache; @@ -295,10 +295,8 @@ impl NetworkBehaviour for Behaviour { let observed = info.observed_addr.clone(); self.events .push_back(ToSwarm::GenerateEvent(Event::Received { peer_id, info })); - self.events.push_back(ToSwarm::ReportObservedAddr { - address: observed, - score: AddressScore::Finite(1), - }); + self.events + .push_back(ToSwarm::NewExternalAddrCandidate(observed)); } handler::Event::Identification => { self.events @@ -405,8 +403,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::NewListener(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) => {} + FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/protocols/kad/src/behaviour.rs b/protocols/kad/src/behaviour.rs index 856a994056a..19bcb49c7bc 100644 --- a/protocols/kad/src/behaviour.rs +++ b/protocols/kad/src/behaviour.rs @@ -2431,13 +2431,14 @@ where FromSwarm::DialFailure(dial_failure) => self.on_dial_failure(dial_failure), FromSwarm::AddressChange(address_change) => self.on_address_change(address_change), FromSwarm::ExpiredListenAddr(_) - | FromSwarm::NewExternalAddr(_) + | FromSwarm::NewExternalAddrCandidate(_) | FromSwarm::NewListenAddr(_) | FromSwarm::ListenFailure(_) | FromSwarm::NewListener(_) | FromSwarm::ListenerClosed(_) | FromSwarm::ListenerError(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/protocols/mdns/src/behaviour.rs b/protocols/mdns/src/behaviour.rs index 8f01439403f..bc102f832df 100644 --- a/protocols/mdns/src/behaviour.rs +++ b/protocols/mdns/src/behaviour.rs @@ -243,8 +243,9 @@ where | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } diff --git a/protocols/perf/src/client/behaviour.rs b/protocols/perf/src/client/behaviour.rs index 3dd932b0c77..912f6d5bb9e 100644 --- a/protocols/perf/src/client/behaviour.rs +++ b/protocols/perf/src/client/behaviour.rs @@ -128,8 +128,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } diff --git a/protocols/perf/src/server/behaviour.rs b/protocols/perf/src/server/behaviour.rs index 6f0047913b6..b15cb70110d 100644 --- a/protocols/perf/src/server/behaviour.rs +++ b/protocols/perf/src/server/behaviour.rs @@ -89,8 +89,9 @@ impl NetworkBehaviour for Behaviour { FromSwarm::ExpiredListenAddr(_) => {} FromSwarm::ListenerError(_) => {} FromSwarm::ListenerClosed(_) => {} - FromSwarm::NewExternalAddr(_) => {} - FromSwarm::ExpiredExternalAddr(_) => {} + FromSwarm::NewExternalAddrCandidate(_) => {} + FromSwarm::ExternalAddrExpired(_) => {} + FromSwarm::ExternalAddrConfirmed(_) => {} } } diff --git a/protocols/ping/src/lib.rs b/protocols/ping/src/lib.rs index 85be866dbf5..22cd340ac11 100644 --- a/protocols/ping/src/lib.rs +++ b/protocols/ping/src/lib.rs @@ -164,8 +164,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/protocols/relay/src/behaviour.rs b/protocols/relay/src/behaviour.rs index 133a5fa7d50..7349c67ad7a 100644 --- a/protocols/relay/src/behaviour.rs +++ b/protocols/relay/src/behaviour.rs @@ -317,8 +317,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } diff --git a/protocols/relay/src/priv_client.rs b/protocols/relay/src/priv_client.rs index 7a264bacb03..c3c80c5b504 100644 --- a/protocols/relay/src/priv_client.rs +++ b/protocols/relay/src/priv_client.rs @@ -229,8 +229,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } diff --git a/protocols/rendezvous/src/client.rs b/protocols/rendezvous/src/client.rs index a8527ba5dfe..d410cce8d89 100644 --- a/protocols/rendezvous/src/client.rs +++ b/protocols/rendezvous/src/client.rs @@ -307,8 +307,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/protocols/rendezvous/src/server.rs b/protocols/rendezvous/src/server.rs index 8568076202a..6d64938ca3d 100644 --- a/protocols/rendezvous/src/server.rs +++ b/protocols/rendezvous/src/server.rs @@ -191,8 +191,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/protocols/request-response/src/lib.rs b/protocols/request-response/src/lib.rs index 10c78703e45..1c3f4cf725f 100644 --- a/protocols/request-response/src/lib.rs +++ b/protocols/request-response/src/lib.rs @@ -756,8 +756,9 @@ where FromSwarm::ExpiredListenAddr(_) => {} FromSwarm::ListenerError(_) => {} FromSwarm::ListenerClosed(_) => {} - FromSwarm::NewExternalAddr(_) => {} - FromSwarm::ExpiredExternalAddr(_) => {} + FromSwarm::NewExternalAddrCandidate(_) => {} + FromSwarm::ExternalAddrExpired(_) => {} + FromSwarm::ExternalAddrConfirmed(_) => {} } } diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 8bcf90e8798..dafd1076218 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -82,8 +82,9 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result syn::Result quote! { - self.#i.on_swarm_event(#from_swarm::NewExternalAddr(#new_external_addr { + self.#i.on_swarm_event(#from_swarm::NewExternalAddrCandidate(#new_external_addr_candidate { addr, })); }, None => quote! { - self.#field_n.on_swarm_event(#from_swarm::NewExternalAddr(#new_external_addr { + self.#field_n.on_swarm_event(#from_swarm::NewExternalAddrCandidate(#new_external_addr_candidate { addr, })); }, @@ -463,20 +464,41 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result quote! { - self.#i.on_swarm_event(#from_swarm::ExpiredExternalAddr(#expired_external_addr { + self.#i.on_swarm_event(#from_swarm::ExternalAddrExpired(#external_addr_expired { addr, })); }, None => quote! { - self.#field_n.on_swarm_event(#from_swarm::ExpiredExternalAddr(#expired_external_addr { + self.#field_n.on_swarm_event(#from_swarm::ExternalAddrExpired(#external_addr_expired { + addr, + })); + }, + }) + }; + + // Build the list of statements to put in the body of `on_swarm_event()` + // for the `FromSwarm::ExternalAddrConfirmed` variant. + let on_external_addr_confirmed_stmts = { + data_struct + .fields + .iter() + .enumerate() + .map(|(field_n, field)| match field.ident { + Some(ref i) => quote! { + self.#i.on_swarm_event(#from_swarm::ExternalAddrConfirmed(#external_addr_confirmed { + addr, + })); + }, + None => quote! { + self.#field_n.on_swarm_event(#from_swarm::ExternalAddrConfirmed(#external_addr_confirmed { addr, })); }, @@ -717,8 +739,14 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result { - return std::task::Poll::Ready(#network_behaviour_action::ReportObservedAddr { address, score }); + std::task::Poll::Ready(#network_behaviour_action::NewExternalAddrCandidate(addr)) => { + return std::task::Poll::Ready(#network_behaviour_action::NewExternalAddrCandidate(addr)); + } + std::task::Poll::Ready(#network_behaviour_action::ExternalAddrConfirmed(addr)) => { + return std::task::Poll::Ready(#network_behaviour_action::ExternalAddrConfirmed(addr)); + } + std::task::Poll::Ready(#network_behaviour_action::ExternalAddrExpired(addr)) => { + return std::task::Poll::Ready(#network_behaviour_action::ExternalAddrExpired(addr)); } std::task::Poll::Ready(#network_behaviour_action::CloseConnection { peer_id, connection }) => { return std::task::Poll::Ready(#network_behaviour_action::CloseConnection { peer_id, connection }); @@ -834,12 +862,15 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result { #(#on_expired_listen_addr_stmts)* } - #from_swarm::NewExternalAddr( - #new_external_addr { addr }) - => { #(#on_new_external_addr_stmts)* } - #from_swarm::ExpiredExternalAddr( - #expired_external_addr { addr }) - => { #(#on_expired_external_addr_stmts)* } + #from_swarm::NewExternalAddrCandidate( + #new_external_addr_candidate { addr }) + => { #(#on_new_external_addr_candidate_stmts)* } + #from_swarm::ExternalAddrExpired( + #external_addr_expired { addr }) + => { #(#on_external_addr_expired_stmts)* } + #from_swarm::ExternalAddrConfirmed( + #external_addr_confirmed { addr }) + => { #(#on_external_addr_confirmed_stmts)* } #from_swarm::ListenerError( #listener_error { listener_id, err }) => { #(#on_listener_error_stmts)* } diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index c5e5b7f25c3..dde96082a0b 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -29,8 +29,8 @@ pub use listen_addresses::ListenAddresses; use crate::connection::ConnectionId; use crate::dial_opts::DialOpts; use crate::{ - AddressRecord, AddressScore, ConnectionDenied, ConnectionHandler, DialError, ListenError, - THandler, THandlerInEvent, THandlerOutEvent, + AddressRecord, ConnectionDenied, ConnectionHandler, DialError, ListenError, THandler, + THandlerInEvent, THandlerOutEvent, }; use libp2p_core::{transport::ListenerId, ConnectedPoint, Endpoint, Multiaddr}; use libp2p_identity::PeerId; @@ -299,21 +299,20 @@ pub enum ToSwarm { event: TInEvent, }, - /// Informs the `Swarm` about an address observed by a remote for - /// the local node by which the local node is supposedly publicly - /// reachable. + /// Reports a new candidate for an external address to the [`Swarm`]. /// - /// It is advisable to issue `ReportObservedAddr` actions at a fixed frequency - /// per node. This way address information will be more accurate over time - /// and individual outliers carry less weight. - ReportObservedAddr { - /// The observed address of the local node. - address: Multiaddr, - /// The score to associate with this observation, i.e. - /// an indicator for the trusworthiness of this address - /// relative to other observed addresses. - score: AddressScore, - }, + /// This address could come from a variety of sources: + /// - A protocol such as identify obtained it from a remote. + /// - The user provided it based on configuration. + /// - We made an educated guess based on one of our listen addresses. + /// - We established a new relay connection. + NewExternalAddrCandidate(Multiaddr), + + /// Indicates to the [`Swarm`] that the provided address is confirmed to be externally reachable. + ExternalAddrConfirmed(Multiaddr), + + /// Indicates to the [`Swarm`] that we are no longer externally reachable under the provided address. + ExternalAddrExpired(Multiaddr), /// Instructs the `Swarm` to initiate a graceful close of one or all connections /// with the given peer. @@ -351,9 +350,6 @@ impl ToSwarm { handler, event: f(event), }, - ToSwarm::ReportObservedAddr { address, score } => { - ToSwarm::ReportObservedAddr { address, score } - } ToSwarm::CloseConnection { peer_id, connection, @@ -361,6 +357,9 @@ impl ToSwarm { peer_id, connection, }, + ToSwarm::NewExternalAddrCandidate(addr) => ToSwarm::NewExternalAddrCandidate(addr), + ToSwarm::ExternalAddrConfirmed(addr) => ToSwarm::ExternalAddrConfirmed(addr), + ToSwarm::ExternalAddrExpired(addr) => ToSwarm::ExternalAddrExpired(addr), } } } @@ -380,9 +379,9 @@ impl ToSwarm { handler, event, }, - ToSwarm::ReportObservedAddr { address, score } => { - ToSwarm::ReportObservedAddr { address, score } - } + ToSwarm::NewExternalAddrCandidate(addr) => ToSwarm::NewExternalAddrCandidate(addr), + ToSwarm::ExternalAddrConfirmed(addr) => ToSwarm::ExternalAddrConfirmed(addr), + ToSwarm::ExternalAddrExpired(addr) => ToSwarm::ExternalAddrExpired(addr), ToSwarm::CloseConnection { peer_id, connection, @@ -449,10 +448,12 @@ pub enum FromSwarm<'a, Handler> { ListenerError(ListenerError<'a>), /// Informs the behaviour that a listener closed. ListenerClosed(ListenerClosed<'a>), - /// Informs the behaviour that we have discovered a new external address for us. - NewExternalAddr(NewExternalAddr<'a>), + /// Informs the behaviour that we have discovered a new candidate for an external address for us. + NewExternalAddrCandidate(NewExternalAddrCandidate<'a>), + /// Informs the behaviour that an external address was removed. + ExternalAddrConfirmed(ExternalAddrConfirmed<'a>), /// Informs the behaviour that an external address was removed. - ExpiredExternalAddr(ExpiredExternalAddr<'a>), + ExternalAddrExpired(ExternalAddrExpired<'a>), } /// [`FromSwarm`] variant that informs the behaviour about a newly established connection to a peer. @@ -549,15 +550,21 @@ pub struct ListenerClosed<'a> { } /// [`FromSwarm`] variant that informs the behaviour -/// that we have discovered a new external address for us. +/// that we have discovered a new candidate for an external address for us. #[derive(Clone, Copy)] -pub struct NewExternalAddr<'a> { +pub struct NewExternalAddrCandidate<'a> { pub addr: &'a Multiaddr, } /// [`FromSwarm`] variant that informs the behaviour that an external address was removed. #[derive(Clone, Copy)] -pub struct ExpiredExternalAddr<'a> { +pub struct ExternalAddrConfirmed<'a> { + pub addr: &'a Multiaddr, +} + +/// [`FromSwarm`] variant that informs the behaviour that an external address was removed. +#[derive(Clone, Copy)] +pub struct ExternalAddrExpired<'a> { pub addr: &'a Multiaddr, } @@ -657,12 +664,9 @@ impl<'a, Handler> FromSwarm<'a, Handler> { listener_id, reason, })), - FromSwarm::NewExternalAddr(NewExternalAddr { addr }) => { - Some(FromSwarm::NewExternalAddr(NewExternalAddr { addr })) - } - FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }) => { - Some(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr })) - } + FromSwarm::NewExternalAddrCandidate(e) => Some(FromSwarm::NewExternalAddrCandidate(e)), + FromSwarm::ExternalAddrExpired(e) => Some(FromSwarm::ExternalAddrExpired(e)), + FromSwarm::ExternalAddrConfirmed(e) => Some(FromSwarm::ExternalAddrConfirmed(e)), } } } diff --git a/swarm/src/behaviour/external_addresses.rs b/swarm/src/behaviour/external_addresses.rs index 49f540f8dfc..88cb2a88d63 100644 --- a/swarm/src/behaviour/external_addresses.rs +++ b/swarm/src/behaviour/external_addresses.rs @@ -1,4 +1,4 @@ -use crate::behaviour::{ExpiredExternalAddr, FromSwarm, NewExternalAddr}; +use crate::behaviour::{ExternalAddrExpired, FromSwarm, NewExternalAddrCandidate}; use libp2p_core::Multiaddr; use std::collections::HashSet; @@ -34,12 +34,12 @@ impl ExternalAddresses { /// Returns whether the event changed our set of external addresses. pub fn on_swarm_event(&mut self, event: &FromSwarm) -> bool { match event { - FromSwarm::NewExternalAddr(NewExternalAddr { addr, .. }) => { + FromSwarm::NewExternalAddrCandidate(NewExternalAddrCandidate { addr, .. }) => { if self.addresses.len() < self.limit { return self.addresses.insert((*addr).clone()); } } - FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr, .. }) => { + FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr, .. }) => { return self.addresses.remove(addr) } _ => {} @@ -80,11 +80,11 @@ mod tests { } fn new_external_addr() -> FromSwarm<'static, dummy::ConnectionHandler> { - FromSwarm::NewExternalAddr(NewExternalAddr { addr: &MEMORY_ADDR }) + FromSwarm::NewExternalAddrCandidate(NewExternalAddrCandidate { addr: &MEMORY_ADDR }) } fn expired_external_addr() -> FromSwarm<'static, dummy::ConnectionHandler> { - FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr: &MEMORY_ADDR }) + FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr: &MEMORY_ADDR }) } static MEMORY_ADDR: Lazy = diff --git a/swarm/src/dummy.rs b/swarm/src/dummy.rs index 563d86a667e..6810abec591 100644 --- a/swarm/src/dummy.rs +++ b/swarm/src/dummy.rs @@ -70,8 +70,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/swarm/src/keep_alive.rs b/swarm/src/keep_alive.rs index f91f80990a6..05cbcdf7b8c 100644 --- a/swarm/src/keep_alive.rs +++ b/swarm/src/keep_alive.rs @@ -73,8 +73,9 @@ impl NetworkBehaviour for Behaviour { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index f0f5f07cb97..6fe3d8a36c1 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -77,13 +77,14 @@ pub mod derive_prelude { pub use crate::behaviour::ConnectionClosed; pub use crate::behaviour::ConnectionEstablished; pub use crate::behaviour::DialFailure; - pub use crate::behaviour::ExpiredExternalAddr; pub use crate::behaviour::ExpiredListenAddr; + pub use crate::behaviour::ExternalAddrConfirmed; + pub use crate::behaviour::ExternalAddrExpired; pub use crate::behaviour::FromSwarm; pub use crate::behaviour::ListenFailure; pub use crate::behaviour::ListenerClosed; pub use crate::behaviour::ListenerError; - pub use crate::behaviour::NewExternalAddr; + pub use crate::behaviour::NewExternalAddrCandidate; pub use crate::behaviour::NewListenAddr; pub use crate::behaviour::NewListener; pub use crate::connection::ConnectionId; @@ -107,10 +108,10 @@ pub mod derive_prelude { } pub use behaviour::{ - AddressChange, CloseConnection, ConnectionClosed, DialFailure, ExpiredExternalAddr, - ExpiredListenAddr, ExternalAddresses, FromSwarm, ListenAddresses, ListenFailure, - ListenerClosed, ListenerError, NetworkBehaviour, NewExternalAddr, NewListenAddr, NotifyHandler, - PollParameters, ToSwarm, + AddressChange, CloseConnection, ConnectionClosed, DialFailure, ExpiredListenAddr, + ExternalAddrExpired, ExternalAddresses, FromSwarm, ListenAddresses, ListenFailure, + ListenerClosed, ListenerError, NetworkBehaviour, NewExternalAddrCandidate, NewListenAddr, + NotifyHandler, PollParameters, ToSwarm, }; pub use connection::pool::ConnectionCounters; pub use connection::{ConnectionError, ConnectionId, SupportedProtocols}; @@ -125,6 +126,7 @@ pub use registry::{AddAddressResult, AddressRecord, AddressScore}; pub use stream::Stream; pub use stream_protocol::{InvalidProtocol, StreamProtocol}; +use crate::behaviour::ExternalAddrConfirmed; use crate::handler::UpgradeInfoSend; use connection::pool::{EstablishedConnection, Pool, PoolConfig, PoolEvent}; use connection::IncomingInfo; @@ -664,14 +666,16 @@ where let expired = match &result { AddAddressResult::Inserted { expired } => { self.behaviour - .on_swarm_event(FromSwarm::NewExternalAddr(NewExternalAddr { addr: &a })); + .on_swarm_event(FromSwarm::NewExternalAddrCandidate( + NewExternalAddrCandidate { addr: &a }, + )); expired } AddAddressResult::Updated { expired } => expired, }; for a in expired { self.behaviour - .on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { + .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr: &a.addr, })); } @@ -687,7 +691,7 @@ where pub fn remove_external_address(&mut self, addr: &Multiaddr) -> bool { if self.external_addrs.remove(addr) { self.behaviour - .on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr })); + .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr })); true } else { false @@ -1136,35 +1140,53 @@ where self.pending_event = Some((peer_id, handler, event)); } - ToSwarm::ReportObservedAddr { address, score } => { - // Maps the given `observed_addr`, representing an address of the local - // node observed by a remote peer, onto the locally known listen addresses - // to yield one or more addresses of the local node that may be publicly - // reachable. - // - // I.e. self method incorporates the view of other peers into the listen - // addresses seen by the local node to account for possible IP and port - // mappings performed by intermediate network devices in an effort to - // obtain addresses for the local peer that are also reachable for peers - // other than the peer who reported the `observed_addr`. - // - // The translation is transport-specific. See [`Transport::address_translation`]. - let translated_addresses = { - let mut addrs: Vec<_> = self - .listened_addrs - .values() - .flatten() - .filter_map(|server| self.transport.address_translation(server, &address)) - .collect(); - - // remove duplicates - addrs.sort_unstable(); - addrs.dedup(); - addrs - }; - for addr in translated_addresses { - self.add_external_address(addr, score); - } + // ToSwarm::ReportObservedAddr { address, score } => { + // // Maps the given `observed_addr`, representing an address of the local + // // node observed by a remote peer, onto the locally known listen addresses + // // to yield one or more addresses of the local node that may be publicly + // // reachable. + // // + // // I.e. self method incorporates the view of other peers into the listen + // // addresses seen by the local node to account for possible IP and port + // // mappings performed by intermediate network devices in an effort to + // // obtain addresses for the local peer that are also reachable for peers + // // other than the peer who reported the `observed_addr`. + // // + // // The translation is transport-specific. See [`Transport::address_translation`]. + // let translated_addresses = { + // let mut addrs: Vec<_> = self + // .listened_addrs + // .values() + // .flatten() + // .filter_map(|server| self.transport.address_translation(server, &address)) + // .collect(); + // + // // remove duplicates + // addrs.sort_unstable(); + // addrs.dedup(); + // addrs + // }; + // for addr in translated_addresses { + // self.add_external_address(addr, score); + // } + // } + ToSwarm::NewExternalAddrCandidate(addr) => { + self.behaviour + .on_swarm_event(FromSwarm::NewExternalAddrCandidate( + NewExternalAddrCandidate { addr: &addr }, + )); + } + ToSwarm::ExternalAddrConfirmed(addr) => { + self.behaviour + .on_swarm_event(FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { + addr: &addr, + })); + } + ToSwarm::ExternalAddrExpired(addr) => { + self.behaviour + .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { + addr: &addr, + })); } ToSwarm::CloseConnection { peer_id, diff --git a/swarm/src/test.rs b/swarm/src/test.rs index 70d4e790956..6f39d56da91 100644 --- a/swarm/src/test.rs +++ b/swarm/src/test.rs @@ -19,8 +19,8 @@ // DEALINGS IN THE SOFTWARE. use crate::behaviour::{ - ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredExternalAddr, ExpiredListenAddr, - FromSwarm, ListenerClosed, ListenerError, NewExternalAddr, NewListenAddr, NewListener, + ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredListenAddr, ExternalAddrExpired, + FromSwarm, ListenerClosed, ListenerError, NewExternalAddrCandidate, NewListenAddr, NewListener, }; use crate::{ ConnectionDenied, ConnectionHandler, ConnectionId, NetworkBehaviour, PollParameters, THandler, @@ -130,8 +130,9 @@ where | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } @@ -500,15 +501,17 @@ where addr, })); } - FromSwarm::NewExternalAddr(NewExternalAddr { addr }) => { + FromSwarm::NewExternalAddrCandidate(NewExternalAddrCandidate { addr }) => { self.on_new_external_addr.push(addr.clone()); self.inner - .on_swarm_event(FromSwarm::NewExternalAddr(NewExternalAddr { addr })); + .on_swarm_event(FromSwarm::NewExternalAddrCandidate( + NewExternalAddrCandidate { addr }, + )); } - FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }) => { + FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr }) => { self.on_expired_external_addr.push(addr.clone()); self.inner - .on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr })); + .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr })); } FromSwarm::ListenerError(ListenerError { listener_id, err }) => { self.on_listener_error.push(listener_id); diff --git a/swarm/tests/swarm_derive.rs b/swarm/tests/swarm_derive.rs index ab1efaca396..fa3f6c69dd0 100644 --- a/swarm/tests/swarm_derive.rs +++ b/swarm/tests/swarm_derive.rs @@ -518,8 +518,9 @@ fn custom_out_event_no_type_parameters() { | FromSwarm::ExpiredListenAddr(_) | FromSwarm::ListenerError(_) | FromSwarm::ListenerClosed(_) - | FromSwarm::NewExternalAddr(_) - | FromSwarm::ExpiredExternalAddr(_) => {} + | FromSwarm::NewExternalAddrCandidate(_) + | FromSwarm::ExternalAddrExpired(_) + | FromSwarm::ExternalAddrConfirmed(_) => {} } } } From d5f45b5e7fba58f2fec9b106d1c4cdec2d307c14 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 16 May 2023 14:06:59 +0200 Subject: [PATCH 02/17] Generate candidates based on address translation --- swarm/src/lib.rs | 53 +++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 6fe3d8a36c1..ba55d784cfa 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -1140,41 +1140,34 @@ where self.pending_event = Some((peer_id, handler, event)); } - // ToSwarm::ReportObservedAddr { address, score } => { - // // Maps the given `observed_addr`, representing an address of the local - // // node observed by a remote peer, onto the locally known listen addresses - // // to yield one or more addresses of the local node that may be publicly - // // reachable. - // // - // // I.e. self method incorporates the view of other peers into the listen - // // addresses seen by the local node to account for possible IP and port - // // mappings performed by intermediate network devices in an effort to - // // obtain addresses for the local peer that are also reachable for peers - // // other than the peer who reported the `observed_addr`. - // // - // // The translation is transport-specific. See [`Transport::address_translation`]. - // let translated_addresses = { - // let mut addrs: Vec<_> = self - // .listened_addrs - // .values() - // .flatten() - // .filter_map(|server| self.transport.address_translation(server, &address)) - // .collect(); - // - // // remove duplicates - // addrs.sort_unstable(); - // addrs.dedup(); - // addrs - // }; - // for addr in translated_addresses { - // self.add_external_address(addr, score); - // } - // } ToSwarm::NewExternalAddrCandidate(addr) => { self.behaviour .on_swarm_event(FromSwarm::NewExternalAddrCandidate( NewExternalAddrCandidate { addr: &addr }, )); + + // Generate more candidates based on address translation. + // For TCP without port-reuse, the observed address contains an ephemeral port which needs to be replaced by the port of a listen address. + + let translated_addresses = { + let mut addrs: Vec<_> = self + .listened_addrs + .values() + .flatten() + .filter_map(|server| self.transport.address_translation(server, &addr)) + .collect(); + + // remove duplicates + addrs.sort_unstable(); + addrs.dedup(); + addrs + }; + for addr in translated_addresses { + self.behaviour + .on_swarm_event(FromSwarm::NewExternalAddrCandidate( + NewExternalAddrCandidate { addr: &addr }, + )); + } } ToSwarm::ExternalAddrConfirmed(addr) => { self.behaviour From ab12bb7e8fb4d46b9d8e674b4fbf089bda7cc00d Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 16 May 2023 14:14:24 +0200 Subject: [PATCH 03/17] Use candidates in AutoNAT --- protocols/autonat/src/behaviour.rs | 17 ++++++++++------- protocols/autonat/src/behaviour/as_client.rs | 6 +++--- swarm/src/behaviour/external_addresses.rs | 6 +++--- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/protocols/autonat/src/behaviour.rs b/protocols/autonat/src/behaviour.rs index 30e70e48768..b5381d62af6 100644 --- a/protocols/autonat/src/behaviour.rs +++ b/protocols/autonat/src/behaviour.rs @@ -39,7 +39,7 @@ use libp2p_swarm::{ AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredListenAddr, ExternalAddrExpired, FromSwarm, }, - ConnectionDenied, ConnectionId, ExternalAddresses, ListenAddresses, NetworkBehaviour, + ConnectionDenied, ConnectionId, ListenAddresses, NetworkBehaviour, NewExternalAddrCandidate, PollParameters, THandler, THandlerInEvent, THandlerOutEvent, ToSwarm, }; use std::{ @@ -214,7 +214,7 @@ pub struct Behaviour { probe_id: ProbeId, listen_addresses: ListenAddresses, - external_addresses: ExternalAddresses, + other_candidates: HashSet, } impl Behaviour { @@ -240,7 +240,7 @@ impl Behaviour { pending_actions: VecDeque::new(), probe_id: ProbeId(0), listen_addresses: Default::default(), - external_addresses: Default::default(), + other_candidates: Default::default(), } } @@ -294,7 +294,7 @@ impl Behaviour { last_probe: &mut self.last_probe, schedule_probe: &mut self.schedule_probe, listen_addresses: &self.listen_addresses, - external_addresses: &self.external_addresses, + other_candidates: &self.other_candidates, } } @@ -532,7 +532,6 @@ impl NetworkBehaviour for Behaviour { fn on_swarm_event(&mut self, event: FromSwarm) { self.listen_addresses.on_swarm_event(&event); - self.external_addresses.on_swarm_event(&event); match event { FromSwarm::ConnectionEstablished(connection_established) => { @@ -566,8 +565,12 @@ impl NetworkBehaviour for Behaviour { .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr })); self.as_client().on_expired_address(addr); } - external_addr @ FromSwarm::NewExternalAddrCandidate(_) => { - self.inner.on_swarm_event(external_addr); + FromSwarm::NewExternalAddrCandidate(NewExternalAddrCandidate { addr }) => { + self.inner + .on_swarm_event(FromSwarm::NewExternalAddrCandidate( + NewExternalAddrCandidate { addr }, + )); + self.other_candidates.insert(addr.to_owned()); self.as_client().on_new_address(); } listen_failure @ FromSwarm::ListenFailure(_) => { diff --git a/protocols/autonat/src/behaviour/as_client.rs b/protocols/autonat/src/behaviour/as_client.rs index 6149a6b35c7..e57523afaf8 100644 --- a/protocols/autonat/src/behaviour/as_client.rs +++ b/protocols/autonat/src/behaviour/as_client.rs @@ -30,7 +30,7 @@ use instant::Instant; use libp2p_core::Multiaddr; use libp2p_identity::PeerId; use libp2p_request_response::{self as request_response, OutboundFailure, RequestId}; -use libp2p_swarm::{ConnectionId, ExternalAddresses, ListenAddresses, PollParameters, ToSwarm}; +use libp2p_swarm::{ConnectionId, ListenAddresses, PollParameters, ToSwarm}; use rand::{seq::SliceRandom, thread_rng}; use std::{ collections::{HashMap, HashSet, VecDeque}, @@ -95,7 +95,7 @@ pub(crate) struct AsClient<'a> { pub(crate) last_probe: &'a mut Option, pub(crate) schedule_probe: &'a mut Delay, pub(crate) listen_addresses: &'a ListenAddresses, - pub(crate) external_addresses: &'a ExternalAddresses, + pub(crate) other_candidates: &'a HashSet, } impl<'a> HandleInnerEvent for AsClient<'a> { @@ -187,7 +187,7 @@ impl<'a> AsClient<'a> { self.schedule_probe.reset(self.config.retry_interval); let addresses = self - .external_addresses + .other_candidates .iter() .chain(self.listen_addresses.iter()) .cloned() diff --git a/swarm/src/behaviour/external_addresses.rs b/swarm/src/behaviour/external_addresses.rs index 88cb2a88d63..89e06e26608 100644 --- a/swarm/src/behaviour/external_addresses.rs +++ b/swarm/src/behaviour/external_addresses.rs @@ -1,4 +1,4 @@ -use crate::behaviour::{ExternalAddrExpired, FromSwarm, NewExternalAddrCandidate}; +use crate::behaviour::{ExternalAddrConfirmed, ExternalAddrExpired, FromSwarm}; use libp2p_core::Multiaddr; use std::collections::HashSet; @@ -34,7 +34,7 @@ impl ExternalAddresses { /// Returns whether the event changed our set of external addresses. pub fn on_swarm_event(&mut self, event: &FromSwarm) -> bool { match event { - FromSwarm::NewExternalAddrCandidate(NewExternalAddrCandidate { addr, .. }) => { + FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { addr }) => { if self.addresses.len() < self.limit { return self.addresses.insert((*addr).clone()); } @@ -80,7 +80,7 @@ mod tests { } fn new_external_addr() -> FromSwarm<'static, dummy::ConnectionHandler> { - FromSwarm::NewExternalAddrCandidate(NewExternalAddrCandidate { addr: &MEMORY_ADDR }) + FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { addr: &MEMORY_ADDR }) } fn expired_external_addr() -> FromSwarm<'static, dummy::ConnectionHandler> { From 43058e1e6d31d71a8fc352527c854ad2723248a9 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 16 May 2023 14:28:43 +0200 Subject: [PATCH 04/17] Only keep minimal external address state in swarm --- examples/rendezvous/src/bin/rzv-register.rs | 4 +- misc/allow-block-list/src/lib.rs | 15 +- protocols/autonat/tests/test_client.rs | 6 +- protocols/autonat/tests/test_server.rs | 12 +- protocols/relay/tests/lib.rs | 10 +- swarm-test/src/lib.rs | 11 +- swarm/src/behaviour.rs | 13 +- swarm/src/lib.rs | 83 +--- swarm/src/registry.rs | 504 -------------------- 9 files changed, 38 insertions(+), 620 deletions(-) delete mode 100644 swarm/src/registry.rs diff --git a/examples/rendezvous/src/bin/rzv-register.rs b/examples/rendezvous/src/bin/rzv-register.rs index 40053aa96b9..03aa56978a3 100644 --- a/examples/rendezvous/src/bin/rzv-register.rs +++ b/examples/rendezvous/src/bin/rzv-register.rs @@ -22,7 +22,7 @@ use futures::StreamExt; use libp2p::{ core::transport::upgrade::Version, identity, noise, ping, rendezvous, - swarm::{keep_alive, AddressScore, NetworkBehaviour, SwarmBuilder, SwarmEvent}, + swarm::{keep_alive, NetworkBehaviour, SwarmBuilder, SwarmEvent}, tcp, yamux, Multiaddr, PeerId, Transport, }; use std::time::Duration; @@ -55,7 +55,7 @@ async fn main() { // In production the external address should be the publicly facing IP address of the rendezvous point. // This address is recorded in the registration entry by the rendezvous point. let external_address = "/ip4/127.0.0.1/tcp/0".parse::().unwrap(); - swarm.add_external_address(external_address, AddressScore::Infinite); + swarm.add_external_address(external_address); log::info!("Local peer id: {}", swarm.local_peer_id()); diff --git a/misc/allow-block-list/src/lib.rs b/misc/allow-block-list/src/lib.rs index eba747462fe..7aa0dd87822 100644 --- a/misc/allow-block-list/src/lib.rs +++ b/misc/allow-block-list/src/lib.rs @@ -411,13 +411,7 @@ mod tests { dialer .dial( DialOpts::unknown_peer_id() - .address( - listener - .external_addresses() - .map(|a| a.addr.clone()) - .next() - .unwrap(), - ) + .address(listener.external_addresses().next().cloned().unwrap()) .build(), ) .unwrap(); @@ -471,12 +465,7 @@ mod tests { { dialer.dial( DialOpts::peer_id(*listener.local_peer_id()) - .addresses( - listener - .external_addresses() - .map(|a| a.addr.clone()) - .collect(), - ) + .addresses(listener.external_addresses().cloned().collect()) .build(), ) } diff --git a/protocols/autonat/tests/test_client.rs b/protocols/autonat/tests/test_client.rs index 221833c9377..d4708f542f9 100644 --- a/protocols/autonat/tests/test_client.rs +++ b/protocols/autonat/tests/test_client.rs @@ -24,7 +24,7 @@ use libp2p_autonat::{ }; use libp2p_core::Multiaddr; use libp2p_identity::PeerId; -use libp2p_swarm::{AddressScore, Swarm, SwarmEvent}; +use libp2p_swarm::{Swarm, SwarmEvent}; use libp2p_swarm_test::SwarmExt as _; use std::time::Duration; @@ -74,7 +74,7 @@ async fn test_auto_probe() { // Artificially add a faulty address. let unreachable_addr: Multiaddr = "/ip4/127.0.0.1/tcp/42".parse().unwrap(); - client.add_external_address(unreachable_addr.clone(), AddressScore::Infinite); + client.add_external_address(unreachable_addr.clone()); let id = match client.next_behaviour_event().await { Event::OutboundProbe(OutboundProbeEvent::Request { probe_id, peer }) => { @@ -198,7 +198,7 @@ async fn test_confidence() { client.listen().await; } else { let unreachable_addr = "/ip4/127.0.0.1/tcp/42".parse().unwrap(); - client.add_external_address(unreachable_addr, AddressScore::Infinite); + client.add_external_address(unreachable_addr); } for i in 0..MAX_CONFIDENCE + 1 { diff --git a/protocols/autonat/tests/test_server.rs b/protocols/autonat/tests/test_server.rs index 319fd84865d..fa0ec5367c8 100644 --- a/protocols/autonat/tests/test_server.rs +++ b/protocols/autonat/tests/test_server.rs @@ -24,7 +24,7 @@ use libp2p_autonat::{ use libp2p_core::{multiaddr::Protocol, ConnectedPoint, Endpoint, Multiaddr}; use libp2p_identity::PeerId; use libp2p_swarm::DialError; -use libp2p_swarm::{AddressScore, Swarm, SwarmEvent}; +use libp2p_swarm::{Swarm, SwarmEvent}; use libp2p_swarm_test::SwarmExt as _; use std::{num::NonZeroU32, time::Duration}; @@ -127,10 +127,7 @@ async fn test_dial_back() { async fn test_dial_error() { let (mut server, server_id, server_addr) = new_server_swarm(None).await; let (mut client, client_id) = new_client_swarm(server_id, server_addr).await; - client.add_external_address( - "/ip4/127.0.0.1/tcp/12345".parse().unwrap(), - AddressScore::Infinite, - ); + client.add_external_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); async_std::task::spawn(client.loop_on_next()); let request_probe_id = match server.next_behaviour_event().await { @@ -267,10 +264,7 @@ async fn test_dial_multiple_addr() { let (mut client, client_id) = new_client_swarm(server_id, server_addr.clone()).await; client.listen().await; - client.add_external_address( - "/ip4/127.0.0.1/tcp/12345".parse().unwrap(), - AddressScore::Infinite, - ); + client.add_external_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); async_std::task::spawn(client.loop_on_next()); let dial_addresses = match server.next_behaviour_event().await { diff --git a/protocols/relay/tests/lib.rs b/protocols/relay/tests/lib.rs index 2103893ba12..98fe2873f09 100644 --- a/protocols/relay/tests/lib.rs +++ b/protocols/relay/tests/lib.rs @@ -34,7 +34,7 @@ use libp2p_identity::PublicKey; use libp2p_ping as ping; use libp2p_plaintext::PlainText2Config; use libp2p_relay as relay; -use libp2p_swarm::{AddressScore, NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent}; +use libp2p_swarm::{NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent}; use std::time::Duration; #[test] @@ -47,7 +47,7 @@ fn reservation() { let relay_peer_id = *relay.local_peer_id(); relay.listen_on(relay_addr.clone()).unwrap(); - relay.add_external_address(relay_addr.clone(), AddressScore::Infinite); + relay.add_external_address(relay_addr.clone()); spawn_swarm_on_pool(&pool, relay); let client_addr = relay_addr @@ -90,7 +90,7 @@ fn new_reservation_to_same_relay_replaces_old() { let relay_peer_id = *relay.local_peer_id(); relay.listen_on(relay_addr.clone()).unwrap(); - relay.add_external_address(relay_addr.clone(), AddressScore::Infinite); + relay.add_external_address(relay_addr.clone()); spawn_swarm_on_pool(&pool, relay); let mut client = build_client(); @@ -183,7 +183,7 @@ fn connect() { let relay_peer_id = *relay.local_peer_id(); relay.listen_on(relay_addr.clone()).unwrap(); - relay.add_external_address(relay_addr.clone(), AddressScore::Infinite); + relay.add_external_address(relay_addr.clone()); spawn_swarm_on_pool(&pool, relay); let mut dst = build_client(); @@ -278,7 +278,7 @@ fn reuse_connection() { let relay_peer_id = *relay.local_peer_id(); relay.listen_on(relay_addr.clone()).unwrap(); - relay.add_external_address(relay_addr.clone(), AddressScore::Infinite); + relay.add_external_address(relay_addr.clone()); spawn_swarm_on_pool(&pool, relay); let client_addr = relay_addr diff --git a/swarm-test/src/lib.rs b/swarm-test/src/lib.rs index 72a9821cced..e70c64bbfd1 100644 --- a/swarm-test/src/lib.rs +++ b/swarm-test/src/lib.rs @@ -29,8 +29,7 @@ use libp2p_identity::PeerId; use libp2p_plaintext::PlainText2Config; use libp2p_swarm::dial_opts::PeerCondition; use libp2p_swarm::{ - dial_opts::DialOpts, AddressScore, NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent, - THandlerErr, + dial_opts::DialOpts, NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent, THandlerErr, }; use libp2p_yamux as yamux; use std::fmt::Debug; @@ -228,11 +227,7 @@ where T: NetworkBehaviour + Send, ::ToSwarm: Debug, { - let external_addresses = other - .external_addresses() - .cloned() - .map(|r| r.addr) - .collect(); + let external_addresses = other.external_addresses().cloned().collect(); let dial_opts = DialOpts::peer_id(*other.local_peer_id()) .addresses(external_addresses) @@ -315,7 +310,7 @@ where .await; // Memory addresses are externally reachable because they all share the same memory-space. - self.add_external_address(memory_multiaddr.clone(), AddressScore::Infinite); + self.add_external_address(memory_multiaddr.clone()); let tcp_addr_listener_id = self .listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap()) diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index dde96082a0b..8e1707b0300 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -29,8 +29,8 @@ pub use listen_addresses::ListenAddresses; use crate::connection::ConnectionId; use crate::dial_opts::DialOpts; use crate::{ - AddressRecord, ConnectionDenied, ConnectionHandler, DialError, ListenError, THandler, - THandlerInEvent, THandlerOutEvent, + ConnectionDenied, ConnectionHandler, DialError, ListenError, THandler, THandlerInEvent, + THandlerOutEvent, }; use libp2p_core::{transport::ListenerId, ConnectedPoint, Endpoint, Multiaddr}; use libp2p_identity::PeerId; @@ -221,8 +221,6 @@ pub trait PollParameters { type SupportedProtocolsIter: ExactSizeIterator>; /// Iterator returned by [`listened_addresses`](PollParameters::listened_addresses). type ListenedAddressesIter: ExactSizeIterator; - /// Iterator returned by [`external_addresses`](PollParameters::external_addresses). - type ExternalAddressesIter: ExactSizeIterator; /// Returns the list of protocol the behaviour supports when a remote negotiates a protocol on /// an inbound substream. @@ -242,13 +240,6 @@ pub trait PollParameters { )] fn listened_addresses(&self) -> Self::ListenedAddressesIter; - /// Returns the list of the addresses nodes can use to reach us. - #[deprecated( - since = "0.42.0", - note = "Use `libp2p_swarm::ExternalAddresses` instead." - )] - fn external_addresses(&self) -> Self::ExternalAddressesIter; - /// Returns the peer id of the local node. #[deprecated( since = "0.42.0", diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index ba55d784cfa..8e80a65ac65 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -57,7 +57,6 @@ mod connection; mod executor; -mod registry; mod stream; mod stream_protocol; #[cfg(test)] @@ -122,7 +121,6 @@ pub use handler::{ }; #[cfg(feature = "macros")] pub use libp2p_swarm_derive::NetworkBehaviour; -pub use registry::{AddAddressResult, AddressRecord, AddressScore}; pub use stream::Stream; pub use stream_protocol::{InvalidProtocol, StreamProtocol}; @@ -144,7 +142,6 @@ use libp2p_core::{ Endpoint, Multiaddr, Transport, }; use libp2p_identity::PeerId; -use registry::{AddressIntoIter, Addresses}; use smallvec::SmallVec; use std::collections::{HashMap, HashSet}; use std::num::{NonZeroU32, NonZeroU8, NonZeroUsize}; @@ -326,13 +323,11 @@ where /// List of protocols that the behaviour says it supports. supported_protocols: SmallVec<[Vec; 16]>, + confirmed_external_addr: HashSet, + /// Multiaddresses that our listeners are listening on, listened_addrs: HashMap>, - /// List of multiaddresses we're listening on, after account for external IP addresses and - /// similar mechanisms. - external_addrs: Addresses, - /// Pending event to be delivered to connection handlers /// (or dropped if the peer disconnected) before the `behaviour` /// can be polled again. @@ -640,62 +635,25 @@ where &self.local_peer_id } - /// Returns an iterator for [`AddressRecord`]s of external addresses - /// of the local node, in decreasing order of their current - /// [score](AddressScore). - pub fn external_addresses(&self) -> impl Iterator { - self.external_addrs.iter() + /// TODO + pub fn external_addresses(&self) -> impl Iterator { + self.confirmed_external_addr.iter() } /// Adds an external address record for the local node. /// - /// An external address is an address of the local node known to - /// be (likely) reachable for other nodes, possibly taking into - /// account NAT. The external addresses of the local node may be - /// shared with other nodes by the `NetworkBehaviour`. - /// - /// The associated score determines both the position of the address - /// in the list of external addresses (which can determine the - /// order in which addresses are used to connect to) as well as - /// how long the address is retained in the list, depending on - /// how frequently it is reported by the `NetworkBehaviour` via - /// [`ToSwarm::ReportObservedAddr`] or explicitly - /// through this method. - pub fn add_external_address(&mut self, a: Multiaddr, s: AddressScore) -> AddAddressResult { - let result = self.external_addrs.add(a.clone(), s); - let expired = match &result { - AddAddressResult::Inserted { expired } => { - self.behaviour - .on_swarm_event(FromSwarm::NewExternalAddrCandidate( - NewExternalAddrCandidate { addr: &a }, - )); - expired - } - AddAddressResult::Updated { expired } => expired, - }; - for a in expired { - self.behaviour - .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { - addr: &a.addr, - })); - } - result + /// TODO + pub fn add_external_address(&mut self, a: Multiaddr) { + self.behaviour + .on_swarm_event(FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { + addr: &a, + })) } - /// Removes an external address of the local node, regardless of - /// its current score. See [`Swarm::add_external_address`] - /// for details. - /// - /// Returns `true` if the address existed and was removed, `false` - /// otherwise. - pub fn remove_external_address(&mut self, addr: &Multiaddr) -> bool { - if self.external_addrs.remove(addr) { - self.behaviour - .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr })); - true - } else { - false - } + /// TODO + pub fn remove_external_address(&mut self, addr: &Multiaddr) { + self.behaviour + .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr })) } /// Disconnects a peer by its peer ID, closing all connections to said peer. @@ -1174,12 +1132,14 @@ where .on_swarm_event(FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { addr: &addr, })); + self.confirmed_external_addr.insert(addr); } ToSwarm::ExternalAddrExpired(addr) => { self.behaviour .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr: &addr, })); + self.confirmed_external_addr.remove(&addr); } ToSwarm::CloseConnection { peer_id, @@ -1252,7 +1212,6 @@ where local_peer_id: &this.local_peer_id, supported_protocols: &this.supported_protocols, listened_addrs: this.listened_addrs.values().flatten().collect(), - external_addrs: &this.external_addrs, }; this.behaviour.poll(cx, &mut parameters) }; @@ -1420,13 +1379,11 @@ pub struct SwarmPollParameters<'a> { local_peer_id: &'a PeerId, supported_protocols: &'a [Vec], listened_addrs: Vec<&'a Multiaddr>, - external_addrs: &'a Addresses, } impl<'a> PollParameters for SwarmPollParameters<'a> { type SupportedProtocolsIter = std::iter::Cloned>>; type ListenedAddressesIter = std::iter::Cloned>; - type ExternalAddressesIter = AddressIntoIter; fn supported_protocols(&self) -> Self::SupportedProtocolsIter { self.supported_protocols.iter().cloned() @@ -1436,10 +1393,6 @@ impl<'a> PollParameters for SwarmPollParameters<'a> { self.listened_addrs.clone().into_iter().cloned() } - fn external_addresses(&self) -> Self::ExternalAddressesIter { - self.external_addrs.clone().into_iter() - } - fn local_peer_id(&self) -> &PeerId { self.local_peer_id } @@ -1628,8 +1581,8 @@ where pool: Pool::new(self.local_peer_id, self.pool_config), behaviour: self.behaviour, supported_protocols: Default::default(), + confirmed_external_addr: Default::default(), listened_addrs: HashMap::new(), - external_addrs: Addresses::default(), pending_event: None, } } diff --git a/swarm/src/registry.rs b/swarm/src/registry.rs deleted file mode 100644 index 7f8225a6a25..00000000000 --- a/swarm/src/registry.rs +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2019 Parity Technologies (UK) Ltd. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use libp2p_core::Multiaddr; -use smallvec::SmallVec; -use std::ops::{Add, Sub}; -use std::{cmp::Ordering, collections::VecDeque, num::NonZeroUsize}; - -/// A ranked collection of [`Multiaddr`] values. -/// -/// Every address has an associated [score](`AddressScore`) and iterating -/// over the addresses will return them in order from highest to lowest score. -/// -/// In addition to the currently held addresses and their score, the collection -/// keeps track of a limited history of the most-recently added addresses. -/// This history determines how address scores are reduced over time as old -/// scores expire in the context of new addresses being added: -/// -/// * An address's score is increased by a given amount whenever it is -/// [(re-)added](Addresses::add) to the collection. -/// * An address's score is decreased by the same amount used when it -/// was added when the least-recently seen addition is (as per the -/// limited history) for this address in the context of [`Addresses::add`]. -/// * If an address's score reaches 0 in the context of [`Addresses::add`], -/// it is removed from the collection. -/// -#[derive(Debug, Clone)] -pub(crate) struct Addresses { - /// The ranked sequence of addresses, from highest to lowest score. - /// - /// By design, the number of finitely scored addresses stored here is - /// never larger (but may be smaller) than the number of historic `reports` - /// at any time. - registry: SmallVec<[AddressRecord; 8]>, - /// The configured limit of the `reports` history of added addresses, - /// and thus also of the size of the `registry` w.r.t. finitely scored - /// addresses. - limit: NonZeroUsize, - /// The limited history of added addresses. If the queue reaches the `limit`, - /// the first record, i.e. the least-recently added, is removed in the - /// context of [`Addresses::add`] and the corresponding record in the - /// `registry` has its score reduced accordingly. - reports: VecDeque, -} - -/// An record in a prioritised list of addresses. -#[derive(Clone, Debug, PartialEq, Eq)] -#[non_exhaustive] -pub struct AddressRecord { - pub addr: Multiaddr, - pub score: AddressScore, -} - -/// A report tracked for a finitely scored address. -#[derive(Debug, Clone)] -struct Report { - addr: Multiaddr, - score: u32, -} - -impl AddressRecord { - fn new(addr: Multiaddr, score: AddressScore) -> Self { - AddressRecord { addr, score } - } -} - -/// The "score" of an address w.r.t. an ordered collection of addresses. -/// -/// A score is a measure of the trusworthyness of a particular -/// observation of an address. The same address may be repeatedly -/// reported with the same or differing scores. -#[derive(PartialEq, Eq, Debug, Clone, Copy, Hash)] -pub enum AddressScore { - /// The score is "infinite", i.e. an address with this score is never - /// purged from the associated address records and remains sorted at - /// the beginning (possibly with other `Infinite`ly scored addresses). - Infinite, - /// The score is finite, i.e. an address with this score has - /// its score increased and decreased as per the frequency of - /// reports (i.e. additions) of the same address relative to - /// the reports of other addresses. - Finite(u32), -} - -impl AddressScore { - fn is_zero(&self) -> bool { - &AddressScore::Finite(0) == self - } -} - -impl PartialOrd for AddressScore { - fn partial_cmp(&self, other: &AddressScore) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for AddressScore { - fn cmp(&self, other: &AddressScore) -> Ordering { - // Semantics of cardinal numbers with a single infinite cardinal. - match (self, other) { - (AddressScore::Infinite, AddressScore::Infinite) => Ordering::Equal, - (AddressScore::Infinite, AddressScore::Finite(_)) => Ordering::Greater, - (AddressScore::Finite(_), AddressScore::Infinite) => Ordering::Less, - (AddressScore::Finite(a), AddressScore::Finite(b)) => a.cmp(b), - } - } -} - -impl Add for AddressScore { - type Output = AddressScore; - - fn add(self, rhs: AddressScore) -> Self::Output { - // Semantics of cardinal numbers with a single infinite cardinal. - match (self, rhs) { - (AddressScore::Infinite, AddressScore::Infinite) => AddressScore::Infinite, - (AddressScore::Infinite, AddressScore::Finite(_)) => AddressScore::Infinite, - (AddressScore::Finite(_), AddressScore::Infinite) => AddressScore::Infinite, - (AddressScore::Finite(a), AddressScore::Finite(b)) => { - AddressScore::Finite(a.saturating_add(b)) - } - } - } -} - -impl Sub for AddressScore { - type Output = AddressScore; - - fn sub(self, rhs: u32) -> Self::Output { - // Semantics of cardinal numbers with a single infinite cardinal. - match self { - AddressScore::Infinite => AddressScore::Infinite, - AddressScore::Finite(score) => AddressScore::Finite(score.saturating_sub(rhs)), - } - } -} - -impl Default for Addresses { - fn default() -> Self { - Addresses::new(NonZeroUsize::new(200).expect("200 > 0")) - } -} - -/// The result of adding an address to an ordered list of -/// addresses with associated scores. -pub enum AddAddressResult { - Inserted { - expired: SmallVec<[AddressRecord; 8]>, - }, - Updated { - expired: SmallVec<[AddressRecord; 8]>, - }, -} - -impl Addresses { - /// Create a new ranked address collection with the given size limit - /// for [finitely scored](AddressScore::Finite) addresses. - pub(crate) fn new(limit: NonZeroUsize) -> Self { - Addresses { - registry: SmallVec::new(), - limit, - reports: VecDeque::with_capacity(limit.get()), - } - } - - /// Add a [`Multiaddr`] to the collection. - /// - /// If the given address already exists in the collection, - /// the given score is added to the current score of the address. - /// - /// If the collection has already observed the configured - /// number of address additions, the least-recently added address - /// as per this limited history has its score reduced by the amount - /// used in this prior report, with removal from the collection - /// occurring when the score drops to 0. - pub(crate) fn add(&mut self, addr: Multiaddr, score: AddressScore) -> AddAddressResult { - // If enough reports (i.e. address additions) occurred, reduce - // the score of the least-recently added address. - if self.reports.len() == self.limit.get() { - let old_report = self.reports.pop_front().expect("len = limit > 0"); - // If the address is still in the collection, decrease its score. - if let Some(record) = self.registry.iter_mut().find(|r| r.addr == old_report.addr) { - record.score = record.score - old_report.score; - isort(&mut self.registry); - } - } - - // Remove addresses that have a score of 0. - let mut expired = SmallVec::new(); - while self - .registry - .last() - .map(|e| e.score.is_zero()) - .unwrap_or(false) - { - if let Some(addr) = self.registry.pop() { - expired.push(addr); - } - } - - // If the address score is finite, remember this report. - if let AddressScore::Finite(score) = score { - self.reports.push_back(Report { - addr: addr.clone(), - score, - }); - } - - // If the address is already in the collection, increase its score. - for r in &mut self.registry { - if r.addr == addr { - r.score = r.score + score; - isort(&mut self.registry); - return AddAddressResult::Updated { expired }; - } - } - - // It is a new record. - self.registry.push(AddressRecord::new(addr, score)); - AddAddressResult::Inserted { expired } - } - - /// Explicitly remove an address from the collection. - /// - /// Returns `true` if the address existed in the collection - /// and was thus removed, false otherwise. - pub(crate) fn remove(&mut self, addr: &Multiaddr) -> bool { - if let Some(pos) = self.registry.iter().position(|r| &r.addr == addr) { - self.registry.remove(pos); - true - } else { - false - } - } - - /// Return an iterator over all [`Multiaddr`] values. - /// - /// The iteration is ordered by descending score. - pub(crate) fn iter(&self) -> AddressIter<'_> { - AddressIter { - items: &self.registry, - offset: 0, - } - } - - /// Return an iterator over all [`Multiaddr`] values. - /// - /// The iteration is ordered by descending score. - pub(crate) fn into_iter(self) -> AddressIntoIter { - AddressIntoIter { - items: self.registry, - } - } -} - -/// An iterator over [`Multiaddr`] values. -#[derive(Clone)] -pub(crate) struct AddressIter<'a> { - items: &'a [AddressRecord], - offset: usize, -} - -impl<'a> Iterator for AddressIter<'a> { - type Item = &'a AddressRecord; - - fn next(&mut self) -> Option { - if self.offset == self.items.len() { - return None; - } - let item = &self.items[self.offset]; - self.offset += 1; - Some(item) - } - - fn size_hint(&self) -> (usize, Option) { - let n = self.items.len() - self.offset; - (n, Some(n)) - } -} - -impl<'a> ExactSizeIterator for AddressIter<'a> {} - -/// An iterator over [`Multiaddr`] values. -#[derive(Clone)] -pub struct AddressIntoIter { - items: SmallVec<[AddressRecord; 8]>, -} - -impl Iterator for AddressIntoIter { - type Item = AddressRecord; - - fn next(&mut self) -> Option { - if !self.items.is_empty() { - Some(self.items.remove(0)) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - let n = self.items.len(); - (n, Some(n)) - } -} - -impl ExactSizeIterator for AddressIntoIter {} - -// Reverse insertion sort. -fn isort(xs: &mut [AddressRecord]) { - for i in 1..xs.len() { - for j in (1..=i).rev() { - if xs[j].score <= xs[j - 1].score { - break; - } - xs.swap(j, j - 1) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use libp2p_core::multiaddr::{Multiaddr, Protocol}; - use quickcheck::*; - use std::num::{NonZeroU8, NonZeroUsize}; - - impl Arbitrary for AddressScore { - fn arbitrary(g: &mut Gen) -> AddressScore { - if g.gen_range(0..10u8) == 0 { - // ~10% "Infinitely" scored addresses - AddressScore::Infinite - } else { - AddressScore::Finite(Arbitrary::arbitrary(g)) - } - } - } - - impl Arbitrary for AddressRecord { - fn arbitrary(g: &mut Gen) -> Self { - let addr = Protocol::Tcp(g.gen_range(0..256)).into(); - let score = AddressScore::arbitrary(g); - AddressRecord::new(addr, score) - } - } - - #[test] - fn isort_sorts() { - fn property(xs: Vec) { - let mut xs = xs - .into_iter() - .map(|score| AddressRecord::new(Multiaddr::empty(), score)) - .collect::>(); - - isort(&mut xs); - - for i in 1..xs.len() { - assert!(xs[i - 1].score >= xs[i].score) - } - } - - quickcheck(property as fn(_)); - } - - #[test] - fn score_retention() { - fn prop(first: AddressRecord, other: AddressRecord) -> TestResult { - if first.addr == other.addr || first.score.is_zero() { - return TestResult::discard(); - } - - let mut addresses = Addresses::default(); - - // Add the first address. - addresses.add(first.addr.clone(), first.score); - assert!(addresses.iter().any(|a| a.addr == first.addr)); - - // Add another address so often that the initial report of - // the first address may be purged and, since it was the - // only report, the address removed. - for _ in 0..addresses.limit.get() + 1 { - addresses.add(other.addr.clone(), other.score); - } - - let exists = addresses.iter().any(|a| a.addr == first.addr); - - match (first.score, other.score) { - // Only finite scores push out other finite scores. - (AddressScore::Finite(_), AddressScore::Finite(_)) => assert!(!exists), - _ => assert!(exists), - } - - TestResult::passed() - } - - quickcheck(prop as fn(_, _) -> _); - } - - #[test] - fn score_retention_finite_0() { - let first = { - let addr = Protocol::Tcp(42).into(); - let score = AddressScore::Finite(0); - AddressRecord::new(addr, score) - }; - let other = { - let addr = Protocol::Udp(42).into(); - let score = AddressScore::Finite(42); - AddressRecord::new(addr, score) - }; - - let mut addresses = Addresses::default(); - - // Add the first address. - addresses.add(first.addr.clone(), first.score); - assert!(addresses.iter().any(|a| a.addr == first.addr)); - - // Add another address so the first will address be purged, - // because its score is finite(0) - addresses.add(other.addr.clone(), other.score); - - assert!(addresses.iter().any(|a| a.addr == other.addr)); - assert!(!addresses.iter().any(|a| a.addr == first.addr)); - } - - #[test] - fn finitely_scored_address_limit() { - fn prop(reports: Vec, limit: NonZeroU8) { - let mut addresses = Addresses::new(limit.into()); - - // Add all reports. - for r in reports { - addresses.add(r.addr, r.score); - } - - // Count the finitely scored addresses. - let num_finite = addresses - .iter() - .filter(|r| { - matches!( - r, - AddressRecord { - score: AddressScore::Finite(_), - .. - } - ) - }) - .count(); - - // Check against the limit. - assert!(num_finite <= limit.get() as usize); - } - - quickcheck(prop as fn(_, _)); - } - - #[test] - fn record_score_sum() { - fn prop(records: Vec) -> bool { - // Make sure the address collection can hold all reports. - let n = std::cmp::max(records.len(), 1); - let mut addresses = Addresses::new(NonZeroUsize::new(n).unwrap()); - - // Add all address reports to the collection. - for r in records.iter() { - addresses.add(r.addr.clone(), r.score); - } - - // Check that each address in the registry has the expected score. - for r in &addresses.registry { - let expected_score = records.iter().fold(None::, |sum, rec| { - if rec.addr == r.addr { - sum.map_or(Some(rec.score), |s| Some(s + rec.score)) - } else { - sum - } - }); - - if Some(r.score) != expected_score { - return false; - } - } - - true - } - - quickcheck(prop as fn(_) -> _) - } -} From 5a945a8794cbc7c4bb6b9f2f2afbb5b42744d667 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 17 May 2023 14:14:47 +0200 Subject: [PATCH 05/17] Update identify docs --- protocols/identify/src/behaviour.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/protocols/identify/src/behaviour.rs b/protocols/identify/src/behaviour.rs index ac08a142a24..8081924fffd 100644 --- a/protocols/identify/src/behaviour.rs +++ b/protocols/identify/src/behaviour.rs @@ -43,8 +43,7 @@ use std::{ /// about them, and answers identify queries from other nodes. /// /// All external addresses of the local node supposedly observed by remotes -/// are reported via [`ToSwarm::ReportObservedAddr`] with a -/// [score](AddressScore) of `1`. +/// are reported via [`ToSwarm::NewExternalAddrCandidate`]. pub struct Behaviour { config: Config, /// For each peer we're connected to, the observed address to send back to it. From 4bcb4c115660cef1791220298228f54236a04649 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 17 May 2023 14:16:39 +0200 Subject: [PATCH 06/17] Insert and remove external addresses --- swarm/src/lib.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 8e80a65ac65..3acac58b5a2 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -647,13 +647,15 @@ where self.behaviour .on_swarm_event(FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { addr: &a, - })) + })); + self.confirmed_external_addr.insert(a); } /// TODO pub fn remove_external_address(&mut self, addr: &Multiaddr) { self.behaviour - .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr })) + .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr })); + self.confirmed_external_addr.remove(addr); } /// Disconnects a peer by its peer ID, closing all connections to said peer. @@ -1128,18 +1130,10 @@ where } } ToSwarm::ExternalAddrConfirmed(addr) => { - self.behaviour - .on_swarm_event(FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { - addr: &addr, - })); - self.confirmed_external_addr.insert(addr); + self.add_external_address(addr); } ToSwarm::ExternalAddrExpired(addr) => { - self.behaviour - .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { - addr: &addr, - })); - self.confirmed_external_addr.remove(&addr); + self.remove_external_address(&addr); } ToSwarm::CloseConnection { peer_id, From 7fef679292f216d758c3cdebcfba17c2d05bbcf8 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 17 May 2023 14:22:22 +0200 Subject: [PATCH 07/17] Update docs --- swarm/src/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index 3acac58b5a2..fad4a5a7f94 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -640,9 +640,10 @@ where self.confirmed_external_addr.iter() } - /// Adds an external address record for the local node. + /// Add a **confirmed** external address for the local node. /// - /// TODO + /// This function should only be called with addresses that are guaranteed to be reachable. + /// The address is broadcast to all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrConfirmed`]. pub fn add_external_address(&mut self, a: Multiaddr) { self.behaviour .on_swarm_event(FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { @@ -651,7 +652,9 @@ where self.confirmed_external_addr.insert(a); } - /// TODO + /// Remove an external address for the local node. + /// + /// The address is broadcast to all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrExpired`]. pub fn remove_external_address(&mut self, addr: &Multiaddr) { self.behaviour .on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr })); From 5f0c01dd61c8a2162ee50499cefb4ec6b8eebc29 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Thu, 18 May 2023 23:51:23 +1000 Subject: [PATCH 08/17] Apply suggestions from code review Co-authored-by: Max Inden --- swarm/src/behaviour.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index 8e1707b0300..b6026109459 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -441,9 +441,9 @@ pub enum FromSwarm<'a, Handler> { ListenerClosed(ListenerClosed<'a>), /// Informs the behaviour that we have discovered a new candidate for an external address for us. NewExternalAddrCandidate(NewExternalAddrCandidate<'a>), - /// Informs the behaviour that an external address was removed. + /// Informs the behaviour that an external address of the local node was removed. ExternalAddrConfirmed(ExternalAddrConfirmed<'a>), - /// Informs the behaviour that an external address was removed. + /// Informs the behaviour that an external address of the local node expired, i.e. is no-longer confirmed. ExternalAddrExpired(ExternalAddrExpired<'a>), } From 0256f8a0cfe57813d7e47fd462d53f092fbe4cea Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 22 May 2023 10:21:14 +0200 Subject: [PATCH 09/17] Fix doc link --- protocols/rendezvous/src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/rendezvous/src/client.rs b/protocols/rendezvous/src/client.rs index d410cce8d89..d1a514f1820 100644 --- a/protocols/rendezvous/src/client.rs +++ b/protocols/rendezvous/src/client.rs @@ -74,7 +74,7 @@ impl Behaviour { /// Register our external addresses in the given namespace with the given rendezvous peer. /// /// External addresses are either manually added via [`libp2p_swarm::Swarm::add_external_address`] or reported - /// by other [`NetworkBehaviour`]s via [`ToSwarm::ReportObservedAddr`]. + /// by other [`NetworkBehaviour`]s via [`ToSwarm::ExternalAddrConfirmed`]. pub fn register(&mut self, namespace: Namespace, rendezvous_node: PeerId, ttl: Option) { self.pending_register_requests .push((namespace, rendezvous_node, ttl)); From 3c38b3f5d6e1bf2a5f0a87acb4be90d1bd6959d6 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 22 May 2023 10:25:37 +0200 Subject: [PATCH 10/17] Remove private NAT status test We no longer test external addresses. --- protocols/autonat/tests/test_client.rs | 46 ++------------------------ 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/protocols/autonat/tests/test_client.rs b/protocols/autonat/tests/test_client.rs index d4708f542f9..e8c923c0842 100644 --- a/protocols/autonat/tests/test_client.rs +++ b/protocols/autonat/tests/test_client.rs @@ -70,48 +70,6 @@ async fn test_auto_probe() { assert!(client.behaviour().public_address().is_none()); assert_eq!(client.behaviour().confidence(), 0); - // Test Private NAT Status - - // Artificially add a faulty address. - let unreachable_addr: Multiaddr = "/ip4/127.0.0.1/tcp/42".parse().unwrap(); - client.add_external_address(unreachable_addr.clone()); - - let id = match client.next_behaviour_event().await { - Event::OutboundProbe(OutboundProbeEvent::Request { probe_id, peer }) => { - assert_eq!(peer, server_id); - probe_id - } - other => panic!("Unexpected behaviour event: {other:?}."), - }; - - match client.next_behaviour_event().await { - Event::OutboundProbe(OutboundProbeEvent::Error { - probe_id, - peer, - error, - }) => { - assert_eq!(peer.unwrap(), server_id); - assert_eq!(probe_id, id); - assert_eq!( - error, - OutboundProbeError::Response(ResponseError::DialError) - ); - } - other => panic!("Unexpected behaviour event: {other:?}."), - } - - match client.next_behaviour_event().await { - Event::StatusChanged { old, new } => { - assert_eq!(old, NatStatus::Unknown); - assert_eq!(new, NatStatus::Private); - } - other => panic!("Unexpected behaviour event: {other:?}."), - } - - assert_eq!(client.behaviour().confidence(), 0); - assert_eq!(client.behaviour().nat_status(), NatStatus::Private); - assert!(client.behaviour().public_address().is_none()); - // Test new public listening address client.listen().await; @@ -142,12 +100,14 @@ async fn test_auto_probe() { } SwarmEvent::Behaviour(Event::StatusChanged { old, new }) => { // Expect to flip status to public - assert_eq!(old, NatStatus::Private); + assert_eq!(old, NatStatus::Unknown); assert!(matches!(new, NatStatus::Public(_))); assert!(new.is_public()); break; } SwarmEvent::IncomingConnection { .. } + | SwarmEvent::ConnectionEstablished { .. } + | SwarmEvent::Dialing(..) | SwarmEvent::NewListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } => {} other => panic!("Unexpected swarm event: {other:?}."), From b1edd30ac0bdf290156fb0dc627e8b33a3382b1b Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 22 May 2023 10:31:33 +0200 Subject: [PATCH 11/17] Fix more doc links --- swarm/src/behaviour.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index b6026109459..98d1d00c1a8 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -290,7 +290,7 @@ pub enum ToSwarm { event: TInEvent, }, - /// Reports a new candidate for an external address to the [`Swarm`]. + /// Reports a new candidate for an external address to the [`Swarm`](crate::Swarm). /// /// This address could come from a variety of sources: /// - A protocol such as identify obtained it from a remote. @@ -299,10 +299,10 @@ pub enum ToSwarm { /// - We established a new relay connection. NewExternalAddrCandidate(Multiaddr), - /// Indicates to the [`Swarm`] that the provided address is confirmed to be externally reachable. + /// Indicates to the [`Swarm`](crate::Swarm) that the provided address is confirmed to be externally reachable. ExternalAddrConfirmed(Multiaddr), - /// Indicates to the [`Swarm`] that we are no longer externally reachable under the provided address. + /// Indicates to the [`Swarm`](crate::Swarm) that we are no longer externally reachable under the provided address. ExternalAddrExpired(Multiaddr), /// Instructs the `Swarm` to initiate a graceful close of one or all connections From fc58b54e8e1aae0759d9adb9ab62a9d398942017 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 22 May 2023 10:32:49 +0200 Subject: [PATCH 12/17] Fix compile error with latest master --- protocols/autonat/tests/test_client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/autonat/tests/test_client.rs b/protocols/autonat/tests/test_client.rs index e8c923c0842..6f89cc2e17c 100644 --- a/protocols/autonat/tests/test_client.rs +++ b/protocols/autonat/tests/test_client.rs @@ -107,7 +107,7 @@ async fn test_auto_probe() { } SwarmEvent::IncomingConnection { .. } | SwarmEvent::ConnectionEstablished { .. } - | SwarmEvent::Dialing(..) + | SwarmEvent::Dialing { .. } | SwarmEvent::NewListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } => {} other => panic!("Unexpected swarm event: {other:?}."), From 62ec4828ca9ea7a293b57cec0b11d697f39eed72 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 22 May 2023 20:20:32 +0200 Subject: [PATCH 13/17] Delete tests --- protocols/autonat/tests/test_server.rs | 105 ------------------------- 1 file changed, 105 deletions(-) diff --git a/protocols/autonat/tests/test_server.rs b/protocols/autonat/tests/test_server.rs index 7d3ead0c0c4..f8bcd375c36 100644 --- a/protocols/autonat/tests/test_server.rs +++ b/protocols/autonat/tests/test_server.rs @@ -23,7 +23,6 @@ use libp2p_autonat::{ }; use libp2p_core::{multiaddr::Protocol, ConnectedPoint, Endpoint, Multiaddr}; use libp2p_identity::PeerId; -use libp2p_swarm::DialError; use libp2p_swarm::{Swarm, SwarmEvent}; use libp2p_swarm_test::SwarmExt as _; use std::{num::NonZeroU32, time::Duration}; @@ -127,51 +126,6 @@ async fn test_dial_back() { } } -#[async_std::test] -async fn test_dial_error() { - let (mut server, server_id, server_addr) = new_server_swarm(None).await; - let (mut client, client_id) = new_client_swarm(server_id, server_addr).await; - client.add_external_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); - async_std::task::spawn(client.loop_on_next()); - - let request_probe_id = match server.next_behaviour_event().await { - Event::InboundProbe(InboundProbeEvent::Request { peer, probe_id, .. }) => { - assert_eq!(peer, client_id); - probe_id - } - other => panic!("Unexpected behaviour event: {other:?}."), - }; - - loop { - match server.next_swarm_event().await { - SwarmEvent::OutgoingConnectionError { peer_id, error, .. } => { - assert_eq!(peer_id.unwrap(), client_id); - assert!(matches!(error, DialError::Transport(_))); - break; - } - SwarmEvent::Dialing { - peer_id: Some(peer), - .. - } => assert_eq!(peer, client_id), - SwarmEvent::NewListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } => {} - other => panic!("Unexpected swarm event: {other:?}."), - } - } - - match server.next_behaviour_event().await { - Event::InboundProbe(InboundProbeEvent::Error { - probe_id, - peer, - error, - }) => { - assert_eq!(probe_id, request_probe_id); - assert_eq!(peer, client_id); - assert_eq!(error, InboundProbeError::Response(ResponseError::DialError)); - } - other => panic!("Unexpected behaviour event: {other:?}."), - } -} - #[async_std::test] async fn test_throttle_global_max() { let (mut server, server_id, server_addr) = new_server_swarm(Some(Config { @@ -259,65 +213,6 @@ async fn test_throttle_peer_max() { }; } -#[async_std::test] -async fn test_dial_multiple_addr() { - let (mut server, server_id, server_addr) = new_server_swarm(Some(Config { - throttle_clients_peer_max: 1, - throttle_clients_period: Duration::from_secs(60), - only_global_ips: false, - ..Default::default() - })) - .await; - - let (mut client, client_id) = new_client_swarm(server_id, server_addr.clone()).await; - client.listen().await; - client.add_external_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); - async_std::task::spawn(client.loop_on_next()); - - let dial_addresses = match server.next_behaviour_event().await { - Event::InboundProbe(InboundProbeEvent::Request { - peer, addresses, .. - }) => { - assert_eq!(addresses.len(), 2); - assert_eq!(client_id, peer); - addresses - } - other => panic!("Unexpected behaviour event: {other:?}."), - }; - - loop { - match server.next_swarm_event().await { - SwarmEvent::ConnectionEstablished { - peer_id, - endpoint: - ConnectedPoint::Dialer { - address, - role_override: Endpoint::Dialer, - }, - concurrent_dial_errors, - .. - } => { - assert_eq!(peer_id, client_id); - let dial_errors = concurrent_dial_errors.unwrap(); - - // The concurrent dial might not be fast enough to produce a dial error. - if let Some((addr, _)) = dial_errors.get(0) { - assert_eq!(addr, &dial_addresses[0]); - } - - assert_eq!(address, dial_addresses[1]); - break; - } - SwarmEvent::Dialing { - peer_id: Some(peer), - .. - } => assert_eq!(peer, client_id), - SwarmEvent::NewListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } => {} - other => panic!("Unexpected swarm event: {other:?}."), - } - } -} - #[async_std::test] async fn test_global_ips_config() { let (mut server, server_id, server_addr) = new_server_swarm(Some(Config { From 1c5d243fe54618a9220609bc55e51a34198fb410 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 22 May 2023 20:30:44 +0200 Subject: [PATCH 14/17] Update docs --- swarm/src/behaviour.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index 98d1d00c1a8..a6560190e48 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -292,6 +292,8 @@ pub enum ToSwarm { /// Reports a new candidate for an external address to the [`Swarm`](crate::Swarm). /// + /// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::NewExternalAddrCandidate`]. + /// /// This address could come from a variety of sources: /// - A protocol such as identify obtained it from a remote. /// - The user provided it based on configuration. @@ -300,9 +302,15 @@ pub enum ToSwarm { NewExternalAddrCandidate(Multiaddr), /// Indicates to the [`Swarm`](crate::Swarm) that the provided address is confirmed to be externally reachable. + /// + /// This is intended to be issued in response to a [`FromSwarm::NewExternalAddrCandidate`] if we are indeed externally reachable on this address. + /// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrConfirmed`]. ExternalAddrConfirmed(Multiaddr), /// Indicates to the [`Swarm`](crate::Swarm) that we are no longer externally reachable under the provided address. + /// + /// This expires an address that was earlier confirmed via [`ToSwarm::ExternalAddrConfirmed`]. + /// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrExpired`]. ExternalAddrExpired(Multiaddr), /// Instructs the `Swarm` to initiate a graceful close of one or all connections From ccc9bf302836811df0c439ee6520e16ef37b3936 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 23 May 2023 12:28:10 +0200 Subject: [PATCH 15/17] Revert "Delete tests" This reverts commit 62ec4828ca9ea7a293b57cec0b11d697f39eed72. --- protocols/autonat/tests/test_server.rs | 105 +++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/protocols/autonat/tests/test_server.rs b/protocols/autonat/tests/test_server.rs index f8bcd375c36..7d3ead0c0c4 100644 --- a/protocols/autonat/tests/test_server.rs +++ b/protocols/autonat/tests/test_server.rs @@ -23,6 +23,7 @@ use libp2p_autonat::{ }; use libp2p_core::{multiaddr::Protocol, ConnectedPoint, Endpoint, Multiaddr}; use libp2p_identity::PeerId; +use libp2p_swarm::DialError; use libp2p_swarm::{Swarm, SwarmEvent}; use libp2p_swarm_test::SwarmExt as _; use std::{num::NonZeroU32, time::Duration}; @@ -126,6 +127,51 @@ async fn test_dial_back() { } } +#[async_std::test] +async fn test_dial_error() { + let (mut server, server_id, server_addr) = new_server_swarm(None).await; + let (mut client, client_id) = new_client_swarm(server_id, server_addr).await; + client.add_external_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); + async_std::task::spawn(client.loop_on_next()); + + let request_probe_id = match server.next_behaviour_event().await { + Event::InboundProbe(InboundProbeEvent::Request { peer, probe_id, .. }) => { + assert_eq!(peer, client_id); + probe_id + } + other => panic!("Unexpected behaviour event: {other:?}."), + }; + + loop { + match server.next_swarm_event().await { + SwarmEvent::OutgoingConnectionError { peer_id, error, .. } => { + assert_eq!(peer_id.unwrap(), client_id); + assert!(matches!(error, DialError::Transport(_))); + break; + } + SwarmEvent::Dialing { + peer_id: Some(peer), + .. + } => assert_eq!(peer, client_id), + SwarmEvent::NewListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } => {} + other => panic!("Unexpected swarm event: {other:?}."), + } + } + + match server.next_behaviour_event().await { + Event::InboundProbe(InboundProbeEvent::Error { + probe_id, + peer, + error, + }) => { + assert_eq!(probe_id, request_probe_id); + assert_eq!(peer, client_id); + assert_eq!(error, InboundProbeError::Response(ResponseError::DialError)); + } + other => panic!("Unexpected behaviour event: {other:?}."), + } +} + #[async_std::test] async fn test_throttle_global_max() { let (mut server, server_id, server_addr) = new_server_swarm(Some(Config { @@ -213,6 +259,65 @@ async fn test_throttle_peer_max() { }; } +#[async_std::test] +async fn test_dial_multiple_addr() { + let (mut server, server_id, server_addr) = new_server_swarm(Some(Config { + throttle_clients_peer_max: 1, + throttle_clients_period: Duration::from_secs(60), + only_global_ips: false, + ..Default::default() + })) + .await; + + let (mut client, client_id) = new_client_swarm(server_id, server_addr.clone()).await; + client.listen().await; + client.add_external_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); + async_std::task::spawn(client.loop_on_next()); + + let dial_addresses = match server.next_behaviour_event().await { + Event::InboundProbe(InboundProbeEvent::Request { + peer, addresses, .. + }) => { + assert_eq!(addresses.len(), 2); + assert_eq!(client_id, peer); + addresses + } + other => panic!("Unexpected behaviour event: {other:?}."), + }; + + loop { + match server.next_swarm_event().await { + SwarmEvent::ConnectionEstablished { + peer_id, + endpoint: + ConnectedPoint::Dialer { + address, + role_override: Endpoint::Dialer, + }, + concurrent_dial_errors, + .. + } => { + assert_eq!(peer_id, client_id); + let dial_errors = concurrent_dial_errors.unwrap(); + + // The concurrent dial might not be fast enough to produce a dial error. + if let Some((addr, _)) = dial_errors.get(0) { + assert_eq!(addr, &dial_addresses[0]); + } + + assert_eq!(address, dial_addresses[1]); + break; + } + SwarmEvent::Dialing { + peer_id: Some(peer), + .. + } => assert_eq!(peer, client_id), + SwarmEvent::NewListenAddr { .. } | SwarmEvent::ExpiredListenAddr { .. } => {} + other => panic!("Unexpected swarm event: {other:?}."), + } + } +} + #[async_std::test] async fn test_global_ips_config() { let (mut server, server_id, server_addr) = new_server_swarm(Some(Config { From a4886f554d1b101acc95d4ebdc8e403fced26b1a Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 23 May 2023 12:33:51 +0200 Subject: [PATCH 16/17] Fix tests by adding a new API to AutoNAT --- protocols/autonat/src/behaviour.rs | 11 +++++++++-- protocols/autonat/tests/test_client.rs | 4 +++- protocols/autonat/tests/test_server.rs | 8 ++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/protocols/autonat/src/behaviour.rs b/protocols/autonat/src/behaviour.rs index b5381d62af6..0437e0849eb 100644 --- a/protocols/autonat/src/behaviour.rs +++ b/protocols/autonat/src/behaviour.rs @@ -279,6 +279,14 @@ impl Behaviour { self.servers.retain(|p| p != peer); } + /// Add a new candidate for an external address. + /// + /// This will trigger a new probe for the given address. + pub fn add_external_address_candidate(&mut self, candidate: Multiaddr) { + self.other_candidates.insert(candidate); + self.as_client().on_new_address(); + } + fn as_client(&mut self) -> AsClient { AsClient { inner: &mut self.inner, @@ -570,8 +578,7 @@ impl NetworkBehaviour for Behaviour { .on_swarm_event(FromSwarm::NewExternalAddrCandidate( NewExternalAddrCandidate { addr }, )); - self.other_candidates.insert(addr.to_owned()); - self.as_client().on_new_address(); + self.add_external_address_candidate(addr.to_owned()); } listen_failure @ FromSwarm::ListenFailure(_) => { self.inner.on_swarm_event(listen_failure) diff --git a/protocols/autonat/tests/test_client.rs b/protocols/autonat/tests/test_client.rs index 6f89cc2e17c..baa65300c2a 100644 --- a/protocols/autonat/tests/test_client.rs +++ b/protocols/autonat/tests/test_client.rs @@ -158,7 +158,9 @@ async fn test_confidence() { client.listen().await; } else { let unreachable_addr = "/ip4/127.0.0.1/tcp/42".parse().unwrap(); - client.add_external_address(unreachable_addr); + client + .behaviour_mut() + .add_external_address_candidate(unreachable_addr); } for i in 0..MAX_CONFIDENCE + 1 { diff --git a/protocols/autonat/tests/test_server.rs b/protocols/autonat/tests/test_server.rs index 7d3ead0c0c4..8753003d6de 100644 --- a/protocols/autonat/tests/test_server.rs +++ b/protocols/autonat/tests/test_server.rs @@ -131,7 +131,9 @@ async fn test_dial_back() { async fn test_dial_error() { let (mut server, server_id, server_addr) = new_server_swarm(None).await; let (mut client, client_id) = new_client_swarm(server_id, server_addr).await; - client.add_external_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); + client + .behaviour_mut() + .add_external_address_candidate("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); async_std::task::spawn(client.loop_on_next()); let request_probe_id = match server.next_behaviour_event().await { @@ -271,7 +273,9 @@ async fn test_dial_multiple_addr() { let (mut client, client_id) = new_client_swarm(server_id, server_addr.clone()).await; client.listen().await; - client.add_external_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); + client + .behaviour_mut() + .add_external_address_candidate("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); async_std::task::spawn(client.loop_on_next()); let dial_addresses = match server.next_behaviour_event().await { From d7da7567a08a609d0a664284ed3517608be0f7cf Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 23 May 2023 12:35:13 +0200 Subject: [PATCH 17/17] Rename to `probe_address` --- protocols/autonat/src/behaviour.rs | 8 +++----- protocols/autonat/tests/test_client.rs | 4 +--- protocols/autonat/tests/test_server.rs | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/protocols/autonat/src/behaviour.rs b/protocols/autonat/src/behaviour.rs index 0437e0849eb..926445c9e49 100644 --- a/protocols/autonat/src/behaviour.rs +++ b/protocols/autonat/src/behaviour.rs @@ -279,10 +279,8 @@ impl Behaviour { self.servers.retain(|p| p != peer); } - /// Add a new candidate for an external address. - /// - /// This will trigger a new probe for the given address. - pub fn add_external_address_candidate(&mut self, candidate: Multiaddr) { + /// Explicitly probe the provided address for external reachability. + pub fn probe_address(&mut self, candidate: Multiaddr) { self.other_candidates.insert(candidate); self.as_client().on_new_address(); } @@ -578,7 +576,7 @@ impl NetworkBehaviour for Behaviour { .on_swarm_event(FromSwarm::NewExternalAddrCandidate( NewExternalAddrCandidate { addr }, )); - self.add_external_address_candidate(addr.to_owned()); + self.probe_address(addr.to_owned()); } listen_failure @ FromSwarm::ListenFailure(_) => { self.inner.on_swarm_event(listen_failure) diff --git a/protocols/autonat/tests/test_client.rs b/protocols/autonat/tests/test_client.rs index baa65300c2a..1911d1a6b2d 100644 --- a/protocols/autonat/tests/test_client.rs +++ b/protocols/autonat/tests/test_client.rs @@ -158,9 +158,7 @@ async fn test_confidence() { client.listen().await; } else { let unreachable_addr = "/ip4/127.0.0.1/tcp/42".parse().unwrap(); - client - .behaviour_mut() - .add_external_address_candidate(unreachable_addr); + client.behaviour_mut().probe_address(unreachable_addr); } for i in 0..MAX_CONFIDENCE + 1 { diff --git a/protocols/autonat/tests/test_server.rs b/protocols/autonat/tests/test_server.rs index 8753003d6de..0f14c6edb27 100644 --- a/protocols/autonat/tests/test_server.rs +++ b/protocols/autonat/tests/test_server.rs @@ -133,7 +133,7 @@ async fn test_dial_error() { let (mut client, client_id) = new_client_swarm(server_id, server_addr).await; client .behaviour_mut() - .add_external_address_candidate("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); + .probe_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); async_std::task::spawn(client.loop_on_next()); let request_probe_id = match server.next_behaviour_event().await { @@ -275,7 +275,7 @@ async fn test_dial_multiple_addr() { client.listen().await; client .behaviour_mut() - .add_external_address_candidate("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); + .probe_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap()); async_std::task::spawn(client.loop_on_next()); let dial_addresses = match server.next_behaviour_event().await {