Simulations overlay topo info (#479)
* Missing json feature for building standalone simapp * Move dummy sim overlay to tests module * OverlayInfoExt in simulation app * Dump overlay info in simapp
This commit is contained in:
parent
1553f29bd9
commit
54dd96dfff
@ -11,7 +11,9 @@ path = "src/bin/app/main.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
blake2 = "0.10"
|
||||
bls-signatures = "0.14"
|
||||
digest = "0.10"
|
||||
csv = "1"
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
ctrlc = "3.4"
|
||||
@ -36,7 +38,7 @@ serde_with = "2.3"
|
||||
serde_json = "1.0"
|
||||
thiserror = "1"
|
||||
tracing = { version = "0.1", default-features = false, features = ["log", "attributes"] }
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "tracing-log"]}
|
||||
tracing-subscriber = { version = "0.3", features = ["json", "env-filter", "tracing-log"]}
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
getrandom = { version = "0.2", features = ["js"] }
|
||||
|
@ -44,6 +44,8 @@ pub struct SimulationApp {
|
||||
log_format: log::LogFormat,
|
||||
#[clap(long, default_value = "stdout")]
|
||||
log_to: log::LogOutput,
|
||||
#[clap(long)]
|
||||
dump_overlay_info: bool,
|
||||
}
|
||||
|
||||
impl SimulationApp {
|
||||
@ -53,6 +55,7 @@ impl SimulationApp {
|
||||
stream_type,
|
||||
log_format: _,
|
||||
log_to: _,
|
||||
dump_overlay_info,
|
||||
} = self;
|
||||
let simulation_settings: SimulationSettings = load_json_from_file(&input_settings)?;
|
||||
|
||||
@ -74,6 +77,18 @@ impl SimulationApp {
|
||||
|
||||
let ids = node_ids.clone();
|
||||
let network = Arc::new(Mutex::new(Network::new(regions_data, seed)));
|
||||
|
||||
if dump_overlay_info {
|
||||
dump_json_to_file(
|
||||
Path::new("overlay_info.json"),
|
||||
&overlay_node::overlay_info(
|
||||
node_ids.clone(),
|
||||
node_ids.first().copied().unwrap(),
|
||||
&simulation_settings.overlay_settings,
|
||||
),
|
||||
)?;
|
||||
}
|
||||
|
||||
let nodes: Vec<BoxedNode<CarnotSettings, CarnotState>> = node_ids
|
||||
.par_iter()
|
||||
.copied()
|
||||
@ -206,6 +221,11 @@ fn load_json_from_file<T: DeserializeOwned>(path: &Path) -> anyhow::Result<T> {
|
||||
Ok(serde_json::from_reader(f)?)
|
||||
}
|
||||
|
||||
fn dump_json_to_file<T: Serialize>(path: &Path, data: &T) -> anyhow::Result<()> {
|
||||
let f = File::create(path).map_err(Box::new)?;
|
||||
Ok(serde_json::to_writer(f, data)?)
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let app: SimulationApp = SimulationApp::parse();
|
||||
log::config_tracing(app.log_format, &app.log_to);
|
||||
|
@ -1,9 +1,12 @@
|
||||
use consensus_engine::overlay::{BranchOverlay, RandomBeaconState};
|
||||
use consensus_engine::overlay::{BranchOverlay, FisherYatesShuffle, RandomBeaconState};
|
||||
use consensus_engine::Overlay;
|
||||
use consensus_engine::{
|
||||
overlay::{FlatOverlay, FreezeMembership, RoundRobin, TreeOverlay},
|
||||
NodeId,
|
||||
};
|
||||
use rand::Rng;
|
||||
use simulations::overlay::overlay_info::{OverlayInfo, OverlayInfoExt};
|
||||
use simulations::settings::OverlaySettings;
|
||||
use simulations::{
|
||||
network::InMemoryNetworkInterface,
|
||||
node::carnot::{messages::CarnotMessage, CarnotNode, CarnotSettings, CarnotState},
|
||||
@ -11,6 +14,46 @@ use simulations::{
|
||||
settings::SimulationSettings,
|
||||
};
|
||||
|
||||
pub fn overlay_info(
|
||||
nodes: Vec<NodeId>,
|
||||
leader: NodeId,
|
||||
overlay_settings: &OverlaySettings,
|
||||
) -> OverlayInfo {
|
||||
match &overlay_settings {
|
||||
simulations::settings::OverlaySettings::Flat => {
|
||||
FlatOverlay::<RoundRobin, FisherYatesShuffle>::new(
|
||||
consensus_engine::overlay::FlatOverlaySettings {
|
||||
nodes: nodes.to_vec(),
|
||||
leader: RoundRobin::new(),
|
||||
leader_super_majority_threshold: None,
|
||||
},
|
||||
)
|
||||
.info()
|
||||
}
|
||||
simulations::settings::OverlaySettings::Tree(tree_settings) => {
|
||||
TreeOverlay::new(consensus_engine::overlay::TreeOverlaySettings {
|
||||
nodes,
|
||||
current_leader: leader,
|
||||
number_of_committees: tree_settings.number_of_committees,
|
||||
leader: RoundRobin::new(),
|
||||
committee_membership: RandomBeaconState::initial_sad_from_entropy([0; 32]),
|
||||
super_majority_threshold: None,
|
||||
})
|
||||
.info()
|
||||
}
|
||||
simulations::settings::OverlaySettings::Branch(branch_settings) => {
|
||||
BranchOverlay::new(consensus_engine::overlay::BranchOverlaySettings {
|
||||
nodes,
|
||||
current_leader: leader,
|
||||
branch_depth: branch_settings.branch_depth,
|
||||
leader: RoundRobin::new(),
|
||||
committee_membership: RandomBeaconState::initial_sad_from_entropy([0; 32]),
|
||||
})
|
||||
.info()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_overlay_node<R: Rng>(
|
||||
node_id: NodeId,
|
||||
nodes: Vec<NodeId>,
|
||||
|
@ -451,7 +451,7 @@ mod tests {
|
||||
dummy::{get_child_nodes, get_parent_nodes, get_roles, DummyRole},
|
||||
Node, NodeId, NodeIdExt, OverlayState, SharedState, SimulationOverlay, ViewOverlay,
|
||||
},
|
||||
overlay::{
|
||||
overlay::tests::{
|
||||
tree::{TreeOverlay, TreeSettings},
|
||||
Overlay,
|
||||
},
|
||||
|
@ -16,7 +16,7 @@ use std::{
|
||||
use parking_lot::RwLock;
|
||||
use serde::{Deserialize, Serialize};
|
||||
// internal
|
||||
use crate::overlay::{Layout, OverlaySettings, SimulationOverlay};
|
||||
use crate::overlay::tests::{Layout, OverlaySettings, SimulationOverlay};
|
||||
|
||||
pub use consensus_engine::NodeId;
|
||||
|
||||
|
@ -1,178 +1,2 @@
|
||||
pub mod flat;
|
||||
pub mod tree;
|
||||
|
||||
// std
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
// crates
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
// internal
|
||||
use crate::node::{CommitteeId, NodeId};
|
||||
|
||||
use self::tree::TreeSettings;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Committee {
|
||||
pub nodes: BTreeSet<NodeId>,
|
||||
}
|
||||
|
||||
impl Committee {
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.nodes.len() == 0
|
||||
}
|
||||
}
|
||||
|
||||
pub type Leaders = BTreeSet<NodeId>;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Layout {
|
||||
pub committees: HashMap<CommitteeId, Committee>,
|
||||
pub from_committee: HashMap<NodeId, CommitteeId>,
|
||||
pub parent: HashMap<CommitteeId, CommitteeId>,
|
||||
pub children: HashMap<CommitteeId, Vec<CommitteeId>>,
|
||||
pub layers: HashMap<CommitteeId, Vec<CommitteeId>>,
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub fn new(
|
||||
committees: HashMap<CommitteeId, Committee>,
|
||||
parent: HashMap<CommitteeId, CommitteeId>,
|
||||
children: HashMap<CommitteeId, Vec<CommitteeId>>,
|
||||
layers: HashMap<CommitteeId, Vec<CommitteeId>>,
|
||||
) -> Self {
|
||||
let from_committee = committees
|
||||
.iter()
|
||||
.flat_map(|(&committee_id, committee)| {
|
||||
committee
|
||||
.nodes
|
||||
.iter()
|
||||
.map(move |&node_id| (node_id, committee_id))
|
||||
})
|
||||
.collect();
|
||||
Self {
|
||||
committees,
|
||||
from_committee,
|
||||
parent,
|
||||
children,
|
||||
layers,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn committee(&self, node_id: NodeId) -> Option<CommitteeId> {
|
||||
self.from_committee.get(&node_id).copied()
|
||||
}
|
||||
|
||||
pub fn committee_nodes(&self, committee_id: CommitteeId) -> &Committee {
|
||||
&self.committees[&committee_id]
|
||||
}
|
||||
|
||||
pub fn parent(&self, committee_id: CommitteeId) -> Option<CommitteeId> {
|
||||
self.parent.get(&committee_id).copied()
|
||||
}
|
||||
|
||||
pub fn parent_nodes(&self, committee_id: CommitteeId) -> Option<Committee> {
|
||||
self.parent(committee_id)
|
||||
.map(|c| self.committees[&c].clone())
|
||||
}
|
||||
|
||||
pub fn children(&self, committee_id: CommitteeId) -> Option<&Vec<CommitteeId>> {
|
||||
self.children.get(&committee_id)
|
||||
}
|
||||
|
||||
pub fn children_nodes(&self, committee_id: CommitteeId) -> Vec<&Committee> {
|
||||
self.children(committee_id)
|
||||
.iter()
|
||||
.flat_map(|&committees| committees.iter().map(|c| &self.committees[c]))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn node_ids(&self) -> impl Iterator<Item = NodeId> + '_ {
|
||||
self.from_committee.keys().copied()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SimulationOverlay {
|
||||
Flat(flat::FlatOverlay),
|
||||
Tree(tree::TreeOverlay),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, 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 leaders<R: Rng>(
|
||||
&self,
|
||||
nodes: &[NodeId],
|
||||
size: usize,
|
||||
rng: &mut R,
|
||||
) -> Box<dyn Iterator<Item = NodeId>>;
|
||||
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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub mod overlay_info;
|
||||
pub mod tests;
|
||||
|
181
simulations/src/overlay/overlay_info.rs
Normal file
181
simulations/src/overlay/overlay_info.rs
Normal file
@ -0,0 +1,181 @@
|
||||
use consensus_engine::{CommitteeId, NodeId, Overlay};
|
||||
use serde::Serialize;
|
||||
use std::collections::{BTreeSet, HashMap, VecDeque};
|
||||
|
||||
pub type Blake2bU32 = blake2::Blake2b<digest::typenum::U32>;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct OverlayInfo {
|
||||
pub committees: BTreeSet<CommitteeId>,
|
||||
pub committee_sizes: HashMap<CommitteeId, usize>,
|
||||
pub edges: Vec<(CommitteeId, CommitteeId)>,
|
||||
pub next_leader: NodeId,
|
||||
pub root_id: CommitteeId,
|
||||
}
|
||||
|
||||
pub trait OverlayInfoExt {
|
||||
fn info(&self) -> OverlayInfo;
|
||||
}
|
||||
|
||||
impl<T: Overlay> OverlayInfoExt for T {
|
||||
fn info(&self) -> OverlayInfo {
|
||||
let mut committees = BTreeSet::new();
|
||||
let mut edges = Vec::new();
|
||||
let mut committee_sizes = HashMap::new();
|
||||
|
||||
let next_leader = self.next_leader();
|
||||
let root = self.root_committee();
|
||||
let root_id = root.id::<Blake2bU32>();
|
||||
committees.insert(root_id);
|
||||
committee_sizes.insert(root_id, root.len());
|
||||
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(root);
|
||||
|
||||
while let Some(current_committee) = queue.pop_front() {
|
||||
let current_id = current_committee.id::<Blake2bU32>();
|
||||
|
||||
if let Some(committee_node) = current_committee.iter().next() {
|
||||
for child in self.child_committees(*committee_node) {
|
||||
let child_id = child.id::<Blake2bU32>();
|
||||
committees.insert(child_id);
|
||||
committee_sizes.insert(child_id, child.len());
|
||||
edges.push((current_id, child_id));
|
||||
queue.push_back(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OverlayInfo {
|
||||
committees,
|
||||
committee_sizes,
|
||||
edges,
|
||||
next_leader,
|
||||
root_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use consensus_engine::{
|
||||
overlay::{
|
||||
BranchOverlay, BranchOverlaySettings, FisherYatesShuffle, RoundRobin, TreeOverlay,
|
||||
TreeOverlaySettings,
|
||||
},
|
||||
NodeId, Overlay,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
const ENTROPY: [u8; 32] = [0; 32];
|
||||
|
||||
#[test]
|
||||
fn tree_overlay_info() {
|
||||
let nodes: Vec<_> = (0..7).map(|i| NodeId::new([i as u8; 32])).collect();
|
||||
let overlay = TreeOverlay::new(TreeOverlaySettings {
|
||||
nodes: nodes.clone(),
|
||||
current_leader: nodes[0],
|
||||
number_of_committees: 3,
|
||||
leader: RoundRobin::new(),
|
||||
committee_membership: FisherYatesShuffle::new(ENTROPY),
|
||||
super_majority_threshold: None,
|
||||
});
|
||||
|
||||
let root_committee = overlay.root_committee();
|
||||
let root_node = root_committee.iter().next().unwrap();
|
||||
let child_committees = overlay.child_committees(*root_node);
|
||||
let child1 = child_committees[0].clone();
|
||||
let child2 = child_committees[1].clone();
|
||||
|
||||
let info = overlay.info();
|
||||
let info_children: Vec<&(CommitteeId, CommitteeId)> = info
|
||||
.edges
|
||||
.iter()
|
||||
.filter(|(p, _)| *p == info.root_id)
|
||||
.collect();
|
||||
|
||||
assert_eq!(info.committees.len(), 3);
|
||||
assert_eq!(root_committee.id::<Blake2bU32>(), info.root_id);
|
||||
|
||||
let mut info_child_iter = info_children.iter();
|
||||
let info_child1 = info_child_iter.next().map(|(_, c)| c).unwrap();
|
||||
let info_child2 = info_child_iter.next().map(|(_, c)| c).unwrap();
|
||||
|
||||
assert_eq!(child1.id::<Blake2bU32>(), *info_child1);
|
||||
assert_eq!(child2.id::<Blake2bU32>(), *info_child2);
|
||||
|
||||
assert_eq!(
|
||||
child1.len(),
|
||||
*info.committee_sizes.get(info_child1).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
child2.len(),
|
||||
*info.committee_sizes.get(info_child2).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_overlay_info() {
|
||||
let nodes: Vec<_> = (0..7).map(|i| NodeId::new([i as u8; 32])).collect();
|
||||
let overlay = BranchOverlay::new(BranchOverlaySettings {
|
||||
nodes: nodes.clone(),
|
||||
current_leader: nodes[0],
|
||||
branch_depth: 3,
|
||||
leader: RoundRobin::new(),
|
||||
committee_membership: FisherYatesShuffle::new(ENTROPY),
|
||||
});
|
||||
|
||||
let root_committee = overlay.root_committee();
|
||||
let root_node = root_committee.iter().next().unwrap();
|
||||
|
||||
let info = overlay.info();
|
||||
assert_eq!(info.committees.len(), 3);
|
||||
assert_eq!(root_committee.id::<Blake2bU32>(), info.root_id);
|
||||
|
||||
assert_eq!(overlay.child_committees(*root_node).len(), 1);
|
||||
let layer1 = overlay
|
||||
.child_committees(*root_node)
|
||||
.first()
|
||||
.unwrap()
|
||||
.clone();
|
||||
let layer1_node = layer1.iter().next().unwrap();
|
||||
|
||||
assert_eq!(overlay.child_committees(*layer1_node).len(), 1);
|
||||
let info_layer1: Vec<&(CommitteeId, CommitteeId)> = info
|
||||
.edges
|
||||
.iter()
|
||||
.filter(|(p, _)| *p == info.root_id)
|
||||
.collect();
|
||||
assert_eq!(info_layer1.len(), 1);
|
||||
let info_layer1 = info_layer1.first().map(|(_, c)| c).unwrap();
|
||||
|
||||
assert_eq!(layer1.id::<Blake2bU32>(), *info_layer1);
|
||||
assert_eq!(
|
||||
layer1.len(),
|
||||
*info.committee_sizes.get(info_layer1).unwrap()
|
||||
);
|
||||
|
||||
let layer2 = overlay
|
||||
.child_committees(*layer1_node)
|
||||
.first()
|
||||
.unwrap()
|
||||
.clone();
|
||||
let layer2_node = layer2.iter().next().unwrap();
|
||||
assert_eq!(overlay.child_committees(*layer2_node).len(), 0);
|
||||
|
||||
let info_layer2: Vec<&(CommitteeId, CommitteeId)> = info
|
||||
.edges
|
||||
.iter()
|
||||
.filter(|(p, _)| *p == layer1.id::<Blake2bU32>())
|
||||
.collect();
|
||||
|
||||
assert_eq!(info_layer2.len(), 1);
|
||||
let info_layer2 = info_layer2.first().map(|(_, c)| c).unwrap();
|
||||
|
||||
assert_eq!(layer2.id::<Blake2bU32>(), *info_layer2);
|
||||
assert_eq!(
|
||||
layer2.len(),
|
||||
*info.committee_sizes.get(info_layer2).unwrap()
|
||||
);
|
||||
}
|
||||
}
|
@ -4,9 +4,8 @@ use consensus_engine::NodeId;
|
||||
use rand::prelude::IteratorRandom;
|
||||
use rand::Rng;
|
||||
// internal
|
||||
use super::Overlay;
|
||||
use super::{Committee, Layout, Overlay};
|
||||
use crate::node::NodeIdExt;
|
||||
use crate::overlay::{Committee, Layout};
|
||||
|
||||
pub struct FlatOverlay;
|
||||
impl FlatOverlay {
|
178
simulations/src/overlay/tests/mod.rs
Normal file
178
simulations/src/overlay/tests/mod.rs
Normal file
@ -0,0 +1,178 @@
|
||||
pub mod flat;
|
||||
pub mod tree;
|
||||
|
||||
// std
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
// crates
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
// internal
|
||||
use crate::node::{CommitteeId, NodeId};
|
||||
|
||||
use self::tree::TreeSettings;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Committee {
|
||||
pub nodes: BTreeSet<NodeId>,
|
||||
}
|
||||
|
||||
impl Committee {
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.nodes.len() == 0
|
||||
}
|
||||
}
|
||||
|
||||
pub type Leaders = BTreeSet<NodeId>;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Layout {
|
||||
pub committees: HashMap<CommitteeId, Committee>,
|
||||
pub from_committee: HashMap<NodeId, CommitteeId>,
|
||||
pub parent: HashMap<CommitteeId, CommitteeId>,
|
||||
pub children: HashMap<CommitteeId, Vec<CommitteeId>>,
|
||||
pub layers: HashMap<CommitteeId, Vec<CommitteeId>>,
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub fn new(
|
||||
committees: HashMap<CommitteeId, Committee>,
|
||||
parent: HashMap<CommitteeId, CommitteeId>,
|
||||
children: HashMap<CommitteeId, Vec<CommitteeId>>,
|
||||
layers: HashMap<CommitteeId, Vec<CommitteeId>>,
|
||||
) -> Self {
|
||||
let from_committee = committees
|
||||
.iter()
|
||||
.flat_map(|(&committee_id, committee)| {
|
||||
committee
|
||||
.nodes
|
||||
.iter()
|
||||
.map(move |&node_id| (node_id, committee_id))
|
||||
})
|
||||
.collect();
|
||||
Self {
|
||||
committees,
|
||||
from_committee,
|
||||
parent,
|
||||
children,
|
||||
layers,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn committee(&self, node_id: NodeId) -> Option<CommitteeId> {
|
||||
self.from_committee.get(&node_id).copied()
|
||||
}
|
||||
|
||||
pub fn committee_nodes(&self, committee_id: CommitteeId) -> &Committee {
|
||||
&self.committees[&committee_id]
|
||||
}
|
||||
|
||||
pub fn parent(&self, committee_id: CommitteeId) -> Option<CommitteeId> {
|
||||
self.parent.get(&committee_id).copied()
|
||||
}
|
||||
|
||||
pub fn parent_nodes(&self, committee_id: CommitteeId) -> Option<Committee> {
|
||||
self.parent(committee_id)
|
||||
.map(|c| self.committees[&c].clone())
|
||||
}
|
||||
|
||||
pub fn children(&self, committee_id: CommitteeId) -> Option<&Vec<CommitteeId>> {
|
||||
self.children.get(&committee_id)
|
||||
}
|
||||
|
||||
pub fn children_nodes(&self, committee_id: CommitteeId) -> Vec<&Committee> {
|
||||
self.children(committee_id)
|
||||
.iter()
|
||||
.flat_map(|&committees| committees.iter().map(|c| &self.committees[c]))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn node_ids(&self) -> impl Iterator<Item = NodeId> + '_ {
|
||||
self.from_committee.keys().copied()
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SimulationOverlay {
|
||||
Flat(flat::FlatOverlay),
|
||||
Tree(tree::TreeOverlay),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, 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 leaders<R: Rng>(
|
||||
&self,
|
||||
nodes: &[NodeId],
|
||||
size: usize,
|
||||
rng: &mut R,
|
||||
) -> Box<dyn Iterator<Item = NodeId>>;
|
||||
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()))
|
||||
}
|
||||
}
|
||||
}
|
@ -75,7 +75,7 @@ mod tests {
|
||||
Node, NodeId, NodeIdExt, OverlayState, SharedState, ViewOverlay,
|
||||
},
|
||||
output_processors::OutData,
|
||||
overlay::{
|
||||
overlay::tests::{
|
||||
tree::{TreeOverlay, TreeSettings},
|
||||
Overlay, SimulationOverlay,
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user