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