Simulation initialization (#122)
* Use enums for different settings types * Enum for overlay settings * Configurable simulation overlay * Use duration type for network behaviour delays * Configurable simulation nodes * Runner for different node types * Seedable rng * Convert settings to required objects * Implement IOStreamSettings deserialization * Use common run method for different node types * Configuration for simapp * Testcase for region distribution * Use unix time if seed is not provided
This commit is contained in:
parent
26d10856ff
commit
0bf6e6d272
|
@ -8,5 +8,9 @@ Cargo.lock
|
||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# Files generated by build processes or applications
|
||||||
config.yml
|
config.yml
|
||||||
store.*
|
store.*
|
||||||
|
sim_config.json
|
||||||
|
*.txt
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"wards": [
|
||||||
|
{
|
||||||
|
"max_view": {
|
||||||
|
"max_view": 10
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_max_view": {
|
||||||
|
"max_gap": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stalled_view": {
|
||||||
|
"consecutive_viewed_checkpoint": 123456789,
|
||||||
|
"criterion": 1000,
|
||||||
|
"threshold": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"network_settings": {
|
||||||
|
"network_behaviors": {},
|
||||||
|
"regions": {
|
||||||
|
"Europe": 0.3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overlay_settings": {
|
||||||
|
"Tree": {
|
||||||
|
"tree_type": "FullBinaryTree",
|
||||||
|
"committee_size": 1,
|
||||||
|
"depth": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_settings": "Dummy",
|
||||||
|
"runner_settings": "Sync",
|
||||||
|
"stream_settings": {
|
||||||
|
"Naive": {
|
||||||
|
"path": "sim_naive_stream.txt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_count": 10,
|
||||||
|
"views_count": 20,
|
||||||
|
"leaders_count": 2,
|
||||||
|
"seed": 12345
|
||||||
|
}
|
|
@ -1,13 +1,24 @@
|
||||||
// std
|
// std
|
||||||
use std::collections::HashMap;
|
use anyhow::Ok;
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
// crates
|
// crates
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use crossbeam::channel;
|
||||||
|
use rand::rngs::SmallRng;
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use rand::{Rng, SeedableRng};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use simulations::network::regions::RegionsData;
|
use simulations::network::behaviour::create_behaviours;
|
||||||
use simulations::network::Network;
|
use simulations::network::regions::{create_regions, RegionsData};
|
||||||
use simulations::overlay::tree::TreeOverlay;
|
use simulations::network::{InMemoryNetworkInterface, Network};
|
||||||
|
use simulations::node::dummy::DummyNode;
|
||||||
|
use simulations::node::{Node, NodeId, OverlayState, ViewOverlay};
|
||||||
|
use simulations::overlay::{create_overlay, Overlay, SimulationOverlay};
|
||||||
use simulations::streaming::StreamType;
|
use simulations::streaming::StreamType;
|
||||||
// internal
|
// internal
|
||||||
use simulations::{
|
use simulations::{
|
||||||
|
@ -33,57 +44,123 @@ impl SimulationApp {
|
||||||
input_settings,
|
input_settings,
|
||||||
stream_type,
|
stream_type,
|
||||||
} = self;
|
} = self;
|
||||||
|
let simulation_settings: SimulationSettings = load_json_from_file(&input_settings)?;
|
||||||
|
|
||||||
let nodes = vec![]; // TODO: Initialize nodes of different types.
|
let seed = simulation_settings.seed.unwrap_or_else(|| {
|
||||||
let regions_data = RegionsData::new(HashMap::new(), HashMap::new());
|
SystemTime::now()
|
||||||
let network = Network::new(regions_data);
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.expect("Time went backwards")
|
||||||
|
.as_secs()
|
||||||
|
});
|
||||||
|
let mut rng = SmallRng::seed_from_u64(seed);
|
||||||
|
let mut node_ids: Vec<NodeId> = (0..simulation_settings.node_count)
|
||||||
|
.map(Into::into)
|
||||||
|
.collect();
|
||||||
|
node_ids.shuffle(&mut rng);
|
||||||
|
|
||||||
// build up series vector
|
let regions = create_regions(&node_ids, &mut rng, &simulation_settings.network_settings);
|
||||||
match stream_type {
|
let behaviours = create_behaviours(&simulation_settings.network_settings);
|
||||||
simulations::streaming::StreamType::Naive => {
|
let regions_data = RegionsData::new(regions, behaviours);
|
||||||
let simulation_settings: SimulationSettings<_, _, _> =
|
let overlay = create_overlay(&simulation_settings.overlay_settings);
|
||||||
load_json_from_file(&input_settings)?;
|
let overlays = generate_overlays(
|
||||||
let simulation_runner: SimulationRunner<
|
&node_ids,
|
||||||
(),
|
&overlay,
|
||||||
CarnotNode,
|
simulation_settings.views_count,
|
||||||
TreeOverlay,
|
simulation_settings.leaders_count,
|
||||||
NaiveProducer<OutData>,
|
&mut rng,
|
||||||
> = SimulationRunner::new(network, nodes, simulation_settings);
|
);
|
||||||
simulation_runner.simulate()?
|
|
||||||
|
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
||||||
|
all_nodes: node_ids.clone(),
|
||||||
|
overlay,
|
||||||
|
overlays,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let mut network = Network::new(regions_data);
|
||||||
|
|
||||||
|
match &simulation_settings.node_settings {
|
||||||
|
simulations::settings::NodeSettings::Carnot => {
|
||||||
|
let nodes = node_ids
|
||||||
|
.iter()
|
||||||
|
.map(|node_id| CarnotNode::new(*node_id))
|
||||||
|
.collect();
|
||||||
|
run(network, nodes, simulation_settings, stream_type)?;
|
||||||
}
|
}
|
||||||
simulations::streaming::StreamType::Polars => {
|
simulations::settings::NodeSettings::Dummy => {
|
||||||
let simulation_settings: SimulationSettings<_, _, _> =
|
let nodes = node_ids
|
||||||
load_json_from_file(&input_settings)?;
|
.iter()
|
||||||
let simulation_runner: SimulationRunner<
|
.map(|node_id| {
|
||||||
(),
|
let (node_message_sender, node_message_receiver) = channel::unbounded();
|
||||||
CarnotNode,
|
let network_message_receiver =
|
||||||
TreeOverlay,
|
network.connect(*node_id, node_message_receiver);
|
||||||
PolarsProducer<OutData>,
|
let network_interface = InMemoryNetworkInterface::new(
|
||||||
> = SimulationRunner::new(network, nodes, simulation_settings);
|
*node_id,
|
||||||
simulation_runner.simulate()?
|
node_message_sender,
|
||||||
}
|
network_message_receiver,
|
||||||
simulations::streaming::StreamType::IO => {
|
);
|
||||||
let simulation_settings: SimulationSettings<_, _, _> =
|
DummyNode::new(*node_id, 0, overlay_state.clone(), network_interface)
|
||||||
load_json_from_file(&input_settings)?;
|
})
|
||||||
let simulation_runner: SimulationRunner<
|
.collect();
|
||||||
(),
|
run(network, nodes, simulation_settings, stream_type)?;
|
||||||
CarnotNode,
|
|
||||||
TreeOverlay,
|
|
||||||
IOProducer<std::io::Stdout, OutData>,
|
|
||||||
> = SimulationRunner::new(network, nodes, simulation_settings);
|
|
||||||
simulation_runner.simulate()?
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run<M, N: Node>(
|
||||||
|
network: Network<M>,
|
||||||
|
nodes: Vec<N>,
|
||||||
|
settings: SimulationSettings,
|
||||||
|
stream_type: StreamType,
|
||||||
|
) -> anyhow::Result<()>
|
||||||
|
where
|
||||||
|
M: Clone + Send + Sync + 'static,
|
||||||
|
N: Send + Sync + 'static,
|
||||||
|
N::Settings: Clone + Send,
|
||||||
|
N::State: Serialize,
|
||||||
|
{
|
||||||
|
let runner = SimulationRunner::new(network, nodes, settings);
|
||||||
|
match stream_type {
|
||||||
|
simulations::streaming::StreamType::Naive => runner.simulate::<NaiveProducer<OutData>>()?,
|
||||||
|
simulations::streaming::StreamType::Polars => {
|
||||||
|
runner.simulate::<PolarsProducer<OutData>>()?
|
||||||
|
}
|
||||||
|
simulations::streaming::StreamType::IO => {
|
||||||
|
runner.simulate::<IOProducer<std::io::Stdout, OutData>>()?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Generically load a json file
|
/// Generically load a json file
|
||||||
fn load_json_from_file<T: DeserializeOwned>(path: &Path) -> anyhow::Result<T> {
|
fn load_json_from_file<T: DeserializeOwned>(path: &Path) -> anyhow::Result<T> {
|
||||||
let f = File::open(path).map_err(Box::new)?;
|
let f = File::open(path).map_err(Box::new)?;
|
||||||
Ok(serde_json::from_reader(f)?)
|
Ok(serde_json::from_reader(f)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper method to pregenerate views.
|
||||||
|
// TODO: Remove once shared overlay can generate new views on demand.
|
||||||
|
fn generate_overlays<R: Rng>(
|
||||||
|
node_ids: &[NodeId],
|
||||||
|
overlay: &SimulationOverlay,
|
||||||
|
overlay_count: usize,
|
||||||
|
leader_count: usize,
|
||||||
|
rng: &mut R,
|
||||||
|
) -> BTreeMap<usize, ViewOverlay> {
|
||||||
|
(0..overlay_count)
|
||||||
|
.map(|view_id| {
|
||||||
|
(
|
||||||
|
view_id,
|
||||||
|
ViewOverlay {
|
||||||
|
leaders: overlay.leaders(node_ids, leader_count, rng).collect(),
|
||||||
|
layout: overlay.layout(node_ids, rng),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let app: SimulationApp = SimulationApp::parse();
|
let app: SimulationApp = SimulationApp::parse();
|
||||||
app.run()?;
|
app.run()?;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
// std
|
// std
|
||||||
use std::time::Duration;
|
use std::{collections::HashMap, time::Duration};
|
||||||
// crates
|
// crates
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::{regions::Region, NetworkSettings};
|
||||||
// internal
|
// internal
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||||
|
@ -24,3 +26,15 @@ impl NetworkBehaviour {
|
||||||
rng.gen_bool(self.drop)
|
rng.gen_bool(self.drop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Takes a reference to the simulation_settings and returns a HashMap representing the
|
||||||
|
// network behaviors for pairs of NodeIds.
|
||||||
|
pub fn create_behaviours(
|
||||||
|
network_settings: &NetworkSettings,
|
||||||
|
) -> HashMap<(Region, Region), NetworkBehaviour> {
|
||||||
|
network_settings
|
||||||
|
.network_behaviors
|
||||||
|
.iter()
|
||||||
|
.map(|((a, b), d)| ((*a, *b), NetworkBehaviour::new(*d, 0.0)))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use std::{
|
||||||
use crossbeam::channel::{self, Receiver, Sender};
|
use crossbeam::channel::{self, Receiver, Sender};
|
||||||
use rand::{rngs::ThreadRng, Rng};
|
use rand::{rngs::ThreadRng, Rng};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
use serde::Deserialize;
|
||||||
// internal
|
// internal
|
||||||
use crate::node::NodeId;
|
use crate::node::NodeId;
|
||||||
|
|
||||||
|
@ -16,6 +17,14 @@ pub mod regions;
|
||||||
|
|
||||||
type NetworkTime = Instant;
|
type NetworkTime = Instant;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Default)]
|
||||||
|
pub struct NetworkSettings {
|
||||||
|
pub network_behaviors: HashMap<(regions::Region, regions::Region), Duration>,
|
||||||
|
/// Represents node distribution in the simulated regions.
|
||||||
|
/// The sum of distributions should be 1.
|
||||||
|
pub regions: HashMap<regions::Region, f32>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Network<M> {
|
pub struct Network<M> {
|
||||||
pub regions: regions::RegionsData,
|
pub regions: regions::RegionsData,
|
||||||
network_time: NetworkTime,
|
network_time: NetworkTime,
|
||||||
|
@ -144,6 +153,39 @@ pub trait NetworkInterface {
|
||||||
fn receive_messages(&self) -> Vec<NetworkMessage<Self::Payload>>;
|
fn receive_messages(&self) -> Vec<NetworkMessage<Self::Payload>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct InMemoryNetworkInterface<M> {
|
||||||
|
id: NodeId,
|
||||||
|
sender: Sender<NetworkMessage<M>>,
|
||||||
|
receiver: Receiver<NetworkMessage<M>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> InMemoryNetworkInterface<M> {
|
||||||
|
pub fn new(
|
||||||
|
id: NodeId,
|
||||||
|
sender: Sender<NetworkMessage<M>>,
|
||||||
|
receiver: Receiver<NetworkMessage<M>>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
sender,
|
||||||
|
receiver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> NetworkInterface for InMemoryNetworkInterface<M> {
|
||||||
|
type Payload = M;
|
||||||
|
|
||||||
|
fn send_message(&self, address: NodeId, message: Self::Payload) {
|
||||||
|
let message = NetworkMessage::new(self.id, address, message);
|
||||||
|
self.sender.send(message).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive_messages(&self) -> Vec<crate::network::NetworkMessage<Self::Payload>> {
|
||||||
|
self.receiver.try_iter().collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{
|
use super::{
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
// std
|
// std
|
||||||
|
use rand::{seq::SliceRandom, Rng};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
// crates
|
// crates
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
// internal
|
// internal
|
||||||
use crate::{network::behaviour::NetworkBehaviour, node::NodeId};
|
use crate::{network::behaviour::NetworkBehaviour, node::NodeId};
|
||||||
|
|
||||||
|
use super::NetworkSettings;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||||
pub enum Region {
|
pub enum Region {
|
||||||
NorthAmerica,
|
NorthAmerica,
|
||||||
|
@ -56,3 +59,118 @@ impl RegionsData {
|
||||||
&self.regions[®ion]
|
&self.regions[®ion]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Takes a reference to the node_ids and simulation_settings and returns a HashMap
|
||||||
|
// representing the regions and their associated node IDs.
|
||||||
|
pub fn create_regions<R: Rng>(
|
||||||
|
node_ids: &[NodeId],
|
||||||
|
rng: &mut R,
|
||||||
|
network_settings: &NetworkSettings,
|
||||||
|
) -> HashMap<Region, Vec<NodeId>> {
|
||||||
|
let mut region_nodes = node_ids.to_vec();
|
||||||
|
region_nodes.shuffle(rng);
|
||||||
|
|
||||||
|
let regions = network_settings
|
||||||
|
.regions
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let last_region_index = regions.len() - 1;
|
||||||
|
|
||||||
|
regions
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, (region, distribution))| {
|
||||||
|
if i < last_region_index {
|
||||||
|
let node_count = (node_ids.len() as f32 * distribution).round() as usize;
|
||||||
|
let nodes = region_nodes.drain(..node_count).collect::<Vec<_>>();
|
||||||
|
(*region, nodes)
|
||||||
|
} else {
|
||||||
|
// Assign the remaining nodes to the last region.
|
||||||
|
(*region, region_nodes.clone())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use rand::rngs::mock::StepRng;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
network::{
|
||||||
|
regions::{create_regions, Region},
|
||||||
|
NetworkSettings,
|
||||||
|
},
|
||||||
|
node::NodeId,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_regions_precision() {
|
||||||
|
struct TestCase {
|
||||||
|
node_count: usize,
|
||||||
|
distributions: Vec<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let test_cases = vec![
|
||||||
|
TestCase {
|
||||||
|
node_count: 10,
|
||||||
|
distributions: vec![0.5, 0.3, 0.2],
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
node_count: 7,
|
||||||
|
distributions: vec![0.6, 0.4],
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
node_count: 20,
|
||||||
|
distributions: vec![0.4, 0.3, 0.2, 0.1],
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
node_count: 23,
|
||||||
|
distributions: vec![0.4, 0.3, 0.3],
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
node_count: 111,
|
||||||
|
distributions: vec![0.3, 0.3, 0.3, 0.1],
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
node_count: 73,
|
||||||
|
distributions: vec![0.3, 0.2, 0.2, 0.2, 0.1],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let mut rng = StepRng::new(1, 0);
|
||||||
|
|
||||||
|
for tcase in test_cases.iter() {
|
||||||
|
let nodes = (0..tcase.node_count)
|
||||||
|
.map(Into::into)
|
||||||
|
.collect::<Vec<NodeId>>();
|
||||||
|
|
||||||
|
let available_regions = vec![
|
||||||
|
Region::NorthAmerica,
|
||||||
|
Region::Europe,
|
||||||
|
Region::Asia,
|
||||||
|
Region::Africa,
|
||||||
|
Region::SouthAmerica,
|
||||||
|
Region::Australia,
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut region_distribution = HashMap::new();
|
||||||
|
for (region, &dist) in available_regions.iter().zip(&tcase.distributions) {
|
||||||
|
region_distribution.insert(*region, dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
let settings = NetworkSettings {
|
||||||
|
network_behaviors: HashMap::new(),
|
||||||
|
regions: region_distribution,
|
||||||
|
};
|
||||||
|
|
||||||
|
let regions = create_regions(&nodes, &mut rng, &settings);
|
||||||
|
|
||||||
|
let total_nodes_in_regions = regions.values().map(|v| v.len()).sum::<usize>();
|
||||||
|
assert_eq!(total_nodes_in_regions, nodes.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use super::{Node, NodeId};
|
||||||
#[derive(Default, Serialize)]
|
#[derive(Default, Serialize)]
|
||||||
pub struct CarnotState {}
|
pub struct CarnotState {}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
#[derive(Clone, Default, Deserialize)]
|
||||||
pub struct CarnotSettings {}
|
pub struct CarnotSettings {}
|
||||||
|
|
||||||
#[allow(dead_code)] // TODO: remove when handling settings
|
#[allow(dead_code)] // TODO: remove when handling settings
|
||||||
|
@ -17,6 +17,16 @@ pub struct CarnotNode {
|
||||||
settings: CarnotSettings,
|
settings: CarnotSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CarnotNode {
|
||||||
|
pub fn new(id: NodeId) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
state: Default::default(),
|
||||||
|
settings: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Node for CarnotNode {
|
impl Node for CarnotNode {
|
||||||
type Settings = CarnotSettings;
|
type Settings = CarnotSettings;
|
||||||
type State = CarnotState;
|
type State = CarnotState;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
// std
|
// std
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
// crates
|
// crates
|
||||||
use crossbeam::channel::{Receiver, Sender};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
// internal
|
// internal
|
||||||
use crate::{
|
use crate::{
|
||||||
network::{NetworkInterface, NetworkMessage},
|
network::{InMemoryNetworkInterface, NetworkInterface, NetworkMessage},
|
||||||
node::{Node, NodeId},
|
node::{Node, NodeId},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,7 +130,7 @@ pub struct DummyNode {
|
||||||
state: DummyState,
|
state: DummyState,
|
||||||
_settings: DummySettings,
|
_settings: DummySettings,
|
||||||
overlay_state: SharedState<OverlayState>,
|
overlay_state: SharedState<OverlayState>,
|
||||||
network_interface: DummyNetworkInterface,
|
network_interface: InMemoryNetworkInterface<DummyMessage>,
|
||||||
local_view: LocalView,
|
local_view: LocalView,
|
||||||
|
|
||||||
// Node in current view might be a leader in the next view.
|
// Node in current view might be a leader in the next view.
|
||||||
|
@ -154,7 +153,7 @@ impl DummyNode {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
view_id: usize,
|
view_id: usize,
|
||||||
overlay_state: SharedState<OverlayState>,
|
overlay_state: SharedState<OverlayState>,
|
||||||
network_interface: DummyNetworkInterface,
|
network_interface: InMemoryNetworkInterface<DummyMessage>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
node_id,
|
node_id,
|
||||||
|
@ -373,39 +372,6 @@ impl Node for DummyNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DummyNetworkInterface {
|
|
||||||
id: NodeId,
|
|
||||||
sender: Sender<NetworkMessage<DummyMessage>>,
|
|
||||||
receiver: Receiver<NetworkMessage<DummyMessage>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DummyNetworkInterface {
|
|
||||||
pub fn new(
|
|
||||||
id: NodeId,
|
|
||||||
sender: Sender<NetworkMessage<DummyMessage>>,
|
|
||||||
receiver: Receiver<NetworkMessage<DummyMessage>>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
id,
|
|
||||||
sender,
|
|
||||||
receiver,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NetworkInterface for DummyNetworkInterface {
|
|
||||||
type Payload = DummyMessage;
|
|
||||||
|
|
||||||
fn send_message(&self, address: NodeId, message: Self::Payload) {
|
|
||||||
let message = NetworkMessage::new(self.id, address, message);
|
|
||||||
self.sender.send(message).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn receive_messages(&self) -> Vec<crate::network::NetworkMessage<Self::Payload>> {
|
|
||||||
self.receiver.try_iter().collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_parent_nodes(node_id: NodeId, view: &ViewOverlay) -> Option<BTreeSet<NodeId>> {
|
fn get_parent_nodes(node_id: NodeId, view: &ViewOverlay) -> Option<BTreeSet<NodeId>> {
|
||||||
let committee_id = view.layout.committee(node_id)?;
|
let committee_id = view.layout.committee(node_id)?;
|
||||||
view.layout.parent_nodes(committee_id).map(|c| c.nodes)
|
view.layout.parent_nodes(committee_id).map(|c| c.nodes)
|
||||||
|
@ -468,11 +434,11 @@ mod tests {
|
||||||
network::{
|
network::{
|
||||||
behaviour::NetworkBehaviour,
|
behaviour::NetworkBehaviour,
|
||||||
regions::{Region, RegionsData},
|
regions::{Region, RegionsData},
|
||||||
Network,
|
InMemoryNetworkInterface, Network,
|
||||||
},
|
},
|
||||||
node::{
|
node::{
|
||||||
dummy::{get_child_nodes, get_parent_nodes, get_roles, DummyRole},
|
dummy::{get_child_nodes, get_parent_nodes, get_roles, DummyRole},
|
||||||
Node, NodeId, OverlayState, SharedState, ViewOverlay,
|
Node, NodeId, OverlayState, SharedState, SimulationOverlay, ViewOverlay,
|
||||||
},
|
},
|
||||||
overlay::{
|
overlay::{
|
||||||
tree::{TreeOverlay, TreeSettings},
|
tree::{TreeOverlay, TreeSettings},
|
||||||
|
@ -480,7 +446,7 @@ mod tests {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{DummyMessage, DummyNetworkInterface, DummyNode, Intent, Vote};
|
use super::{DummyMessage, DummyNode, Intent, Vote};
|
||||||
|
|
||||||
fn init_network(node_ids: &[NodeId]) -> Network<DummyMessage> {
|
fn init_network(node_ids: &[NodeId]) -> Network<DummyMessage> {
|
||||||
let regions = HashMap::from([(Region::Europe, node_ids.to_vec())]);
|
let regions = HashMap::from([(Region::Europe, node_ids.to_vec())]);
|
||||||
|
@ -502,7 +468,7 @@ mod tests {
|
||||||
.map(|node_id| {
|
.map(|node_id| {
|
||||||
let (node_message_sender, node_message_receiver) = channel::unbounded();
|
let (node_message_sender, node_message_receiver) = channel::unbounded();
|
||||||
let network_message_receiver = network.connect(*node_id, node_message_receiver);
|
let network_message_receiver = network.connect(*node_id, node_message_receiver);
|
||||||
let network_interface = DummyNetworkInterface::new(
|
let network_interface = InMemoryNetworkInterface::new(
|
||||||
*node_id,
|
*node_id,
|
||||||
node_message_sender,
|
node_message_sender,
|
||||||
network_message_receiver,
|
network_message_receiver,
|
||||||
|
@ -515,9 +481,9 @@ mod tests {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_overlays<O: Overlay, R: Rng>(
|
fn generate_overlays<R: Rng>(
|
||||||
node_ids: &[NodeId],
|
node_ids: &[NodeId],
|
||||||
overlay: O,
|
overlay: &SimulationOverlay,
|
||||||
overlay_count: usize,
|
overlay_count: usize,
|
||||||
leader_count: usize,
|
leader_count: usize,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
|
@ -576,6 +542,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
||||||
all_nodes: node_ids.clone(),
|
all_nodes: node_ids.clone(),
|
||||||
|
overlay: SimulationOverlay::Tree(overlay),
|
||||||
overlays: BTreeMap::from([
|
overlays: BTreeMap::from([
|
||||||
(0, view.clone()),
|
(0, view.clone()),
|
||||||
(1, view.clone()),
|
(1, view.clone()),
|
||||||
|
@ -710,19 +677,20 @@ mod tests {
|
||||||
let mut rng = SmallRng::seed_from_u64(timestamp);
|
let mut rng = SmallRng::seed_from_u64(timestamp);
|
||||||
|
|
||||||
let committee_size = 1;
|
let committee_size = 1;
|
||||||
let overlay = TreeOverlay::new(TreeSettings {
|
let overlay = SimulationOverlay::Tree(TreeOverlay::new(TreeSettings {
|
||||||
tree_type: Default::default(),
|
tree_type: Default::default(),
|
||||||
depth: 3,
|
depth: 3,
|
||||||
committee_size,
|
committee_size,
|
||||||
});
|
}));
|
||||||
|
|
||||||
// There are more nodes in the network than in a tree overlay.
|
// There are more nodes in the network than in a tree overlay.
|
||||||
let node_ids: Vec<NodeId> = (0..100).map(Into::into).collect();
|
let node_ids: Vec<NodeId> = (0..100).map(Into::into).collect();
|
||||||
let mut network = init_network(&node_ids);
|
let mut network = init_network(&node_ids);
|
||||||
|
|
||||||
let overlays = generate_overlays(&node_ids, overlay, 4, 3, &mut rng);
|
let overlays = generate_overlays(&node_ids, &overlay, 4, 3, &mut rng);
|
||||||
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
||||||
all_nodes: node_ids.clone(),
|
all_nodes: node_ids.clone(),
|
||||||
|
overlay,
|
||||||
overlays: overlays.clone(),
|
overlays: overlays.clone(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -759,19 +727,20 @@ mod tests {
|
||||||
let mut rng = SmallRng::seed_from_u64(timestamp);
|
let mut rng = SmallRng::seed_from_u64(timestamp);
|
||||||
|
|
||||||
let committee_size = 100;
|
let committee_size = 100;
|
||||||
let overlay = TreeOverlay::new(TreeSettings {
|
let overlay = SimulationOverlay::Tree(TreeOverlay::new(TreeSettings {
|
||||||
tree_type: Default::default(),
|
tree_type: Default::default(),
|
||||||
depth: 3,
|
depth: 3,
|
||||||
committee_size,
|
committee_size,
|
||||||
});
|
}));
|
||||||
|
|
||||||
// There are more nodes in the network than in a tree overlay.
|
// There are more nodes in the network than in a tree overlay.
|
||||||
let node_ids: Vec<NodeId> = (0..10000).map(Into::into).collect();
|
let node_ids: Vec<NodeId> = (0..10000).map(Into::into).collect();
|
||||||
let mut network = init_network(&node_ids);
|
let mut network = init_network(&node_ids);
|
||||||
|
|
||||||
let overlays = generate_overlays(&node_ids, overlay, 4, 100, &mut rng);
|
let overlays = generate_overlays(&node_ids, &overlay, 4, 100, &mut rng);
|
||||||
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
||||||
all_nodes: node_ids.clone(),
|
all_nodes: node_ids.clone(),
|
||||||
|
overlay,
|
||||||
overlays: overlays.clone(),
|
overlays: overlays.clone(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -808,19 +777,20 @@ mod tests {
|
||||||
let mut rng = SmallRng::seed_from_u64(timestamp);
|
let mut rng = SmallRng::seed_from_u64(timestamp);
|
||||||
|
|
||||||
let committee_size = 500;
|
let committee_size = 500;
|
||||||
let overlay = TreeOverlay::new(TreeSettings {
|
let overlay = SimulationOverlay::Tree(TreeOverlay::new(TreeSettings {
|
||||||
tree_type: Default::default(),
|
tree_type: Default::default(),
|
||||||
depth: 5,
|
depth: 5,
|
||||||
committee_size,
|
committee_size,
|
||||||
});
|
}));
|
||||||
|
|
||||||
// There are more nodes in the network than in a tree overlay.
|
// There are more nodes in the network than in a tree overlay.
|
||||||
let node_ids: Vec<NodeId> = (0..100000).map(Into::into).collect();
|
let node_ids: Vec<NodeId> = (0..100000).map(Into::into).collect();
|
||||||
let mut network = init_network(&node_ids);
|
let mut network = init_network(&node_ids);
|
||||||
|
|
||||||
let overlays = generate_overlays(&node_ids, overlay, 4, 1000, &mut rng);
|
let overlays = generate_overlays(&node_ids, &overlay, 4, 1000, &mut rng);
|
||||||
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
||||||
all_nodes: node_ids.clone(),
|
all_nodes: node_ids.clone(),
|
||||||
|
overlay,
|
||||||
overlays: overlays.clone(),
|
overlays: overlays.clone(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ use std::{
|
||||||
// crates
|
// crates
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
// internal
|
// internal
|
||||||
use crate::overlay::Layout;
|
use crate::overlay::{Layout, OverlaySettings, SimulationOverlay};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
|
@ -126,11 +126,25 @@ pub struct ViewOverlay {
|
||||||
pub layout: Layout,
|
pub layout: Layout,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<OverlaySettings> for ViewOverlay {
|
||||||
|
fn from(value: OverlaySettings) -> Self {
|
||||||
|
match value {
|
||||||
|
OverlaySettings::Flat => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
OverlaySettings::Tree(_) => {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type SharedState<S> = Arc<RwLock<S>>;
|
pub type SharedState<S> = Arc<RwLock<S>>;
|
||||||
|
|
||||||
/// A state that represents how nodes are interconnected in the network.
|
/// A state that represents how nodes are interconnected in the network.
|
||||||
pub struct OverlayState {
|
pub struct OverlayState {
|
||||||
pub all_nodes: Vec<NodeId>,
|
pub all_nodes: Vec<NodeId>,
|
||||||
|
pub overlay: SimulationOverlay,
|
||||||
pub overlays: BTreeMap<usize, ViewOverlay>,
|
pub overlays: BTreeMap<usize, ViewOverlay>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,19 @@ use crate::node::NodeId;
|
||||||
use crate::overlay::{Committee, Layout};
|
use crate::overlay::{Committee, Layout};
|
||||||
|
|
||||||
pub struct FlatOverlay;
|
pub struct FlatOverlay;
|
||||||
|
impl FlatOverlay {
|
||||||
impl Overlay for FlatOverlay {
|
pub fn new() -> Self {
|
||||||
type Settings = ();
|
|
||||||
|
|
||||||
fn new(_settings: Self::Settings) -> Self {
|
|
||||||
Self
|
Self
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FlatOverlay {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Overlay for FlatOverlay {
|
||||||
fn nodes(&self) -> Vec<NodeId> {
|
fn nodes(&self) -> Vec<NodeId> {
|
||||||
(0..10).map(NodeId::from).collect()
|
(0..10).map(NodeId::from).collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,12 @@ pub mod tree;
|
||||||
use std::collections::{BTreeSet, HashMap};
|
use std::collections::{BTreeSet, HashMap};
|
||||||
// crates
|
// crates
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use serde::Deserialize;
|
||||||
// internal
|
// internal
|
||||||
use crate::node::{CommitteeId, NodeId};
|
use crate::node::{CommitteeId, NodeId};
|
||||||
|
|
||||||
|
use self::tree::TreeSettings;
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Committee {
|
pub struct Committee {
|
||||||
pub nodes: BTreeSet<NodeId>,
|
pub nodes: BTreeSet<NodeId>,
|
||||||
|
@ -89,10 +92,70 @@ impl Layout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Overlay {
|
pub enum SimulationOverlay {
|
||||||
type Settings;
|
Flat(flat::FlatOverlay),
|
||||||
|
Tree(tree::TreeOverlay),
|
||||||
|
}
|
||||||
|
|
||||||
fn new(settings: Self::Settings) -> Self;
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
|
pub enum OverlaySettings {
|
||||||
|
Flat,
|
||||||
|
Tree(TreeSettings),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OverlaySettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Tree(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TreeSettings> for OverlaySettings {
|
||||||
|
fn from(settings: TreeSettings) -> OverlaySettings {
|
||||||
|
OverlaySettings::Tree(settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<TreeSettings> for OverlaySettings {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<TreeSettings, Self::Error> {
|
||||||
|
if let Self::Tree(settings) = self {
|
||||||
|
Ok(settings)
|
||||||
|
} else {
|
||||||
|
Err("unable to convert to tree settings".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Overlay for SimulationOverlay {
|
||||||
|
fn nodes(&self) -> Vec<NodeId> {
|
||||||
|
match self {
|
||||||
|
SimulationOverlay::Flat(overlay) => overlay.nodes(),
|
||||||
|
SimulationOverlay::Tree(overlay) => overlay.nodes(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaders<R: Rng>(
|
||||||
|
&self,
|
||||||
|
nodes: &[NodeId],
|
||||||
|
size: usize,
|
||||||
|
rng: &mut R,
|
||||||
|
) -> Box<dyn Iterator<Item = NodeId>> {
|
||||||
|
match self {
|
||||||
|
SimulationOverlay::Flat(overlay) => overlay.leaders(nodes, size, rng),
|
||||||
|
SimulationOverlay::Tree(overlay) => overlay.leaders(nodes, size, rng),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout<R: Rng>(&self, nodes: &[NodeId], rng: &mut R) -> Layout {
|
||||||
|
match self {
|
||||||
|
SimulationOverlay::Flat(overlay) => overlay.layout(nodes, rng),
|
||||||
|
SimulationOverlay::Tree(overlay) => overlay.layout(nodes, rng),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Overlay {
|
||||||
fn nodes(&self) -> Vec<NodeId>;
|
fn nodes(&self) -> Vec<NodeId>;
|
||||||
fn leaders<R: Rng>(
|
fn leaders<R: Rng>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -102,3 +165,14 @@ pub trait Overlay {
|
||||||
) -> Box<dyn Iterator<Item = NodeId>>;
|
) -> Box<dyn Iterator<Item = NodeId>>;
|
||||||
fn layout<R: Rng>(&self, nodes: &[NodeId], rng: &mut R) -> Layout;
|
fn layout<R: Rng>(&self, nodes: &[NodeId], rng: &mut R) -> Layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Takes a reference to the simulation_settings and returns a SimulationOverlay instance based
|
||||||
|
// on the overlay settings specified in simulation_settings.
|
||||||
|
pub fn create_overlay(overlay_settings: &OverlaySettings) -> SimulationOverlay {
|
||||||
|
match &overlay_settings {
|
||||||
|
OverlaySettings::Flat => SimulationOverlay::Flat(flat::FlatOverlay::new()),
|
||||||
|
OverlaySettings::Tree(settings) => {
|
||||||
|
SimulationOverlay::Tree(tree::TreeOverlay::new(settings.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@ use serde::Deserialize;
|
||||||
use super::{Committee, Layout, Overlay};
|
use super::{Committee, Layout, Overlay};
|
||||||
use crate::node::{CommitteeId, NodeId};
|
use crate::node::{CommitteeId, NodeId};
|
||||||
|
|
||||||
#[derive(Clone, Default, Deserialize)]
|
#[derive(Clone, Debug, Default, Deserialize)]
|
||||||
pub enum TreeType {
|
pub enum TreeType {
|
||||||
#[default]
|
#[default]
|
||||||
FullBinaryTree,
|
FullBinaryTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct TreeSettings {
|
pub struct TreeSettings {
|
||||||
pub tree_type: TreeType,
|
pub tree_type: TreeType,
|
||||||
pub committee_size: usize,
|
pub committee_size: usize,
|
||||||
|
@ -40,6 +40,10 @@ struct TreeProperties {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TreeOverlay {
|
impl TreeOverlay {
|
||||||
|
pub fn new(settings: TreeSettings) -> Self {
|
||||||
|
Self { settings }
|
||||||
|
}
|
||||||
|
|
||||||
fn build_full_binary_tree<R: rand::Rng>(
|
fn build_full_binary_tree<R: rand::Rng>(
|
||||||
node_ids: &[NodeId],
|
node_ids: &[NodeId],
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
|
@ -99,12 +103,6 @@ impl TreeOverlay {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Overlay for TreeOverlay {
|
impl Overlay for TreeOverlay {
|
||||||
type Settings = TreeSettings;
|
|
||||||
|
|
||||||
fn new(settings: Self::Settings) -> Self {
|
|
||||||
Self { settings }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nodes(&self) -> Vec<NodeId> {
|
fn nodes(&self) -> Vec<NodeId> {
|
||||||
let properties = get_tree_properties(&self.settings);
|
let properties = get_tree_properties(&self.settings);
|
||||||
(0..properties.node_count).map(From::from).collect()
|
(0..properties.node_count).map(From::from).collect()
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::node::{Node, NodeId};
|
use crate::node::{Node, NodeId};
|
||||||
use crate::overlay::Overlay;
|
|
||||||
use crate::runner::{SimulationRunner, SimulationRunnerHandle};
|
use crate::runner::{SimulationRunner, SimulationRunnerHandle};
|
||||||
use crate::streaming::{Producer, Subscriber};
|
use crate::streaming::{Producer, Subscriber};
|
||||||
use crate::warding::SimulationState;
|
use crate::warding::SimulationState;
|
||||||
|
@ -12,8 +11,8 @@ use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Simulate with sending the network state to any subscriber
|
/// Simulate with sending the network state to any subscriber
|
||||||
pub fn simulate<M, N: Node, O: Overlay, P: Producer>(
|
pub fn simulate<M, N: Node, P: Producer>(
|
||||||
runner: SimulationRunner<M, N, O, P>,
|
runner: SimulationRunner<M, N>,
|
||||||
chunk_size: usize,
|
chunk_size: usize,
|
||||||
) -> anyhow::Result<SimulationRunnerHandle>
|
) -> anyhow::Result<SimulationRunnerHandle>
|
||||||
where
|
where
|
||||||
|
@ -21,7 +20,6 @@ where
|
||||||
N: Send + Sync + 'static,
|
N: Send + Sync + 'static,
|
||||||
N::Settings: Clone + Send,
|
N::Settings: Clone + Send,
|
||||||
N::State: Serialize,
|
N::State: Serialize,
|
||||||
O::Settings: Clone + Send,
|
|
||||||
P::Subscriber: Send + Sync + 'static,
|
P::Subscriber: Send + Sync + 'static,
|
||||||
<P::Subscriber as Subscriber>::Record:
|
<P::Subscriber as Subscriber>::Record:
|
||||||
Send + Sync + 'static + for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
Send + Sync + 'static + for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
||||||
|
@ -44,7 +42,7 @@ where
|
||||||
let handle = SimulationRunnerHandle {
|
let handle = SimulationRunnerHandle {
|
||||||
stop_tx,
|
stop_tx,
|
||||||
handle: std::thread::spawn(move || {
|
handle: std::thread::spawn(move || {
|
||||||
let p = P::new(runner.stream_settings.settings)?;
|
let p = P::new(runner.stream_settings)?;
|
||||||
scopeguard::defer!(if let Err(e) = p.stop() {
|
scopeguard::defer!(if let Err(e) = p.stop() {
|
||||||
eprintln!("Error stopping producer: {e}");
|
eprintln!("Error stopping producer: {e}");
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::node::{Node, NodeId};
|
use crate::node::{Node, NodeId};
|
||||||
use crate::overlay::Overlay;
|
|
||||||
use crate::runner::{SimulationRunner, SimulationRunnerHandle};
|
use crate::runner::{SimulationRunner, SimulationRunnerHandle};
|
||||||
use crate::streaming::{Producer, Subscriber};
|
use crate::streaming::{Producer, Subscriber};
|
||||||
use crate::warding::SimulationState;
|
use crate::warding::SimulationState;
|
||||||
|
@ -13,8 +12,8 @@ use std::sync::Arc;
|
||||||
/// Simulate with sending the network state to any subscriber.
|
/// Simulate with sending the network state to any subscriber.
|
||||||
///
|
///
|
||||||
/// [Glauber dynamics simulation](https://en.wikipedia.org/wiki/Glauber_dynamics)
|
/// [Glauber dynamics simulation](https://en.wikipedia.org/wiki/Glauber_dynamics)
|
||||||
pub fn simulate<M, N: Node, O: Overlay, P: Producer>(
|
pub fn simulate<M, N: Node, P: Producer>(
|
||||||
runner: SimulationRunner<M, N, O, P>,
|
runner: SimulationRunner<M, N>,
|
||||||
update_rate: usize,
|
update_rate: usize,
|
||||||
maximum_iterations: usize,
|
maximum_iterations: usize,
|
||||||
) -> anyhow::Result<SimulationRunnerHandle>
|
) -> anyhow::Result<SimulationRunnerHandle>
|
||||||
|
@ -23,7 +22,6 @@ where
|
||||||
N: Send + Sync + 'static,
|
N: Send + Sync + 'static,
|
||||||
N::Settings: Clone + Send,
|
N::Settings: Clone + Send,
|
||||||
N::State: Serialize,
|
N::State: Serialize,
|
||||||
O::Settings: Clone + Send,
|
|
||||||
P::Subscriber: Send + Sync + 'static,
|
P::Subscriber: Send + Sync + 'static,
|
||||||
<P::Subscriber as Subscriber>::Record:
|
<P::Subscriber as Subscriber>::Record:
|
||||||
for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
||||||
|
@ -42,7 +40,7 @@ where
|
||||||
let (stop_tx, stop_rx) = bounded(1);
|
let (stop_tx, stop_rx) = bounded(1);
|
||||||
let handle = SimulationRunnerHandle {
|
let handle = SimulationRunnerHandle {
|
||||||
handle: std::thread::spawn(move || {
|
handle: std::thread::spawn(move || {
|
||||||
let p = P::new(runner.stream_settings.settings)?;
|
let p = P::new(runner.stream_settings)?;
|
||||||
scopeguard::defer!(if let Err(e) = p.stop() {
|
scopeguard::defer!(if let Err(e) = p.stop() {
|
||||||
eprintln!("Error stopping producer: {e}");
|
eprintln!("Error stopping producer: {e}");
|
||||||
});
|
});
|
||||||
|
|
|
@ -40,7 +40,6 @@ use rand::rngs::SmallRng;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
// internal
|
// internal
|
||||||
use crate::node::{Node, NodeId};
|
use crate::node::{Node, NodeId};
|
||||||
use crate::overlay::Overlay;
|
|
||||||
use crate::runner::SimulationRunner;
|
use crate::runner::SimulationRunner;
|
||||||
use crate::streaming::{Producer, Subscriber};
|
use crate::streaming::{Producer, Subscriber};
|
||||||
use crate::warding::SimulationState;
|
use crate::warding::SimulationState;
|
||||||
|
@ -48,8 +47,8 @@ use crate::warding::SimulationState;
|
||||||
use super::SimulationRunnerHandle;
|
use super::SimulationRunnerHandle;
|
||||||
|
|
||||||
/// Simulate with sending the network state to any subscriber
|
/// Simulate with sending the network state to any subscriber
|
||||||
pub fn simulate<M, N: Node, O: Overlay, P: Producer>(
|
pub fn simulate<M, N: Node, P: Producer>(
|
||||||
runner: SimulationRunner<M, N, O, P>,
|
runner: SimulationRunner<M, N>,
|
||||||
gap: usize,
|
gap: usize,
|
||||||
distribution: Option<Vec<f32>>,
|
distribution: Option<Vec<f32>>,
|
||||||
) -> anyhow::Result<SimulationRunnerHandle>
|
) -> anyhow::Result<SimulationRunnerHandle>
|
||||||
|
@ -58,7 +57,6 @@ where
|
||||||
N: Send + Sync + 'static,
|
N: Send + Sync + 'static,
|
||||||
N::Settings: Clone + Send,
|
N::Settings: Clone + Send,
|
||||||
N::State: Serialize,
|
N::State: Serialize,
|
||||||
O::Settings: Clone + Send,
|
|
||||||
P::Subscriber: Send + Sync + 'static,
|
P::Subscriber: Send + Sync + 'static,
|
||||||
<P::Subscriber as Subscriber>::Record:
|
<P::Subscriber as Subscriber>::Record:
|
||||||
for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
||||||
|
@ -68,7 +66,7 @@ where
|
||||||
|
|
||||||
let layers: Vec<usize> = (0..gap).collect();
|
let layers: Vec<usize> = (0..gap).collect();
|
||||||
|
|
||||||
let mut deque = build_node_ids_deque(gap, &runner);
|
let mut deque = build_node_ids_deque::<M, N>(gap, &runner);
|
||||||
|
|
||||||
let simulation_state = SimulationState {
|
let simulation_state = SimulationState {
|
||||||
nodes: Arc::clone(&runner.nodes),
|
nodes: Arc::clone(&runner.nodes),
|
||||||
|
@ -80,7 +78,7 @@ where
|
||||||
let handle = SimulationRunnerHandle {
|
let handle = SimulationRunnerHandle {
|
||||||
stop_tx,
|
stop_tx,
|
||||||
handle: std::thread::spawn(move || {
|
handle: std::thread::spawn(move || {
|
||||||
let p = P::new(runner.stream_settings.settings)?;
|
let p = P::new(runner.stream_settings)?;
|
||||||
scopeguard::defer!(if let Err(e) = p.stop() {
|
scopeguard::defer!(if let Err(e) = p.stop() {
|
||||||
eprintln!("Error stopping producer: {e}");
|
eprintln!("Error stopping producer: {e}");
|
||||||
});
|
});
|
||||||
|
@ -172,14 +170,12 @@ fn choose_random_layer_and_node_id(
|
||||||
(i, *node_id)
|
(i, *node_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_node_ids_deque<M, N, O, P>(
|
fn build_node_ids_deque<M, N>(
|
||||||
gap: usize,
|
gap: usize,
|
||||||
runner: &SimulationRunner<M, N, O, P>,
|
runner: &SimulationRunner<M, N>,
|
||||||
) -> FixedSliceDeque<BTreeSet<NodeId>>
|
) -> FixedSliceDeque<BTreeSet<NodeId>>
|
||||||
where
|
where
|
||||||
N: Node,
|
N: Node,
|
||||||
O: Overlay,
|
|
||||||
P: Producer,
|
|
||||||
{
|
{
|
||||||
// add a +1 so we always have
|
// add a +1 so we always have
|
||||||
let mut deque = FixedSliceDeque::new(gap + 1);
|
let mut deque = FixedSliceDeque::new(gap + 1);
|
||||||
|
|
|
@ -4,12 +4,11 @@ mod layered_runner;
|
||||||
mod sync_runner;
|
mod sync_runner;
|
||||||
|
|
||||||
// std
|
// std
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
// crates
|
// crates
|
||||||
use crate::streaming::{Producer, Subscriber};
|
use crate::streaming::{Producer, StreamSettings, Subscriber};
|
||||||
use crossbeam::channel::Sender;
|
use crossbeam::channel::Sender;
|
||||||
use rand::rngs::SmallRng;
|
use rand::rngs::SmallRng;
|
||||||
use rand::{RngCore, SeedableRng};
|
use rand::{RngCore, SeedableRng};
|
||||||
|
@ -19,9 +18,7 @@ use serde::Serialize;
|
||||||
// internal
|
// internal
|
||||||
use crate::network::Network;
|
use crate::network::Network;
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
use crate::overlay::Overlay;
|
|
||||||
use crate::settings::{RunnerSettings, SimulationSettings};
|
use crate::settings::{RunnerSettings, SimulationSettings};
|
||||||
use crate::streaming::StreamSettings;
|
|
||||||
use crate::warding::{SimulationState, SimulationWard, Ward};
|
use crate::warding::{SimulationState, SimulationWard, Ward};
|
||||||
|
|
||||||
pub struct SimulationRunnerHandle {
|
pub struct SimulationRunnerHandle {
|
||||||
|
@ -81,35 +78,24 @@ where
|
||||||
|
|
||||||
/// Encapsulation solution for the simulations runner
|
/// Encapsulation solution for the simulations runner
|
||||||
/// Holds the network state, the simulating nodes and the simulation settings.
|
/// Holds the network state, the simulating nodes and the simulation settings.
|
||||||
pub struct SimulationRunner<M, N, O, P>
|
pub struct SimulationRunner<M, N>
|
||||||
where
|
where
|
||||||
N: Node,
|
N: Node,
|
||||||
O: Overlay,
|
|
||||||
P: Producer,
|
|
||||||
{
|
{
|
||||||
inner: Arc<RwLock<SimulationRunnerInner<M>>>,
|
inner: Arc<RwLock<SimulationRunnerInner<M>>>,
|
||||||
nodes: Arc<RwLock<Vec<N>>>,
|
nodes: Arc<RwLock<Vec<N>>>,
|
||||||
runner_settings: RunnerSettings,
|
runner_settings: RunnerSettings,
|
||||||
stream_settings: StreamSettings<P::Settings>,
|
stream_settings: StreamSettings,
|
||||||
_overlay: PhantomData<O>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, N: Node, O: Overlay, P: Producer> SimulationRunner<M, N, O, P>
|
impl<M, N: Node> SimulationRunner<M, N>
|
||||||
where
|
where
|
||||||
M: Clone + Send + Sync + 'static,
|
M: Clone + Send + Sync + 'static,
|
||||||
N: Send + Sync + 'static,
|
N: Send + Sync + 'static,
|
||||||
N::Settings: Clone + Send,
|
N::Settings: Clone + Send,
|
||||||
N::State: Serialize,
|
N::State: Serialize,
|
||||||
O::Settings: Clone + Send,
|
|
||||||
P::Subscriber: Send + Sync + 'static,
|
|
||||||
<P::Subscriber as Subscriber>::Record:
|
|
||||||
Send + Sync + 'static + for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(network: Network<M>, nodes: Vec<N>, settings: SimulationSettings) -> Self {
|
||||||
network: Network<M>,
|
|
||||||
nodes: Vec<N>,
|
|
||||||
settings: SimulationSettings<N::Settings, O::Settings, P::Settings>,
|
|
||||||
) -> Self {
|
|
||||||
let seed = settings
|
let seed = settings
|
||||||
.seed
|
.seed
|
||||||
.unwrap_or_else(|| rand::thread_rng().next_u64());
|
.unwrap_or_else(|| rand::thread_rng().next_u64());
|
||||||
|
@ -119,42 +105,46 @@ where
|
||||||
let rng = SmallRng::seed_from_u64(seed);
|
let rng = SmallRng::seed_from_u64(seed);
|
||||||
let nodes = Arc::new(RwLock::new(nodes));
|
let nodes = Arc::new(RwLock::new(nodes));
|
||||||
let SimulationSettings {
|
let SimulationSettings {
|
||||||
network_behaviors: _,
|
|
||||||
regions: _,
|
|
||||||
wards,
|
wards,
|
||||||
overlay_settings: _,
|
overlay_settings: _,
|
||||||
node_settings: _,
|
node_settings: _,
|
||||||
runner_settings,
|
runner_settings,
|
||||||
stream_settings,
|
stream_settings,
|
||||||
node_count: _,
|
node_count: _,
|
||||||
committee_size: _,
|
|
||||||
seed: _,
|
seed: _,
|
||||||
|
views_count: _,
|
||||||
|
leaders_count: _,
|
||||||
|
network_settings: _,
|
||||||
} = settings;
|
} = settings;
|
||||||
Self {
|
Self {
|
||||||
stream_settings,
|
|
||||||
runner_settings,
|
|
||||||
inner: Arc::new(RwLock::new(SimulationRunnerInner {
|
inner: Arc::new(RwLock::new(SimulationRunnerInner {
|
||||||
network,
|
network,
|
||||||
rng,
|
rng,
|
||||||
wards,
|
wards,
|
||||||
})),
|
})),
|
||||||
nodes,
|
nodes,
|
||||||
_overlay: PhantomData,
|
runner_settings,
|
||||||
|
stream_settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simulate(self) -> anyhow::Result<SimulationRunnerHandle> {
|
pub fn simulate<P: Producer>(self) -> anyhow::Result<SimulationRunnerHandle>
|
||||||
|
where
|
||||||
|
P::Subscriber: Send + Sync + 'static,
|
||||||
|
<P::Subscriber as Subscriber>::Record:
|
||||||
|
Send + Sync + 'static + for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
||||||
|
{
|
||||||
match self.runner_settings.clone() {
|
match self.runner_settings.clone() {
|
||||||
RunnerSettings::Sync => sync_runner::simulate::<_, _, _, P>(self),
|
RunnerSettings::Sync => sync_runner::simulate::<_, _, P>(self),
|
||||||
RunnerSettings::Async { chunks } => async_runner::simulate::<_, _, _, P>(self, chunks),
|
RunnerSettings::Async { chunks } => async_runner::simulate::<_, _, P>(self, chunks),
|
||||||
RunnerSettings::Glauber {
|
RunnerSettings::Glauber {
|
||||||
maximum_iterations,
|
maximum_iterations,
|
||||||
update_rate,
|
update_rate,
|
||||||
} => glauber_runner::simulate::<_, _, _, P>(self, update_rate, maximum_iterations),
|
} => glauber_runner::simulate::<_, _, P>(self, update_rate, maximum_iterations),
|
||||||
RunnerSettings::Layered {
|
RunnerSettings::Layered {
|
||||||
rounds_gap,
|
rounds_gap,
|
||||||
distribution,
|
distribution,
|
||||||
} => layered_runner::simulate::<_, _, _, P>(self, rounds_gap, distribution),
|
} => layered_runner::simulate::<_, _, P>(self, rounds_gap, distribution),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,20 @@ use serde::Serialize;
|
||||||
|
|
||||||
use super::{SimulationRunner, SimulationRunnerHandle};
|
use super::{SimulationRunner, SimulationRunnerHandle};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
use crate::overlay::Overlay;
|
|
||||||
use crate::streaming::{Producer, Subscriber};
|
use crate::streaming::{Producer, Subscriber};
|
||||||
use crate::warding::SimulationState;
|
use crate::warding::SimulationState;
|
||||||
use crossbeam::channel::{bounded, select};
|
use crossbeam::channel::{bounded, select};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Simulate with sending the network state to any subscriber
|
/// Simulate with sending the network state to any subscriber
|
||||||
pub fn simulate<M, N: Node, O: Overlay, P: Producer>(
|
pub fn simulate<M, N: Node, P: Producer>(
|
||||||
runner: SimulationRunner<M, N, O, P>,
|
runner: SimulationRunner<M, N>,
|
||||||
) -> anyhow::Result<SimulationRunnerHandle>
|
) -> anyhow::Result<SimulationRunnerHandle>
|
||||||
where
|
where
|
||||||
M: Send + Sync + Clone + 'static,
|
M: Send + Sync + Clone + 'static,
|
||||||
N: Send + Sync + 'static,
|
N: Send + Sync + 'static,
|
||||||
N::Settings: Clone + Send,
|
N::Settings: Clone + Send,
|
||||||
N::State: Serialize,
|
N::State: Serialize,
|
||||||
O::Settings: Clone,
|
|
||||||
P::Subscriber: Send + Sync + 'static,
|
P::Subscriber: Send + Sync + 'static,
|
||||||
<P::Subscriber as Subscriber>::Record:
|
<P::Subscriber as Subscriber>::Record:
|
||||||
Send + Sync + 'static + for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
Send + Sync + 'static + for<'a> TryFrom<&'a SimulationState<N>, Error = anyhow::Error>,
|
||||||
|
@ -33,7 +31,7 @@ where
|
||||||
let handle = SimulationRunnerHandle {
|
let handle = SimulationRunnerHandle {
|
||||||
stop_tx,
|
stop_tx,
|
||||||
handle: std::thread::spawn(move || {
|
handle: std::thread::spawn(move || {
|
||||||
let p = P::new(runner.stream_settings.settings)?;
|
let p = P::new(runner.stream_settings)?;
|
||||||
scopeguard::defer!(if let Err(e) = p.stop() {
|
scopeguard::defer!(if let Err(e) = p.stop() {
|
||||||
eprintln!("Error stopping producer: {e}");
|
eprintln!("Error stopping producer: {e}");
|
||||||
});
|
});
|
||||||
|
@ -79,20 +77,18 @@ mod tests {
|
||||||
network::{
|
network::{
|
||||||
behaviour::NetworkBehaviour,
|
behaviour::NetworkBehaviour,
|
||||||
regions::{Region, RegionsData},
|
regions::{Region, RegionsData},
|
||||||
Network,
|
InMemoryNetworkInterface, Network,
|
||||||
},
|
},
|
||||||
node::{
|
node::{
|
||||||
dummy::{DummyMessage, DummyNetworkInterface, DummyNode, DummySettings},
|
dummy::{DummyMessage, DummyNode},
|
||||||
Node, NodeId, OverlayState, SharedState, ViewOverlay,
|
Node, NodeId, OverlayState, SharedState, ViewOverlay,
|
||||||
},
|
},
|
||||||
output_processors::OutData,
|
|
||||||
overlay::{
|
overlay::{
|
||||||
tree::{TreeOverlay, TreeSettings},
|
tree::{TreeOverlay, TreeSettings},
|
||||||
Overlay,
|
Overlay, SimulationOverlay,
|
||||||
},
|
},
|
||||||
runner::SimulationRunner,
|
runner::SimulationRunner,
|
||||||
settings::SimulationSettings,
|
settings::SimulationSettings,
|
||||||
streaming::naive::{NaiveProducer, NaiveSettings},
|
|
||||||
};
|
};
|
||||||
use crossbeam::channel;
|
use crossbeam::channel;
|
||||||
use rand::rngs::mock::StepRng;
|
use rand::rngs::mock::StepRng;
|
||||||
|
@ -122,7 +118,7 @@ mod tests {
|
||||||
.map(|node_id| {
|
.map(|node_id| {
|
||||||
let (node_message_sender, node_message_receiver) = channel::unbounded();
|
let (node_message_sender, node_message_receiver) = channel::unbounded();
|
||||||
let network_message_receiver = network.connect(*node_id, node_message_receiver);
|
let network_message_receiver = network.connect(*node_id, node_message_receiver);
|
||||||
let network_interface = DummyNetworkInterface::new(
|
let network_interface = InMemoryNetworkInterface::new(
|
||||||
*node_id,
|
*node_id,
|
||||||
node_message_sender,
|
node_message_sender,
|
||||||
network_message_receiver,
|
network_message_receiver,
|
||||||
|
@ -134,16 +130,15 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn runner_one_step() {
|
fn runner_one_step() {
|
||||||
let settings: SimulationSettings<DummySettings, TreeSettings, NaiveSettings> =
|
let settings: SimulationSettings = SimulationSettings {
|
||||||
SimulationSettings {
|
|
||||||
node_count: 10,
|
node_count: 10,
|
||||||
committee_size: 1,
|
overlay_settings: TreeSettings::default().into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut rng = StepRng::new(1, 0);
|
let mut rng = StepRng::new(1, 0);
|
||||||
let node_ids: Vec<NodeId> = (0..settings.node_count).map(Into::into).collect();
|
let node_ids: Vec<NodeId> = (0..settings.node_count).map(Into::into).collect();
|
||||||
let overlay = TreeOverlay::new(settings.overlay_settings.clone());
|
let overlay = TreeOverlay::new(settings.overlay_settings.clone().try_into().unwrap());
|
||||||
let mut network = init_network(&node_ids);
|
let mut network = init_network(&node_ids);
|
||||||
let view = ViewOverlay {
|
let view = ViewOverlay {
|
||||||
leaders: overlay.leaders(&node_ids, 1, &mut rng).collect(),
|
leaders: overlay.leaders(&node_ids, 1, &mut rng).collect(),
|
||||||
|
@ -151,11 +146,12 @@ mod tests {
|
||||||
};
|
};
|
||||||
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
||||||
all_nodes: node_ids.clone(),
|
all_nodes: node_ids.clone(),
|
||||||
|
overlay: SimulationOverlay::Tree(overlay),
|
||||||
overlays: BTreeMap::from([(0, view.clone()), (1, view)]),
|
overlays: BTreeMap::from([(0, view.clone()), (1, view)]),
|
||||||
}));
|
}));
|
||||||
let nodes = init_dummy_nodes(&node_ids, &mut network, overlay_state);
|
let nodes = init_dummy_nodes(&node_ids, &mut network, overlay_state);
|
||||||
|
|
||||||
let runner: SimulationRunner<DummyMessage, DummyNode, TreeOverlay, NaiveProducer<OutData>> =
|
let runner: SimulationRunner<DummyMessage, DummyNode> =
|
||||||
SimulationRunner::new(network, nodes, settings);
|
SimulationRunner::new(network, nodes, settings);
|
||||||
let mut nodes = runner.nodes.write().unwrap();
|
let mut nodes = runner.nodes.write().unwrap();
|
||||||
runner.inner.write().unwrap().step(&mut nodes);
|
runner.inner.write().unwrap().step(&mut nodes);
|
||||||
|
@ -169,16 +165,14 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn runner_send_receive() {
|
fn runner_send_receive() {
|
||||||
let settings: SimulationSettings<DummySettings, TreeSettings, NaiveSettings> =
|
let settings: SimulationSettings = SimulationSettings {
|
||||||
SimulationSettings {
|
|
||||||
node_count: 10,
|
node_count: 10,
|
||||||
committee_size: 1,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut rng = StepRng::new(1, 0);
|
let mut rng = StepRng::new(1, 0);
|
||||||
let node_ids: Vec<NodeId> = (0..settings.node_count).map(Into::into).collect();
|
let node_ids: Vec<NodeId> = (0..settings.node_count).map(Into::into).collect();
|
||||||
let overlay = TreeOverlay::new(settings.overlay_settings.clone());
|
let overlay = TreeOverlay::new(settings.overlay_settings.clone().try_into().unwrap());
|
||||||
let mut network = init_network(&node_ids);
|
let mut network = init_network(&node_ids);
|
||||||
let view = ViewOverlay {
|
let view = ViewOverlay {
|
||||||
leaders: overlay.leaders(&node_ids, 1, &mut rng).collect(),
|
leaders: overlay.leaders(&node_ids, 1, &mut rng).collect(),
|
||||||
|
@ -186,6 +180,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
let overlay_state = Arc::new(RwLock::new(OverlayState {
|
||||||
all_nodes: node_ids.clone(),
|
all_nodes: node_ids.clone(),
|
||||||
|
overlay: SimulationOverlay::Tree(overlay),
|
||||||
overlays: BTreeMap::from([
|
overlays: BTreeMap::from([
|
||||||
(0, view.clone()),
|
(0, view.clone()),
|
||||||
(1, view.clone()),
|
(1, view.clone()),
|
||||||
|
@ -202,7 +197,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
network.collect_messages();
|
network.collect_messages();
|
||||||
|
|
||||||
let runner: SimulationRunner<DummyMessage, DummyNode, TreeOverlay, NaiveProducer<OutData>> =
|
let runner: SimulationRunner<DummyMessage, DummyNode> =
|
||||||
SimulationRunner::new(network, nodes, settings);
|
SimulationRunner::new(network, nodes, settings);
|
||||||
|
|
||||||
let mut nodes = runner.nodes.write().unwrap();
|
let mut nodes = runner.nodes.write().unwrap();
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use crate::network::regions::Region;
|
use crate::network::NetworkSettings;
|
||||||
use crate::node::StepTime;
|
use crate::overlay::OverlaySettings;
|
||||||
use crate::streaming::StreamSettings;
|
use crate::streaming::StreamSettings;
|
||||||
use crate::warding::Ward;
|
use crate::warding::Ward;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Default)]
|
#[derive(Clone, Debug, Deserialize, Default)]
|
||||||
pub enum RunnerSettings {
|
pub enum RunnerSettings {
|
||||||
|
@ -22,17 +21,24 @@ pub enum RunnerSettings {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Default)]
|
||||||
|
pub enum NodeSettings {
|
||||||
|
Carnot,
|
||||||
|
#[default]
|
||||||
|
Dummy,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize)]
|
#[derive(Default, Deserialize)]
|
||||||
pub struct SimulationSettings<N, O, P> {
|
pub struct SimulationSettings {
|
||||||
pub network_behaviors: HashMap<(Region, Region), StepTime>,
|
|
||||||
pub regions: Vec<Region>,
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub wards: Vec<Ward>,
|
pub wards: Vec<Ward>,
|
||||||
pub overlay_settings: O,
|
pub network_settings: NetworkSettings,
|
||||||
pub node_settings: N,
|
pub overlay_settings: OverlaySettings,
|
||||||
|
pub node_settings: NodeSettings,
|
||||||
pub runner_settings: RunnerSettings,
|
pub runner_settings: RunnerSettings,
|
||||||
pub stream_settings: StreamSettings<P>,
|
pub stream_settings: StreamSettings,
|
||||||
pub node_count: usize,
|
pub node_count: usize,
|
||||||
pub committee_size: usize,
|
pub views_count: usize,
|
||||||
|
pub leaders_count: usize,
|
||||||
pub seed: Option<u64>,
|
pub seed: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,52 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::{
|
||||||
|
any::Any,
|
||||||
|
io::stdout,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{Producer, Receivers, Subscriber};
|
use super::{Producer, Receivers, StreamSettings, Subscriber};
|
||||||
use arc_swap::ArcSwapOption;
|
use arc_swap::ArcSwapOption;
|
||||||
use crossbeam::channel::{bounded, unbounded, Sender};
|
use crossbeam::channel::{bounded, unbounded, Sender};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default, Deserialize)]
|
||||||
pub struct IOStreamSettings<W = std::io::Stdout> {
|
pub struct IOStreamSettings {
|
||||||
pub writer: W,
|
pub writer_type: WriteType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for IOStreamSettings {
|
#[derive(Debug, Default, Deserialize)]
|
||||||
fn default() -> Self {
|
pub enum WriteType {
|
||||||
Self {
|
#[default]
|
||||||
writer: std::io::stdout(),
|
Stdout,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ToWriter<W: std::io::Write + Send + Sync + 'static> {
|
||||||
|
fn to_writer(&self) -> Result<W, String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W: std::io::Write + Send + Sync + 'static> ToWriter<W> for WriteType {
|
||||||
|
fn to_writer(&self) -> Result<W, String> {
|
||||||
|
match self {
|
||||||
|
WriteType::Stdout => {
|
||||||
|
let stdout = Box::new(stdout());
|
||||||
|
let boxed_any = Box::new(stdout) as Box<dyn Any + Send + Sync>;
|
||||||
|
boxed_any
|
||||||
|
.downcast::<W>()
|
||||||
|
.map(|boxed| *boxed)
|
||||||
|
.map_err(|_| "Writer type mismatch".to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for IOStreamSettings {
|
impl TryFrom<StreamSettings> for IOStreamSettings {
|
||||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
type Error = String;
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
fn try_from(settings: StreamSettings) -> Result<Self, Self::Error> {
|
||||||
{
|
match settings {
|
||||||
Ok(Self {
|
StreamSettings::IO(settings) => Ok(settings),
|
||||||
writer: std::io::stdout(),
|
_ => Err("io settings can't be created".into()),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,21 +63,28 @@ where
|
||||||
W: std::io::Write + Send + Sync + 'static,
|
W: std::io::Write + Send + Sync + 'static,
|
||||||
R: Serialize + Send + Sync + 'static,
|
R: Serialize + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
type Settings = IOStreamSettings<W>;
|
type Settings = IOStreamSettings;
|
||||||
|
|
||||||
type Subscriber = IOSubscriber<W, R>;
|
type Subscriber = IOSubscriber<W, R>;
|
||||||
|
|
||||||
fn new(settings: Self::Settings) -> anyhow::Result<Self>
|
fn new(settings: StreamSettings) -> anyhow::Result<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
let settings: IOStreamSettings = settings
|
||||||
|
.try_into()
|
||||||
|
.expect("io settings from stream settings");
|
||||||
|
let writer = settings
|
||||||
|
.writer_type
|
||||||
|
.to_writer()
|
||||||
|
.expect("writer from writer type");
|
||||||
let (sender, recv) = unbounded();
|
let (sender, recv) = unbounded();
|
||||||
let (stop_tx, stop_rx) = bounded(1);
|
let (stop_tx, stop_rx) = bounded(1);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sender,
|
sender,
|
||||||
recvs: ArcSwapOption::from(Some(Arc::new(Receivers { stop_rx, recv }))),
|
recvs: ArcSwapOption::from(Some(Arc::new(Receivers { stop_rx, recv }))),
|
||||||
stop_tx,
|
stop_tx,
|
||||||
writer: ArcSwapOption::from(Some(Arc::new(Mutex::new(settings.writer)))),
|
writer: ArcSwapOption::from(Some(Arc::new(Mutex::new(writer)))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,9 +167,7 @@ mod tests {
|
||||||
Network,
|
Network,
|
||||||
},
|
},
|
||||||
node::{dummy_streaming::DummyStreamingNode, Node, NodeId},
|
node::{dummy_streaming::DummyStreamingNode, Node, NodeId},
|
||||||
overlay::tree::TreeOverlay,
|
|
||||||
runner::SimulationRunner,
|
runner::SimulationRunner,
|
||||||
streaming::{StreamSettings, StreamType},
|
|
||||||
warding::SimulationState,
|
warding::SimulationState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -169,12 +195,6 @@ mod tests {
|
||||||
fn test_streaming() {
|
fn test_streaming() {
|
||||||
let simulation_settings = crate::settings::SimulationSettings {
|
let simulation_settings = crate::settings::SimulationSettings {
|
||||||
seed: Some(1),
|
seed: Some(1),
|
||||||
stream_settings: StreamSettings {
|
|
||||||
ty: StreamType::IO,
|
|
||||||
settings: IOStreamSettings {
|
|
||||||
writer: std::io::stdout(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -231,14 +251,10 @@ mod tests {
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
});
|
});
|
||||||
let simulation_runner: SimulationRunner<
|
let simulation_runner: SimulationRunner<(), DummyStreamingNode<()>> =
|
||||||
(),
|
SimulationRunner::new(network, nodes, simulation_settings);
|
||||||
DummyStreamingNode<()>,
|
|
||||||
TreeOverlay,
|
|
||||||
IOProducer<std::io::Stdout, IORecord>,
|
|
||||||
> = SimulationRunner::new(network, nodes, simulation_settings);
|
|
||||||
simulation_runner
|
simulation_runner
|
||||||
.simulate()
|
.simulate::<IOProducer<std::io::Stdout, IORecord>>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.stop_after(Duration::from_millis(100))
|
.stop_after(Duration::from_millis(100))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crossbeam::channel::Receiver;
|
use crossbeam::channel::Receiver;
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod naive;
|
pub mod naive;
|
||||||
|
@ -45,18 +45,24 @@ impl<'de> serde::Deserialize<'de> for StreamType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, serde::Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct StreamSettings<S> {
|
pub enum StreamSettings {
|
||||||
#[serde(rename = "type")]
|
Naive(naive::NaiveSettings),
|
||||||
pub ty: StreamType,
|
IO(io::IOStreamSettings),
|
||||||
pub settings: S,
|
Polars(polars::PolarsSettings),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for StreamSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::IO(Default::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Producer: Send + Sync + 'static {
|
pub trait Producer: Send + Sync + 'static {
|
||||||
type Settings: Send;
|
type Settings: Send;
|
||||||
type Subscriber: Subscriber;
|
type Subscriber: Subscriber;
|
||||||
|
|
||||||
fn new(settings: Self::Settings) -> anyhow::Result<Self>
|
fn new(settings: StreamSettings) -> anyhow::Result<Self>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Producer, Receivers, Subscriber};
|
use super::{Producer, Receivers, StreamSettings, Subscriber};
|
||||||
use arc_swap::ArcSwapOption;
|
use arc_swap::ArcSwapOption;
|
||||||
use crossbeam::channel::{bounded, unbounded, Sender};
|
use crossbeam::channel::{bounded, unbounded, Sender};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -15,6 +15,17 @@ pub struct NaiveSettings {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<StreamSettings> for NaiveSettings {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(settings: StreamSettings) -> Result<Self, Self::Error> {
|
||||||
|
match settings {
|
||||||
|
StreamSettings::Naive(settings) => Ok(settings),
|
||||||
|
_ => Err("naive settings can't be created".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for NaiveSettings {
|
impl Default for NaiveSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut tmp = std::env::temp_dir();
|
let mut tmp = std::env::temp_dir();
|
||||||
|
@ -40,10 +51,11 @@ where
|
||||||
|
|
||||||
type Subscriber = NaiveSubscriber<R>;
|
type Subscriber = NaiveSubscriber<R>;
|
||||||
|
|
||||||
fn new(settings: Self::Settings) -> anyhow::Result<Self>
|
fn new(settings: StreamSettings) -> anyhow::Result<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
let settings = settings.try_into().expect("naive settings");
|
||||||
let (sender, recv) = unbounded();
|
let (sender, recv) = unbounded();
|
||||||
let (stop_tx, stop_rx) = bounded(1);
|
let (stop_tx, stop_rx) = bounded(1);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -138,7 +150,6 @@ mod tests {
|
||||||
Network,
|
Network,
|
||||||
},
|
},
|
||||||
node::{dummy_streaming::DummyStreamingNode, Node, NodeId},
|
node::{dummy_streaming::DummyStreamingNode, Node, NodeId},
|
||||||
overlay::tree::TreeOverlay,
|
|
||||||
runner::SimulationRunner,
|
runner::SimulationRunner,
|
||||||
warding::SimulationState,
|
warding::SimulationState,
|
||||||
};
|
};
|
||||||
|
@ -225,13 +236,11 @@ mod tests {
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
});
|
});
|
||||||
let simulation_runner: SimulationRunner<
|
let simulation_runner: SimulationRunner<(), DummyStreamingNode<()>> =
|
||||||
(),
|
SimulationRunner::new(network, nodes, simulation_settings);
|
||||||
DummyStreamingNode<()>,
|
|
||||||
TreeOverlay,
|
|
||||||
NaiveProducer<NaiveRecord>,
|
|
||||||
> = SimulationRunner::new(network, nodes, simulation_settings);
|
|
||||||
|
|
||||||
simulation_runner.simulate().unwrap();
|
simulation_runner
|
||||||
|
.simulate::<NaiveProducer<NaiveRecord>>()
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use std::{
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Producer, Receivers, Subscriber};
|
use super::{Producer, Receivers, StreamSettings, Subscriber};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize)]
|
#[derive(Debug, Clone, Copy, Serialize)]
|
||||||
pub enum PolarsFormat {
|
pub enum PolarsFormat {
|
||||||
|
@ -50,6 +50,17 @@ pub struct PolarsSettings {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<StreamSettings> for PolarsSettings {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(settings: StreamSettings) -> Result<Self, Self::Error> {
|
||||||
|
match settings {
|
||||||
|
StreamSettings::Polars(settings) => Ok(settings),
|
||||||
|
_ => Err("polars settings can't be created".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PolarsProducer<R> {
|
pub struct PolarsProducer<R> {
|
||||||
sender: Sender<R>,
|
sender: Sender<R>,
|
||||||
|
@ -66,10 +77,11 @@ where
|
||||||
|
|
||||||
type Subscriber = PolarsSubscriber<R>;
|
type Subscriber = PolarsSubscriber<R>;
|
||||||
|
|
||||||
fn new(settings: Self::Settings) -> anyhow::Result<Self>
|
fn new(settings: StreamSettings) -> anyhow::Result<Self>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
let settings = settings.try_into().expect("polars settings");
|
||||||
let (sender, recv) = unbounded();
|
let (sender, recv) = unbounded();
|
||||||
let (stop_tx, stop_rx) = bounded(1);
|
let (stop_tx, stop_rx) = bounded(1);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
Loading…
Reference in New Issue