How to configure the Kademlia DHT to discover more peers when using rust-libp2p

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:

(async () => {
    const node = await createLibp2p({
        addresses: {
            listen: ['/ip4/0.0.0.0/tcp/0']
        },
        transports: [new TCP()],
        streamMuxers: [new Mplex()],
        connectionEncryption: [new Noise()],
        dht: new KadDHT({
            kBucketSize: 20,
            clientMode: false,
        }),
        peerDiscovery: [
            new Bootstrap({
                interval: 60e3,
                list: ['/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ']
            })
        ]
    })

    node.connectionManager.addEventListener('peer:connect', (evt) => {
        const connection = evt.detail

        node.peerStore.addressBook.add(connection.remotePeer, [connection.remoteAddr])
        console.log('Connection established to:', connection.remotePeer.toString())
    })

    node.addEventListener('peer:discovery', (evt) => {
        const peer = evt.detail
        console.log('Discovered:', peer.id.toString(), peer.multiaddrs.toString())
    })

    node.peerStore.addEventListener('peer', (peerId) => {
        console.log(`added to peer store: ${JSON.stringify(peerId.detail.id)}`)
    })

    await node.start()
})();

And when I run it, I see the following in the console:

Discovered: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ /ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
Discovered: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ /ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
Connection established to: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
...<after about 10 seconds of pause>....
Discovered: 12D3KooWHzYS5y4jNuVixHSgH6scDkH4sMajjMsARRxRXtUsJSMt /ip4/127.0.0.1/tcp/4001,/ip6/::1/tcp/4001,/ip4/148.59.59.172/tcp/4001,/ip4/10.20.20.96/udp/4001/quic,/ip4/127.0.0.1/udp/4001/quic,/ip6/::1/udp/4001/quic,/ip4/10.20.20.96/tcp/4001
Discovered: QmNrW6qRFC2tExR7o33XSakfuZXuewv3A77FYEAUCWsSbS /ip4/10.0.68.134/tcp/4001,/ip4/54.211.214.244/udp/4001/quic,/ip4/127.0.0.1/tcp/4001,/ip4/10.0.68.134/udp/4001/quic,/ip6/::1/udp/4001/quic,/ip6/64:ff9b::36d3:d6f4/udp/4001/quic,/ip4/54.211.214.244/udp/1024/quic,/ip4/127.0.0.1/udp/4001/quic,/ip4/54.211.214.244/tcp/4001,/ip6/::1/tcp/4001,/ip6/64:ff9b::36d3:d6f4/tcp/4001
Discovered: 12D3KooWHBvqsc47XpWovZJGmjFWJb414fzz1Vw2v5BnudvmncxZ /ip4/127.0.0.1/udp/30006/quic,/ip4/13.59.159.106/udp/30006/quic,/ip4/13.59.159.106/tcp/30006,/ip4/172.31.11.43/tcp/30006,/ip4/127.0.0.1/tcp/30006,/ip4/172.31.11.43/udp/30006/quic
Discovered: QmeJBm1E2NdNEE4dGK4zu9jo8XdDdnUayRGnjGQKenJ2Ui /ip4/139.178.68.153/tcp/4001,/ip4/139.178.68.153/tcp/4002/ws,/ip4/139.178.68.153/udp/4001/quic,/ip6/2604:1380:45e2:b200::7/tcp/4001,/ip6/2604:1380:45e2:b200::7/tcp/4002/ws,/ip6/2604:1380:45e2:b200::7/udp/4001/quic
...

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:

#[derive(NetworkBehaviour)]
#[behaviour(event_process = true)]
struct CustomBehaviour {
    mdns: Mdns,
    kad: Kademlia<MemoryStore>
}

impl NetworkBehaviourEventProcess<MdnsEvent> for CustomBehaviour {
    // Called when `mdns` produces an event.
    fn inject_event(&mut self, event: MdnsEvent) {
        if let MdnsEvent::Discovered(list) = event {
            for (peer_id, multiaddr) in list {
                println!("multiaddr {:?}", multiaddr);
                println!("peer_id {:?}", peer_id);
            }
        }
    }
}

impl NetworkBehaviourEventProcess<KademliaEvent> for CustomBehaviour {
    fn inject_event(&mut self, event: KademliaEvent) {
        println!("{:?}", event);
    }
}

#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let local_key = identity::Keypair::generate_ed25519();
    let peer_id = PeerId::from(local_key.public());
    println!("Local peer id: {:?}", peer_id);

    let transport = libp2p::development_transport(local_key).await?;

    //let behaviour: Behaviour = Ping::new(PingConfig::new().with_keep_alive(true));
    let mdnsBehaviour = Mdns::new(MdnsConfig::default()).await?;
    let mut kadBehaviour = Kademlia::new(peer_id, MemoryStore::new(peer_id));

    let bootaddr = Multiaddr::from_str("/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ")?;
    for peer in &BOOTNODES {
        kadBehaviour.add_address(&PeerId::from_str(peer)?, bootaddr.clone());
    }

    let mut swarm = Swarm::new(transport, CustomBehaviour {
        mdns: mdnsBehaviour,
        kad: kadBehaviour
    }, peer_id);

    swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;

    if let Some(addr) = std::env::args().nth(1) {
        let remote: Multiaddr = addr.parse()?;
        swarm.dial(remote)?;
        println!("Dialed {}", addr)
    }

    loop {
        match swarm.select_next_some().await {
            SwarmEvent::NewListenAddr {address, ..} => println!("Listening on {:?}", address),
            _ => ()
        }
    }
}

and when I run it I get the following in the output:

warning: `scanp2p` (bin "scanp2p") generated 5 warnings
    Finished dev [unoptimized + debuginfo] target(s) in 0.44s
     Running `target/debug/scanp2p`
Local peer id: PeerId("12D3KooWMXvTUp8dYc4VgW46fhkr5Q1Xe8BdXVnoa6rEanZEMjoJ")
Listening on "/ip4/127.0.0.1/tcp/51372"
Listening on "/ip4/192.168.101.41/tcp/51372"
RoutingUpdated { peer: PeerId("QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"), is_new_peer: true, addresses: ["/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"], bucket_range: (Distance(28948022309329048855892746252171976963317496166410141009864396001978282409984), Distance(57896044618658097711785492504343953926634992332820282019728792003956564819967)), old_peer: None }

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?

Mhh, surprising. Mind posting with RUST_LOG=debug? Note, that you will have to run let _ = env_logger::try_init();

@mxinden as requested:

warning: scanp2p (bin “scanp2p”) generated 2 warnings
Finished dev [unoptimized + debuginfo] target(s) in 0.25s
Running target/debug/scanp2p
Local peer id: PeerId(“12D3KooWHTE5D2eoCh5ck5exuSoSZETHwVGiKyPAAidEF8EvpMns”)
[2022-05-29T16:35:35Z DEBUG libp2p_tcp] listening on 0.0.0.0:0
[2022-05-29T16:35:35Z DEBUG libp2p_tcp] New listen address: /ip4/127.0.0.1/tcp/64798
[2022-05-29T16:35:35Z DEBUG libp2p_swarm] Listener ListenerId(1); New address: “/ip4/127.0.0.1/tcp/64798”
Listening on “/ip4/127.0.0.1/tcp/64798”
[2022-05-29T16:35:35Z DEBUG libp2p_tcp] New listen address: /ip4/192.168.178.73/tcp/64798
[2022-05-29T16:35:35Z DEBUG libp2p_swarm] Listener ListenerId(1); New address: “/ip4/192.168.178.73/tcp/64798”
Listening on “/ip4/192.168.178.73/tcp/64798”
[2022-05-29T16:35:35Z INFO libp2p_mdns::behaviour::iface] creating instance on iface 192.168.178.73
RoutingUpdated { peer: PeerId(“QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN”), is_new_peer: true, addresses: ["/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"], bucket_range: (Distance(57896044618658097711785492504343953926634992332820282019728792003956564819968), Distance(115792089237316195423570985008687907853269984665640564039457584007913129639935)), old_peer: None }
RoutingUpdated { peer: PeerId(“QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa”), is_new_peer: true, addresses: ["/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"], bucket_range: (Distance(28948022309329048855892746252171976963317496166410141009864396001978282409984), Distance(57896044618658097711785492504343953926634992332820282019728792003956564819967)), old_peer: None }
RoutingUpdated { peer: PeerId(“QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb”), is_new_peer: true, addresses: ["/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"], bucket_range: (Distance(57896044618658097711785492504343953926634992332820282019728792003956564819968), Distance(115792089237316195423570985008687907853269984665640564039457584007913129639935)), old_peer: None }
RoutingUpdated { peer: PeerId(“QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt”), is_new_peer: true, addresses: ["/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"], bucket_range: (Distance(28948022309329048855892746252171976963317496166410141009864396001978282409984), Distance(57896044618658097711785492504343953926634992332820282019728792003956564819967)), old_peer: None }
[2022-05-29T16:35:39Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii
[2022-05-29T16:35:42Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii
[2022-05-29T16:35:51Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii
[2022-05-29T16:36:03Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii
[2022-05-29T16:36:06Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii
[2022-05-29T16:36:14Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii
[2022-05-29T16:36:17Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii
[2022-05-29T16:36:26Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii
[2022-05-29T16:36:44Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii
[2022-05-29T16:36:47Z DEBUG libp2p_mdns::behaviour::iface::query] Parsing mdns packet failed: LabelIsNotAscii

1 Like

First post, but here it goes!

Nothing else gets consoled to the logs even after waiting for minutes.

I really gained a lot from printing all events to the console, maybe you will too. Try updating the match statement in your loop to be:

event = swarm.select_next_some().await => match event {
    SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {:?}", address),
    _ => println!("{:?}", event),
}

This will print all events to the console so you can identify which ones are of interest to you.

The rust trace seems like it discovered more peers on the KademliaEvent::RoutingUpdated. Another question to ask might be, is your bootstrap node already connected to other peers?

I hope this helps.