summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/transport/libp2p.rs40
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()