diff --git a/sim-cli/src/main.rs b/sim-cli/src/main.rs index a2cf9906..f8686cfc 100644 --- a/sim-cli/src/main.rs +++ b/sim-cli/src/main.rs @@ -45,22 +45,6 @@ fn deserialize_f64_greater_than_zero(x: String) -> Result { } } -/// Deserializes a hexadecimal seed string into a byte array -fn deserialize_fix_seed(hex: String) -> Result<[u8; 32], String> { - if hex.len() != 64 { - return Err("Seed hex must be 64-characters long.".to_string()); - } - - hex::decode(hex) - .map(|byte_vec| { - let mut seed = [0; 32]; - let seed_from_hex = byte_vec.as_slice(); - seed.clone_from_slice(seed_from_hex); - seed - }) - .map_err(|e| e.to_string()) -} - #[derive(Parser)] #[command(version, about)] struct Cli { @@ -90,10 +74,9 @@ struct Cli { /// Do not create an output file containing the simulations results #[clap(long, default_value_t = false)] no_results: bool, - /// Seed to run random activity generator "deterministically", i.e. in the same order. - /// Expected values are hexadecimal-encoded [u8;32] seeds, e.g. hex::encode([42;32]) - #[clap(long, short, value_parser = clap::builder::StringValueParser::new().try_map(deserialize_fix_seed))] - fix_seed: Option<[u8; 32]>, + /// Seed to run random activity generator deterministically. + #[clap(long, short, value_parser = clap::builder::RangedU64ValueParser::::new().range(0..u64::MAX))] + fix_seed: Option, } #[tokio::main] diff --git a/sim-lib/src/lib.rs b/sim-lib/src/lib.rs index 87fb908c..76488228 100644 --- a/sim-lib/src/lib.rs +++ b/sim-lib/src/lib.rs @@ -409,8 +409,8 @@ pub struct Simulation { activity_multiplier: f64, /// Configurations for printing results to CSV. Results are not written if this option is None. write_results: Option, - /// Seed to deterministically run the random activity generator - seed: Option<[u8; 32]>, + /// Seed to deterministically run the random activity generator. + seed: Option, } #[derive(Clone)] @@ -439,7 +439,7 @@ impl Simulation { expected_payment_msat: u64, activity_multiplier: f64, write_results: Option, - seed: Option<[u8; 32]>, + seed: Option, ) -> Self { let (shutdown_trigger, shutdown_listener) = triggered::trigger(); Self { @@ -726,7 +726,7 @@ impl Simulation { async fn activity_executors( &self, - seed: Option<[u8; 32]>, + seed: Option, ) -> Result, SimulationError> { let mut generators = Vec::new(); @@ -761,7 +761,7 @@ impl Simulation { /// that have sufficient capacity to generate payments of our expected payment amount. async fn random_activity_nodes( &self, - seed: Option<[u8; 32]>, + seed: Option, ) -> Result, SimulationError> { // Collect capacity of each node from its view of its own channels. Total capacity is divided by two to // avoid double counting capacity (as each node has a counterparty in the channel). diff --git a/sim-lib/src/random_activity.rs b/sim-lib/src/random_activity.rs index 09bf128d..e2b86303 100644 --- a/sim-lib/src/random_activity.rs +++ b/sim-lib/src/random_activity.rs @@ -1,5 +1,5 @@ use core::fmt; -use rand::{rngs::ThreadRng, CryptoRng, Rng, RngCore, SeedableRng}; +use rand::{RngCore, SeedableRng}; use rand_chacha::ChaCha8Rng; use std::fmt::Display; use thiserror::Error; @@ -29,7 +29,7 @@ pub enum RandomActivityError { pub struct NetworkGraphView { node_picker: WeightedIndex, nodes: Vec<(NodeInfo, u64)>, - seed: Option<[u8; 32]>, + seed: Option, } impl NetworkGraphView { @@ -38,7 +38,7 @@ impl NetworkGraphView { /// send to itself). pub fn new( nodes: Vec<(NodeInfo, u64)>, - seed: Option<[u8; 32]>, + seed: Option, ) -> Result { if nodes.len() < 2 { return Err(RandomActivityError::ValueError( @@ -112,7 +112,7 @@ pub struct RandomPaymentActivity { expected_payment_amt: u64, source_capacity: u64, event_dist: Exp, - seed: Option<[u8; 32]>, + seed: Option, } impl RandomPaymentActivity { @@ -123,7 +123,7 @@ impl RandomPaymentActivity { source_capacity_msat: u64, expected_payment_amt: u64, multiplier: f64, - seed: Option<[u8; 32]>, + seed: Option, ) -> Result { if source_capacity_msat == 0 { return Err(RandomActivityError::ValueError( @@ -208,10 +208,6 @@ fn events_per_month(source_capacity_msat: u64, multiplier: f64, expected_payment (source_capacity_msat as f64 * multiplier) / expected_payment_amt as f64 } -trait SimRng: CryptoRng + RngCore {} -impl SimRng for ChaCha8Rng {} -impl SimRng for ThreadRng {} - impl PaymentGenerator for RandomPaymentActivity { /// Returns the time that the payments should start. This will always be 0 for the RandomPaymentActivity type. fn payment_start(&self) -> Duration { @@ -287,21 +283,19 @@ impl Display for RandomPaymentActivity { } /// Random number generator that takes an optional seed with which deterministic -/// behaviour can be simulated -fn sim_rng(seed: Option<[u8; 32]>) -> impl SimRng { +/// behaviour can be simulated. +fn sim_rng(seed: Option) -> Box { match seed { - Some(seed) => rand_chacha::ChaCha8Rng::from_seed(seed), + Some(seed) => Box::new(ChaCha8Rng::seed_from_u64(seed)), None => { - let mut thread_rng = rand::thread_rng(); - ChaCha8Rng::seed_from_u64(thread_rng.gen::()) + let thread_rng = rand::thread_rng(); + Box::new(thread_rng) }, } } #[cfg(test)] mod tests { - use crate::test_utils::{generate_random_seed, seed_hex}; - mod test_network_graph_view { use ntest::timeout; @@ -313,7 +307,7 @@ mod tests { // Check that we need, at least, two nodes for i in 0..2 { assert!(matches!( - NetworkGraphView::new(create_nodes(i, 42 * (i as u64 + 1)), None), + NetworkGraphView::new(create_nodes(i, 42 * (i as u64 + 1)), Some(u64::MAX)), Err(RandomActivityError::ValueError { .. }) )); } @@ -323,18 +317,18 @@ mod tests { let mut nodes = create_nodes(1, 0); nodes.extend(create_nodes(1, 21)); assert!(matches!( - NetworkGraphView::new(nodes, None), + NetworkGraphView::new(nodes, Some(u64::MAX)), Err(RandomActivityError::InsufficientCapacity { .. }) )); // All of them are 0 assert!(matches!( - NetworkGraphView::new(create_nodes(2, 0), None), + NetworkGraphView::new(create_nodes(2, 0), Some(u64::MAX)), Err(RandomActivityError::InsufficientCapacity { .. }) )); // Otherwise we should be good - assert!(NetworkGraphView::new(create_nodes(2, 42), None).is_ok()); + assert!(NetworkGraphView::new(create_nodes(2, 42), Some(u64::MAX)).is_ok()); } #[test] @@ -364,7 +358,7 @@ mod tests { nodes.extend(create_nodes(big_node_count, big_node_capacity)); let big_node = nodes.last().unwrap().0.pubkey; - let view = NetworkGraphView::new(nodes, None).unwrap(); + let view = NetworkGraphView::new(nodes, Some(u64::MAX)).unwrap(); for _ in 0..10 { view.choose_destination(big_node); @@ -386,7 +380,7 @@ mod tests { 2 * expected_payment, expected_payment, 1.0, - Some([42; 32]) + Some(u64::MAX) ) .is_ok()); assert!(matches!( @@ -394,7 +388,7 @@ mod tests { 2 * expected_payment, expected_payment + 1, 1.0, - Some([42; 32]) + Some(u64::MAX) ), Err(RandomActivityError::InsufficientCapacity { .. }) )); @@ -406,7 +400,7 @@ mod tests { 0, get_random_int(1, 10), get_random_int(1, 10) as f64, - Some([42; 32]) + Some(u64::MAX) ), Err(RandomActivityError::ValueError { .. }) )); @@ -415,7 +409,7 @@ mod tests { get_random_int(1, 10), 0, get_random_int(1, 10) as f64, - Some([42; 32]) + Some(u64::MAX) ), Err(RandomActivityError::ValueError { .. }) )); @@ -424,7 +418,7 @@ mod tests { get_random_int(1, 10), get_random_int(1, 10), 0.0, - Some([42; 32]) + Some(u64::MAX) ), Err(RandomActivityError::ValueError { .. }) )); @@ -459,7 +453,7 @@ mod tests { let expected_payment = get_random_int(1, 100); let source_capacity = 2 * expected_payment; let pag = - RandomPaymentActivity::new(source_capacity, expected_payment, 1.0, Some([42; 32])) + RandomPaymentActivity::new(source_capacity, expected_payment, 1.0, Some(u64::MAX)) .unwrap(); // Wrong cases @@ -486,15 +480,4 @@ mod tests { )); } } - - #[test] - fn random_seed_generation() { - let seed = generate_random_seed(); - let seed_hex = seed_hex(seed); - let hex_decode = hex::decode(seed_hex).expect("Hex decoding failed"); - - for (i, e) in hex_decode.into_iter().enumerate() { - assert_eq!(e, seed[i]); - } - } }