aboutsummaryrefslogtreecommitdiffstats
path: root/src/transport/libp2p/book.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-01 05:00:43 +0100
committertv <tv@krebsco.de>2026-11-01 05:00:43 +0100
commit67a476525bf23fec7aa10a962668cc77cce6c685 (patch)
treea259ef08154e1bc11efee95b22d3f615f564538b /src/transport/libp2p/book.rs
parentc08574fac02c781b615969943e3d0d95ee402537 (diff)
libp2p: dial newly announced peer addresses
Diffstat (limited to 'src/transport/libp2p/book.rs')
-rw-r--r--src/transport/libp2p/book.rs38
1 files changed, 37 insertions, 1 deletions
diff --git a/src/transport/libp2p/book.rs b/src/transport/libp2p/book.rs
index 44b2694..7de4be7 100644
--- a/src/transport/libp2p/book.rs
+++ b/src/transport/libp2p/book.rs
@@ -41,6 +41,9 @@ pub(super) struct Book {
/// connection to the peer closes, as a peer restarted elsewhere is found by what
/// the others say.
pub(super) identified: HashMap<PeerId, Vec<Multiaddr>>,
+ /// Addresses of directly connected peers dialled for a better path (`explore`):
+ /// not again while connected, unless our own interfaces change.
+ pub(super) explored: HashMap<PeerId, std::collections::HashSet<Multiaddr>>,
pub(super) listening: Vec<Multiaddr>,
/// Where the router forwards to our listen addresses (UPnP, `Libp2pConfig::upnp`).
pub(super) mapped: Vec<Multiaddr>,
@@ -213,6 +216,7 @@ impl Book {
for peer in &stale {
self.addresses.remove(peer);
self.identified.remove(peer);
+ self.explored.remove(peer);
self.relays.remove(peer);
self.public_relays.remove(peer);
self.continuum.remove(peer);
@@ -475,6 +479,38 @@ impl Book {
addresses.truncate(ADDRESSES_PER_PEER);
}
+ /// The addresses `explore` dials `peer` at, noted as dialled: a node of the swarm
+ /// connected directly, at addresses of its not dialled so yet, and with `again`
+ /// not only those at an IP it isn't connected at (an inbound connection's remote
+ /// port isn't where the peer listens).
+ pub(super) fn to_explore(&mut self, peer: PeerId, again: bool) -> Vec<Multiaddr> {
+ if !self.continuum.contains(&peer)
+ || book_connection(&self.connections, &peer) != Some(Connection::Direct)
+ {
+ return Vec::new();
+ }
+ let used: Vec<Option<std::net::IpAddr>> = self
+ .connections
+ .values()
+ .filter(|(connected, relayed, _)| *connected == peer && !relayed)
+ .map(|(_, _, address)| ip_of(address))
+ .collect();
+ let tried = self.explored.entry(peer).or_default();
+ let candidates: Vec<Multiaddr> = self
+ .addresses
+ .get(&peer)
+ .into_iter()
+ .flatten()
+ .filter(|address| is_ip(address) && !left_out(&self.ignored, address))
+ .filter(|address| again || !used.contains(&ip_of(address)))
+ .filter(|address| !tried.contains(*address))
+ .take(EXPLORED_AT_ONCE)
+ .cloned()
+ .collect();
+ tried.extend(candidates.iter().cloned());
+ candidates
+ }
+
/// `peer`, connected, identified itself at `listen` (`published`): its direct
/// addresses are those from now on, while connected (`remember`); those through
/// relays and by name stay. Kept in order of `preference`: of a peer with many,
@@ -520,7 +556,7 @@ impl Book {
}
/// The IP address `address` starts with, if any.
-fn ip_of(address: &Multiaddr) -> Option<std::net::IpAddr> {
+pub(super) fn ip_of(address: &Multiaddr) -> Option<std::net::IpAddr> {
match address.iter().next() {
Some(Protocol::Ip4(ip)) => Some(ip.into()),
Some(Protocol::Ip6(ip)) => Some(ip.into()),