mina_node_testing/scenarios/solo_node/
bootstrap.rs1use crate::{
2 hosts,
3 node::RustNodeTestingConfig,
4 scenario::{ListenerNode, ScenarioStep},
5 scenarios::ClusterRunner,
6};
7use mina_core::constants::constraint_constants;
8use node::transition_frontier::sync::TransitionFrontierSyncState;
9use redux::Instant;
10use std::time::Duration;
11
12#[derive(documented::Documented, Default, Clone, Copy)]
19pub struct SoloNodeBootstrap;
20
21fn first_block_slot_timestamp_nanos(config: &RustNodeTestingConfig) -> u64 {
25 let first_block_global_slot = 2000000; let protocol_constants = config.genesis.protocol_constants().unwrap();
27 let genesis_timestamp_ms = protocol_constants.genesis_state_timestamp.0.as_u64();
28 let milliseconds_per_slot = constraint_constants().block_window_duration_ms;
29 let first_block_global_slot_delta_ms = first_block_global_slot * milliseconds_per_slot;
30
31 genesis_timestamp_ms
33 .checked_add(first_block_global_slot_delta_ms)
34 .unwrap()
35 .checked_mul(1_000_000)
36 .unwrap()
37}
38
39impl SoloNodeBootstrap {
40 pub async fn run(self, mut runner: ClusterRunner<'_>) {
41 std::env::set_var("MINA_DISCOVERY_FILTER_ADDR", "true");
42 use self::TransitionFrontierSyncState::*;
43
44 const TIMEOUT: Duration = Duration::from_secs(60 * 60);
45
46 let replayer = hosts::replayer();
47
48 let mut config = RustNodeTestingConfig::devnet_default();
49
50 config.initial_time = redux::Timestamp::new(first_block_slot_timestamp_nanos(&config));
51
52 let node_id =
53 runner.add_rust_node(config.initial_peers(vec![ListenerNode::Custom(replayer)]));
54 eprintln!("launch Mina Rust node with default configuration, id: {node_id}");
55
56 let mut timeout = TIMEOUT;
57 let mut last_time = Instant::now();
58 loop {
59 if runner
60 .wait_for_pending_events_with_timeout(Duration::from_secs(1))
61 .await
62 {
63 let steps = runner
64 .pending_events(true)
65 .flat_map(|(node_id, _, events)| {
66 events.map(move |(_, event)| ScenarioStep::Event {
67 node_id,
68 event: event.to_string(),
69 })
70 })
71 .collect::<Vec<_>>();
72
73 for step in steps {
74 runner.exec_step(step).await.unwrap();
75 }
76 }
77
78 runner
79 .exec_step(ScenarioStep::CheckTimeouts { node_id })
80 .await
81 .unwrap();
82
83 let new = Instant::now();
84 let elapsed = new - last_time;
85 last_time = new;
86
87 match timeout.checked_sub(elapsed) {
88 Some(new_timeout) => timeout = new_timeout,
89 None => panic!("timeout"),
90 }
91
92 runner
93 .exec_step(ScenarioStep::AdvanceNodeTime {
94 node_id,
95 by_nanos: elapsed.as_nanos() as _,
96 })
97 .await
98 .unwrap();
99
100 let this = runner.node(node_id).unwrap();
101 let best_chain = &this.state().transition_frontier.best_chain;
102 let sync_state = &this.state().transition_frontier.sync;
103 if let Synced { time } = &sync_state {
104 if best_chain.len() > 1 {
105 eprintln!(
106 "node: {node_id}, is synced at {time:?}, total elapsed {:?}",
107 TIMEOUT - timeout
108 );
109
110 break;
111 }
112 }
113 }
114 }
115}