How to configure the Kademlia DHT to discover more peers when using rust-libp2p #2673
-
I am trying to configure rust-libp2p, to use kademlia for peer discovery and to be able to discover more peers after connecting to a bootstrap node. I was able to achieve what I wanted with js-libp2p but could not with rust-libp2p. The js-libp2p code is as follows:
And when I run it, I see the following in the console:
Which shows, that after establishing connection to QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ, there was a pause, and more peers were discovered. I tried to replicate this in Rust as follows:
and when I run it I get the following in the output:
Showing that it connected to the bootnode but that is where it stopped. Nothing else gets consoled to the logs even after waiting for minutes. What am I missing in the rust-libp2p version? What do I need to configure, to enable it to discover more peers after connecting to the bootnode, just like how the js-libp2p version behaved? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
Followed up here: https://discuss.libp2p.io/t/how-to-configure-the-kademlia-dht-to-discover-more-peers-when-using-rust-libp2p/1442/2 |
Beta Was this translation helpful? Give feedback.
-
Ran into the same issue and I was told to bring this discussion back to the Github discussion here... use futures::StreamExt;
use libp2p::{
core::transport::upgrade::Version,
identify, identity,
kad::{record::store::MemoryStore, Kademlia, KademliaConfig, KademliaEvent, Mode, QueryResult},
noise,
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
tcp, yamux, PeerId, Transport,
};
use once_cell::sync::Lazy;
use std::time::Duration;
use tokio::{io::AsyncBufReadExt, select};
#[derive(NetworkBehaviour)]
#[behaviour(to_swarm = "MyBehaviourEvent")]
struct MyBehaviour {
identify: identify::Behaviour,
kad: Kademlia<MemoryStore>,
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
enum MyBehaviourEvent {
Identify(identify::Event),
Kademlia(KademliaEvent),
}
impl From<identify::Event> for MyBehaviourEvent {
fn from(event: identify::Event) -> Self {
MyBehaviourEvent::Identify(event)
}
}
impl From<KademliaEvent> for MyBehaviourEvent {
fn from(event: KademliaEvent) -> Self {
MyBehaviourEvent::Kademlia(event)
}
}
static KEYS: Lazy<identity::Keypair> = Lazy::new(|| identity::Keypair::generate_ed25519());
static PEER_ID: Lazy<PeerId> = Lazy::new(|| PeerId::from(KEYS.public()));
#[tokio::main]
async fn main() {
// create transport
let transport = tcp::tokio::Transport::default()
.upgrade(Version::V1Lazy)
.authenticate(noise::Config::new(&KEYS).unwrap())
.multiplex(yamux::Config::default())
.boxed();
// create peer identity
let identify = identify::Behaviour::new(identify::Config::new(
"Testing/0.1.0".to_string(),
KEYS.public(),
));
// create kademlia DHT
let kad = Kademlia::with_config(
*PEER_ID,
MemoryStore::new(*PEER_ID),
KademliaConfig::default(),
);
// print peer id
println!("Peer ID: {}", *PEER_ID);
// create swarm
let mut swarm =
SwarmBuilder::with_tokio_executor(transport, MyBehaviour { identify, kad }, *PEER_ID)
.idle_connection_timeout(Duration::from_secs(5))
.build();
// set kademlia to server mode
swarm.behaviour_mut().kad.set_mode(Some(Mode::Server));
// start listening
let _ = swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap());
// start stdin reader
let mut stdin = tokio::io::BufReader::new(tokio::io::stdin()).lines();
// start main loop
loop {
// select between swarm events and stdin
select! {
line = stdin.next_line() => {
if let Some(line) = line.expect("line exists") {
handle_input_line(&mut swarm.behaviour_mut().kad, line);
}
},
event = swarm.next() => {
match event {
Some(SwarmEvent::NewListenAddr { address, .. }) => {
println!("Listening on {}", address);
}
Some(SwarmEvent::ConnectionEstablished { peer_id, .. }) => {
println!("Connected to {}", peer_id);
}
Some(SwarmEvent::ConnectionClosed { peer_id, .. }) => {
println!("Disconnected from {}", peer_id);
}
Some(SwarmEvent::Behaviour(MyBehaviourEvent::Identify(event))) => {
println!("Identify event: {:?}", event);
}
Some(SwarmEvent::Behaviour(MyBehaviourEvent::Kademlia(event))) => match event {
KademliaEvent::OutboundQueryProgressed {
result: QueryResult::GetClosestPeers(result),
..
} => {
if let Ok(result) = result {
println!("Closest peers: {:?}", result.peers);
}
}
KademliaEvent::RoutingUpdated { peer, .. } => {
println!("Routing updated for peer: {:?}", peer);
}
_ => {
println!("Kademlia event: {:?}", event);
}
},
other => {
println!("Unhandled {:?}", other);
}
}
},
}
}
}
fn handle_input_line(kademlia: &mut Kademlia<MemoryStore>, line: String) {
let mut args = line.split(' ');
match args.next() {
Some("BOOTSTRAP") => {
let bootstrap = kademlia.bootstrap();
println!("Bootstrap: {:?}", bootstrap);
}
Some("ADD_PEER") => {
let peer = args.next().unwrap();
let peer = peer.parse().unwrap();
let addr = args.next().unwrap();
let addr = addr.parse().unwrap();
kademlia.add_address(&peer, addr);
let bootstrap = kademlia.bootstrap();
println!("Bootstrap: {:?}", bootstrap);
}
Some("CLOSEST_PEER") => {
let key = args.next().unwrap().as_bytes().to_vec();
let closest_peers = kademlia.get_closest_peers(key);
println!("Closest Peers: {:?}", closest_peers);
}
Some("LIST_PEERS") => {
for bucket in kademlia.kbuckets() {
for peer in bucket.iter() {
let peer = peer.node.key.preimage().to_base58();
println!("Peer: {}", peer);
}
}
}
_ => {}
}
} |
Beta Was this translation helpful? Give feedback.
Have you read
rust-libp2p/protocols/kad/src/lib.rs
Lines 21 to 34 in 38ea7ad