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