mina_node_testing/scenarios/p2p/
kademlia.rs

1use node::ActionKind;
2
3use crate::{
4    cluster::ClusterNodeId,
5    node::RustNodeTestingConfig,
6    scenario::ListenerNode,
7    scenarios::{
8        multi_node::connection_discovery::{
9            check_kademlia_entries, wait_for_identify, wait_for_node_ready,
10        },
11        ClusterRunner, RunCfg,
12    },
13};
14
15/// Kademlia bootstrap test.
16/// 1. Create seed node and wait for it to be ready
17/// 2. Create NUM nodes that will connect to seed node but not perform further discovery
18/// 3. Check that seed nodes has all nodes in it's routing table
19/// 4. Create new node with only seed node as peer
20/// 5. Wait for new node to bootstrap
21/// 6. Check that new node has all peers in it table
22#[derive(documented::Documented, Default, Clone, Copy)]
23pub struct KademliaBootstrap;
24
25impl KademliaBootstrap {
26    pub async fn run(self, mut runner: ClusterRunner<'_>) {
27        std::env::set_var("MINA_DISCOVERY_FILTER_ADDR", "false");
28        const NUM: u8 = 16;
29
30        let seed_node = runner.add_rust_node(RustNodeTestingConfig::devnet_default());
31        wait_for_node_ready(&mut runner, seed_node).await;
32        let mut nodes = vec![];
33
34        let config = RustNodeTestingConfig {
35            initial_peers: vec![ListenerNode::Rust(seed_node)],
36            ..RustNodeTestingConfig::devnet_default()
37        };
38        std::env::set_var("MINA_DISCOVERY_FILTER_ADDR", "true");
39        for _ in 0..NUM {
40            let node_id = runner.add_rust_node(config.clone());
41            let peer_id = runner.node(node_id).expect("Node not found").peer_id();
42
43            nodes.push((node_id, peer_id));
44
45            wait_for_bootstrap(&mut runner, node_id).await;
46            wait_for_identify(&mut runner, seed_node, peer_id, "mina").await;
47        }
48
49        let peer_ids = nodes.iter().map(|node| node.1);
50        let seed_has_peers =
51            check_kademlia_entries(&mut runner, seed_node, peer_ids.clone()).unwrap_or_default();
52        assert!(
53            seed_has_peers,
54            "Seed doesn't have all peers in it's routing table"
55        );
56
57        std::env::set_var("MINA_DISCOVERY_FILTER_ADDR", "true");
58        let new_node = runner.add_rust_node(config);
59        let new_node_peer_id = runner.node(new_node).expect("Not note found").peer_id();
60
61        wait_for_bootstrap(&mut runner, new_node).await;
62        wait_for_identify(&mut runner, seed_node, new_node_peer_id, "mina").await;
63        let new_has_peers =
64            check_kademlia_entries(&mut runner, seed_node, peer_ids).unwrap_or_default();
65        assert!(
66            new_has_peers,
67            "Node doesn't have all peers in it's routing table"
68        );
69    }
70}
71
72async fn wait_for_bootstrap(runner: &mut ClusterRunner<'_>, node_id: ClusterNodeId) {
73    runner
74        .run(RunCfg::default().action_handler(move |node, _, _, action| {
75            node == node_id
76                && matches!(
77                    action.action().kind(),
78                    ActionKind::P2pNetworkKademliaBootstrapFinished
79                )
80        }))
81        .await
82        .expect("Node failed to bootstrap")
83}