mina_node_testing/scenarios/solo_node/
basic_connectivity_initial_joining.rs

1#![allow(warnings)]
2
3use std::{collections::HashMap, time::Duration};
4
5use libp2p::Multiaddr;
6
7use node::{
8    core::log::{debug, system_time},
9    p2p::connection::outgoing::P2pConnectionOutgoingInitOpts,
10};
11
12use crate::{
13    hosts,
14    node::RustNodeTestingConfig,
15    scenario::{ListenerNode, ScenarioStep},
16    scenarios::ClusterRunner,
17};
18
19/// Local test to ensure that the Rust node can connect to an existing OCaml testnet.
20/// Launch a Rust node and connect it to seed nodes of the public (or private) OCaml testnet.
21/// Run the simulation until:
22/// * Number of known peers is greater than or equal to the maximum number of peers.
23/// * Number of connected peers is greater than or equal to some threshold.
24/// Fail the test if the specified number of steps occur but the condition is not met.
25#[derive(documented::Documented, Default, Clone, Copy)]
26pub struct SoloNodeBasicConnectivityInitialJoining;
27
28impl SoloNodeBasicConnectivityInitialJoining {
29    pub async fn run(self, mut runner: ClusterRunner<'_>) {
30        std::env::set_var("MINA_DISCOVERY_FILTER_ADDR", "true");
31        const MAX_PEERS_PER_NODE: usize = 100;
32        const KNOWN_PEERS: usize = 5; // current devnet network
33        const STEPS: usize = 3_000;
34        const STEP_DELAY: Duration = Duration::from_millis(200);
35
36        let initial_peers = hosts::devnet();
37        eprintln!("set max peers per node: {MAX_PEERS_PER_NODE}");
38        for seed in &initial_peers {
39            eprintln!("add initial peer: {seed:?}");
40        }
41        let config = RustNodeTestingConfig::devnet_default()
42            .max_peers(MAX_PEERS_PER_NODE)
43            .initial_peers(initial_peers);
44
45        let node_id = runner.add_rust_node(config);
46        let peer_id = libp2p::PeerId::try_from(
47            runner
48                .node(node_id)
49                .expect("must exist")
50                .state()
51                .p2p
52                .my_id(),
53        )
54        .unwrap();
55        eprintln!("launch Mina Rust node, id: {node_id}, peer_id: {peer_id}");
56
57        for step in 0..STEPS {
58            tokio::time::sleep(STEP_DELAY).await;
59
60            let steps = runner
61                .pending_events(true)
62                .map(|(node_id, _, events)| {
63                    events.map(move |(_, event)| ScenarioStep::Event {
64                        node_id,
65                        event: event.to_string(),
66                    })
67                })
68                .flatten()
69                .collect::<Vec<_>>();
70
71            for step in steps {
72                runner.exec_step(step).await.unwrap();
73            }
74
75            runner
76                .exec_step(ScenarioStep::AdvanceNodeTime {
77                    node_id,
78                    by_nanos: STEP_DELAY.as_nanos() as _,
79                })
80                .await
81                .unwrap();
82
83            runner
84                .exec_step(ScenarioStep::CheckTimeouts { node_id })
85                .await
86                .unwrap();
87
88            let node = runner.node(node_id).expect("must exist");
89            let ready_peers = node.state().p2p.ready_peers_iter().count();
90            let my_id = node.state().p2p.my_id();
91            let known_peers: usize = node
92                .state()
93                .p2p
94                .ready()
95                .and_then(|p2p| p2p.network.scheduler.discovery_state())
96                .map_or(0, |discovery_state| {
97                    discovery_state
98                        .routing_table
99                        .closest_peers(&my_id.try_into().unwrap())
100                        .count()
101                });
102
103            println!("step: {step}");
104            println!("known peers: {known_peers}");
105            println!("connected peers: {ready_peers}");
106
107            // TODO: the threshold is too small, node cannot connect to many peer before the timeout
108            if ready_peers >= KNOWN_PEERS && known_peers >= KNOWN_PEERS {
109                debug!(system_time(); "Step: {}, known peers: {}, connected peers: {}, success", step, known_peers, ready_peers);
110
111                if let Some(debugger) = runner.debugger() {
112                    tokio::time::sleep(Duration::from_secs(10)).await;
113                    let connections = debugger
114                        .connections_raw(0)
115                        .map(|(id, c)| (id, (c.info.addr, c.info.fd, c.info.pid, c.incoming)))
116                        .collect::<HashMap<_, _>>();
117
118                    // dbg
119                    for (id, cn) in &connections {
120                        eprintln!("{id}: {}", serde_json::to_string(cn).unwrap());
121                    }
122                    // dbg
123                    for (id, msg) in debugger.messages(0, "") {
124                        eprintln!("{id}: {}", serde_json::to_string(&msg).unwrap());
125                    }
126                    // TODO: fix debugger returns timeout
127                    let connections = debugger
128                        .connections()
129                        .filter_map(|id| Some((id, connections.get(&id)?.clone())))
130                        .collect::<HashMap<_, _>>();
131                    let incoming = connections.iter().filter(|(_, (_, _, _, i))| *i).count();
132                    let outgoing = connections.len() - incoming;
133                    eprintln!(
134                        "debugger seen {incoming} incoming connections and {outgoing} outgoing connections",
135                    );
136                    let state_machine_peers = if cfg!(feature = "p2p-webrtc") {
137                        ready_peers
138                    } else {
139                        ready_peers.max(known_peers)
140                    };
141                    assert_eq!(
142                        incoming + outgoing,
143                        state_machine_peers,
144                        "debugger must see the same number of connections as the state machine"
145                    );
146                } else {
147                    eprintln!("no debugger, run test with --use-debugger for additional check");
148                }
149
150                return;
151            }
152        }
153
154        panic!("timeout");
155    }
156}