diff options
| -rw-r--r-- | src/transport/libp2p.rs | 40 |
1 files changed, 36 insertions, 4 deletions
diff --git a/src/transport/libp2p.rs b/src/transport/libp2p.rs index c3e2d98..8746206 100644 --- a/src/transport/libp2p.rs +++ b/src/transport/libp2p.rs @@ -282,6 +282,9 @@ struct Book { lan: std::collections::HashSet<PeerId>, /// Peers that speak continuum (identify says so). continuum: std::collections::HashSet<PeerId>, + /// Peers identify says don't speak continuum, and whether they relay: not sent to + /// (`send_encoded`), so that a seed that's no node says so. + not_nodes: HashMap<PeerId, bool>, /// Peers found on the LAN that speak continuum, with their address: seeds not /// handed out yet (`discovered_seeds`). discovered: Vec<Multiaddr>, @@ -532,6 +535,7 @@ impl Book { self.relays.remove(peer); self.public_relays.remove(peer); self.continuum.remove(peer); + self.not_nodes.remove(peer); self.lan.remove(peer); self.failed_relays.remove(peer); self.upgrades.remove(peer); @@ -1623,7 +1627,15 @@ async fn run( { book.public_relays.insert(peer_id, address); } + if !info.protocols.contains(&PROTOCOL) + && (book.not_nodes.len() < MAX_PEERS + || book.not_nodes.contains_key(&peer_id)) + { + let relays = info.protocols.contains(&::libp2p::relay::HOP_PROTOCOL_NAME); + book.not_nodes.insert(peer_id, relays); + } if info.protocols.contains(&PROTOCOL) { + book.not_nodes.remove(&peer_id); book.continuum.insert(peer_id); if book.lan.remove(&peer_id) { book.discover(peer_id); @@ -1886,6 +1898,17 @@ impl Transport for Libp2pTransport { .with_context(|| format!("{} is no libp2p peer ID", message.peer))?; let started = std::time::Instant::now(); self.connect(peer).await?; + // The protocol goes with the first data (`swarm_config`), so a peer that doesn't + // speak it seems to take the message: once identify has told, say so. + if let Some(relays) = lock(&self.book).not_nodes.get(&peer).copied() { + if relays { + bail!( + "{peer} is a relay, not a node: give a node behind it as the seed \ + (<relay>/p2p-circuit/p2p/<peer ID>, or /p2p/<peer ID> with libp2p-relays)" + ); + } + bail!("{peer} doesn't speak continuum"); + } let connected = started.elapsed(); let mut control = self.control.clone(); let body = message.body.clone(); @@ -2314,15 +2337,24 @@ mod tests { let (from, _) = at_b.recv().await.unwrap(); assert_eq!(from, a.local_id()); - // The relay itself doesn't speak continuum: it takes no messages (a send to it - // isn't refused, though: the protocol goes with the first data, `swarm_config`, - // so the relay's refusal comes too late; nodes never send to it, as it never - // proves itself a node). + // The relay itself doesn't speak continuum: it takes no messages, and a send to + // it is refused once identify has told (the relay's own refusal comes too late: + // the protocol goes with the first data, `swarm_config`), saying what to give + // as a seed instead. assert_eq!( a.resolve_seed(&r_address.to_string()).await.unwrap(), r.local_id() ); assert!( + eventually(|| lock(&a.book).not_nodes.get(&r.peer_id) == Some(&true)).await, + "identify didn't tell" + ); + let refused = a.send_message(r.local_id(), &status()).await.unwrap_err(); + assert!( + refused.to_string().contains("is a relay, not a node"), + "{refused:#}" + ); + assert!( r.start_consumer(Box::new(|_, _, _| Box::pin(async { Ok(()) }))) .await .is_err() |
