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:
Thomas Eizinger
2023-05-24 09:52:16 +02:00
committed by GitHub
parent a424310d60
commit 5e8f2e82e4
32 changed files with 273 additions and 822 deletions

View File

@ -25,8 +25,8 @@ use libp2p_identity::PeerId;
use libp2p_identity::PublicKey;
use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm};
use libp2p_swarm::{
AddressScore, ConnectionDenied, DialError, ExternalAddresses, ListenAddresses,
NetworkBehaviour, NotifyHandler, PollParameters, StreamUpgradeError, THandlerInEvent, ToSwarm,
ConnectionDenied, DialError, ExternalAddresses, ListenAddresses, NetworkBehaviour,
NotifyHandler, PollParameters, StreamUpgradeError, THandlerInEvent, ToSwarm,
};
use libp2p_swarm::{ConnectionId, THandler, THandlerOutEvent};
use lru::LruCache;
@ -43,8 +43,7 @@ use std::{
/// about them, and answers identify queries from other nodes.
///
/// All external addresses of the local node supposedly observed by remotes
/// are reported via [`ToSwarm::ReportObservedAddr`] with a
/// [score](AddressScore) of `1`.
/// are reported via [`ToSwarm::NewExternalAddrCandidate`].
pub struct Behaviour {
config: Config,
/// For each peer we're connected to, the observed address to send back to it.
@ -295,10 +294,8 @@ impl NetworkBehaviour for Behaviour {
let observed = info.observed_addr.clone();
self.events
.push_back(ToSwarm::GenerateEvent(Event::Received { peer_id, info }));
self.events.push_back(ToSwarm::ReportObservedAddr {
address: observed,
score: AddressScore::Finite(1),
});
self.events
.push_back(ToSwarm::NewExternalAddrCandidate(observed));
}
handler::Event::Identification => {
self.events
@ -405,8 +402,9 @@ impl NetworkBehaviour for Behaviour {
| FromSwarm::NewListener(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
| FromSwarm::NewExternalAddrCandidate(_)
| FromSwarm::ExternalAddrExpired(_) => {}
FromSwarm::ExternalAddrConfirmed(_) => {}
}
}
}