From 67a476525bf23fec7aa10a962668cc77cce6c685 Mon Sep 17 00:00:00 2001 From: tv Date: Sun, 1 Nov 2026 05:00:43 +0100 Subject: libp2p: dial newly announced peer addresses --- src/transport/libp2p/book.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'src/transport/libp2p/book.rs') 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>, + /// Addresses of directly connected peers dialled for a better path (`explore`): + /// not again while connected, unless our own interfaces change. + pub(super) explored: HashMap>, pub(super) listening: Vec, /// Where the router forwards to our listen addresses (UPnP, `Libp2pConfig::upnp`). pub(super) mapped: Vec, @@ -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 { + if !self.continuum.contains(&peer) + || book_connection(&self.connections, &peer) != Some(Connection::Direct) + { + return Vec::new(); + } + let used: Vec> = 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 = 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 { +pub(super) fn ip_of(address: &Multiaddr) -> Option { match address.iter().next() { Some(Protocol::Ip4(ip)) => Some(ip.into()), Some(Protocol::Ip6(ip)) => Some(ip.into()), -- cgit v1.3.1