diff --git a/script/research/validatord/Cargo.toml b/script/research/validatord/Cargo.toml index f09ab12f4..d36b9a53e 100644 --- a/script/research/validatord/Cargo.toml +++ b/script/research/validatord/Cargo.toml @@ -17,9 +17,6 @@ async-channel = "1.6.1" async-executor = "1.4.1" easy-parallel = "3.2.0" -# Crypto -rand = "0.8.5" - # Storage sled = "0.34.7" diff --git a/script/research/validatord/src/main.rs b/script/research/validatord/src/main.rs index e86a491f6..507e4637a 100644 --- a/script/research/validatord/src/main.rs +++ b/script/research/validatord/src/main.rs @@ -4,7 +4,6 @@ use async_executor::Executor; use async_trait::async_trait; use easy_parallel::Parallel; use log::{debug, error, info}; -use rand::{rngs::OsRng, RngCore}; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use simplelog::{ColorChoice, TermLogger, TerminalMode}; @@ -314,10 +313,8 @@ impl JsonRpcInterface { return Err(InvalidParams) } - // TODO: add proper tx hash here - let random_id = OsRng.next_u32(); let payload = String::from(args[0].as_str().unwrap()); - let tx = Tx { hash: random_id, payload }; + let tx = Tx { payload }; self.state.write().unwrap().append_tx(tx.clone()); diff --git a/src/consensus/block.rs b/src/consensus/block.rs index d70feefe4..6fd03c0e1 100644 --- a/src/consensus/block.rs +++ b/src/consensus/block.rs @@ -1,4 +1,3 @@ -use serde::{Deserialize, Serialize}; use std::{ hash::{Hash, Hasher}, io, @@ -15,10 +14,10 @@ use crate::{ /// This struct represents a tuple of the form (st, sl, txs, metadata). /// Each blocks parent hash h may be computed simply as a hash of the parent block. -#[derive(Debug, Clone, Deserialize, Serialize, SerialEncodable, SerialDecodable)] +#[derive(Debug, Clone, SerialEncodable, SerialDecodable)] pub struct Block { /// Previous block hash - pub st: String, // Change this to a proper hash type + pub st: blake3::Hash, /// Slot uid, generated by the beacon pub sl: u64, /// Transactions payload @@ -29,7 +28,7 @@ pub struct Block { impl Block { pub fn new( - st: String, + st: blake3::Hash, sl: u64, txs: Vec, proof: String, @@ -53,7 +52,7 @@ impl Hash for Block { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, SerialEncodable, SerialDecodable)] +#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)] pub struct BlockProposal { /// leader public key pub public_key: PublicKey, @@ -62,7 +61,7 @@ pub struct BlockProposal { /// leader id pub id: u64, /// Previous block hash - pub st: String, // Change this to a proper hash type + pub st: blake3::Hash, /// Slot uid, generated by the beacon pub sl: u64, /// Transactions payload @@ -74,7 +73,7 @@ impl BlockProposal { public_key: PublicKey, signature: Signature, id: u64, - st: String, + st: blake3::Hash, sl: u64, txs: Vec, ) -> BlockProposal { diff --git a/src/consensus/blockchain.rs b/src/consensus/blockchain.rs index e62d5f4f1..df5cd9905 100644 --- a/src/consensus/blockchain.rs +++ b/src/consensus/blockchain.rs @@ -1,16 +1,12 @@ -use std::{ - collections::hash_map::DefaultHasher, - hash::{Hash, Hasher}, - io, -}; +use std::io; use crate::{ impl_vec, - util::serial::{Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt}, + util::serial::{serialize, Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt}, Result, }; -use super::block::Block; +use super::{block::Block, util::GENESIS_HASH_BYTES}; /// This struct represents a sequence of blocks starting with the genesis block. #[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)] @@ -27,11 +23,11 @@ impl Blockchain { /// previous block and their epochs are incremental, exluding genesis. /// Additional validity rules can be applied. pub fn check_block_validity(&self, block: &Block, previous_block: &Block) { - assert!(block.st != "⊥", "Genesis block provided."); - let mut hasher = DefaultHasher::new(); - previous_block.hash(&mut hasher); + assert!(block.st.as_bytes() != &GENESIS_HASH_BYTES, "Genesis block provided."); + let serialized = serialize(previous_block); + let previous_block_hash = blake3::hash(&serialized); assert!( - block.st == hasher.finish().to_string() && block.sl > previous_block.sl, + block.st == previous_block_hash && block.sl > previous_block.sl, "Provided block is invalid." ); } diff --git a/src/consensus/metadata.rs b/src/consensus/metadata.rs index ce26a9cb8..67e706a9a 100644 --- a/src/consensus/metadata.rs +++ b/src/consensus/metadata.rs @@ -1,4 +1,4 @@ -use serde::{Deserialize, Serialize}; +use crate::util::serial::{SerialDecodable, SerialEncodable}; use super::{ participant::Participant, @@ -6,10 +6,8 @@ use super::{ vote::Vote, }; -use crate::util::serial::{SerialDecodable, SerialEncodable}; - /// This struct represents additional Block information used by the consensus protocol. -#[derive(Debug, Clone, Deserialize, Serialize, SerialEncodable, SerialDecodable)] +#[derive(Debug, Clone, SerialEncodable, SerialDecodable)] pub struct Metadata { /// Block information used by Ouroboros consensus pub om: OuroborosMetadata, @@ -30,7 +28,7 @@ impl Metadata { } /// This struct represents Block information used by Ouroboros consensus protocol. -#[derive(Debug, Clone, Deserialize, Serialize, SerialEncodable, SerialDecodable)] +#[derive(Debug, Clone, SerialEncodable, SerialDecodable)] pub struct OuroborosMetadata { /// Proof the stakeholder is the block owner pub proof: String, @@ -47,7 +45,7 @@ impl OuroborosMetadata { } /// This struct represents Block information used by Streamlet consensus protocol. -#[derive(Debug, Clone, Deserialize, Serialize, SerialEncodable, SerialDecodable)] +#[derive(Debug, Clone, SerialEncodable, SerialDecodable)] pub struct StreamletMetadata { /// Epoch votes pub votes: Vec, diff --git a/src/consensus/participant.rs b/src/consensus/participant.rs index f0be5bd10..895aa19d3 100644 --- a/src/consensus/participant.rs +++ b/src/consensus/participant.rs @@ -1,4 +1,3 @@ -use serde::{Deserialize, Serialize}; use std::{collections::BTreeMap, io}; use crate::{ @@ -8,7 +7,7 @@ use crate::{ }; /// This struct represents a tuple of the form (node_id, epoch_joined, last_epoch_voted). -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, SerialEncodable, SerialDecodable)] +#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)] pub struct Participant { /// Node id pub id: u64, diff --git a/src/consensus/state.rs b/src/consensus/state.rs index 3d27ad9b3..a8d6dd995 100644 --- a/src/consensus/state.rs +++ b/src/consensus/state.rs @@ -22,7 +22,7 @@ use super::{ blockchain::Blockchain, participant::Participant, tx::Tx, - util::Timestamp, + util::{Timestamp, GENESIS_HASH_BYTES}, vote::Vote, }; @@ -36,7 +36,7 @@ pub type StatePtr = Arc>; /// Each node is numbered and has a secret-public keys pair, to sign messages. /// Nodes hold a set of Blockchains(some of which are not notarized) /// and a set of unconfirmed pending transactions. -#[derive(SerialEncodable, SerialDecodable)] +#[derive(Debug, SerialEncodable, SerialDecodable)] pub struct State { pub id: u64, pub genesis_time: Timestamp, @@ -121,9 +121,8 @@ impl State { pub fn propose_block(&self) -> Result> { let epoch = self.get_current_epoch(); let longest_notarized_chain = self.find_longest_notarized_chain(); - let mut hasher = DefaultHasher::new(); - longest_notarized_chain.blocks.last().unwrap().hash(&mut hasher); - let hash = hasher.finish().to_string(); + let serialized = serialize(longest_notarized_chain.blocks.last().unwrap()); + let hash = blake3::hash(&serialized); let unproposed_txs = self.get_unproposed_txs(); let mut encoded_block = vec![]; hash.encode(&mut encoded_block)?; @@ -249,21 +248,20 @@ impl State { /// Given a block, node finds the index of the blockchain it extends. pub fn find_extended_blockchain_index(&self, block: &Block, leader: bool) -> i64 { - let mut hasher = DefaultHasher::new(); for (index, blockchain) in self.node_blockchains.iter().enumerate() { let last_block = blockchain.blocks.last().unwrap(); - last_block.hash(&mut hasher); - if (leader && block.st == hasher.finish().to_string() && block.sl >= last_block.sl) || - (!leader && block.st == hasher.finish().to_string() && block.sl > last_block.sl) + let last_block_hash = blake3::hash(&serialize(last_block)); + if (leader && block.st == last_block_hash && block.sl >= last_block.sl) || + (!leader && block.st == last_block_hash && block.sl > last_block.sl) { return index as i64 } } let last_block = self.canonical_blockchain.blocks.last().unwrap(); - last_block.hash(&mut hasher); - if (leader && block.st != hasher.finish().to_string() || block.sl < last_block.sl) || - (!leader && block.st != hasher.finish().to_string() || block.sl <= last_block.sl) + let last_block_hash = blake3::hash(&serialize(last_block)); + if (leader && block.st != last_block_hash || block.sl < last_block.sl) || + (!leader && block.st != last_block_hash || block.sl <= last_block.sl) { debug!("Proposed block doesn't extend any known chains."); return -2 @@ -381,10 +379,8 @@ impl State { self.canonical_blockchain.blocks.push(block.clone()); } - let mut hasher = DefaultHasher::new(); let last_finalized_block = self.canonical_blockchain.blocks.last().unwrap(); - last_finalized_block.hash(&mut hasher); - let last_finalized_block_hash = hasher.finish().to_string(); + let last_finalized_block_hash = blake3::hash(&serialize(last_finalized_block)); let mut dropped_blockchains = Vec::new(); for (index, blockchain) in self.node_blockchains.iter().enumerate() { let first_block = blockchain.blocks.first().unwrap(); @@ -493,7 +489,7 @@ impl State { pub fn reset(genesis: i64, id: u64, db: &sled::Db) -> Result { // Genesis block is generated. let mut genesis_block = Block::new( - String::from("⊥"), + blake3::Hash::from(GENESIS_HASH_BYTES), 0, vec![], String::from("proof"), diff --git a/src/consensus/tx.rs b/src/consensus/tx.rs index 289be376a..3a8a1be33 100644 --- a/src/consensus/tx.rs +++ b/src/consensus/tx.rs @@ -1,4 +1,3 @@ -use serde::{Deserialize, Serialize}; use std::io; use crate::{ @@ -7,9 +6,8 @@ use crate::{ Result, }; -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, SerialEncodable, SerialDecodable)] +#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)] pub struct Tx { - pub hash: u32, // Change this to a proper hash type pub payload: String, } diff --git a/src/consensus/util.rs b/src/consensus/util.rs index f7fd6118e..4ca0b1b65 100644 --- a/src/consensus/util.rs +++ b/src/consensus/util.rs @@ -1,10 +1,19 @@ use chrono::{NaiveDateTime, Utc}; -use serde::{Deserialize, Serialize}; +use std::io; -use crate::util::serial::{SerialDecodable, SerialEncodable}; +use crate::{ + util::serial::{Decodable, Encodable, ReadExt, SerialDecodable, SerialEncodable, WriteExt}, + Result, +}; + +// Serialized blake3 hash bytes for character "⊥" +pub const GENESIS_HASH_BYTES: [u8; 32] = [ + 254, 233, 82, 102, 23, 208, 153, 87, 96, 165, 163, 194, 238, 7, 1, 88, 14, 1, 249, 118, 197, + 29, 180, 211, 87, 66, 59, 38, 86, 54, 12, 39, +]; /// Util structure to represend chrono UTC timestamps. -#[derive(Debug, Clone, Serialize, Deserialize, SerialDecodable, SerialEncodable)] +#[derive(Debug, Clone, SerialDecodable, SerialEncodable)] pub struct Timestamp(pub i64); impl Timestamp { @@ -21,3 +30,18 @@ impl Timestamp { pub fn get_current_time() -> Timestamp { Timestamp(Utc::now().timestamp()) } + +impl Encodable for blake3::Hash { + fn encode(&self, mut s: S) -> Result { + s.write_slice(self.as_bytes())?; + Ok(32) + } +} + +impl Decodable for blake3::Hash { + fn decode(mut d: D) -> Result { + let mut bytes = [0u8; 32]; + d.read_slice(&mut bytes)?; + Ok(bytes.into()) + } +} diff --git a/src/consensus/vote.rs b/src/consensus/vote.rs index 0147a2765..1df17a6c9 100644 --- a/src/consensus/vote.rs +++ b/src/consensus/vote.rs @@ -1,4 +1,3 @@ -use serde::{Deserialize, Serialize}; use std::io; use super::block::BlockProposal; @@ -11,13 +10,13 @@ use crate::{ }; /// This struct represents a tuple of the form (vote, B, id). -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, SerialDecodable, SerialEncodable)] +#[derive(Debug, Clone, PartialEq, SerialDecodable, SerialEncodable)] pub struct Vote { /// Node public key pub node_public_key: PublicKey, /// signed block pub vote: Signature, - /// block hash to vote on + /// block proposal to vote on pub block: BlockProposal, /// node id pub id: u64,