//! Simulation action types for testing. use commonware_consensus::types::Round; use commonware_cryptography::PublicKey; use commonware_p2p::simulated::Link; use commonware_runtime::deterministic; use std::{ops::RangeInclusive, time::Duration}; /// Crash strategy for a simulation run. #[derive(Clone)] pub enum Crash { /// Periodically crash random validators and restart them after /// a downtime period. Random { /// How often to trigger crashes. frequency: Duration, /// How long crashed validators stay offline. downtime: Duration, /// Number of validators to crash each time. count: usize, }, /// Delay specific validators until the given round is observed. DelayRound { /// Validators to delay. participants: Vec

, /// Round to wait for before starting delayed validators. round: Round, }, /// Crash a validator when its application enters a processed-height window, /// then restart it after the configured downtime. ProcessedHeight { /// Validator to crash. participant: P, /// Processed-height window in which the crash must occur. heights: RangeInclusive, /// How long the validator remains offline. downtime: Duration, }, /// Time-indexed action schedule for precise control. Schedule(Schedule

), } /// A time-ordered sequence of simulation actions. #[derive(Clone)] pub struct Schedule { /// Time-indexed actions. pub events: Vec<(Duration, Action

)>, } impl Schedule

{ /// Create an empty schedule. pub const fn new() -> Self { Self { events: vec![] } } /// Add an action at the given simulation time. /// /// Panics if `time` is earlier than the most recently added event. pub fn at(mut self, time: Duration, action: Action

) -> Self { if let Some((last_time, _)) = self.events.last() { assert!( time >= *last_time, "schedule events must be added in nondecreasing time order" ); } self.events.push((time, action)); self } } impl Default for Schedule

{ fn default() -> Self { Self::new() } } /// A single simulation action to apply at a specific time. #[derive(Clone)] pub enum Action { /// Update deterministic storage fault injection. SetStorageFault(deterministic::FaultConfig), /// Reset all directed links, restoring full connectivity with the given link. Heal(Link), /// Update a specific directed link by removing and re-adding it. UpdateLink { /// Source peer. from: P, /// Destination peer. to: P, /// New link configuration. link: Link, }, /// Crash a specific validator. Crash(P), /// Restart a previously crashed validator. Restart(P), } #[cfg(test)] mod tests { use super::{Action, Schedule}; use commonware_cryptography::{Signer as _, ed25519}; use std::time::Duration; #[test] #[should_panic(expected = "schedule events must be added in nondecreasing time order")] fn schedule_rejects_out_of_order_events() { let pk = ed25519::PrivateKey::from_seed(0).public_key(); let _ = Schedule::new() .at(Duration::from_secs(5), Action::Crash(pk.clone())) .at(Duration::from_secs(2), Action::Restart(pk)); } }