Skip to content

Commit 0c388b9

Browse files
authored
fix(iroh-p2p): implement full local lookup (#537)
We were previously only returning the peer id, external addrs, and listening addrs. We now return the same content as performing a lookup on a remote peer.
1 parent 066aefd commit 0c388b9

File tree

8 files changed

+136
-23
lines changed

8 files changed

+136
-23
lines changed

iroh-api/src/p2p.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,7 @@ impl P2p {
2424
}
2525

2626
pub async fn lookup_local(&self) -> Result<Lookup> {
27-
let (_, listen_addrs) = self
28-
.client
29-
.get_listening_addrs()
30-
.await
31-
.map_err(|e| map_service_error("p2p", e))?;
32-
Ok(Lookup {
33-
peer_id: self.client.local_peer_id().await?,
34-
listen_addrs,
35-
observed_addrs: self.client.external_addresses().await?,
36-
protocol_version: String::new(),
37-
agent_version: String::new(),
38-
protocols: Default::default(),
39-
})
27+
self.client.lookup_local().await
4028
}
4129

4230
pub async fn lookup(&self, addr: &PeerIdOrAddr) -> Result<Lookup> {

iroh-p2p/src/behaviour.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ use crate::config::Libp2pConfig;
2727
mod event;
2828
mod peer_manager;
2929

30+
pub const PROTOCOL_VERSION: &str = "ipfs/0.1.0";
31+
pub const AGENT_VERSION: &str = concat!("iroh/", env!("CARGO_PKG_VERSION"));
32+
3033
/// Libp2p behaviour for the node.
3134
#[derive(NetworkBehaviour)]
3235
#[behaviour(out_event = "Event")]
@@ -188,8 +191,8 @@ impl NodeBehaviour {
188191
};
189192

190193
let identify = {
191-
let config = identify::Config::new("ipfs/0.1.0".into(), local_key.public())
192-
.with_agent_version(format!("iroh/{}", env!("CARGO_PKG_VERSION")))
194+
let config = identify::Config::new(PROTOCOL_VERSION.into(), local_key.public())
195+
.with_agent_version(String::from(AGENT_VERSION))
193196
.with_cache_size(64 * 1024);
194197
identify::Behaviour::new(config)
195198
};

iroh-p2p/src/behaviour/peer_manager.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use lru::LruCache;
2121
pub struct PeerManager {
2222
info: AHashMap<PeerId, Info>,
2323
bad_peers: LruCache<PeerId, ()>,
24+
supported_protocols: Vec<String>,
2425
}
2526

2627
#[derive(Default, Debug, Clone)]
@@ -43,6 +44,7 @@ impl Default for PeerManager {
4344
PeerManager {
4445
info: Default::default(),
4546
bad_peers: LruCache::new(DEFAULT_BAD_PEER_CAP.unwrap()),
47+
supported_protocols: Default::default(),
4648
}
4749
}
4850
}
@@ -68,6 +70,10 @@ impl PeerManager {
6870
pub fn info_for_peer(&self, peer_id: &PeerId) -> Option<&Info> {
6971
self.info.get(peer_id)
7072
}
73+
74+
pub fn supported_protocols(&self) -> Vec<String> {
75+
self.supported_protocols.clone()
76+
}
7177
}
7278

7379
impl NetworkBehaviour for PeerManager {
@@ -186,8 +192,26 @@ impl NetworkBehaviour for PeerManager {
186192
fn poll(
187193
&mut self,
188194
_cx: &mut Context<'_>,
189-
_params: &mut impl PollParameters,
195+
params: &mut impl PollParameters,
190196
) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ConnectionHandler>> {
197+
// TODO(ramfox):
198+
// We can only get the supported protocols of the local node by examining the
199+
// `PollParameters`, which mean you can only get the supported protocols by examining the
200+
// `PollParameters` in this method (`poll`) of a network behaviour.
201+
// I injected this responsibility in the `peer_manager`, because it's the only "simple"
202+
// network behaviour we have implemented.
203+
// There is an issue up to remove `PollParameters`, and a discussion into how to instead
204+
// get the `supported_protocols` of the node:
205+
// https://github.com/libp2p/rust-libp2p/issues/3124
206+
// When that is resolved, we can hopefully remove this responsibility from the `peer_manager`,
207+
// where it, frankly, doesn't belong.
208+
if self.supported_protocols.is_empty() {
209+
self.supported_protocols = params
210+
.supported_protocols()
211+
.map(|p| String::from_utf8_lossy(&p).to_string())
212+
.collect();
213+
}
214+
191215
Poll::Pending
192216
}
193217
}

iroh-p2p/src/node.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use tokio::task::JoinHandle;
3131
use tracing::{debug, error, info, trace, warn};
3232

3333
use iroh_bitswap::{BitswapEvent, Block};
34+
use iroh_rpc_client::Lookup;
3435

3536
use crate::keys::{Keychain, Storage};
3637
use crate::providers::Providers;
@@ -953,6 +954,29 @@ impl<KeyStorage: Storage> Node<KeyStorage> {
953954
response_channel.send(None).ok();
954955
}
955956
}
957+
RpcMessage::LookupLocalPeerInfo(response_channel) => {
958+
let peer_id = self.swarm.local_peer_id();
959+
let listen_addrs = self.swarm.listeners().cloned().collect();
960+
let observed_addrs = self
961+
.swarm
962+
.external_addresses()
963+
.map(|a| a.addr.clone())
964+
.collect();
965+
let protocol_version = String::from(crate::behaviour::PROTOCOL_VERSION);
966+
let agent_version = String::from(crate::behaviour::AGENT_VERSION);
967+
let protocols = self.swarm.behaviour().peer_manager.supported_protocols();
968+
969+
response_channel
970+
.send(Lookup {
971+
peer_id: *peer_id,
972+
listen_addrs,
973+
observed_addrs,
974+
agent_version,
975+
protocol_version,
976+
protocols,
977+
})
978+
.ok();
979+
}
956980
RpcMessage::CancelListenForIdentify(response_channel, peer_id) => {
957981
self.lookup_queries.remove(&peer_id);
958982
response_channel.send(()).ok();
@@ -1312,6 +1336,12 @@ mod tests {
13121336
let peer_id_b = test_runner_b.client.local_peer_id().await?;
13131337
assert_eq!(test_runner_b.peer_id, peer_id_b);
13141338

1339+
let lookup_a = test_runner_a.client.lookup_local().await?;
1340+
// since we aren't connected to any other nodes, we should not
1341+
// have any information about our observed addresses
1342+
assert!(lookup_a.observed_addrs.is_empty());
1343+
assert_lookup(lookup_a, test_runner_a.peer_id, &test_runner_a.addr)?;
1344+
13151345
// connect
13161346
test_runner_a.client.connect(peer_id_b, addrs_b).await?;
13171347
// Make sure we have exchanged identity information
@@ -1323,8 +1353,7 @@ mod tests {
13231353

13241354
// lookup
13251355
let lookup_b = test_runner_a.client.lookup(peer_id_b, None).await?;
1326-
assert_eq!(peer_id_b, lookup_b.peer_id);
1327-
1356+
assert_lookup(lookup_b, test_runner_b.peer_id, &test_runner_b.addr)?;
13281357
// now that we are connected & have exchanged identity information,
13291358
// we should now be able to view the node's external addrs
13301359
// these are the addresses that other nodes tell you "this is the address I see for you"
@@ -1339,6 +1368,39 @@ mod tests {
13391368
Ok(())
13401369
}
13411370

1371+
// assert_lookup ensures each part of the lookup is equal
1372+
fn assert_lookup(
1373+
got: Lookup,
1374+
expected_peer_id: PeerId,
1375+
expected_addr: &Multiaddr,
1376+
) -> Result<()> {
1377+
let expected_protocols = vec![
1378+
"/ipfs/ping/1.0.0",
1379+
"/ipfs/id/1.0.0",
1380+
"/ipfs/id/push/1.0.0",
1381+
"/ipfs/bitswap/1.2.0",
1382+
"/ipfs/bitswap/1.1.0",
1383+
"/ipfs/bitswap/1.0.0",
1384+
"/ipfs/bitswap",
1385+
"/ipfs/kad/1.0.0",
1386+
"/libp2p/autonat/1.0.0",
1387+
"/libp2p/circuit/relay/0.2.0/hop",
1388+
"/libp2p/circuit/relay/0.2.0/stop",
1389+
"/libp2p/dcutr",
1390+
"/meshsub/1.1.0",
1391+
"/meshsub/1.0.0",
1392+
];
1393+
let expected_protocol_version = "ipfs/0.1.0";
1394+
let expected_agent_version = "iroh/0.1.0";
1395+
1396+
assert_eq!(expected_peer_id, got.peer_id);
1397+
assert!(got.listen_addrs.contains(expected_addr));
1398+
assert_eq!(expected_protocols, got.protocols);
1399+
assert_eq!(expected_protocol_version, got.protocol_version);
1400+
assert_eq!(expected_agent_version, got.agent_version);
1401+
Ok(())
1402+
}
1403+
13421404
#[tokio::test]
13431405
async fn test_gossipsub() -> Result<()> {
13441406
let mut test_runner_a = TestRunnerBuilder::new().no_bootstrap().build().await?;

iroh-p2p/src/rpc.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use tracing::{debug, trace};
2020

2121
use async_trait::async_trait;
2222
use iroh_bitswap::Block;
23+
use iroh_rpc_client::Lookup;
2324
use iroh_rpc_types::p2p::{
2425
BitswapRequest, BitswapResponse, ConnectByPeerIdRequest, ConnectRequest, DisconnectRequest,
2526
GetListeningAddrsResponse, GetPeersResponse, GossipsubAllPeersResponse, GossipsubPeerAndTopics,
@@ -319,6 +320,14 @@ impl RpcP2p for P2p {
319320
Ok(ack)
320321
}
321322

323+
#[tracing::instrument(skip(self))]
324+
async fn lookup_local(&self, _: ()) -> Result<PeerInfo> {
325+
let (s, r) = oneshot::channel();
326+
self.sender.send(RpcMessage::LookupLocalPeerInfo(s)).await?;
327+
let lookup = r.await?;
328+
Ok(peer_info_from_lookup(lookup))
329+
}
330+
322331
#[tracing::instrument(skip(self, req))]
323332
async fn lookup(&self, req: LookupRequest) -> Result<PeerInfo> {
324333
let (s, r) = oneshot::channel();
@@ -522,7 +531,18 @@ fn peer_info_from_identify_info(i: IdentifyInfo) -> PeerInfo {
522531
.map(|addr| addr.to_vec())
523532
.collect(),
524533
protocols: i.protocols,
525-
observed_addr: i.observed_addr.to_vec(),
534+
observed_addrs: vec![i.observed_addr.to_vec()],
535+
}
536+
}
537+
538+
fn peer_info_from_lookup(l: Lookup) -> PeerInfo {
539+
PeerInfo {
540+
peer_id: l.peer_id.to_bytes(),
541+
protocol_version: l.protocol_version,
542+
agent_version: l.agent_version,
543+
listen_addrs: l.listen_addrs.iter().map(|a| a.to_vec()).collect(),
544+
protocols: l.protocols,
545+
observed_addrs: l.observed_addrs.iter().map(|a| a.to_vec()).collect(),
526546
}
527547
}
528548

@@ -583,6 +603,7 @@ pub enum RpcMessage {
583603
ListenForIdentify(oneshot::Sender<Result<IdentifyInfo>>, PeerId),
584604
CancelListenForIdentify(oneshot::Sender<()>, PeerId),
585605
AddressesOfPeer(oneshot::Sender<Vec<Multiaddr>>, PeerId),
606+
LookupLocalPeerInfo(oneshot::Sender<Lookup>),
586607
Shutdown,
587608
}
588609

iroh-rpc-client/src/network.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@ impl P2pClient {
187187
Lookup::from_peer_info(peer_info)
188188
}
189189

190+
#[tracing::instrument(skip(self))]
191+
pub async fn lookup_local(&self) -> Result<Lookup> {
192+
let peer_info = self.backend.lookup_local(()).await?;
193+
Lookup::from_peer_info(peer_info)
194+
}
195+
190196
#[tracing::instrument(skip(self))]
191197
pub async fn disconnect(&self, peer_id: PeerId) -> Result<()> {
192198
warn!("NetDisconnect not yet implemented on p2p node");
@@ -296,14 +302,14 @@ impl Lookup {
296302
fn from_peer_info(p: PeerInfo) -> Result<Self> {
297303
let peer_id = peer_id_from_bytes(p.peer_id)?;
298304
let listen_addrs = addrs_from_bytes(p.listen_addrs)?;
299-
let addr = addr_from_bytes(p.observed_addr)?;
305+
let observed_addrs = addrs_from_bytes(p.observed_addrs)?;
300306
Ok(Self {
301307
peer_id,
302308
protocol_version: p.protocol_version,
303309
agent_version: p.agent_version,
304310
listen_addrs,
305311
protocols: p.protocols,
306-
observed_addrs: vec![addr],
312+
observed_addrs,
307313
})
308314
}
309315
}
@@ -523,6 +529,13 @@ mod tests {
523529
todo!()
524530
}
525531

532+
async fn lookup_local(
533+
&self,
534+
_request: Request<()>,
535+
) -> Result<tonic::Response<PeerInfo>, tonic::Status> {
536+
todo!()
537+
}
538+
526539
async fn gossipsub_add_explicit_peer(
527540
&self,
528541
_request: Request<GossipsubPeerIdMsg>,

iroh-rpc-types/proto/p2p.proto

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ service P2p {
2222
rpc PeerDisconnect(DisconnectRequest) returns (google.protobuf.Empty) {}
2323
rpc Shutdown(google.protobuf.Empty) returns (google.protobuf.Empty) {}
2424
rpc Lookup(LookupRequest) returns (PeerInfo) {}
25+
rpc LookupLocal(google.protobuf.Empty) returns (PeerInfo) {}
2526

2627
rpc GossipsubAddExplicitPeer(GossipsubPeerIdMsg) returns (google.protobuf.Empty) {}
2728
rpc GossipsubAllMeshPeers(google.protobuf.Empty) returns (GossipsubPeersResponse) {}
@@ -132,8 +133,8 @@ message PeerInfo {
132133
repeated bytes listen_addrs = 4;
133134
// vec of Strings
134135
repeated string protocols = 5;
135-
// Multiaddr
136-
bytes observed_addr = 6;
136+
// vec of Multiaddr
137+
repeated bytes observed_addrs = 6;
137138
}
138139
message Multiaddrs {
139140
// Serialized list of multiaddrs

iroh-rpc-types/src/p2p.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ proxy!(
1616
peer_connect_by_peer_id: ConnectByPeerIdRequest => () => (),
1717
peer_disconnect: DisconnectRequest => () => (),
1818
lookup: LookupRequest => PeerInfo => PeerInfo,
19+
lookup_local: () => PeerInfo => PeerInfo,
1920
gossipsub_add_explicit_peer: GossipsubPeerIdMsg => () => (),
2021
gossipsub_all_mesh_peers: () => GossipsubPeersResponse => GossipsubPeersResponse,
2122
gossipsub_all_peers: () => GossipsubAllPeersResponse => GossipsubAllPeersResponse,

0 commit comments

Comments
 (0)