diff --git a/consensus/carnot-engine/tests/fuzz/mod.rs b/consensus/carnot-engine/tests/fuzz/mod.rs index e8d18602..6a464dae 100644 --- a/consensus/carnot-engine/tests/fuzz/mod.rs +++ b/consensus/carnot-engine/tests/fuzz/mod.rs @@ -1,3 +1,10 @@ mod ref_state; pub mod sut; mod transition; + +type Block = carnot_engine::Block<[u8; 32]>; +type AggregateQc = carnot_engine::AggregateQc<[u8; 32]>; +type Qc = carnot_engine::Qc<[u8; 32]>; +type StandardQc = carnot_engine::StandardQc<[u8; 32]>; +type TimeoutQc = carnot_engine::TimeoutQc<[u8; 32]>; +type NewView = carnot_engine::NewView<[u8; 32]>; diff --git a/consensus/carnot-engine/tests/fuzz/ref_state.rs b/consensus/carnot-engine/tests/fuzz/ref_state.rs index 71b148f7..e5df7ea0 100644 --- a/consensus/carnot-engine/tests/fuzz/ref_state.rs +++ b/consensus/carnot-engine/tests/fuzz/ref_state.rs @@ -1,13 +1,12 @@ use std::collections::{BTreeMap, HashSet}; -use carnot_engine::{ - AggregateQc, Block, BlockId, LeaderProof, NodeId, Qc, StandardQc, TimeoutQc, View, -}; +use carnot_engine::{LeaderProof, NodeId, View}; use proptest::prelude::*; use proptest::strategy::BoxedStrategy; use proptest_state_machine::ReferenceStateMachine; use crate::fuzz::transition::Transition; +use crate::fuzz::{AggregateQc, Block, Qc, StandardQc, TimeoutQc}; // A reference state machine (RefState) is used to generated state transitions. // To generate some kinds of transition, we may need to keep historical blocks in RefState. @@ -42,8 +41,8 @@ impl ReferenceStateMachine for RefState { fn init_state() -> BoxedStrategy { let genesis_block = Block { view: View::new(0), - id: BlockId::zeros(), - parent_qc: Qc::Standard(StandardQc::genesis()), + id: [0; 32], + parent_qc: Qc::Standard(StandardQc::genesis([0; 32])), leader_proof: LEADER_PROOF.clone(), }; @@ -330,10 +329,11 @@ impl RefState { fn transition_receive_safe_block_with_aggregated_qc(&self) -> BoxedStrategy { //TODO: more randomness let current_view = self.current_view(); - + let mut id = [0; 32]; + rand::thread_rng().fill_bytes(&mut id); Just(Transition::ReceiveSafeBlock(Block { view: current_view.next(), - id: BlockId::random(&mut rand::thread_rng()), + id, parent_qc: Qc::Aggregated(AggregateQc { high_qc: self.high_qc(), view: current_view, @@ -360,9 +360,13 @@ impl RefState { pub fn high_qc(&self) -> StandardQc { self.chain .values() - .map(|entry| entry.high_qc().unwrap_or_else(StandardQc::genesis)) + .map(|entry| { + entry + .high_qc() + .unwrap_or_else(|| StandardQc::genesis([0; 32])) + }) .max_by_key(|qc| qc.view) - .unwrap_or_else(StandardQc::genesis) + .unwrap_or_else(|| StandardQc::genesis([0; 32])) } pub fn latest_timeout_qcs(&self) -> Vec { @@ -386,17 +390,19 @@ impl RefState { self.contains_block(block.parent_qc.block()) } - fn contains_block(&self, block_id: BlockId) -> bool { + fn contains_block(&self, block_id: [u8; 32]) -> bool { self.chain .iter() .any(|(_, entry)| entry.blocks.iter().any(|block| block.id == block_id)) } fn consecutive_block(parent: &Block) -> Block { + let mut id = [0; 32]; + rand::thread_rng().fill_bytes(&mut id); Block { // use rand because we don't want this to be shrinked by proptest view: parent.view.next(), - id: BlockId::random(&mut rand::thread_rng()), + id, parent_qc: Qc::Standard(StandardQc { view: parent.view, id: parent.id, diff --git a/consensus/carnot-engine/tests/fuzz/sut.rs b/consensus/carnot-engine/tests/fuzz/sut.rs index 0cb2a435..1778167e 100644 --- a/consensus/carnot-engine/tests/fuzz/sut.rs +++ b/consensus/carnot-engine/tests/fuzz/sut.rs @@ -8,13 +8,13 @@ use carnot_engine::{ use proptest_state_machine::{ReferenceStateMachine, StateMachineTest}; use crate::fuzz::ref_state::RefState; -use crate::fuzz::transition::Transition; +use crate::fuzz::{transition::Transition, Block}; // ConsensusEngineTest defines a state that we want to test. // This is called as SUT (System Under Test). #[derive(Clone, Debug)] pub struct ConsensusEngineTest { - pub engine: Carnot>, + pub engine: Carnot, [u8; 32]>, } impl ConsensusEngineTest { @@ -23,8 +23,8 @@ impl ConsensusEngineTest { NodeId::new([0; 32]), Block { view: View::new(0), - id: BlockId::zeros(), - parent_qc: Qc::Standard(StandardQc::genesis()), + id: [0; 32], + parent_qc: Qc::Standard(StandardQc::genesis([0; 32])), leader_proof: LeaderProof::LeaderId { leader_id: NodeId::new([0; 32]), }, diff --git a/consensus/carnot-engine/tests/fuzz/transition.rs b/consensus/carnot-engine/tests/fuzz/transition.rs index 4ea721dd..6b0386f7 100644 --- a/consensus/carnot-engine/tests/fuzz/transition.rs +++ b/consensus/carnot-engine/tests/fuzz/transition.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use carnot_engine::{Block, NewView, TimeoutQc}; +use crate::fuzz::{Block, NewView, TimeoutQc}; // State transtitions that will be picked randomly #[derive(Clone, Debug)] diff --git a/nomos-core/Cargo.toml b/nomos-core/Cargo.toml index 56da0cd1..b65c6804 100644 --- a/nomos-core/Cargo.toml +++ b/nomos-core/Cargo.toml @@ -22,6 +22,7 @@ thiserror = "1.0" bincode = "1.3" once_cell = "1.0" indexmap = { version = "1.9", features = ["serde"] } +const-hex = "1" [dev-dependencies] rand = "0.8" diff --git a/nomos-core/src/header/mod.rs b/nomos-core/src/header/mod.rs index ae8fd190..75877569 100644 --- a/nomos-core/src/header/mod.rs +++ b/nomos-core/src/header/mod.rs @@ -1,14 +1,14 @@ use serde::{Deserialize, Serialize}; -use crate::utils::display_hex_bytes_newtype; +use crate::utils::{display_hex_bytes_newtype, serde_bytes_newtype}; pub mod carnot; pub mod cryptarchia; -#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash, Serialize, Deserialize, PartialOrd, Ord)] +#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash, PartialOrd, Ord)] pub struct HeaderId([u8; 32]); -#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)] pub struct ContentId([u8; 32]); #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -73,3 +73,15 @@ impl From for [u8; 32] { display_hex_bytes_newtype!(HeaderId); display_hex_bytes_newtype!(ContentId); + +serde_bytes_newtype!(HeaderId, 32); +serde_bytes_newtype!(ContentId, 32); + +#[test] +fn test_serde() { + assert_eq!( + crate::wire::deserialize::(&crate::wire::serialize(&HeaderId([0; 32])).unwrap()) + .unwrap(), + HeaderId([0; 32]) + ); +} diff --git a/nomos-core/src/utils/mod.rs b/nomos-core/src/utils/mod.rs index 88f2fad1..b8459a9e 100644 --- a/nomos-core/src/utils/mod.rs +++ b/nomos-core/src/utils/mod.rs @@ -14,4 +14,40 @@ macro_rules! display_hex_bytes_newtype { }; } +macro_rules! serde_bytes_newtype { + ($newtype:ty, $len:expr) => { + impl serde::Serialize for $newtype { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + const_hex::const_encode::<$len, false>(&self.0) + .as_str() + .serialize(serializer) + } else { + self.0.serialize(serializer) + } + } + } + + impl<'de> serde::Deserialize<'de> for $newtype { + fn deserialize(deserializer: D) -> Result<$newtype, D::Error> + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + let s = <&str>::deserialize(deserializer)?; + const_hex::decode_to_array(s) + .map(Self) + .map_err(serde::de::Error::custom) + } else { + <[u8; $len]>::deserialize(deserializer).map(Self) + } + } + } + }; +} + pub(crate) use display_hex_bytes_newtype; +pub(crate) use serde_bytes_newtype; diff --git a/nomos-services/carnot-consensus/src/lib.rs b/nomos-services/carnot-consensus/src/lib.rs index cedcf6f9..9ffe63d3 100644 --- a/nomos-services/carnot-consensus/src/lib.rs +++ b/nomos-services/carnot-consensus/src/lib.rs @@ -306,6 +306,7 @@ where ); if carnot.is_next_leader() { + tracing::info!("is next leader, gathering vores"); let network_adapter = adapter.clone(); task_manager.push(genesis_block.view.next(), async move { let Event::Approve { qc, .. } = Self::gather_votes( @@ -319,6 +320,7 @@ where tracing::debug!("Failed to gather initial votes"); return Event::None; }; + tracing::info!("got enough votes"); Event::ProposeBlock { qc } }); } diff --git a/nomos-services/carnot-consensus/src/network/adapters/libp2p.rs b/nomos-services/carnot-consensus/src/network/adapters/libp2p.rs index a240baca..46717bcc 100644 --- a/nomos-services/carnot-consensus/src/network/adapters/libp2p.rs +++ b/nomos-services/carnot-consensus/src/network/adapters/libp2p.rs @@ -264,7 +264,7 @@ impl NetworkAdapter for Libp2pAdapter { } } NetworkMessage::Vote(msg) => { - tracing::debug!("received vote"); + tracing::debug!("received vote {:?}", msg); let mut cache = cache.cache.lock().unwrap(); let view = msg.vote.view; if let Some(messages) = cache.get_mut(&view) { diff --git a/nomos-services/carnot-consensus/src/network/messages.rs b/nomos-services/carnot-consensus/src/network/messages.rs index fb82fdaa..35dade01 100644 --- a/nomos-services/carnot-consensus/src/network/messages.rs +++ b/nomos-services/carnot-consensus/src/network/messages.rs @@ -86,7 +86,7 @@ impl TimeoutQcMsg { } } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub enum NetworkMessage { Timeout(TimeoutMsg), TimeoutQc(TimeoutQcMsg), diff --git a/nomos-services/carnot-consensus/src/tally/happy.rs b/nomos-services/carnot-consensus/src/tally/happy.rs index a0a52cd1..5a3f03e5 100644 --- a/nomos-services/carnot-consensus/src/tally/happy.rs +++ b/nomos-services/carnot-consensus/src/tally/happy.rs @@ -84,7 +84,6 @@ impl Tally for CarnotTally { )); } } - Err(CarnotTallyError::StreamEnded) } } diff --git a/nomos-services/mempool/tests/mock.rs b/nomos-services/mempool/tests/mock.rs index 5024a640..1a4685f2 100644 --- a/nomos-services/mempool/tests/mock.rs +++ b/nomos-services/mempool/tests/mock.rs @@ -1,5 +1,5 @@ use nomos_core::{ - block::BlockId, + header::HeaderId, tx::mock::{MockTransaction, MockTxId}, }; use nomos_log::{Logger, LoggerSettings}; @@ -23,7 +23,7 @@ struct MockPoolNode { mockpool: ServiceHandle< MempoolService< MockAdapter, - MockPool, MockTxId>, + MockPool, MockTxId>, Transaction, >, >, @@ -80,7 +80,7 @@ fn test_mockmempool() { let network = app.handle().relay::>(); let mempool = app.handle().relay::, MockTxId>, + MockPool, MockTxId>, Transaction, >>(); @@ -102,7 +102,7 @@ fn test_mockmempool() { let (mtx, mrx) = tokio::sync::oneshot::channel(); mempool_outbound .send(MempoolMsg::View { - ancestor_hint: BlockId::default(), + ancestor_hint: [0; 32].into(), reply_channel: mtx, }) .await diff --git a/tests/src/tests/unhappy.rs b/tests/src/tests/unhappy.rs index 6e1a437a..4d933d61 100644 --- a/tests/src/tests/unhappy.rs +++ b/tests/src/tests/unhappy.rs @@ -1,13 +1,17 @@ use carnot_consensus::CarnotInfo; -use carnot_engine::{Block, NodeId, TimeoutQc, View}; +use carnot_engine::{NodeId, View}; use fraction::Fraction; use futures::stream::{self, StreamExt}; +use nomos_core::header::HeaderId; use std::{collections::HashSet, time::Duration}; use tests::{adjust_timeout, ConsensusConfig, MixNode, Node, NomosNode, SpawnConfig}; const TARGET_VIEW: View = View::new(20); const DUMMY_NODE_ID: NodeId = NodeId::new([0u8; 32]); +type Block = carnot_engine::Block; +type TimeoutQc = carnot_engine::TimeoutQc; + #[tokio::test] async fn ten_nodes_one_down() { let (_mixnodes, mixnet_config) = MixNode::spawn_nodes(3).await;