mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-18 12:31:22 +00:00
feat(swarm): replace address scoring with explicit candidates
Previously, a `NetworkBehaviour` could report an `AddressScore` for an external address. This score was a `u32` and addresses would be ranked amongst those. In reality, an address is either confirmed to be publicly reachable (via a protocol such as AutoNAT) or merely represents a candidate that might be an external address. In a way, addresses are guilty (private) until proven innocent (publicly reachable). When a `NetworkBehaviour` reports an address candidate, we perform address translation on it to potentially correct for ephemeral ports of TCP. These candidates are then injected back into the `NetworkBehaviour`. Protocols such as AutoNAT can use these addresses as a source for probing their NAT status. Once confirmed, they can emit a `ToSwarm::ExternalAddrConfirmed` event which again will be passed to all `NetworkBehaviour`s. This simplified approach will allow us implement Kademlia's client-mode (https://github.com/libp2p/rust-libp2p/issues/2032) without additional configuration options: As soon as an address is reported as publicly reachable, we can activate server-mode for that connection. Related: https://github.com/libp2p/rust-libp2p/pull/3877. Related: https://github.com/libp2p/rust-libp2p/issues/3953. Related: https://github.com/libp2p/rust-libp2p/issues/2032. Related: https://github.com/libp2p/go-libp2p/issues/2229. Co-authored-by: Max Inden <mail@max-inden.de> Pull-Request: #3954.
This commit is contained in:
@ -22,7 +22,7 @@ use futures::StreamExt;
|
|||||||
use libp2p::{
|
use libp2p::{
|
||||||
core::transport::upgrade::Version,
|
core::transport::upgrade::Version,
|
||||||
identity, noise, ping, rendezvous,
|
identity, noise, ping, rendezvous,
|
||||||
swarm::{keep_alive, AddressScore, NetworkBehaviour, SwarmBuilder, SwarmEvent},
|
swarm::{keep_alive, NetworkBehaviour, SwarmBuilder, SwarmEvent},
|
||||||
tcp, yamux, Multiaddr, PeerId, Transport,
|
tcp, yamux, Multiaddr, PeerId, Transport,
|
||||||
};
|
};
|
||||||
use std::time::Duration;
|
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.
|
// 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.
|
// This address is recorded in the registration entry by the rendezvous point.
|
||||||
let external_address = "/ip4/127.0.0.1/tcp/0".parse::<Multiaddr>().unwrap();
|
let external_address = "/ip4/127.0.0.1/tcp/0".parse::<Multiaddr>().unwrap();
|
||||||
swarm.add_external_address(external_address, AddressScore::Infinite);
|
swarm.add_external_address(external_address);
|
||||||
|
|
||||||
log::info!("Local peer id: {}", swarm.local_peer_id());
|
log::info!("Local peer id: {}", swarm.local_peer_id());
|
||||||
|
|
||||||
|
@ -243,8 +243,9 @@ where
|
|||||||
FromSwarm::ExpiredListenAddr(_) => {}
|
FromSwarm::ExpiredListenAddr(_) => {}
|
||||||
FromSwarm::ListenerError(_) => {}
|
FromSwarm::ListenerError(_) => {}
|
||||||
FromSwarm::ListenerClosed(_) => {}
|
FromSwarm::ListenerClosed(_) => {}
|
||||||
FromSwarm::NewExternalAddr(_) => {}
|
FromSwarm::NewExternalAddrCandidate(_) => {}
|
||||||
FromSwarm::ExpiredExternalAddr(_) => {}
|
FromSwarm::ExternalAddrExpired(_) => {}
|
||||||
|
FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,13 +411,7 @@ mod tests {
|
|||||||
dialer
|
dialer
|
||||||
.dial(
|
.dial(
|
||||||
DialOpts::unknown_peer_id()
|
DialOpts::unknown_peer_id()
|
||||||
.address(
|
.address(listener.external_addresses().next().cloned().unwrap())
|
||||||
listener
|
|
||||||
.external_addresses()
|
|
||||||
.map(|a| a.addr.clone())
|
|
||||||
.next()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -470,12 +465,7 @@ mod tests {
|
|||||||
{
|
{
|
||||||
dialer.dial(
|
dialer.dial(
|
||||||
DialOpts::peer_id(*listener.local_peer_id())
|
DialOpts::peer_id(*listener.local_peer_id())
|
||||||
.addresses(
|
.addresses(listener.external_addresses().cloned().collect())
|
||||||
listener
|
|
||||||
.external_addresses()
|
|
||||||
.map(|a| a.addr.clone())
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -337,8 +337,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
FromSwarm::ExpiredListenAddr(_) => {}
|
FromSwarm::ExpiredListenAddr(_) => {}
|
||||||
FromSwarm::ListenerError(_) => {}
|
FromSwarm::ListenerError(_) => {}
|
||||||
FromSwarm::ListenerClosed(_) => {}
|
FromSwarm::ListenerClosed(_) => {}
|
||||||
FromSwarm::NewExternalAddr(_) => {}
|
FromSwarm::NewExternalAddrCandidate(_) => {}
|
||||||
FromSwarm::ExpiredExternalAddr(_) => {}
|
FromSwarm::ExternalAddrExpired(_) => {}
|
||||||
|
FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +36,10 @@ use libp2p_request_response::{
|
|||||||
};
|
};
|
||||||
use libp2p_swarm::{
|
use libp2p_swarm::{
|
||||||
behaviour::{
|
behaviour::{
|
||||||
AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredExternalAddr,
|
AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredListenAddr,
|
||||||
ExpiredListenAddr, FromSwarm,
|
ExternalAddrExpired, FromSwarm,
|
||||||
},
|
},
|
||||||
ConnectionDenied, ConnectionId, ExternalAddresses, ListenAddresses, NetworkBehaviour,
|
ConnectionDenied, ConnectionId, ListenAddresses, NetworkBehaviour, NewExternalAddrCandidate,
|
||||||
PollParameters, THandler, THandlerInEvent, THandlerOutEvent, ToSwarm,
|
PollParameters, THandler, THandlerInEvent, THandlerOutEvent, ToSwarm,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
@ -214,7 +214,7 @@ pub struct Behaviour {
|
|||||||
probe_id: ProbeId,
|
probe_id: ProbeId,
|
||||||
|
|
||||||
listen_addresses: ListenAddresses,
|
listen_addresses: ListenAddresses,
|
||||||
external_addresses: ExternalAddresses,
|
other_candidates: HashSet<Multiaddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Behaviour {
|
impl Behaviour {
|
||||||
@ -240,7 +240,7 @@ impl Behaviour {
|
|||||||
pending_actions: VecDeque::new(),
|
pending_actions: VecDeque::new(),
|
||||||
probe_id: ProbeId(0),
|
probe_id: ProbeId(0),
|
||||||
listen_addresses: Default::default(),
|
listen_addresses: Default::default(),
|
||||||
external_addresses: Default::default(),
|
other_candidates: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,6 +279,12 @@ impl Behaviour {
|
|||||||
self.servers.retain(|p| p != peer);
|
self.servers.retain(|p| p != peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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();
|
||||||
|
}
|
||||||
|
|
||||||
fn as_client(&mut self) -> AsClient {
|
fn as_client(&mut self) -> AsClient {
|
||||||
AsClient {
|
AsClient {
|
||||||
inner: &mut self.inner,
|
inner: &mut self.inner,
|
||||||
@ -294,7 +300,7 @@ impl Behaviour {
|
|||||||
last_probe: &mut self.last_probe,
|
last_probe: &mut self.last_probe,
|
||||||
schedule_probe: &mut self.schedule_probe,
|
schedule_probe: &mut self.schedule_probe,
|
||||||
listen_addresses: &self.listen_addresses,
|
listen_addresses: &self.listen_addresses,
|
||||||
external_addresses: &self.external_addresses,
|
other_candidates: &self.other_candidates,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,7 +538,6 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
|
|
||||||
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
|
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
|
||||||
self.listen_addresses.on_swarm_event(&event);
|
self.listen_addresses.on_swarm_event(&event);
|
||||||
self.external_addresses.on_swarm_event(&event);
|
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
FromSwarm::ConnectionEstablished(connection_established) => {
|
FromSwarm::ConnectionEstablished(connection_established) => {
|
||||||
@ -561,14 +566,17 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
}));
|
}));
|
||||||
self.as_client().on_expired_address(addr);
|
self.as_client().on_expired_address(addr);
|
||||||
}
|
}
|
||||||
FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }) => {
|
FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr }) => {
|
||||||
self.inner
|
self.inner
|
||||||
.on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }));
|
.on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr }));
|
||||||
self.as_client().on_expired_address(addr);
|
self.as_client().on_expired_address(addr);
|
||||||
}
|
}
|
||||||
external_addr @ FromSwarm::NewExternalAddr(_) => {
|
FromSwarm::NewExternalAddrCandidate(NewExternalAddrCandidate { addr }) => {
|
||||||
self.inner.on_swarm_event(external_addr);
|
self.inner
|
||||||
self.as_client().on_new_address();
|
.on_swarm_event(FromSwarm::NewExternalAddrCandidate(
|
||||||
|
NewExternalAddrCandidate { addr },
|
||||||
|
));
|
||||||
|
self.probe_address(addr.to_owned());
|
||||||
}
|
}
|
||||||
listen_failure @ FromSwarm::ListenFailure(_) => {
|
listen_failure @ FromSwarm::ListenFailure(_) => {
|
||||||
self.inner.on_swarm_event(listen_failure)
|
self.inner.on_swarm_event(listen_failure)
|
||||||
@ -580,6 +588,7 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
listener_closed @ FromSwarm::ListenerClosed(_) => {
|
listener_closed @ FromSwarm::ListenerClosed(_) => {
|
||||||
self.inner.on_swarm_event(listener_closed)
|
self.inner.on_swarm_event(listener_closed)
|
||||||
}
|
}
|
||||||
|
confirmed @ FromSwarm::ExternalAddrConfirmed(_) => self.inner.on_swarm_event(confirmed),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,9 +30,7 @@ use instant::Instant;
|
|||||||
use libp2p_core::Multiaddr;
|
use libp2p_core::Multiaddr;
|
||||||
use libp2p_identity::PeerId;
|
use libp2p_identity::PeerId;
|
||||||
use libp2p_request_response::{self as request_response, OutboundFailure, RequestId};
|
use libp2p_request_response::{self as request_response, OutboundFailure, RequestId};
|
||||||
use libp2p_swarm::{
|
use libp2p_swarm::{ConnectionId, ListenAddresses, PollParameters, ToSwarm};
|
||||||
AddressScore, ConnectionId, ExternalAddresses, ListenAddresses, PollParameters, ToSwarm,
|
|
||||||
};
|
|
||||||
use rand::{seq::SliceRandom, thread_rng};
|
use rand::{seq::SliceRandom, thread_rng};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet, VecDeque},
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
@ -97,13 +95,13 @@ pub(crate) struct AsClient<'a> {
|
|||||||
pub(crate) last_probe: &'a mut Option<Instant>,
|
pub(crate) last_probe: &'a mut Option<Instant>,
|
||||||
pub(crate) schedule_probe: &'a mut Delay,
|
pub(crate) schedule_probe: &'a mut Delay,
|
||||||
pub(crate) listen_addresses: &'a ListenAddresses,
|
pub(crate) listen_addresses: &'a ListenAddresses,
|
||||||
pub(crate) external_addresses: &'a ExternalAddresses,
|
pub(crate) other_candidates: &'a HashSet<Multiaddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> HandleInnerEvent for AsClient<'a> {
|
impl<'a> HandleInnerEvent for AsClient<'a> {
|
||||||
fn handle_event(
|
fn handle_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &mut impl PollParameters,
|
_: &mut impl PollParameters,
|
||||||
event: request_response::Event<DialRequest, DialResponse>,
|
event: request_response::Event<DialRequest, DialResponse>,
|
||||||
) -> VecDeque<Action> {
|
) -> VecDeque<Action> {
|
||||||
match event {
|
match event {
|
||||||
@ -147,19 +145,7 @@ impl<'a> HandleInnerEvent for AsClient<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(address) = response.result {
|
if let Ok(address) = response.result {
|
||||||
// Update observed address score if it is finite.
|
actions.push_back(ToSwarm::ExternalAddrConfirmed(address));
|
||||||
#[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
|
actions
|
||||||
@ -201,7 +187,7 @@ impl<'a> AsClient<'a> {
|
|||||||
self.schedule_probe.reset(self.config.retry_interval);
|
self.schedule_probe.reset(self.config.retry_interval);
|
||||||
|
|
||||||
let addresses = self
|
let addresses = self
|
||||||
.external_addresses
|
.other_candidates
|
||||||
.iter()
|
.iter()
|
||||||
.chain(self.listen_addresses.iter())
|
.chain(self.listen_addresses.iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -24,7 +24,7 @@ use libp2p_autonat::{
|
|||||||
};
|
};
|
||||||
use libp2p_core::Multiaddr;
|
use libp2p_core::Multiaddr;
|
||||||
use libp2p_identity::PeerId;
|
use libp2p_identity::PeerId;
|
||||||
use libp2p_swarm::{AddressScore, Swarm, SwarmEvent};
|
use libp2p_swarm::{Swarm, SwarmEvent};
|
||||||
use libp2p_swarm_test::SwarmExt as _;
|
use libp2p_swarm_test::SwarmExt as _;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@ -70,48 +70,6 @@ async fn test_auto_probe() {
|
|||||||
assert!(client.behaviour().public_address().is_none());
|
assert!(client.behaviour().public_address().is_none());
|
||||||
assert_eq!(client.behaviour().confidence(), 0);
|
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(), AddressScore::Infinite);
|
|
||||||
|
|
||||||
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
|
// Test new public listening address
|
||||||
client.listen().await;
|
client.listen().await;
|
||||||
|
|
||||||
@ -142,12 +100,14 @@ async fn test_auto_probe() {
|
|||||||
}
|
}
|
||||||
SwarmEvent::Behaviour(Event::StatusChanged { old, new }) => {
|
SwarmEvent::Behaviour(Event::StatusChanged { old, new }) => {
|
||||||
// Expect to flip status to public
|
// Expect to flip status to public
|
||||||
assert_eq!(old, NatStatus::Private);
|
assert_eq!(old, NatStatus::Unknown);
|
||||||
assert!(matches!(new, NatStatus::Public(_)));
|
assert!(matches!(new, NatStatus::Public(_)));
|
||||||
assert!(new.is_public());
|
assert!(new.is_public());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SwarmEvent::IncomingConnection { .. }
|
SwarmEvent::IncomingConnection { .. }
|
||||||
|
| SwarmEvent::ConnectionEstablished { .. }
|
||||||
|
| SwarmEvent::Dialing { .. }
|
||||||
| SwarmEvent::NewListenAddr { .. }
|
| SwarmEvent::NewListenAddr { .. }
|
||||||
| SwarmEvent::ExpiredListenAddr { .. } => {}
|
| SwarmEvent::ExpiredListenAddr { .. } => {}
|
||||||
other => panic!("Unexpected swarm event: {other:?}."),
|
other => panic!("Unexpected swarm event: {other:?}."),
|
||||||
@ -198,7 +158,7 @@ async fn test_confidence() {
|
|||||||
client.listen().await;
|
client.listen().await;
|
||||||
} else {
|
} else {
|
||||||
let unreachable_addr = "/ip4/127.0.0.1/tcp/42".parse().unwrap();
|
let unreachable_addr = "/ip4/127.0.0.1/tcp/42".parse().unwrap();
|
||||||
client.add_external_address(unreachable_addr, AddressScore::Infinite);
|
client.behaviour_mut().probe_address(unreachable_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..MAX_CONFIDENCE + 1 {
|
for i in 0..MAX_CONFIDENCE + 1 {
|
||||||
|
@ -24,7 +24,7 @@ use libp2p_autonat::{
|
|||||||
use libp2p_core::{multiaddr::Protocol, ConnectedPoint, Endpoint, Multiaddr};
|
use libp2p_core::{multiaddr::Protocol, ConnectedPoint, Endpoint, Multiaddr};
|
||||||
use libp2p_identity::PeerId;
|
use libp2p_identity::PeerId;
|
||||||
use libp2p_swarm::DialError;
|
use libp2p_swarm::DialError;
|
||||||
use libp2p_swarm::{AddressScore, Swarm, SwarmEvent};
|
use libp2p_swarm::{Swarm, SwarmEvent};
|
||||||
use libp2p_swarm_test::SwarmExt as _;
|
use libp2p_swarm_test::SwarmExt as _;
|
||||||
use std::{num::NonZeroU32, time::Duration};
|
use std::{num::NonZeroU32, time::Duration};
|
||||||
|
|
||||||
@ -131,10 +131,9 @@ async fn test_dial_back() {
|
|||||||
async fn test_dial_error() {
|
async fn test_dial_error() {
|
||||||
let (mut server, server_id, server_addr) = new_server_swarm(None).await;
|
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;
|
let (mut client, client_id) = new_client_swarm(server_id, server_addr).await;
|
||||||
client.add_external_address(
|
client
|
||||||
"/ip4/127.0.0.1/tcp/12345".parse().unwrap(),
|
.behaviour_mut()
|
||||||
AddressScore::Infinite,
|
.probe_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap());
|
||||||
);
|
|
||||||
async_std::task::spawn(client.loop_on_next());
|
async_std::task::spawn(client.loop_on_next());
|
||||||
|
|
||||||
let request_probe_id = match server.next_behaviour_event().await {
|
let request_probe_id = match server.next_behaviour_event().await {
|
||||||
@ -274,10 +273,9 @@ async fn test_dial_multiple_addr() {
|
|||||||
|
|
||||||
let (mut client, client_id) = new_client_swarm(server_id, server_addr.clone()).await;
|
let (mut client, client_id) = new_client_swarm(server_id, server_addr.clone()).await;
|
||||||
client.listen().await;
|
client.listen().await;
|
||||||
client.add_external_address(
|
client
|
||||||
"/ip4/127.0.0.1/tcp/12345".parse().unwrap(),
|
.behaviour_mut()
|
||||||
AddressScore::Infinite,
|
.probe_address("/ip4/127.0.0.1/tcp/12345".parse().unwrap());
|
||||||
);
|
|
||||||
async_std::task::spawn(client.loop_on_next());
|
async_std::task::spawn(client.loop_on_next());
|
||||||
|
|
||||||
let dial_addresses = match server.next_behaviour_event().await {
|
let dial_addresses = match server.next_behaviour_event().await {
|
||||||
|
@ -441,8 +441,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,8 +494,9 @@ impl NetworkBehaviour for Floodsub {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3500,8 +3500,9 @@ where
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ use libp2p_identity::PeerId;
|
|||||||
use libp2p_identity::PublicKey;
|
use libp2p_identity::PublicKey;
|
||||||
use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm};
|
use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm};
|
||||||
use libp2p_swarm::{
|
use libp2p_swarm::{
|
||||||
AddressScore, ConnectionDenied, DialError, ExternalAddresses, ListenAddresses,
|
ConnectionDenied, DialError, ExternalAddresses, ListenAddresses, NetworkBehaviour,
|
||||||
NetworkBehaviour, NotifyHandler, PollParameters, StreamUpgradeError, THandlerInEvent, ToSwarm,
|
NotifyHandler, PollParameters, StreamUpgradeError, THandlerInEvent, ToSwarm,
|
||||||
};
|
};
|
||||||
use libp2p_swarm::{ConnectionId, THandler, THandlerOutEvent};
|
use libp2p_swarm::{ConnectionId, THandler, THandlerOutEvent};
|
||||||
use lru::LruCache;
|
use lru::LruCache;
|
||||||
@ -43,8 +43,7 @@ use std::{
|
|||||||
/// about them, and answers identify queries from other nodes.
|
/// about them, and answers identify queries from other nodes.
|
||||||
///
|
///
|
||||||
/// All external addresses of the local node supposedly observed by remotes
|
/// All external addresses of the local node supposedly observed by remotes
|
||||||
/// are reported via [`ToSwarm::ReportObservedAddr`] with a
|
/// are reported via [`ToSwarm::NewExternalAddrCandidate`].
|
||||||
/// [score](AddressScore) of `1`.
|
|
||||||
pub struct Behaviour {
|
pub struct Behaviour {
|
||||||
config: Config,
|
config: Config,
|
||||||
/// For each peer we're connected to, the observed address to send back to it.
|
/// For each peer we're connected to, the observed address to send back to it.
|
||||||
@ -295,10 +294,8 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
let observed = info.observed_addr.clone();
|
let observed = info.observed_addr.clone();
|
||||||
self.events
|
self.events
|
||||||
.push_back(ToSwarm::GenerateEvent(Event::Received { peer_id, info }));
|
.push_back(ToSwarm::GenerateEvent(Event::Received { peer_id, info }));
|
||||||
self.events.push_back(ToSwarm::ReportObservedAddr {
|
self.events
|
||||||
address: observed,
|
.push_back(ToSwarm::NewExternalAddrCandidate(observed));
|
||||||
score: AddressScore::Finite(1),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
handler::Event::Identification => {
|
handler::Event::Identification => {
|
||||||
self.events
|
self.events
|
||||||
@ -405,8 +402,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::NewListener(_)
|
| FromSwarm::NewListener(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_) => {}
|
||||||
|
FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2431,13 +2431,14 @@ where
|
|||||||
FromSwarm::DialFailure(dial_failure) => self.on_dial_failure(dial_failure),
|
FromSwarm::DialFailure(dial_failure) => self.on_dial_failure(dial_failure),
|
||||||
FromSwarm::AddressChange(address_change) => self.on_address_change(address_change),
|
FromSwarm::AddressChange(address_change) => self.on_address_change(address_change),
|
||||||
FromSwarm::ExpiredListenAddr(_)
|
FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::NewListenAddr(_)
|
| FromSwarm::NewListenAddr(_)
|
||||||
| FromSwarm::ListenFailure(_)
|
| FromSwarm::ListenFailure(_)
|
||||||
| FromSwarm::NewListener(_)
|
| FromSwarm::NewListener(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,8 +243,9 @@ where
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,8 +128,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,8 +89,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
FromSwarm::ExpiredListenAddr(_) => {}
|
FromSwarm::ExpiredListenAddr(_) => {}
|
||||||
FromSwarm::ListenerError(_) => {}
|
FromSwarm::ListenerError(_) => {}
|
||||||
FromSwarm::ListenerClosed(_) => {}
|
FromSwarm::ListenerClosed(_) => {}
|
||||||
FromSwarm::NewExternalAddr(_) => {}
|
FromSwarm::NewExternalAddrCandidate(_) => {}
|
||||||
FromSwarm::ExpiredExternalAddr(_) => {}
|
FromSwarm::ExternalAddrExpired(_) => {}
|
||||||
|
FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,8 +164,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,8 +317,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,8 +229,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ use libp2p_identity::PublicKey;
|
|||||||
use libp2p_ping as ping;
|
use libp2p_ping as ping;
|
||||||
use libp2p_plaintext::PlainText2Config;
|
use libp2p_plaintext::PlainText2Config;
|
||||||
use libp2p_relay as relay;
|
use libp2p_relay as relay;
|
||||||
use libp2p_swarm::{AddressScore, NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent};
|
use libp2p_swarm::{NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -47,7 +47,7 @@ fn reservation() {
|
|||||||
let relay_peer_id = *relay.local_peer_id();
|
let relay_peer_id = *relay.local_peer_id();
|
||||||
|
|
||||||
relay.listen_on(relay_addr.clone()).unwrap();
|
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);
|
spawn_swarm_on_pool(&pool, relay);
|
||||||
|
|
||||||
let client_addr = relay_addr
|
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();
|
let relay_peer_id = *relay.local_peer_id();
|
||||||
|
|
||||||
relay.listen_on(relay_addr.clone()).unwrap();
|
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);
|
spawn_swarm_on_pool(&pool, relay);
|
||||||
|
|
||||||
let mut client = build_client();
|
let mut client = build_client();
|
||||||
@ -183,7 +183,7 @@ fn connect() {
|
|||||||
let relay_peer_id = *relay.local_peer_id();
|
let relay_peer_id = *relay.local_peer_id();
|
||||||
|
|
||||||
relay.listen_on(relay_addr.clone()).unwrap();
|
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);
|
spawn_swarm_on_pool(&pool, relay);
|
||||||
|
|
||||||
let mut dst = build_client();
|
let mut dst = build_client();
|
||||||
@ -281,7 +281,7 @@ fn reuse_connection() {
|
|||||||
let relay_peer_id = *relay.local_peer_id();
|
let relay_peer_id = *relay.local_peer_id();
|
||||||
|
|
||||||
relay.listen_on(relay_addr.clone()).unwrap();
|
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);
|
spawn_swarm_on_pool(&pool, relay);
|
||||||
|
|
||||||
let client_addr = relay_addr
|
let client_addr = relay_addr
|
||||||
|
@ -74,7 +74,7 @@ impl Behaviour {
|
|||||||
/// Register our external addresses in the given namespace with the given rendezvous peer.
|
/// 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
|
/// 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<Ttl>) {
|
pub fn register(&mut self, namespace: Namespace, rendezvous_node: PeerId, ttl: Option<Ttl>) {
|
||||||
self.pending_register_requests
|
self.pending_register_requests
|
||||||
.push((namespace, rendezvous_node, ttl));
|
.push((namespace, rendezvous_node, ttl));
|
||||||
@ -307,8 +307,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,8 +191,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -756,8 +756,9 @@ where
|
|||||||
FromSwarm::ExpiredListenAddr(_) => {}
|
FromSwarm::ExpiredListenAddr(_) => {}
|
||||||
FromSwarm::ListenerError(_) => {}
|
FromSwarm::ListenerError(_) => {}
|
||||||
FromSwarm::ListenerClosed(_) => {}
|
FromSwarm::ListenerClosed(_) => {}
|
||||||
FromSwarm::NewExternalAddr(_) => {}
|
FromSwarm::NewExternalAddrCandidate(_) => {}
|
||||||
FromSwarm::ExpiredExternalAddr(_) => {}
|
FromSwarm::ExternalAddrExpired(_) => {}
|
||||||
|
FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,8 +82,9 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result<Toke
|
|||||||
let new_listener = quote! { #prelude_path::NewListener };
|
let new_listener = quote! { #prelude_path::NewListener };
|
||||||
let new_listen_addr = quote! { #prelude_path::NewListenAddr };
|
let new_listen_addr = quote! { #prelude_path::NewListenAddr };
|
||||||
let expired_listen_addr = quote! { #prelude_path::ExpiredListenAddr };
|
let expired_listen_addr = quote! { #prelude_path::ExpiredListenAddr };
|
||||||
let new_external_addr = quote! { #prelude_path::NewExternalAddr };
|
let new_external_addr_candidate = quote! { #prelude_path::NewExternalAddrCandidate };
|
||||||
let expired_external_addr = quote! { #prelude_path::ExpiredExternalAddr };
|
let external_addr_expired = quote! { #prelude_path::ExternalAddrExpired };
|
||||||
|
let external_addr_confirmed = quote! { #prelude_path::ExternalAddrConfirmed };
|
||||||
let listener_error = quote! { #prelude_path::ListenerError };
|
let listener_error = quote! { #prelude_path::ListenerError };
|
||||||
let listener_closed = quote! { #prelude_path::ListenerClosed };
|
let listener_closed = quote! { #prelude_path::ListenerClosed };
|
||||||
let t_handler = quote! { #prelude_path::THandler };
|
let t_handler = quote! { #prelude_path::THandler };
|
||||||
@ -443,19 +444,19 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result<Toke
|
|||||||
|
|
||||||
// Build the list of statements to put in the body of `on_swarm_event()`
|
// Build the list of statements to put in the body of `on_swarm_event()`
|
||||||
// for the `FromSwarm::NewExternalAddr` variant.
|
// for the `FromSwarm::NewExternalAddr` variant.
|
||||||
let on_new_external_addr_stmts = {
|
let on_new_external_addr_candidate_stmts = {
|
||||||
data_struct
|
data_struct
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(field_n, field)| match field.ident {
|
.map(|(field_n, field)| match field.ident {
|
||||||
Some(ref i) => quote! {
|
Some(ref i) => 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,
|
addr,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
None => quote! {
|
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,
|
addr,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
@ -463,20 +464,41 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result<Toke
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Build the list of statements to put in the body of `on_swarm_event()`
|
// Build the list of statements to put in the body of `on_swarm_event()`
|
||||||
// for the `FromSwarm::ExpiredExternalAddr` variant.
|
// for the `FromSwarm::ExternalAddrExpired` variant.
|
||||||
let on_expired_external_addr_stmts = {
|
let on_external_addr_expired_stmts = {
|
||||||
data_struct
|
data_struct
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(field_n, field)| match field.ident {
|
.map(|(field_n, field)| match field.ident {
|
||||||
Some(ref i) => quote! {
|
Some(ref i) => quote! {
|
||||||
self.#i.on_swarm_event(#from_swarm::ExpiredExternalAddr(#expired_external_addr {
|
self.#i.on_swarm_event(#from_swarm::ExternalAddrExpired(#external_addr_expired {
|
||||||
addr,
|
addr,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
None => quote! {
|
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,
|
addr,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
@ -717,8 +739,14 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result<Toke
|
|||||||
event: #wrapped_event,
|
event: #wrapped_event,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
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::ReportObservedAddr { address, score });
|
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 }) => {
|
std::task::Poll::Ready(#network_behaviour_action::CloseConnection { peer_id, connection }) => {
|
||||||
return 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<Toke
|
|||||||
#from_swarm::ExpiredListenAddr(
|
#from_swarm::ExpiredListenAddr(
|
||||||
#expired_listen_addr { listener_id, addr })
|
#expired_listen_addr { listener_id, addr })
|
||||||
=> { #(#on_expired_listen_addr_stmts)* }
|
=> { #(#on_expired_listen_addr_stmts)* }
|
||||||
#from_swarm::NewExternalAddr(
|
#from_swarm::NewExternalAddrCandidate(
|
||||||
#new_external_addr { addr })
|
#new_external_addr_candidate { addr })
|
||||||
=> { #(#on_new_external_addr_stmts)* }
|
=> { #(#on_new_external_addr_candidate_stmts)* }
|
||||||
#from_swarm::ExpiredExternalAddr(
|
#from_swarm::ExternalAddrExpired(
|
||||||
#expired_external_addr { addr })
|
#external_addr_expired { addr })
|
||||||
=> { #(#on_expired_external_addr_stmts)* }
|
=> { #(#on_external_addr_expired_stmts)* }
|
||||||
|
#from_swarm::ExternalAddrConfirmed(
|
||||||
|
#external_addr_confirmed { addr })
|
||||||
|
=> { #(#on_external_addr_confirmed_stmts)* }
|
||||||
#from_swarm::ListenerError(
|
#from_swarm::ListenerError(
|
||||||
#listener_error { listener_id, err })
|
#listener_error { listener_id, err })
|
||||||
=> { #(#on_listener_error_stmts)* }
|
=> { #(#on_listener_error_stmts)* }
|
||||||
|
@ -29,8 +29,7 @@ use libp2p_identity::PeerId;
|
|||||||
use libp2p_plaintext::PlainText2Config;
|
use libp2p_plaintext::PlainText2Config;
|
||||||
use libp2p_swarm::dial_opts::PeerCondition;
|
use libp2p_swarm::dial_opts::PeerCondition;
|
||||||
use libp2p_swarm::{
|
use libp2p_swarm::{
|
||||||
dial_opts::DialOpts, AddressScore, NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent,
|
dial_opts::DialOpts, NetworkBehaviour, Swarm, SwarmBuilder, SwarmEvent, THandlerErr,
|
||||||
THandlerErr,
|
|
||||||
};
|
};
|
||||||
use libp2p_yamux as yamux;
|
use libp2p_yamux as yamux;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@ -228,11 +227,7 @@ where
|
|||||||
T: NetworkBehaviour + Send,
|
T: NetworkBehaviour + Send,
|
||||||
<T as NetworkBehaviour>::ToSwarm: Debug,
|
<T as NetworkBehaviour>::ToSwarm: Debug,
|
||||||
{
|
{
|
||||||
let external_addresses = other
|
let external_addresses = other.external_addresses().cloned().collect();
|
||||||
.external_addresses()
|
|
||||||
.cloned()
|
|
||||||
.map(|r| r.addr)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let dial_opts = DialOpts::peer_id(*other.local_peer_id())
|
let dial_opts = DialOpts::peer_id(*other.local_peer_id())
|
||||||
.addresses(external_addresses)
|
.addresses(external_addresses)
|
||||||
@ -315,7 +310,7 @@ where
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Memory addresses are externally reachable because they all share the same memory-space.
|
// 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
|
let tcp_addr_listener_id = self
|
||||||
.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap())
|
.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap())
|
||||||
|
@ -29,8 +29,8 @@ pub use listen_addresses::ListenAddresses;
|
|||||||
use crate::connection::ConnectionId;
|
use crate::connection::ConnectionId;
|
||||||
use crate::dial_opts::DialOpts;
|
use crate::dial_opts::DialOpts;
|
||||||
use crate::{
|
use crate::{
|
||||||
AddressRecord, AddressScore, ConnectionDenied, ConnectionHandler, DialError, ListenError,
|
ConnectionDenied, ConnectionHandler, DialError, ListenError, THandler, THandlerInEvent,
|
||||||
THandler, THandlerInEvent, THandlerOutEvent,
|
THandlerOutEvent,
|
||||||
};
|
};
|
||||||
use libp2p_core::{transport::ListenerId, ConnectedPoint, Endpoint, Multiaddr};
|
use libp2p_core::{transport::ListenerId, ConnectedPoint, Endpoint, Multiaddr};
|
||||||
use libp2p_identity::PeerId;
|
use libp2p_identity::PeerId;
|
||||||
@ -221,8 +221,6 @@ pub trait PollParameters {
|
|||||||
type SupportedProtocolsIter: ExactSizeIterator<Item = Vec<u8>>;
|
type SupportedProtocolsIter: ExactSizeIterator<Item = Vec<u8>>;
|
||||||
/// Iterator returned by [`listened_addresses`](PollParameters::listened_addresses).
|
/// Iterator returned by [`listened_addresses`](PollParameters::listened_addresses).
|
||||||
type ListenedAddressesIter: ExactSizeIterator<Item = Multiaddr>;
|
type ListenedAddressesIter: ExactSizeIterator<Item = Multiaddr>;
|
||||||
/// Iterator returned by [`external_addresses`](PollParameters::external_addresses).
|
|
||||||
type ExternalAddressesIter: ExactSizeIterator<Item = AddressRecord>;
|
|
||||||
|
|
||||||
/// Returns the list of protocol the behaviour supports when a remote negotiates a protocol on
|
/// Returns the list of protocol the behaviour supports when a remote negotiates a protocol on
|
||||||
/// an inbound substream.
|
/// an inbound substream.
|
||||||
@ -242,13 +240,6 @@ pub trait PollParameters {
|
|||||||
)]
|
)]
|
||||||
fn listened_addresses(&self) -> Self::ListenedAddressesIter;
|
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.
|
/// Returns the peer id of the local node.
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "0.42.0",
|
since = "0.42.0",
|
||||||
@ -299,21 +290,28 @@ pub enum ToSwarm<TOutEvent, TInEvent> {
|
|||||||
event: TInEvent,
|
event: TInEvent,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Informs the `Swarm` about an address observed by a remote for
|
/// Reports a new candidate for an external address to the [`Swarm`](crate::Swarm).
|
||||||
/// the local node by which the local node is supposedly publicly
|
|
||||||
/// reachable.
|
|
||||||
///
|
///
|
||||||
/// It is advisable to issue `ReportObservedAddr` actions at a fixed frequency
|
/// This address will be shared with all [`NetworkBehaviour`]s via [`FromSwarm::NewExternalAddrCandidate`].
|
||||||
/// per node. This way address information will be more accurate over time
|
///
|
||||||
/// and individual outliers carry less weight.
|
/// This address could come from a variety of sources:
|
||||||
ReportObservedAddr {
|
/// - A protocol such as identify obtained it from a remote.
|
||||||
/// The observed address of the local node.
|
/// - The user provided it based on configuration.
|
||||||
address: Multiaddr,
|
/// - We made an educated guess based on one of our listen addresses.
|
||||||
/// The score to associate with this observation, i.e.
|
/// - We established a new relay connection.
|
||||||
/// an indicator for the trusworthiness of this address
|
NewExternalAddrCandidate(Multiaddr),
|
||||||
/// relative to other observed addresses.
|
|
||||||
score: AddressScore,
|
/// 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
|
/// Instructs the `Swarm` to initiate a graceful close of one or all connections
|
||||||
/// with the given peer.
|
/// with the given peer.
|
||||||
@ -351,9 +349,6 @@ impl<TOutEvent, TInEventOld> ToSwarm<TOutEvent, TInEventOld> {
|
|||||||
handler,
|
handler,
|
||||||
event: f(event),
|
event: f(event),
|
||||||
},
|
},
|
||||||
ToSwarm::ReportObservedAddr { address, score } => {
|
|
||||||
ToSwarm::ReportObservedAddr { address, score }
|
|
||||||
}
|
|
||||||
ToSwarm::CloseConnection {
|
ToSwarm::CloseConnection {
|
||||||
peer_id,
|
peer_id,
|
||||||
connection,
|
connection,
|
||||||
@ -361,6 +356,9 @@ impl<TOutEvent, TInEventOld> ToSwarm<TOutEvent, TInEventOld> {
|
|||||||
peer_id,
|
peer_id,
|
||||||
connection,
|
connection,
|
||||||
},
|
},
|
||||||
|
ToSwarm::NewExternalAddrCandidate(addr) => ToSwarm::NewExternalAddrCandidate(addr),
|
||||||
|
ToSwarm::ExternalAddrConfirmed(addr) => ToSwarm::ExternalAddrConfirmed(addr),
|
||||||
|
ToSwarm::ExternalAddrExpired(addr) => ToSwarm::ExternalAddrExpired(addr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -380,9 +378,9 @@ impl<TOutEvent, THandlerIn> ToSwarm<TOutEvent, THandlerIn> {
|
|||||||
handler,
|
handler,
|
||||||
event,
|
event,
|
||||||
},
|
},
|
||||||
ToSwarm::ReportObservedAddr { address, score } => {
|
ToSwarm::NewExternalAddrCandidate(addr) => ToSwarm::NewExternalAddrCandidate(addr),
|
||||||
ToSwarm::ReportObservedAddr { address, score }
|
ToSwarm::ExternalAddrConfirmed(addr) => ToSwarm::ExternalAddrConfirmed(addr),
|
||||||
}
|
ToSwarm::ExternalAddrExpired(addr) => ToSwarm::ExternalAddrExpired(addr),
|
||||||
ToSwarm::CloseConnection {
|
ToSwarm::CloseConnection {
|
||||||
peer_id,
|
peer_id,
|
||||||
connection,
|
connection,
|
||||||
@ -449,10 +447,12 @@ pub enum FromSwarm<'a, Handler> {
|
|||||||
ListenerError(ListenerError<'a>),
|
ListenerError(ListenerError<'a>),
|
||||||
/// Informs the behaviour that a listener closed.
|
/// Informs the behaviour that a listener closed.
|
||||||
ListenerClosed(ListenerClosed<'a>),
|
ListenerClosed(ListenerClosed<'a>),
|
||||||
/// Informs the behaviour that we have discovered a new external address for us.
|
/// Informs the behaviour that we have discovered a new candidate for an external address for us.
|
||||||
NewExternalAddr(NewExternalAddr<'a>),
|
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.
|
||||||
ExpiredExternalAddr(ExpiredExternalAddr<'a>),
|
ExternalAddrConfirmed(ExternalAddrConfirmed<'a>),
|
||||||
|
/// Informs the behaviour that an external address of the local node expired, i.e. is no-longer confirmed.
|
||||||
|
ExternalAddrExpired(ExternalAddrExpired<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`FromSwarm`] variant that informs the behaviour about a newly established connection to a peer.
|
/// [`FromSwarm`] variant that informs the behaviour about a newly established connection to a peer.
|
||||||
@ -549,15 +549,21 @@ pub struct ListenerClosed<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// [`FromSwarm`] variant that informs the behaviour
|
/// [`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)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct NewExternalAddr<'a> {
|
pub struct NewExternalAddrCandidate<'a> {
|
||||||
pub addr: &'a Multiaddr,
|
pub addr: &'a Multiaddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`FromSwarm`] variant that informs the behaviour that an external address was removed.
|
/// [`FromSwarm`] variant that informs the behaviour that an external address was removed.
|
||||||
#[derive(Clone, Copy)]
|
#[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,
|
pub addr: &'a Multiaddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -657,12 +663,9 @@ impl<'a, Handler> FromSwarm<'a, Handler> {
|
|||||||
listener_id,
|
listener_id,
|
||||||
reason,
|
reason,
|
||||||
})),
|
})),
|
||||||
FromSwarm::NewExternalAddr(NewExternalAddr { addr }) => {
|
FromSwarm::NewExternalAddrCandidate(e) => Some(FromSwarm::NewExternalAddrCandidate(e)),
|
||||||
Some(FromSwarm::NewExternalAddr(NewExternalAddr { addr }))
|
FromSwarm::ExternalAddrExpired(e) => Some(FromSwarm::ExternalAddrExpired(e)),
|
||||||
}
|
FromSwarm::ExternalAddrConfirmed(e) => Some(FromSwarm::ExternalAddrConfirmed(e)),
|
||||||
FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }) => {
|
|
||||||
Some(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::behaviour::{ExpiredExternalAddr, FromSwarm, NewExternalAddr};
|
use crate::behaviour::{ExternalAddrConfirmed, ExternalAddrExpired, FromSwarm};
|
||||||
use libp2p_core::Multiaddr;
|
use libp2p_core::Multiaddr;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
@ -34,12 +34,12 @@ impl ExternalAddresses {
|
|||||||
/// Returns whether the event changed our set of external addresses.
|
/// Returns whether the event changed our set of external addresses.
|
||||||
pub fn on_swarm_event<THandler>(&mut self, event: &FromSwarm<THandler>) -> bool {
|
pub fn on_swarm_event<THandler>(&mut self, event: &FromSwarm<THandler>) -> bool {
|
||||||
match event {
|
match event {
|
||||||
FromSwarm::NewExternalAddr(NewExternalAddr { addr, .. }) => {
|
FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { addr }) => {
|
||||||
if self.addresses.len() < self.limit {
|
if self.addresses.len() < self.limit {
|
||||||
return self.addresses.insert((*addr).clone());
|
return self.addresses.insert((*addr).clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr, .. }) => {
|
FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr, .. }) => {
|
||||||
return self.addresses.remove(addr)
|
return self.addresses.remove(addr)
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -80,11 +80,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_external_addr() -> FromSwarm<'static, dummy::ConnectionHandler> {
|
fn new_external_addr() -> FromSwarm<'static, dummy::ConnectionHandler> {
|
||||||
FromSwarm::NewExternalAddr(NewExternalAddr { addr: &MEMORY_ADDR })
|
FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed { addr: &MEMORY_ADDR })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expired_external_addr() -> FromSwarm<'static, dummy::ConnectionHandler> {
|
fn expired_external_addr() -> FromSwarm<'static, dummy::ConnectionHandler> {
|
||||||
FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr: &MEMORY_ADDR })
|
FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr: &MEMORY_ADDR })
|
||||||
}
|
}
|
||||||
|
|
||||||
static MEMORY_ADDR: Lazy<Multiaddr> =
|
static MEMORY_ADDR: Lazy<Multiaddr> =
|
||||||
|
@ -70,8 +70,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,8 +73,9 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
133
swarm/src/lib.rs
133
swarm/src/lib.rs
@ -57,7 +57,6 @@
|
|||||||
|
|
||||||
mod connection;
|
mod connection;
|
||||||
mod executor;
|
mod executor;
|
||||||
mod registry;
|
|
||||||
mod stream;
|
mod stream;
|
||||||
mod stream_protocol;
|
mod stream_protocol;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -77,13 +76,14 @@ pub mod derive_prelude {
|
|||||||
pub use crate::behaviour::ConnectionClosed;
|
pub use crate::behaviour::ConnectionClosed;
|
||||||
pub use crate::behaviour::ConnectionEstablished;
|
pub use crate::behaviour::ConnectionEstablished;
|
||||||
pub use crate::behaviour::DialFailure;
|
pub use crate::behaviour::DialFailure;
|
||||||
pub use crate::behaviour::ExpiredExternalAddr;
|
|
||||||
pub use crate::behaviour::ExpiredListenAddr;
|
pub use crate::behaviour::ExpiredListenAddr;
|
||||||
|
pub use crate::behaviour::ExternalAddrConfirmed;
|
||||||
|
pub use crate::behaviour::ExternalAddrExpired;
|
||||||
pub use crate::behaviour::FromSwarm;
|
pub use crate::behaviour::FromSwarm;
|
||||||
pub use crate::behaviour::ListenFailure;
|
pub use crate::behaviour::ListenFailure;
|
||||||
pub use crate::behaviour::ListenerClosed;
|
pub use crate::behaviour::ListenerClosed;
|
||||||
pub use crate::behaviour::ListenerError;
|
pub use crate::behaviour::ListenerError;
|
||||||
pub use crate::behaviour::NewExternalAddr;
|
pub use crate::behaviour::NewExternalAddrCandidate;
|
||||||
pub use crate::behaviour::NewListenAddr;
|
pub use crate::behaviour::NewListenAddr;
|
||||||
pub use crate::behaviour::NewListener;
|
pub use crate::behaviour::NewListener;
|
||||||
pub use crate::connection::ConnectionId;
|
pub use crate::connection::ConnectionId;
|
||||||
@ -107,10 +107,10 @@ pub mod derive_prelude {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub use behaviour::{
|
pub use behaviour::{
|
||||||
AddressChange, CloseConnection, ConnectionClosed, DialFailure, ExpiredExternalAddr,
|
AddressChange, CloseConnection, ConnectionClosed, DialFailure, ExpiredListenAddr,
|
||||||
ExpiredListenAddr, ExternalAddresses, FromSwarm, ListenAddresses, ListenFailure,
|
ExternalAddrExpired, ExternalAddresses, FromSwarm, ListenAddresses, ListenFailure,
|
||||||
ListenerClosed, ListenerError, NetworkBehaviour, NewExternalAddr, NewListenAddr, NotifyHandler,
|
ListenerClosed, ListenerError, NetworkBehaviour, NewExternalAddrCandidate, NewListenAddr,
|
||||||
PollParameters, ToSwarm,
|
NotifyHandler, PollParameters, ToSwarm,
|
||||||
};
|
};
|
||||||
pub use connection::pool::ConnectionCounters;
|
pub use connection::pool::ConnectionCounters;
|
||||||
pub use connection::{ConnectionError, ConnectionId, SupportedProtocols};
|
pub use connection::{ConnectionError, ConnectionId, SupportedProtocols};
|
||||||
@ -121,10 +121,10 @@ pub use handler::{
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "macros")]
|
#[cfg(feature = "macros")]
|
||||||
pub use libp2p_swarm_derive::NetworkBehaviour;
|
pub use libp2p_swarm_derive::NetworkBehaviour;
|
||||||
pub use registry::{AddAddressResult, AddressRecord, AddressScore};
|
|
||||||
pub use stream::Stream;
|
pub use stream::Stream;
|
||||||
pub use stream_protocol::{InvalidProtocol, StreamProtocol};
|
pub use stream_protocol::{InvalidProtocol, StreamProtocol};
|
||||||
|
|
||||||
|
use crate::behaviour::ExternalAddrConfirmed;
|
||||||
use crate::handler::UpgradeInfoSend;
|
use crate::handler::UpgradeInfoSend;
|
||||||
use connection::pool::{EstablishedConnection, Pool, PoolConfig, PoolEvent};
|
use connection::pool::{EstablishedConnection, Pool, PoolConfig, PoolEvent};
|
||||||
use connection::IncomingInfo;
|
use connection::IncomingInfo;
|
||||||
@ -142,7 +142,6 @@ use libp2p_core::{
|
|||||||
Endpoint, Multiaddr, Transport,
|
Endpoint, Multiaddr, Transport,
|
||||||
};
|
};
|
||||||
use libp2p_identity::PeerId;
|
use libp2p_identity::PeerId;
|
||||||
use registry::{AddressIntoIter, Addresses};
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::num::{NonZeroU32, NonZeroU8, NonZeroUsize};
|
use std::num::{NonZeroU32, NonZeroU8, NonZeroUsize};
|
||||||
@ -340,13 +339,11 @@ where
|
|||||||
/// List of protocols that the behaviour says it supports.
|
/// List of protocols that the behaviour says it supports.
|
||||||
supported_protocols: SmallVec<[Vec<u8>; 16]>,
|
supported_protocols: SmallVec<[Vec<u8>; 16]>,
|
||||||
|
|
||||||
|
confirmed_external_addr: HashSet<Multiaddr>,
|
||||||
|
|
||||||
/// Multiaddresses that our listeners are listening on,
|
/// Multiaddresses that our listeners are listening on,
|
||||||
listened_addrs: HashMap<ListenerId, SmallVec<[Multiaddr; 1]>>,
|
listened_addrs: HashMap<ListenerId, SmallVec<[Multiaddr; 1]>>,
|
||||||
|
|
||||||
/// 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
|
/// Pending event to be delivered to connection handlers
|
||||||
/// (or dropped if the peer disconnected) before the `behaviour`
|
/// (or dropped if the peer disconnected) before the `behaviour`
|
||||||
/// can be polled again.
|
/// can be polled again.
|
||||||
@ -654,60 +651,30 @@ where
|
|||||||
&self.local_peer_id
|
&self.local_peer_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator for [`AddressRecord`]s of external addresses
|
/// TODO
|
||||||
/// of the local node, in decreasing order of their current
|
pub fn external_addresses(&self) -> impl Iterator<Item = &Multiaddr> {
|
||||||
/// [score](AddressScore).
|
self.confirmed_external_addr.iter()
|
||||||
pub fn external_addresses(&self) -> impl Iterator<Item = &AddressRecord> {
|
|
||||||
self.external_addrs.iter()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an external address record for the local node.
|
/// Add a **confirmed** external address for the local node.
|
||||||
///
|
///
|
||||||
/// An external address is an address of the local node known to
|
/// This function should only be called with addresses that are guaranteed to be reachable.
|
||||||
/// be (likely) reachable for other nodes, possibly taking into
|
/// The address is broadcast to all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrConfirmed`].
|
||||||
/// account NAT. The external addresses of the local node may be
|
pub fn add_external_address(&mut self, a: Multiaddr) {
|
||||||
/// shared with other nodes by the `NetworkBehaviour`.
|
self.behaviour
|
||||||
///
|
.on_swarm_event(FromSwarm::ExternalAddrConfirmed(ExternalAddrConfirmed {
|
||||||
/// The associated score determines both the position of the address
|
addr: &a,
|
||||||
/// in the list of external addresses (which can determine the
|
}));
|
||||||
/// order in which addresses are used to connect to) as well as
|
self.confirmed_external_addr.insert(a);
|
||||||
/// 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::NewExternalAddr(NewExternalAddr { addr: &a }));
|
|
||||||
expired
|
|
||||||
}
|
|
||||||
AddAddressResult::Updated { expired } => expired,
|
|
||||||
};
|
|
||||||
for a in expired {
|
|
||||||
self.behaviour
|
|
||||||
.on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr {
|
|
||||||
addr: &a.addr,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes an external address of the local node, regardless of
|
/// Remove an external address for the local node.
|
||||||
/// its current score. See [`Swarm::add_external_address`]
|
|
||||||
/// for details.
|
|
||||||
///
|
///
|
||||||
/// Returns `true` if the address existed and was removed, `false`
|
/// The address is broadcast to all [`NetworkBehaviour`]s via [`FromSwarm::ExternalAddrExpired`].
|
||||||
/// otherwise.
|
pub fn remove_external_address(&mut self, addr: &Multiaddr) {
|
||||||
pub fn remove_external_address(&mut self, addr: &Multiaddr) -> bool {
|
self.behaviour
|
||||||
if self.external_addrs.remove(addr) {
|
.on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr }));
|
||||||
self.behaviour
|
self.confirmed_external_addr.remove(addr);
|
||||||
.on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }));
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disconnects a peer by its peer ID, closing all connections to said peer.
|
/// Disconnects a peer by its peer ID, closing all connections to said peer.
|
||||||
@ -1162,25 +1129,21 @@ where
|
|||||||
|
|
||||||
self.pending_event = Some((peer_id, handler, event));
|
self.pending_event = Some((peer_id, handler, event));
|
||||||
}
|
}
|
||||||
ToSwarm::ReportObservedAddr { address, score } => {
|
ToSwarm::NewExternalAddrCandidate(addr) => {
|
||||||
// Maps the given `observed_addr`, representing an address of the local
|
self.behaviour
|
||||||
// node observed by a remote peer, onto the locally known listen addresses
|
.on_swarm_event(FromSwarm::NewExternalAddrCandidate(
|
||||||
// to yield one or more addresses of the local node that may be publicly
|
NewExternalAddrCandidate { addr: &addr },
|
||||||
// reachable.
|
));
|
||||||
//
|
|
||||||
// I.e. self method incorporates the view of other peers into the listen
|
// Generate more candidates based on address translation.
|
||||||
// addresses seen by the local node to account for possible IP and port
|
// For TCP without port-reuse, the observed address contains an ephemeral port which needs to be replaced by the port of a listen address.
|
||||||
// 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 translated_addresses = {
|
||||||
let mut addrs: Vec<_> = self
|
let mut addrs: Vec<_> = self
|
||||||
.listened_addrs
|
.listened_addrs
|
||||||
.values()
|
.values()
|
||||||
.flatten()
|
.flatten()
|
||||||
.filter_map(|server| self.transport.address_translation(server, &address))
|
.filter_map(|server| self.transport.address_translation(server, &addr))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// remove duplicates
|
// remove duplicates
|
||||||
@ -1189,9 +1152,18 @@ where
|
|||||||
addrs
|
addrs
|
||||||
};
|
};
|
||||||
for addr in translated_addresses {
|
for addr in translated_addresses {
|
||||||
self.add_external_address(addr, score);
|
self.behaviour
|
||||||
|
.on_swarm_event(FromSwarm::NewExternalAddrCandidate(
|
||||||
|
NewExternalAddrCandidate { addr: &addr },
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ToSwarm::ExternalAddrConfirmed(addr) => {
|
||||||
|
self.add_external_address(addr);
|
||||||
|
}
|
||||||
|
ToSwarm::ExternalAddrExpired(addr) => {
|
||||||
|
self.remove_external_address(&addr);
|
||||||
|
}
|
||||||
ToSwarm::CloseConnection {
|
ToSwarm::CloseConnection {
|
||||||
peer_id,
|
peer_id,
|
||||||
connection,
|
connection,
|
||||||
@ -1263,7 +1235,6 @@ where
|
|||||||
local_peer_id: &this.local_peer_id,
|
local_peer_id: &this.local_peer_id,
|
||||||
supported_protocols: &this.supported_protocols,
|
supported_protocols: &this.supported_protocols,
|
||||||
listened_addrs: this.listened_addrs.values().flatten().collect(),
|
listened_addrs: this.listened_addrs.values().flatten().collect(),
|
||||||
external_addrs: &this.external_addrs,
|
|
||||||
};
|
};
|
||||||
this.behaviour.poll(cx, &mut parameters)
|
this.behaviour.poll(cx, &mut parameters)
|
||||||
};
|
};
|
||||||
@ -1431,13 +1402,11 @@ pub struct SwarmPollParameters<'a> {
|
|||||||
local_peer_id: &'a PeerId,
|
local_peer_id: &'a PeerId,
|
||||||
supported_protocols: &'a [Vec<u8>],
|
supported_protocols: &'a [Vec<u8>],
|
||||||
listened_addrs: Vec<&'a Multiaddr>,
|
listened_addrs: Vec<&'a Multiaddr>,
|
||||||
external_addrs: &'a Addresses,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PollParameters for SwarmPollParameters<'a> {
|
impl<'a> PollParameters for SwarmPollParameters<'a> {
|
||||||
type SupportedProtocolsIter = std::iter::Cloned<std::slice::Iter<'a, std::vec::Vec<u8>>>;
|
type SupportedProtocolsIter = std::iter::Cloned<std::slice::Iter<'a, std::vec::Vec<u8>>>;
|
||||||
type ListenedAddressesIter = std::iter::Cloned<std::vec::IntoIter<&'a Multiaddr>>;
|
type ListenedAddressesIter = std::iter::Cloned<std::vec::IntoIter<&'a Multiaddr>>;
|
||||||
type ExternalAddressesIter = AddressIntoIter;
|
|
||||||
|
|
||||||
fn supported_protocols(&self) -> Self::SupportedProtocolsIter {
|
fn supported_protocols(&self) -> Self::SupportedProtocolsIter {
|
||||||
self.supported_protocols.iter().cloned()
|
self.supported_protocols.iter().cloned()
|
||||||
@ -1447,10 +1416,6 @@ impl<'a> PollParameters for SwarmPollParameters<'a> {
|
|||||||
self.listened_addrs.clone().into_iter().cloned()
|
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 {
|
fn local_peer_id(&self) -> &PeerId {
|
||||||
self.local_peer_id
|
self.local_peer_id
|
||||||
}
|
}
|
||||||
@ -1639,8 +1604,8 @@ where
|
|||||||
pool: Pool::new(self.local_peer_id, self.pool_config),
|
pool: Pool::new(self.local_peer_id, self.pool_config),
|
||||||
behaviour: self.behaviour,
|
behaviour: self.behaviour,
|
||||||
supported_protocols: Default::default(),
|
supported_protocols: Default::default(),
|
||||||
|
confirmed_external_addr: Default::default(),
|
||||||
listened_addrs: HashMap::new(),
|
listened_addrs: HashMap::new(),
|
||||||
external_addrs: Addresses::default(),
|
|
||||||
pending_event: None,
|
pending_event: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<Report>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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<Ordering> {
|
|
||||||
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<u32> 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<Self::Item> {
|
|
||||||
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<usize>) {
|
|
||||||
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<Self::Item> {
|
|
||||||
if !self.items.is_empty() {
|
|
||||||
Some(self.items.remove(0))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
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<AddressScore>) {
|
|
||||||
let mut xs = xs
|
|
||||||
.into_iter()
|
|
||||||
.map(|score| AddressRecord::new(Multiaddr::empty(), score))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
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<AddressRecord>, 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<AddressRecord>) -> 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::<AddressScore>, |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(_) -> _)
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,8 +19,8 @@
|
|||||||
// DEALINGS IN THE SOFTWARE.
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
use crate::behaviour::{
|
use crate::behaviour::{
|
||||||
ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredExternalAddr, ExpiredListenAddr,
|
ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredListenAddr, ExternalAddrExpired,
|
||||||
FromSwarm, ListenerClosed, ListenerError, NewExternalAddr, NewListenAddr, NewListener,
|
FromSwarm, ListenerClosed, ListenerError, NewExternalAddrCandidate, NewListenAddr, NewListener,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
ConnectionDenied, ConnectionHandler, ConnectionId, NetworkBehaviour, PollParameters, THandler,
|
ConnectionDenied, ConnectionHandler, ConnectionId, NetworkBehaviour, PollParameters, THandler,
|
||||||
@ -130,8 +130,9 @@ where
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,15 +501,17 @@ where
|
|||||||
addr,
|
addr,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
FromSwarm::NewExternalAddr(NewExternalAddr { addr }) => {
|
FromSwarm::NewExternalAddrCandidate(NewExternalAddrCandidate { addr }) => {
|
||||||
self.on_new_external_addr.push(addr.clone());
|
self.on_new_external_addr.push(addr.clone());
|
||||||
self.inner
|
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.on_expired_external_addr.push(addr.clone());
|
||||||
self.inner
|
self.inner
|
||||||
.on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }));
|
.on_swarm_event(FromSwarm::ExternalAddrExpired(ExternalAddrExpired { addr }));
|
||||||
}
|
}
|
||||||
FromSwarm::ListenerError(ListenerError { listener_id, err }) => {
|
FromSwarm::ListenerError(ListenerError { listener_id, err }) => {
|
||||||
self.on_listener_error.push(listener_id);
|
self.on_listener_error.push(listener_id);
|
||||||
|
@ -518,8 +518,9 @@ fn custom_out_event_no_type_parameters() {
|
|||||||
| FromSwarm::ExpiredListenAddr(_)
|
| FromSwarm::ExpiredListenAddr(_)
|
||||||
| FromSwarm::ListenerError(_)
|
| FromSwarm::ListenerError(_)
|
||||||
| FromSwarm::ListenerClosed(_)
|
| FromSwarm::ListenerClosed(_)
|
||||||
| FromSwarm::NewExternalAddr(_)
|
| FromSwarm::NewExternalAddrCandidate(_)
|
||||||
| FromSwarm::ExpiredExternalAddr(_) => {}
|
| FromSwarm::ExternalAddrExpired(_)
|
||||||
|
| FromSwarm::ExternalAddrConfirmed(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user