1pub mod multi_node;
60pub mod record_replay;
61pub mod simulation;
62pub mod solo_node;
63
64pub mod p2p;
65
66mod driver;
67pub use driver::*;
68
69pub use crate::cluster::runner::*;
70
71use mina_core::log::{debug, system_time, warn};
72use strum_macros::{EnumIter, EnumString, IntoStaticStr};
73
74use crate::{
75 cluster::{Cluster, ClusterConfig},
76 scenario::{Scenario, ScenarioId, ScenarioStep},
77};
78
79use self::{
80 multi_node::{
81 basic_connectivity_initial_joining::MultiNodeBasicConnectivityInitialJoining,
82 basic_connectivity_peer_discovery::MultiNodeBasicConnectivityPeerDiscovery,
83 connection_discovery::{
84 OCamlToRust, OCamlToRustViaSeed,
85 RustNodeAsSeed as P2pConnectionDiscoveryRustNodeAsSeed, RustToOCaml,
86 RustToOCamlViaSeed,
87 },
88 pubsub_advanced::MultiNodePubsubPropagateBlock,
89 sync_4_block_producers::MultiNodeSync4BlockProducers,
90 vrf_correct_ledgers::MultiNodeVrfGetCorrectLedgers,
91 vrf_correct_slots::MultiNodeVrfGetCorrectSlots,
92 vrf_epoch_bounds_correct_ledgers::MultiNodeVrfEpochBoundsCorrectLedger,
93 vrf_epoch_bounds_evaluation::MultiNodeVrfEpochBoundsEvaluation,
94 },
95 p2p::{
96 basic_connection_handling::{
97 AllNodesConnectionsAreSymmetric, MaxNumberOfPeersIncoming, MaxNumberOfPeersIs1,
98 SeedConnectionsAreSymmetric, SimultaneousConnections,
99 },
100 basic_incoming_connections::{AcceptIncomingConnection, AcceptMultipleIncomingConnections},
101 basic_outgoing_connections::{
102 ConnectToInitialPeers, ConnectToInitialPeersBecomeReady,
103 ConnectToUnavailableInitialPeers, DontConnectToInitialPeerWithSameId,
104 DontConnectToNodeWithSameId, DontConnectToSelfInitialPeer,
105 MakeMultipleOutgoingConnections, MakeOutgoingConnection,
106 },
107 kademlia::KademliaBootstrap,
108 pubsub::P2pReceiveMessage,
109 signaling::P2pSignaling,
110 },
111 record_replay::{
112 block_production::RecordReplayBlockProduction, bootstrap::RecordReplayBootstrap,
113 },
114 simulation::{small::SimulationSmall, small_forever_real_time::SimulationSmallForeverRealTime},
115 solo_node::{
116 basic_connectivity_accept_incoming::SoloNodeBasicConnectivityAcceptIncoming,
117 basic_connectivity_initial_joining::SoloNodeBasicConnectivityInitialJoining,
118 bootstrap::SoloNodeBootstrap, sync_root_snarked_ledger::SoloNodeSyncRootSnarkedLedger,
119 sync_to_genesis::SoloNodeSyncToGenesis,
120 sync_to_genesis_custom::SoloNodeSyncToGenesisCustom,
121 },
122};
123
124#[derive(EnumIter, EnumString, IntoStaticStr, derive_more::From, Clone, Copy)]
125#[strum(serialize_all = "kebab-case")]
126pub enum Scenarios {
127 SoloNodeSyncToGenesis(SoloNodeSyncToGenesis),
128 SoloNodeBootstrap(SoloNodeBootstrap),
129 SoloNodeSyncToGenesisCustom(SoloNodeSyncToGenesisCustom),
130 SoloNodeSyncRootSnarkedLedger(SoloNodeSyncRootSnarkedLedger),
131 SoloNodeBasicConnectivityInitialJoining(SoloNodeBasicConnectivityInitialJoining),
132 SoloNodeBasicConnectivityAcceptIncoming(SoloNodeBasicConnectivityAcceptIncoming),
133 MultiNodeSync4BlockProducers(MultiNodeSync4BlockProducers),
134 MultiNodeVrfGetCorrectLedgers(MultiNodeVrfGetCorrectLedgers),
135 MultiNodeVrfGetCorrectSlots(MultiNodeVrfGetCorrectSlots),
136 MultiNodeVrfEpochBoundsEvaluation(MultiNodeVrfEpochBoundsEvaluation),
137 MultiNodeVrfEpochBoundsCorrectLedger(MultiNodeVrfEpochBoundsCorrectLedger),
138 MultiNodeBasicConnectivityInitialJoining(MultiNodeBasicConnectivityInitialJoining),
139 MultiNodeBasicConnectivityPeerDiscovery(MultiNodeBasicConnectivityPeerDiscovery),
140 SimulationSmall(SimulationSmall),
141 SimulationSmallForeverRealTime(SimulationSmallForeverRealTime),
142 P2pReceiveMessage(P2pReceiveMessage),
143 P2pSignaling(P2pSignaling),
144 P2pConnectionDiscoveryRustNodeAsSeed(P2pConnectionDiscoveryRustNodeAsSeed),
145 MultiNodePubsubPropagateBlock(MultiNodePubsubPropagateBlock),
146 RecordReplayBootstrap(RecordReplayBootstrap),
147 RecordReplayBlockProduction(RecordReplayBlockProduction),
148
149 RustToOCaml(RustToOCaml),
150 OCamlToRust(OCamlToRust),
151 OCamlToRustViaSeed(OCamlToRustViaSeed),
152 RustToOCamlViaSeed(RustToOCamlViaSeed),
153 KademliaBootstrap(KademliaBootstrap),
154 AcceptIncomingConnection(AcceptIncomingConnection),
155 MakeOutgoingConnection(MakeOutgoingConnection),
156 AcceptMultipleIncomingConnections(AcceptMultipleIncomingConnections),
157 MakeMultipleOutgoingConnections(MakeMultipleOutgoingConnections),
158 DontConnectToNodeWithSameId(DontConnectToNodeWithSameId),
159 DontConnectToInitialPeerWithSameId(DontConnectToInitialPeerWithSameId),
160 DontConnectToSelfInitialPeer(DontConnectToSelfInitialPeer),
161 SimultaneousConnections(SimultaneousConnections),
162 ConnectToInitialPeers(ConnectToInitialPeers),
163 ConnectToUnavailableInitialPeers(ConnectToUnavailableInitialPeers),
164 AllNodesConnectionsAreSymmetric(AllNodesConnectionsAreSymmetric),
165 ConnectToInitialPeersBecomeReady(ConnectToInitialPeersBecomeReady),
166 SeedConnectionsAreSymmetric(SeedConnectionsAreSymmetric),
167 MaxNumberOfPeersIncoming(MaxNumberOfPeersIncoming),
168 MaxNumberOfPeersIs1(MaxNumberOfPeersIs1),
169}
170
171impl Scenarios {
172 pub fn iter() -> impl IntoIterator<Item = Scenarios> {
174 <Self as strum::IntoEnumIterator>::iter().filter(|s| !s.skip())
175 }
176
177 pub fn find_by_name(name: &str) -> Option<Self> {
178 <Self as strum::IntoEnumIterator>::iter().find(|v| v.to_str() == name)
179 }
180
181 fn skip(&self) -> bool {
182 match self {
183 Self::SoloNodeSyncToGenesis(_) => true,
184 Self::SoloNodeSyncToGenesisCustom(_) => true,
185 Self::SoloNodeBasicConnectivityAcceptIncoming(_) => cfg!(feature = "p2p-webrtc"),
186 Self::MultiNodeBasicConnectivityPeerDiscovery(_) => cfg!(feature = "p2p-webrtc"),
187 Self::SimulationSmall(_) => true,
188 Self::SimulationSmallForeverRealTime(_) => true,
189 Self::MultiNodePubsubPropagateBlock(_) => true, Self::P2pSignaling(_) => !cfg!(feature = "p2p-webrtc"),
191 _ => false,
192 }
193 }
194
195 pub fn id(self) -> ScenarioId {
196 self.into()
197 }
198
199 pub fn to_str(self) -> &'static str {
200 self.into()
201 }
202
203 pub fn parent(self) -> Option<Self> {
204 match self {
205 Self::MultiNodeSync4BlockProducers(_) => Some(SoloNodeSyncToGenesis.into()),
206 Self::MultiNodeVrfGetCorrectLedgers(_) => Some(SoloNodeSyncToGenesisCustom.into()),
207 Self::MultiNodeVrfGetCorrectSlots(_) => Some(SoloNodeSyncToGenesisCustom.into()),
208 Self::MultiNodeVrfEpochBoundsEvaluation(_) => Some(SoloNodeSyncToGenesisCustom.into()),
209 Self::MultiNodeVrfEpochBoundsCorrectLedger(_) => {
210 Some(SoloNodeSyncToGenesisCustom.into())
211 }
212 _ => None,
213 }
214 }
215
216 pub fn parent_id(self) -> Option<ScenarioId> {
217 self.parent().map(Self::id)
218 }
219
220 pub fn description(self) -> &'static str {
221 use documented::Documented;
222 match self {
223 Self::SoloNodeSyncToGenesis(_) => SoloNodeSyncToGenesis::DOCS,
224 Self::SoloNodeBootstrap(_) => SoloNodeBootstrap::DOCS,
225 Self::SoloNodeSyncToGenesisCustom(_) => SoloNodeSyncToGenesis::DOCS,
226 Self::SoloNodeSyncRootSnarkedLedger(_) => SoloNodeSyncRootSnarkedLedger::DOCS,
227 Self::SoloNodeBasicConnectivityInitialJoining(_) => {
228 SoloNodeBasicConnectivityInitialJoining::DOCS
229 }
230 Self::SoloNodeBasicConnectivityAcceptIncoming(_) => {
231 SoloNodeBasicConnectivityAcceptIncoming::DOCS
232 }
233 Self::MultiNodeSync4BlockProducers(_) => MultiNodeSync4BlockProducers::DOCS,
234 Self::MultiNodeVrfGetCorrectLedgers(_) => MultiNodeVrfGetCorrectLedgers::DOCS,
235 Self::MultiNodeVrfGetCorrectSlots(_) => MultiNodeVrfGetCorrectSlots::DOCS,
236 Self::MultiNodeVrfEpochBoundsEvaluation(_) => MultiNodeVrfEpochBoundsEvaluation::DOCS,
237 Self::MultiNodeVrfEpochBoundsCorrectLedger(_) => {
238 MultiNodeVrfEpochBoundsCorrectLedger::DOCS
239 }
240 Self::MultiNodeBasicConnectivityInitialJoining(_) => {
241 MultiNodeBasicConnectivityInitialJoining::DOCS
242 }
243 Self::MultiNodeBasicConnectivityPeerDiscovery(_) => {
244 MultiNodeBasicConnectivityPeerDiscovery::DOCS
245 }
246 Self::SimulationSmall(_) => SimulationSmall::DOCS,
247 Self::SimulationSmallForeverRealTime(_) => SimulationSmallForeverRealTime::DOCS,
248 Self::P2pReceiveMessage(_) => P2pReceiveMessage::DOCS,
249 Self::P2pSignaling(_) => P2pSignaling::DOCS,
250 Self::P2pConnectionDiscoveryRustNodeAsSeed(_) => {
251 P2pConnectionDiscoveryRustNodeAsSeed::DOCS
252 }
253 Self::MultiNodePubsubPropagateBlock(_) => MultiNodePubsubPropagateBlock::DOCS,
254 Self::RecordReplayBootstrap(_) => RecordReplayBootstrap::DOCS,
255 Self::RecordReplayBlockProduction(_) => RecordReplayBlockProduction::DOCS,
256
257 Self::RustToOCaml(_) => RustToOCaml::DOCS,
258 Self::OCamlToRust(_) => OCamlToRust::DOCS,
259 Self::OCamlToRustViaSeed(_) => OCamlToRustViaSeed::DOCS,
260 Self::RustToOCamlViaSeed(_) => RustToOCamlViaSeed::DOCS,
261 Self::KademliaBootstrap(_) => KademliaBootstrap::DOCS,
262 Self::AcceptIncomingConnection(_) => AcceptIncomingConnection::DOCS,
263 Self::MakeOutgoingConnection(_) => MakeOutgoingConnection::DOCS,
264 Self::AcceptMultipleIncomingConnections(_) => AcceptMultipleIncomingConnections::DOCS,
265 Self::MakeMultipleOutgoingConnections(_) => MakeMultipleOutgoingConnections::DOCS,
266 Self::DontConnectToNodeWithSameId(_) => DontConnectToNodeWithSameId::DOCS,
267 Self::DontConnectToInitialPeerWithSameId(_) => DontConnectToInitialPeerWithSameId::DOCS,
268 Self::DontConnectToSelfInitialPeer(_) => DontConnectToSelfInitialPeer::DOCS,
269 Self::SimultaneousConnections(_) => SimultaneousConnections::DOCS,
270 Self::ConnectToInitialPeers(_) => ConnectToInitialPeers::DOCS,
271 Self::ConnectToUnavailableInitialPeers(_) => ConnectToUnavailableInitialPeers::DOCS,
272 Self::AllNodesConnectionsAreSymmetric(_) => AllNodesConnectionsAreSymmetric::DOCS,
273 Self::ConnectToInitialPeersBecomeReady(_) => ConnectToInitialPeersBecomeReady::DOCS,
274 Self::SeedConnectionsAreSymmetric(_) => SeedConnectionsAreSymmetric::DOCS,
275 Self::MaxNumberOfPeersIncoming(_) => MaxNumberOfPeersIncoming::DOCS,
276 Self::MaxNumberOfPeersIs1(_) => MaxNumberOfPeersIs1::DOCS,
277 }
278 }
279
280 pub fn default_cluster_config(self) -> Result<ClusterConfig, anyhow::Error> {
281 let config = ClusterConfig::new(None)
282 .map_err(|err| anyhow::anyhow!("failed to create cluster configuration: {err}"))?;
283
284 match self {
285 Self::P2pSignaling(v) => v.default_cluster_config(config),
286 _ => Ok(config),
287 }
288 }
289
290 pub fn blank_scenario(self) -> Scenario {
291 let mut scenario = Scenario::new(self.id(), self.parent_id());
292 scenario.set_description(self.description().to_owned());
293 scenario.info.nodes = Vec::new();
294
295 scenario
296 }
297
298 async fn run<F>(self, cluster: &mut Cluster, add_step: F)
299 where
300 F: Send + FnMut(&ScenarioStep),
301 {
302 let runner = ClusterRunner::new(cluster, add_step);
303 match self {
304 Self::SoloNodeSyncToGenesis(v) => v.run(runner).await,
305 Self::SoloNodeBootstrap(v) => v.run(runner).await,
306 Self::SoloNodeSyncToGenesisCustom(v) => v.run(runner).await,
307 Self::SoloNodeSyncRootSnarkedLedger(v) => v.run(runner).await,
308 Self::SoloNodeBasicConnectivityInitialJoining(v) => v.run(runner).await,
309 Self::SoloNodeBasicConnectivityAcceptIncoming(v) => v.run(runner).await,
310 Self::MultiNodeSync4BlockProducers(v) => v.run(runner).await,
311 Self::MultiNodeVrfGetCorrectLedgers(v) => v.run(runner).await,
312 Self::MultiNodeVrfGetCorrectSlots(v) => v.run(runner).await,
313 Self::MultiNodeVrfEpochBoundsEvaluation(v) => v.run(runner).await,
314 Self::MultiNodeVrfEpochBoundsCorrectLedger(v) => v.run(runner).await,
315 Self::MultiNodeBasicConnectivityInitialJoining(v) => v.run(runner).await,
316 Self::MultiNodeBasicConnectivityPeerDiscovery(v) => v.run(runner).await,
317 Self::SimulationSmall(v) => v.run(runner).await,
318 Self::SimulationSmallForeverRealTime(v) => v.run(runner).await,
319 Self::P2pReceiveMessage(v) => v.run(runner).await,
320 Self::P2pSignaling(v) => v.run(runner).await,
321 Self::P2pConnectionDiscoveryRustNodeAsSeed(v) => v.run(runner).await,
322 Self::MultiNodePubsubPropagateBlock(v) => v.run(runner).await,
323 Self::RecordReplayBootstrap(v) => v.run(runner).await,
324 Self::RecordReplayBlockProduction(v) => v.run(runner).await,
325
326 Self::RustToOCaml(v) => v.run(runner).await,
327 Self::OCamlToRust(v) => v.run(runner).await,
328 Self::OCamlToRustViaSeed(v) => v.run(runner).await,
329 Self::RustToOCamlViaSeed(v) => v.run(runner).await,
330 Self::KademliaBootstrap(v) => v.run(runner).await,
331 Self::AcceptIncomingConnection(v) => v.run(runner).await,
332 Self::MakeOutgoingConnection(v) => v.run(runner).await,
333 Self::AcceptMultipleIncomingConnections(v) => v.run(runner).await,
334 Self::MakeMultipleOutgoingConnections(v) => v.run(runner).await,
335 Self::DontConnectToNodeWithSameId(v) => v.run(runner).await,
336 Self::DontConnectToInitialPeerWithSameId(v) => v.run(runner).await,
337 Self::DontConnectToSelfInitialPeer(v) => v.run(runner).await,
338 Self::SimultaneousConnections(v) => v.run(runner).await,
339 Self::ConnectToInitialPeers(v) => v.run(runner).await,
340 Self::ConnectToUnavailableInitialPeers(v) => v.run(runner).await,
341 Self::AllNodesConnectionsAreSymmetric(v) => v.run(runner).await,
342 Self::ConnectToInitialPeersBecomeReady(v) => v.run(runner).await,
343 Self::SeedConnectionsAreSymmetric(v) => v.run(runner).await,
344 Self::MaxNumberOfPeersIncoming(v) => v.run(runner).await,
345 Self::MaxNumberOfPeersIs1(v) => v.run(runner).await,
346 }
347 }
348
349 pub async fn run_and_save(self, cluster: &mut Cluster) {
350 struct ScenarioSaveOnExit(Scenario);
351
352 impl Drop for ScenarioSaveOnExit {
353 fn drop(&mut self) {
354 let info = self.0.info.clone();
355 let steps = std::mem::take(&mut self.0.steps);
356 let scenario = Scenario { info, steps };
357
358 debug!(system_time(); "saving scenario({}) before exit...", scenario.info.id);
359 if let Err(err) = scenario.save_sync() {
360 warn!(system_time();
361 "failed to save scenario({})! error: {}",
362 scenario.info.id, err
363 );
364 }
365 }
366 }
367
368 debug!(system_time(); "run_and_save: {}", self.to_str());
369 let mut scenario = ScenarioSaveOnExit(self.blank_scenario());
370 self.run(cluster, |step| scenario.0.add_step(step.clone()).unwrap())
371 .await;
372 let _ = scenario;
374 }
375
376 pub async fn run_only(self, cluster: &mut Cluster) {
377 debug!(system_time(); "run_only: {}", self.to_str());
378 self.run(cluster, |_| {}).await
379 }
380
381 async fn build_cluster_and_run_parents(self, config: ClusterConfig) -> Cluster {
382 let mut parents = std::iter::repeat(())
383 .scan(self.parent(), |parent, _| {
384 let cur_parent = parent.take();
385 *parent = cur_parent.and_then(|p| p.parent());
386 cur_parent
387 })
388 .collect::<Vec<_>>();
389
390 let mut cluster = Cluster::new(config);
391 while let Some(scenario) = parents.pop() {
392 scenario.run_only(&mut cluster).await;
393 }
394
395 cluster
396 }
397
398 pub async fn run_and_save_from_scratch(self, config: ClusterConfig) {
399 let mut cluster = self.build_cluster_and_run_parents(config).await;
400 self.run_and_save(&mut cluster).await;
401 }
402
403 pub async fn run_only_from_scratch(self, config: ClusterConfig) {
404 let mut cluster = self.build_cluster_and_run_parents(config).await;
405 self.run_only(&mut cluster).await;
406 }
407}