diff --git a/simulations/Cargo.toml b/simulations/Cargo.toml index bb56b945..39005617 100644 --- a/simulations/Cargo.toml +++ b/simulations/Cargo.toml @@ -3,15 +3,12 @@ name = "simulations" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2", features = ["js"] } [dependencies] rand = { version = "0.8", features = ["small_rng"] } serde = { version = "1.0", features = ["derive", "rc"] } -serde_with = "2.3" +serde_with = "2" serde_json = "1.0" - clap = { version = "4", features = ["derive"] } - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2", features = ["js"] } diff --git a/simulations/src/bin/app.rs b/simulations/src/bin/app.rs index 0b53f879..bbcd19f8 100644 --- a/simulations/src/bin/app.rs +++ b/simulations/src/bin/app.rs @@ -103,7 +103,7 @@ pub fn main() -> Result<(), Box> { >(std::fs::File::open(config)?)?; #[allow(clippy::unit_arg)] let overlay = FlatOverlay::new(cfg.overlay_settings); - let node_ids = (0..cfg.node_count).collect::>(); + let node_ids = (0..cfg.node_count).map(From::from).collect::>(); let mut rng = thread_rng(); let layout = overlay.layout(&node_ids, &mut rng); let leaders = overlay.leaders(&node_ids, 1, &mut rng).collect(); diff --git a/simulations/src/node/carnot.rs b/simulations/src/node/carnot.rs index 01963c34..2c4fa393 100644 --- a/simulations/src/node/carnot.rs +++ b/simulations/src/node/carnot.rs @@ -30,6 +30,7 @@ fn leader_receive_proposal( .iter() .filter_map(|&sender| network.send_message_cost(rng, sender, node)) .max() + .map(From::from) .unwrap() } @@ -46,6 +47,7 @@ fn receive_proposal( .filter_map(|&sender| network.send_message_cost(rng, sender, node)) .max() .unwrap() + .into() } fn receive_commit( @@ -66,6 +68,7 @@ fn receive_commit( }) .max() .unwrap() + .into() } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] @@ -236,7 +239,7 @@ impl Node for CarnotNode { Self { id, rng, settings } } - fn id(&self) -> usize { + fn id(&self) -> NodeId { self.id } @@ -256,7 +259,7 @@ impl Node for CarnotNode { Some(parent) => { solver(&mut self.rng, self.id, &parent, &self.settings.network) } - None => Duration::ZERO, + None => Duration::ZERO.into(), } } ChildCommitteeReceiverSolver(solver) => solver( @@ -286,9 +289,9 @@ impl Node for CarnotNode { } }; - overall_steps_time += step_time + overall_steps_time += step_time.0 } - overall_steps_time + overall_steps_time.into() } } diff --git a/simulations/src/node/mod.rs b/simulations/src/node/mod.rs index 67a058ed..128a7aeb 100644 --- a/simulations/src/node/mod.rs +++ b/simulations/src/node/mod.rs @@ -1,16 +1,120 @@ pub mod carnot; // std -use std::time::Duration; +use std::{ + ops::{Deref, DerefMut}, + time::Duration, +}; // crates use rand::Rng; +use serde::{Deserialize, Serialize}; use self::carnot::CarnotStep; // internal -pub type NodeId = usize; -pub type CommitteeId = usize; -pub type StepTime = Duration; +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[serde(transparent)] +pub struct NodeId(usize); + +impl NodeId { + #[inline] + pub const fn new(id: usize) -> Self { + Self(id) + } + + #[inline] + pub const fn inner(&self) -> usize { + self.0 + } +} + +impl From for NodeId { + fn from(id: usize) -> Self { + Self(id) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[serde(transparent)] +pub struct CommitteeId(usize); + +impl CommitteeId { + #[inline] + pub const fn new(id: usize) -> Self { + Self(id) + } +} + +impl From for CommitteeId { + fn from(id: usize) -> Self { + Self(id) + } +} + +#[serde_with::serde_as] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[serde(transparent)] +pub struct StepTime(#[serde_as(as = "serde_with::DurationMilliSeconds")] Duration); + +impl From for StepTime { + fn from(duration: Duration) -> Self { + Self(duration) + } +} + +impl StepTime { + #[inline] + pub const fn new(duration: Duration) -> Self { + Self(duration) + } + + #[inline] + pub const fn into_inner(&self) -> Duration { + self.0 + } + + #[inline] + pub const fn from_millis(millis: u64) -> Self { + Self(Duration::from_millis(millis)) + } + + #[inline] + pub const fn from_secs(secs: u64) -> Self { + Self(Duration::from_secs(secs)) + } +} + +impl Deref for StepTime { + type Target = Duration; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for StepTime { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl core::iter::Sum for StepTime { + fn sum>(iter: I) -> Self { + Self(iter.into_iter().map(|s| s.0).sum()) + } +} + +impl core::iter::Sum for StepTime { + fn sum>(iter: I) -> Self { + Self(iter.into_iter().sum()) + } +} + +impl core::iter::Sum for Duration { + fn sum>(iter: I) -> Self { + iter.into_iter().map(|s| s.0).sum() + } +} pub trait Node: Clone { type Settings; diff --git a/simulations/src/overlay/flat.rs b/simulations/src/overlay/flat.rs index 36478cdd..a9948084 100644 --- a/simulations/src/overlay/flat.rs +++ b/simulations/src/overlay/flat.rs @@ -18,7 +18,7 @@ impl Overlay for FlatOverlay { } fn nodes(&self) -> Vec { - (0..10).collect() + (0..10).map(NodeId::from).collect() } fn leaders( @@ -33,16 +33,16 @@ impl Overlay for FlatOverlay { fn layout(&self, nodes: &[NodeId], _rng: &mut R) -> Layout { let committees = std::iter::once(( - 0, + 0.into(), Committee { nodes: nodes.iter().copied().collect(), role: CarnotRole::Leader, }, )) .collect(); - let parent = std::iter::once((0, 0)).collect(); - let children = std::iter::once((0, vec![0])).collect(); - let layers = std::iter::once((0, vec![0])).collect(); + let parent = std::iter::once((0.into(), 0.into())).collect(); + let children = std::iter::once((0.into(), vec![0.into()])).collect(); + let layers = std::iter::once((0.into(), vec![0.into()])).collect(); Layout::new(committees, parent, children, layers) } } diff --git a/simulations/src/overlay/mod.rs b/simulations/src/overlay/mod.rs index 3b0c09d9..7d40418a 100644 --- a/simulations/src/overlay/mod.rs +++ b/simulations/src/overlay/mod.rs @@ -29,7 +29,7 @@ pub struct Layout { pub from_committee: HashMap, pub parent: HashMap, pub children: HashMap>, - pub layers: HashMap>, + pub layers: HashMap>, } impl Layout { @@ -37,7 +37,7 @@ impl Layout { committees: HashMap, parent: HashMap, children: HashMap>, - layers: HashMap>, + layers: HashMap>, ) -> Self { let from_committee = committees .iter() diff --git a/simulations/src/overlay/tree.rs b/simulations/src/overlay/tree.rs index 88c79da3..e660121a 100644 --- a/simulations/src/overlay/tree.rs +++ b/simulations/src/overlay/tree.rs @@ -6,7 +6,7 @@ use rand::seq::IteratorRandom; use super::{Committee, Layout, Overlay}; use crate::node::{ carnot::{CarnotNode, CarnotRole}, - NodeId, + CommitteeId, NodeId, }; pub enum TreeType { @@ -57,14 +57,17 @@ impl TreeOverlay { // Check for leaf nodes. if right_child_id <= properties.committee_count { - children.insert(committee_id, vec![left_child_id, right_child_id]); + children.insert( + committee_id.into(), + vec![left_child_id.into(), right_child_id.into()], + ); has_children = true; } // Root node has no parent. if committee_id > 0 { let parent_id = get_parent_id(committee_id); - parents.insert(committee_id, parent_id); + parents.insert(committee_id.into(), parent_id.into()); } let role = match (committee_id, has_children) { @@ -78,12 +81,12 @@ impl TreeOverlay { role, }; - committees.insert(committee_id, committee); + committees.insert(committee_id.into(), committee); layers .entry(get_layer(committee_id)) .or_insert_with(Vec::new) - .push(committee_id); + .push(committee_id.into()); } Layout::new(committees, parents, children, layers) @@ -99,7 +102,7 @@ impl Overlay for TreeOverlay { fn nodes(&self) -> Vec { let properties = get_tree_properties(&self.settings); - (0..properties.node_count).collect() + (0..properties.node_count).map(From::from).collect() } fn leaders( @@ -139,8 +142,8 @@ fn get_parent_id(id: usize) -> usize { } /// Get a layer in a tree of a given committee id. -fn get_layer(id: usize) -> usize { - (id as f64 + 1.).log2().floor() as usize +fn get_layer(id: usize) -> CommitteeId { + CommitteeId::new((id as f64 + 1.).log2().floor() as usize) } #[cfg(test)] @@ -173,24 +176,33 @@ mod tests { }); let nodes = overlay.nodes(); let layout = overlay.layout(&nodes, &mut rng); - assert_eq!(layout.children[&0], vec![1, 2]); - assert_eq!(layout.parent[&1], 0); - assert_eq!(layout.parent[&2], 0); + assert_eq!( + layout.children[&CommitteeId::new(0)], + vec![1.into(), 2.into()] + ); + assert_eq!(layout.parent[&CommitteeId::new(1)], 0.into()); + assert_eq!(layout.parent[&CommitteeId::new(2)], 0.into()); - assert_eq!(layout.children[&1], vec![3, 4]); - assert_eq!(layout.children[&2], vec![5, 6]); + assert_eq!( + layout.children[&CommitteeId::new(1)], + vec![3.into(), 4.into()] + ); + assert_eq!( + layout.children[&CommitteeId::new(2)], + vec![5.into(), 6.into()] + ); - assert_eq!(layout.parent[&3], 1); - assert_eq!(layout.children.get(&3), None); + assert_eq!(layout.parent[&CommitteeId::new(3)], 1.into()); + assert_eq!(layout.children.get(&CommitteeId::new(3)), None); - assert_eq!(layout.parent[&4], 1); - assert_eq!(layout.children.get(&4), None); + assert_eq!(layout.parent[&CommitteeId::new(4)], 1.into()); + assert_eq!(layout.children.get(&CommitteeId::new(4)), None); - assert_eq!(layout.parent[&5], 2); - assert_eq!(layout.children.get(&5), None); + assert_eq!(layout.parent[&CommitteeId::new(5)], 2.into()); + assert_eq!(layout.children.get(&CommitteeId::new(5)), None); - assert_eq!(layout.parent[&6], 2); - assert_eq!(layout.children.get(&6), None); + assert_eq!(layout.parent[&CommitteeId::new(6)], 2.into()); + assert_eq!(layout.children.get(&CommitteeId::new(6)), None); } #[test] @@ -207,15 +219,15 @@ mod tests { // 2^h - 1 assert_eq!(layout.committees.len(), 1023); - let root_nodes = &layout.committees[&0].nodes; + let root_nodes = &layout.committees[&CommitteeId::new(0)].nodes; assert_eq!(root_nodes.len(), 10); - assert_eq!(root_nodes.first(), Some(&0)); - assert_eq!(root_nodes.last(), Some(&9)); + assert_eq!(root_nodes.first(), Some(&NodeId::new(0))); + assert_eq!(root_nodes.last(), Some(&NodeId::new(9))); - let last_nodes = &layout.committees[&1022].nodes; + let last_nodes = &layout.committees[&CommitteeId::new(1022)].nodes; assert_eq!(last_nodes.len(), 10); - assert_eq!(last_nodes.first(), Some(&10220)); - assert_eq!(last_nodes.last(), Some(&10229)); + assert_eq!(last_nodes.first(), Some(&NodeId::new(10220))); + assert_eq!(last_nodes.last(), Some(&NodeId::new(10229))); } #[test] @@ -229,11 +241,26 @@ mod tests { let nodes = overlay.nodes(); let layout = overlay.layout(&nodes, &mut rng); - assert_eq!(layout.committees[&0].role, CarnotRole::Root); - assert_eq!(layout.committees[&1].role, CarnotRole::Intermediate); - assert_eq!(layout.committees[&2].role, CarnotRole::Intermediate); - assert_eq!(layout.committees[&3].role, CarnotRole::Leaf); - assert_eq!(layout.committees[&6].role, CarnotRole::Leaf); + assert_eq!( + layout.committees[&CommitteeId::new(0)].role, + CarnotRole::Root + ); + assert_eq!( + layout.committees[&CommitteeId::new(1)].role, + CarnotRole::Intermediate + ); + assert_eq!( + layout.committees[&CommitteeId::new(2)].role, + CarnotRole::Intermediate + ); + assert_eq!( + layout.committees[&CommitteeId::new(3)].role, + CarnotRole::Leaf + ); + assert_eq!( + layout.committees[&CommitteeId::new(6)].role, + CarnotRole::Leaf + ); } #[test] @@ -246,8 +273,14 @@ mod tests { }); let nodes = overlay.nodes(); let layout = overlay.layout(&nodes, &mut rng); - assert_eq!(layout.layers[&0], vec![0]); - assert_eq!(layout.layers[&1], vec![1, 2]); - assert_eq!(layout.layers[&2], vec![3, 4, 5, 6]); + assert_eq!(layout.layers[&CommitteeId::new(0)], vec![0.into()]); + assert_eq!( + layout.layers[&CommitteeId::new(1)], + vec![1.into(), 2.into()] + ); + assert_eq!( + layout.layers[&CommitteeId::new(2)], + vec![3.into(), 4.into(), 5.into(), 6.into()] + ); } } diff --git a/simulations/src/runner.rs b/simulations/src/runner.rs index 8f50b0c2..7938539b 100644 --- a/simulations/src/runner.rs +++ b/simulations/src/runner.rs @@ -2,7 +2,7 @@ use crate::node::carnot::{ CarnotRole, CARNOT_INTERMEDIATE_STEPS, CARNOT_LEADER_STEPS, CARNOT_LEAF_STEPS, CARNOT_ROOT_STEPS, CARNOT_UNKNOWN_MESSAGE_RECEIVED_STEPS, }; -use crate::node::{Node, NodeId, StepTime}; +use crate::node::{CommitteeId, Node, NodeId, StepTime}; use crate::overlay::Layout; use rand::Rng; use std::collections::HashMap; @@ -93,14 +93,17 @@ where } } -fn get_layer_nodes(layer_committees: &[NodeId], layout: &Layout) -> Vec<(NodeId, NodeId)> { +fn get_layer_nodes( + layer_committees: &[CommitteeId], + layout: &Layout, +) -> Vec<(CommitteeId, NodeId)> { layer_committees .iter() .flat_map(|committee_id| get_committee_nodes(committee_id, layout)) .collect() } -fn get_committee_nodes(committee: &NodeId, layout: &Layout) -> Vec<(NodeId, NodeId)> { +fn get_committee_nodes(committee: &CommitteeId, layout: &Layout) -> Vec<(CommitteeId, NodeId)> { layout.committees[committee] .nodes .clone() @@ -145,7 +148,6 @@ mod test { NetworkBehaviour::new(Duration::from_millis(100), 0.0), )) .collect(); - let node_settings: CarnotNodeSettings = CarnotNodeSettings { steps_costs: CARNOT_STEPS_COSTS.iter().cloned().collect(), network: Network::new(RegionsData::new(regions, network_behaviour)), @@ -344,11 +346,15 @@ mod test { steps_costs: CARNOT_STEPS_COSTS.iter().cloned().collect(), network: Network::new(RegionsData::new(regions, network_behaviour)), layout: overlay.layout(&node_ids, &mut rng), - leaders: leaders.clone(), + leaders: leaders.clone().into_iter().map(From::from).collect(), }; - let mut runner = - ConsensusRunner::::new(&mut rng, layout, leaders, Rc::new(node_settings)); + let mut runner = ConsensusRunner::::new( + &mut rng, + layout, + leaders.into_iter().map(From::from).collect(), + Rc::new(node_settings), + ); assert_eq!( Duration::from_millis(7800), @@ -402,11 +408,15 @@ mod test { steps_costs: CARNOT_STEPS_COSTS.iter().cloned().collect(), network: Network::new(RegionsData::new(regions, network_behaviour)), layout: overlay.layout(&node_ids, &mut rng), - leaders: leaders.clone(), + leaders: leaders.clone().into_iter().map(From::from).collect(), }; - let mut runner = - ConsensusRunner::::new(&mut rng, layout, leaders, Rc::new(node_settings)); + let mut runner = ConsensusRunner::::new( + &mut rng, + layout, + leaders.into_iter().map(From::from).collect(), + Rc::new(node_settings), + ); assert_eq!( Duration::from_millis(7800),