diff --git a/nomos-services/http/src/backends/axum.rs b/nomos-services/http/src/backends/axum.rs
index 4b103c67..0d473f65 100644
--- a/nomos-services/http/src/backends/axum.rs
+++ b/nomos-services/http/src/backends/axum.rs
@@ -113,7 +113,7 @@ impl HttpBackend for AxumBackend {
let router = self.router.clone();
let service = tower::service_fn(move |request: Request
| {
let mut router = router.lock().clone();
- async move { router.call(request).await }
+ router.call(request)
});
axum::Server::bind(&self.config.address)
@@ -125,8 +125,8 @@ impl HttpBackend for AxumBackend {
impl AxumBackend {
fn add_data_route(&self, method: HttpMethod, path: &str, req_stream: Sender) {
- let handle_data = |Query(query): Query>, payload: Option| async move {
- handle_req(req_stream, query, payload).await
+ let handle_data = |Query(query): Query>, payload: Option| {
+ handle_req(req_stream, query, payload)
};
let handler = match method {
diff --git a/simulations/Cargo.toml b/simulations/Cargo.toml
index 7b67530a..ba058de7 100644
--- a/simulations/Cargo.toml
+++ b/simulations/Cargo.toml
@@ -7,9 +7,11 @@ edition = "2021"
[dependencies]
rand = { version = "0.8", features = ["small_rng"] }
-serde = { version = "1.0", features = ["derive"] }
+serde = { version = "1.0", features = ["derive", "rc"] }
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 8df0541b..61569104 100644
--- a/simulations/src/bin/app.rs
+++ b/simulations/src/bin/app.rs
@@ -1,3 +1,146 @@
-pub fn main() {
- println!("WIP");
+use std::{path::PathBuf, str::FromStr};
+
+use clap::Parser;
+use rand::thread_rng;
+use serde::{Deserialize, Serialize};
+use simulations::{
+ config::Config,
+ node::{
+ carnot::{CarnotNode, CarnotStep},
+ Node, StepTime,
+ },
+ overlay::{flat::FlatOverlay, Overlay},
+ runner::{ConsensusRunner, LayoutNodes},
+};
+
+/// Simple program to greet a person
+#[derive(Parser, Debug)]
+#[command(author, version, about, long_about = None)]
+struct Args {
+ /// Path for a yaml-encoded network config file
+ config: std::path::PathBuf,
+ #[arg(long, default_value_t = OverlayType::Flat)]
+ overlay_type: OverlayType,
+ #[arg(long, default_value_t = NodeType::Carnot)]
+ node_type: NodeType,
+ #[arg(short, long, default_value_t = OutputType::StdOut)]
+ output: OutputType,
+}
+
+#[derive(clap::ValueEnum, Debug, Copy, Clone, Serialize, Deserialize)]
+enum OverlayType {
+ Flat,
+}
+
+impl core::fmt::Display for OverlayType {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ match self {
+ Self::Flat => write!(f, "flat"),
+ }
+ }
+}
+
+#[derive(clap::ValueEnum, Debug, Copy, Clone, Serialize, Deserialize)]
+enum NodeType {
+ Carnot,
+}
+
+impl core::fmt::Display for NodeType {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ match self {
+ Self::Carnot => write!(f, "carnot"),
+ }
+ }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+enum OutputType {
+ File(PathBuf),
+ StdOut,
+ StdErr,
+}
+
+impl core::fmt::Display for OutputType {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ OutputType::File(path) => write!(f, "{}", path.display()),
+ OutputType::StdOut => write!(f, "stdout"),
+ OutputType::StdErr => write!(f, "stderr"),
+ }
+ }
+}
+
+impl FromStr for OutputType {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result {
+ match s.to_lowercase().as_str() {
+ "stdout" => Ok(Self::StdOut),
+ "stderr" => Ok(Self::StdErr),
+ path => Ok(Self::File(PathBuf::from(path))),
+ }
+ }
+}
+
+pub fn main() -> Result<(), Box> {
+ let Args {
+ config,
+ overlay_type,
+ node_type,
+ output,
+ } = Args::parse();
+
+ let report = match (overlay_type, node_type) {
+ (OverlayType::Flat, NodeType::Carnot) => {
+ let cfg = serde_json::from_reader::<
+ _,
+ Config<
+ ::Settings,
+ ::Settings,
+ CarnotStep,
+ >,
+ >(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 mut rng = thread_rng();
+ let layout = overlay.layout(&node_ids, &mut rng);
+ let leaders = overlay.leaders(&node_ids, 1, &mut rng).collect();
+
+ let carnot_steps: Vec<_> = cfg
+ .steps
+ .iter()
+ .copied()
+ .map(|step| {
+ (
+ LayoutNodes::Leader,
+ step,
+ Box::new(|times: &[StepTime]| *times.iter().max().unwrap())
+ as Box StepTime>,
+ )
+ })
+ .collect();
+
+ let mut runner: simulations::runner::ConsensusRunner =
+ ConsensusRunner::new(&mut rng, layout, leaders, cfg.node_settings);
+ runner.run(&carnot_steps)
+ }
+ };
+
+ let json = serde_json::to_string_pretty(&report)?;
+ match output {
+ OutputType::File(f) => {
+ use std::{fs::OpenOptions, io::Write};
+
+ let mut file = OpenOptions::new()
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(f)?;
+ file.write_all(json.as_bytes())?;
+ }
+ OutputType::StdOut => println!("{json}"),
+ OutputType::StdErr => eprintln!("{json}"),
+ }
+ Ok(())
}
diff --git a/simulations/src/config.rs b/simulations/src/config.rs
new file mode 100644
index 00000000..fa7f74d5
--- /dev/null
+++ b/simulations/src/config.rs
@@ -0,0 +1,18 @@
+use crate::network::regions::Region;
+use crate::node::StepTime;
+use serde::{Deserialize, Serialize};
+use std::collections::HashMap;
+
+#[derive(Serialize, Deserialize)]
+pub struct Config
+where
+ S: core::str::FromStr,
+{
+ pub network_behaviors: HashMap<(Region, Region), StepTime>,
+ pub regions: Vec,
+ pub overlay_settings: O,
+ pub node_settings: N,
+ pub node_count: usize,
+ pub committee_size: usize,
+ pub steps: Vec,
+}
diff --git a/simulations/src/lib.rs b/simulations/src/lib.rs
index bde0e784..f538d575 100644
--- a/simulations/src/lib.rs
+++ b/simulations/src/lib.rs
@@ -1,3 +1,4 @@
+pub mod config;
pub mod network;
pub mod node;
pub mod overlay;
diff --git a/simulations/src/network/behaviour.rs b/simulations/src/network/behaviour.rs
index cae6784a..aa99ca65 100644
--- a/simulations/src/network/behaviour.rs
+++ b/simulations/src/network/behaviour.rs
@@ -5,7 +5,7 @@ use rand::Rng;
use serde::{Deserialize, Serialize};
// internal
-#[derive(Default, Serialize, Deserialize)]
+#[derive(Default, Debug, Serialize, Deserialize)]
pub struct NetworkBehaviour {
pub delay: Duration,
pub drop: f64,
diff --git a/simulations/src/network/mod.rs b/simulations/src/network/mod.rs
index fc781f9b..3f65cd1c 100644
--- a/simulations/src/network/mod.rs
+++ b/simulations/src/network/mod.rs
@@ -8,6 +8,7 @@ use crate::node::NodeId;
pub mod behaviour;
pub mod regions;
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct Network {
pub regions: regions::RegionsData,
}
diff --git a/simulations/src/network/regions.rs b/simulations/src/network/regions.rs
index 83301f80..5f9fc120 100644
--- a/simulations/src/network/regions.rs
+++ b/simulations/src/network/regions.rs
@@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
// internal
use crate::{network::behaviour::NetworkBehaviour, node::NodeId};
-#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum Region {
NorthAmerica,
Europe,
@@ -15,7 +15,7 @@ pub enum Region {
Australia,
}
-#[derive(Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize)]
pub struct RegionsData {
pub regions: HashMap>,
#[serde(skip)]
diff --git a/simulations/src/node/carnot.rs b/simulations/src/node/carnot.rs
index 233bbb55..996b9d3a 100644
--- a/simulations/src/node/carnot.rs
+++ b/simulations/src/node/carnot.rs
@@ -49,7 +49,7 @@ fn receive_commit(
.unwrap()
}
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
pub enum CarnotStep {
ReceiveProposal,
ValidateProposal,
@@ -57,6 +57,20 @@ pub enum CarnotStep {
ValidateVote,
}
+impl core::str::FromStr for CarnotStep {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result {
+ match s.trim().to_lowercase().as_str() {
+ "receiveproposal" => Ok(Self::ReceiveProposal),
+ "validateproposal" => Ok(Self::ValidateProposal),
+ "receivevote" => Ok(Self::ReceiveVote),
+ "validatevote" => Ok(Self::ValidateVote),
+ _ => Err(format!("Unknown step: {s}")),
+ }
+ }
+}
+
#[derive(Clone)]
pub enum CarnotStepSolver {
Plain(StepTime),
@@ -64,8 +78,30 @@ pub enum CarnotStepSolver {
ChildCommitteeReceiverSolver(ChildCommitteeReceiverSolver),
}
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
+pub enum CarnotStepSolverType {
+ Plain(StepTime),
+ ParentCommitteeReceiverSolver,
+ ChildCommitteeReceiverSolver,
+}
+
+impl CarnotStepSolverType {
+ pub fn to_solver(self) -> CarnotStepSolver {
+ match self {
+ Self::Plain(time) => CarnotStepSolver::Plain(time),
+ Self::ParentCommitteeReceiverSolver => {
+ CarnotStepSolver::ParentCommitteeReceiverSolver(receive_proposal)
+ }
+ Self::ChildCommitteeReceiverSolver => {
+ CarnotStepSolver::ChildCommitteeReceiverSolver(receive_commit)
+ }
+ }
+ }
+}
+
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct CarnotNodeSettings {
- pub steps_costs: HashMap,
+ pub steps_costs: HashMap,
pub network: Network,
pub layout: Layout,
}
@@ -76,22 +112,22 @@ pub struct CarnotNode {
settings: Rc,
}
-pub const CARNOT_STEPS_COSTS: &[(CarnotStep, CarnotStepSolver)] = &[
+pub const CARNOT_STEPS_COSTS: &[(CarnotStep, CarnotStepSolverType)] = &[
(
CarnotStep::ReceiveProposal,
- CarnotStepSolver::ParentCommitteeReceiverSolver(receive_proposal),
+ CarnotStepSolverType::ParentCommitteeReceiverSolver,
),
(
CarnotStep::ValidateProposal,
- CarnotStepSolver::Plain(StepTime::from_secs(1)),
+ CarnotStepSolverType::Plain(StepTime::from_secs(1)),
),
(
CarnotStep::ReceiveVote,
- CarnotStepSolver::ChildCommitteeReceiverSolver(receive_commit),
+ CarnotStepSolverType::ChildCommitteeReceiverSolver,
),
(
CarnotStep::ValidateVote,
- CarnotStepSolver::Plain(StepTime::from_secs(1)),
+ CarnotStepSolverType::Plain(StepTime::from_secs(1)),
),
];
@@ -130,27 +166,27 @@ impl Node for CarnotNode {
fn run_step(&mut self, step: Self::Step) -> StepTime {
use CarnotStepSolver::*;
match self.settings.steps_costs.get(&step) {
- Some(Plain(t)) => *t,
- Some(ParentCommitteeReceiverSolver(solver)) => solver(
- &mut self.rng,
- self.id,
- self.settings
- .layout
- .parent_nodes(self.settings.layout.committee(self.id)),
- &self.settings.network,
- ),
- Some(ChildCommitteeReceiverSolver(solver)) => solver(
- &mut self.rng,
- self.id,
- &self
- .settings
- .layout
- .children_nodes(self.settings.layout.committee(self.id)),
- &self.settings.network,
- ),
- None => {
- panic!("Unknown step: {step:?}");
- }
+ Some(step) => match step.to_solver() {
+ Plain(t) => t,
+ ParentCommitteeReceiverSolver(solver) => solver(
+ &mut self.rng,
+ self.id,
+ self.settings
+ .layout
+ .parent_nodes(self.settings.layout.committee(self.id)),
+ &self.settings.network,
+ ),
+ ChildCommitteeReceiverSolver(solver) => solver(
+ &mut self.rng,
+ self.id,
+ &self
+ .settings
+ .layout
+ .children_nodes(self.settings.layout.committee(self.id)),
+ &self.settings.network,
+ ),
+ },
+ None => panic!("Unknown step: {step:?}"),
}
}
}
diff --git a/simulations/src/overlay/mod.rs b/simulations/src/overlay/mod.rs
index ec88db45..fc594655 100644
--- a/simulations/src/overlay/mod.rs
+++ b/simulations/src/overlay/mod.rs
@@ -10,6 +10,7 @@ use crate::node::{CommitteeId, NodeId};
pub type Committee = BTreeSet;
pub type Leaders = BTreeSet;
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct Layout {
pub committees: HashMap,
pub from_committee: HashMap,
@@ -73,6 +74,7 @@ impl Layout {
pub trait Overlay {
type Settings;
+
fn new(settings: Self::Settings) -> Self;
fn leaders(
&self,
diff --git a/simulations/src/runner.rs b/simulations/src/runner.rs
index e823eec8..64653e5d 100644
--- a/simulations/src/runner.rs
+++ b/simulations/src/runner.rs
@@ -14,7 +14,7 @@ pub struct ConsensusRunner {
}
#[allow(dead_code)]
-#[derive(Debug)]
+#[derive(Debug, serde::Serialize)]
pub struct Report {
round_time: Duration,
}