rings-core 0.10.0

Chord DHT implementation with ICE
Documentation
use rings_transport::core::transport::WebrtcConnectionState;

use crate::ecc::tests::gen_ordered_keys;
use crate::ecc::SecretKey;
use crate::tests::default::assert_no_more_msg;
use crate::tests::default::prepare_node;
use crate::tests::default::wait_for_msgs;
use crate::tests::manually_establish_connection;

#[tokio::test]
async fn test_handshake_on_both_sides_ordered() {
    let keys = gen_ordered_keys(3);
    let (key1, key2, key3) = (keys[0], keys[1], keys[2]);
    test_handshake_on_both_sides(key1, key2, key3).await
}

#[tokio::test]
async fn test_handshake_on_both_sides_desc_ordered() {
    let keys = gen_ordered_keys(3);
    let (key3, key2, key1) = (keys[0], keys[1], keys[2]);
    test_handshake_on_both_sides(key1, key2, key3).await
}

async fn test_handshake_on_both_sides(key1: SecretKey, key2: SecretKey, key3: SecretKey) {
    let node1 = prepare_node(key1).await;
    let node2 = prepare_node(key2).await;
    let node3 = prepare_node(key3).await;

    assert!(node1.swarm.transport.get_connection(node2.did()).is_none());
    assert!(node2.swarm.transport.get_connection(node1.did()).is_none());

    // connect to middle peer
    manually_establish_connection(&node1.swarm, &node3.swarm).await;
    manually_establish_connection(&node2.swarm, &node3.swarm).await;
    wait_for_msgs([&node1, &node2, &node3]).await;
    assert_no_more_msg([&node1, &node2, &node3]).await;

    assert_eq!(
        node3
            .swarm
            .transport
            .get_connection(node1.did())
            .unwrap()
            .webrtc_connection_state(),
        WebrtcConnectionState::Connected
    );
    assert_eq!(
        node3
            .swarm
            .transport
            .get_connection(node2.did())
            .unwrap()
            .webrtc_connection_state(),
        WebrtcConnectionState::Connected
    );

    assert_eq!(
        node1
            .swarm
            .transport
            .get_connection(node3.did())
            .unwrap()
            .webrtc_connection_state(),
        WebrtcConnectionState::Connected
    );
    assert_eq!(
        node2
            .swarm
            .transport
            .get_connection(node3.did())
            .unwrap()
            .webrtc_connection_state(),
        WebrtcConnectionState::Connected
    );

    // connect to each at same time
    // Node 1 -> Offer -> Node 2
    // Node 2 -> Offer -> Node 1
    _ = node1.swarm.connect(node2.did()).await;
    _ = node2.swarm.connect(node1.did()).await;

    // Both sides have just initiated an outbound connection (offer created) but no answer has
    // been exchanged yet, so neither has reached `Connected`. The exact pre-connected sub-state —
    // `New` vs `Connecting` — depends on whether the peer's offer has already arrived and started
    // ICE, which is webrtc-version/timing dependent; the invariant we assert is only that the glare
    // handshake is still in progress.
    let node1_to_node2 = node1
        .swarm
        .transport
        .get_connection(node2.did())
        .unwrap()
        .webrtc_connection_state();
    assert!(
        matches!(
            node1_to_node2,
            WebrtcConnectionState::New | WebrtcConnectionState::Connecting
        ),
        "swarm1 -> swarm2 should still be handshaking, got {node1_to_node2:?}",
    );
    let node2_to_node1 = node2
        .swarm
        .transport
        .get_connection(node1.did())
        .unwrap()
        .webrtc_connection_state();
    assert!(
        matches!(
            node2_to_node1,
            WebrtcConnectionState::New | WebrtcConnectionState::Connecting
        ),
        "swarm2 -> swarm1 should still be handshaking, got {node2_to_node1:?}",
    );

    wait_for_msgs([&node1, &node2, &node3]).await;
    assert_no_more_msg([&node1, &node2, &node3]).await;

    // When node 1 got offer, node 1 may accept offer if did 1 < did 2, drop local connection
    // and response answer
    // When node 2 got offer, node 2 reject offer if did 1 < did 2

    assert_eq!(
        node1
            .swarm
            .transport
            .get_connection(node2.did())
            .unwrap()
            .webrtc_connection_state(),
        WebrtcConnectionState::Connected,
    );

    assert_eq!(
        node2
            .swarm
            .transport
            .get_connection(node1.did())
            .unwrap()
            .webrtc_connection_state(),
        WebrtcConnectionState::Connected,
    )
}