rustlibp2p

Ping in reverse order


I run ping pong example in two different console windows like described in that tutorial.

use libp2p::futures::StreamExt;
use libp2p::ping::{Ping, PingConfig};
use libp2p::swarm::{Swarm, SwarmEvent};
use libp2p::{identity, Multiaddr, PeerId};
use std::error::Error;

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

    let transport = libp2p::development_transport(local_key).await?;
    let behaviour = Ping::new(PingConfig::new().with_keep_alive(true));
    let mut swarm = Swarm::new(transport, behaviour, local_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),
            SwarmEvent::Behaviour(event) => println!("{:?}", event),
            _ => {}
        }
    }
}

console 1:

cargo run
Local peer id: PeerId("12D3KooWGi2AZgQL5sXDx4WYcPbtpXQDJJf2JTzEfHMKoYARohUN")
Listening on "/ip4/127.0.0.1/tcp/53912"
Listening on "/ip4/192.168.100.4/tcp/53912"
Event { peer: PeerId("12D3KooWQTRrShA41Kh7qoQYUc3G63uDZcXPSFw68AmzZqmaaHSh"), result: Ok(Pong) }
Event { peer: PeerId("12D3KooWQTRrShA41Kh7qoQYUc3G63uDZcXPSFw68AmzZqmaaHSh"), result: Ok(Ping { rtt: 1.112947ms }) }
Event { peer: PeerId("12D3KooWQTRrShA41Kh7qoQYUc3G63uDZcXPSFw68AmzZqmaaHSh"), result: Ok(Pong) }
Event { peer: PeerId("12D3KooWQTRrShA41Kh7qoQYUc3G63uDZcXPSFw68AmzZqmaaHSh"), result: Ok(Ping { rtt: 1.682508ms }) }

console 2

cargo run -- /ip4/192.168.100.4/tcp/53912
Local peer id: PeerId("12D3KooWQTRrShA41Kh7qoQYUc3G63uDZcXPSFw68AmzZqmaaHSh")
Dialed /ip4/192.168.100.4/tcp/53912
Listening on "/ip4/127.0.0.1/tcp/53913"
Listening on "/ip4/192.168.100.4/tcp/53913"
Event { peer: PeerId("12D3KooWGi2AZgQL5sXDx4WYcPbtpXQDJJf2JTzEfHMKoYARohUN"), result: Ok(Pong) }
Event { peer: PeerId("12D3KooWGi2AZgQL5sXDx4WYcPbtpXQDJJf2JTzEfHMKoYARohUN"), result: Ok(Ping { rtt: 869.493µs }) }
Event { peer: PeerId("12D3KooWGi2AZgQL5sXDx4WYcPbtpXQDJJf2JTzEfHMKoYARohUN"), result: Ok(Pong) }
Event { peer: PeerId("12D3KooWGi2AZgQL5sXDx4WYcPbtpXQDJJf2JTzEfHMKoYARohUN"), result: Ok(Ping { rtt: 2.109459ms }) }

What confuses me is the order of ping and pong messages. This example creates two nodes which send ping pong messages each other. But why do they start with Pong msg every time I run these nodes? I expect first Ping and then Pong event. Do I miss something?


Solution

  • That seems to simply be down to the library's semantics: if you go look at the documentation for PingSuccess (the "success" side of a ping operation), the two variants are:

    Pong Received a ping and sent back a pong.

    Ping Sent a ping and received back a pong. Includes the round-trip time.

    So the events are not asymmetric: while "pong" means "I received a ping and sent a pong", "ping" means I received a response to my ping, which is why it can report the RTT. And so the timeline is

    ping ->
         <- pong
         triggers PingSuccess::Pong
    triggers PingSuccess::Ping
    

    Thus the order you can see here.