From 4ccc19f5a32d21d856971a078cdea86e113e5117 Mon Sep 17 00:00:00 2001 From: Al Liu Date: Wed, 21 Jun 2023 16:31:36 +0800 Subject: [PATCH] Support configurable records (#200) * support configurable records --- simulations/src/bin/app/main.rs | 6 +- simulations/src/node/carnot/mod.rs | 125 +++++++++++++++++++++++++++-- simulations/src/runner/mod.rs | 1 + simulations/src/settings.rs | 4 + 4 files changed, 129 insertions(+), 7 deletions(-) diff --git a/simulations/src/bin/app/main.rs b/simulations/src/bin/app/main.rs index f2983c8d..b2c3e1aa 100644 --- a/simulations/src/bin/app/main.rs +++ b/simulations/src/bin/app/main.rs @@ -97,7 +97,11 @@ impl SimulationApp { ); CarnotNode::>::new( node_id, - CarnotSettings::new(nodes, simulation_settings.node_settings.timeout), + CarnotSettings::new( + nodes, + simulation_settings.node_settings.timeout, + simulation_settings.record_settings.clone(), + ), overlay_settings, genesis, network_interface, diff --git a/simulations/src/node/carnot/mod.rs b/simulations/src/node/carnot/mod.rs index ef900fd8..d186c5a5 100644 --- a/simulations/src/node/carnot/mod.rs +++ b/simulations/src/node/carnot/mod.rs @@ -30,12 +30,38 @@ use nomos_consensus::{ network::messages::{NewViewMsg, TimeoutMsg, VoteMsg}, }; -#[derive(Serialize)] +const CURRENT_VIEW: &str = "current_view"; +const HIGHEST_VOTED_VIEW: &str = "highest_voted_view"; +const LOCAL_HIGH_QC: &str = "local_high_qc"; +const SAFE_BLOCKS: &str = "safe_blocks"; +const LAST_VIEW_TIMEOUT_QC: &str = "last_view_timeout_qc"; +const LATEST_COMMITTED_BLOCK: &str = "latest_committed_block"; +const LATEST_COMMITTED_VIEW: &str = "latest_committed_view"; +const ROOT_COMMITTEE: &str = "root_committee"; +const PARENT_COMMITTEE: &str = "parent_committee"; +const CHILD_COMMITTEES: &str = "child_committees"; +const COMMITTED_BLOCKS: &str = "committed_blocks"; + +pub const CARNOT_RECORD_KEYS: &[&str] = &[ + CURRENT_VIEW, + HIGHEST_VOTED_VIEW, + LOCAL_HIGH_QC, + SAFE_BLOCKS, + LAST_VIEW_TIMEOUT_QC, + LATEST_COMMITTED_BLOCK, + LATEST_COMMITTED_VIEW, + ROOT_COMMITTEE, + PARENT_COMMITTEE, + CHILD_COMMITTEES, + COMMITTED_BLOCKS, +]; + +static RECORD_SETTINGS: std::sync::OnceLock> = std::sync::OnceLock::new(); + pub struct CarnotState { current_view: View, highest_voted_view: View, local_high_qc: StandardQc, - #[serde(serialize_with = "serialize_blocks")] safe_blocks: HashMap, last_view_timeout_qc: Option, latest_committed_block: Block, @@ -46,6 +72,81 @@ pub struct CarnotState { committed_blocks: Vec, } +impl serde::Serialize for CarnotState { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + if let Some(rs) = RECORD_SETTINGS.get() { + let keys = rs + .iter() + .filter_map(|(k, v)| { + if CARNOT_RECORD_KEYS.contains(&k.trim()) && *v { + Some(k) + } else { + None + } + }) + .collect::>(); + + let mut ser = serializer.serialize_struct("CarnotState", keys.len())?; + for k in keys { + match k.trim() { + CURRENT_VIEW => ser.serialize_field(CURRENT_VIEW, &self.current_view)?, + HIGHEST_VOTED_VIEW => { + ser.serialize_field(HIGHEST_VOTED_VIEW, &self.highest_voted_view)? + } + LOCAL_HIGH_QC => ser.serialize_field(LOCAL_HIGH_QC, &self.local_high_qc)?, + SAFE_BLOCKS => { + #[derive(Serialize)] + #[serde(transparent)] + struct SafeBlockHelper<'a> { + #[serde(serialize_with = "serialize_blocks")] + safe_blocks: &'a HashMap, + } + ser.serialize_field( + SAFE_BLOCKS, + &SafeBlockHelper { + safe_blocks: &self.safe_blocks, + }, + )?; + } + LAST_VIEW_TIMEOUT_QC => { + ser.serialize_field(LAST_VIEW_TIMEOUT_QC, &self.last_view_timeout_qc)? + } + LATEST_COMMITTED_BLOCK => { + ser.serialize_field(LATEST_COMMITTED_BLOCK, &self.latest_committed_block)? + } + LATEST_COMMITTED_VIEW => { + ser.serialize_field(LATEST_COMMITTED_VIEW, &self.latest_committed_view)? + } + ROOT_COMMITTEE => ser.serialize_field(ROOT_COMMITTEE, &self.root_committe)?, + PARENT_COMMITTEE => { + ser.serialize_field(PARENT_COMMITTEE, &self.parent_committe)? + } + CHILD_COMMITTEES => { + ser.serialize_field(CHILD_COMMITTEES, &self.child_committees)? + } + COMMITTED_BLOCKS => { + ser.serialize_field(COMMITTED_BLOCKS, &self.committed_blocks)? + } + _ => {} + } + } + ser.end() + } else { + serializer.serialize_none() + } + } +} + +impl CarnotState { + const fn keys() -> &'static [&'static str] { + CARNOT_RECORD_KEYS + } +} + /// Have to implement this manually because of the `serde_json` will panic if the key of map /// is not a string. fn serialize_blocks(blocks: &HashMap, serializer: S) -> Result @@ -87,11 +188,20 @@ impl From<&Carnot> for CarnotState { pub struct CarnotSettings { nodes: Vec, timeout: Duration, + record_settings: HashMap, } impl CarnotSettings { - pub fn new(nodes: Vec, timeout: Duration) -> Self { - Self { nodes, timeout } + pub fn new( + nodes: Vec, + timeout: Duration, + record_settings: HashMap, + ) -> Self { + Self { + nodes, + timeout, + record_settings, + } } } @@ -120,11 +230,12 @@ impl CarnotNode { let engine = Carnot::from_genesis(id, genesis.header().clone(), overlay); let state = CarnotState::from(&engine); let timeout = settings.timeout; + RECORD_SETTINGS.get_or_init(|| settings.record_settings.clone()); // pk is generated in an insecure way, but for simulation purpouses using a rng like smallrng is more useful let mut pk_buff = [0; 32]; rng.fill_bytes(&mut pk_buff); let random_beacon_pk = PrivateKey::new(pk_buff); - Self { + let mut this = Self { id, state, settings, @@ -133,7 +244,9 @@ impl CarnotNode { event_builder: event_builder::EventBuilder::new(id, timeout), engine, random_beacon_pk, - } + }; + this.state = CarnotState::from(&this.engine); + this } pub(crate) fn send_message(&self, message: NetworkMessage) { diff --git a/simulations/src/runner/mod.rs b/simulations/src/runner/mod.rs index 4fd01486..44c64bbd 100644 --- a/simulations/src/runner/mod.rs +++ b/simulations/src/runner/mod.rs @@ -149,6 +149,7 @@ where leaders_count: _, network_settings: _, step_time: _, + record_settings: _, } = settings; Ok(Self { runner_settings, diff --git a/simulations/src/settings.rs b/simulations/src/settings.rs index 59059a70..5aeed54c 100644 --- a/simulations/src/settings.rs +++ b/simulations/src/settings.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::network::NetworkSettings; use crate::overlay::OverlaySettings; use crate::streaming::StreamSettings; @@ -31,6 +33,8 @@ pub struct NodeSettings { pub struct SimulationSettings { #[serde(default)] pub wards: Vec, + #[serde(default)] + pub record_settings: HashMap, pub network_settings: NetworkSettings, pub overlay_settings: OverlaySettings, pub node_settings: NodeSettings,