Преглед на файлове

src/consensus: blake3 hashes used insted of String, removed serde Deserialize/Serialize (finally)

aggstam преди 4 години
родител
ревизия
8ea28e752f

+ 0 - 3
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"
 

+ 1 - 4
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());
 

+ 6 - 7
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<Tx>,
         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<Tx>,
     ) -> BlockProposal {

+ 7 - 11
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."
         );
     }

+ 4 - 6
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<Vote>,

+ 1 - 2
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,

+ 12 - 16
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<RwLock<State>>;
 /// 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<Option<BlockProposal>> {
         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<State> {
         // Genesis block is generated.
         let mut genesis_block = Block::new(
-            String::from("⊥"),
+            blake3::Hash::from(GENESIS_HASH_BYTES),
             0,
             vec![],
             String::from("proof"),

+ 1 - 3
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,
 }
 

+ 27 - 3
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<S: io::Write>(&self, mut s: S) -> Result<usize> {
+        s.write_slice(self.as_bytes())?;
+        Ok(32)
+    }
+}
+
+impl Decodable for blake3::Hash {
+    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+        let mut bytes = [0u8; 32];
+        d.read_slice(&mut bytes)?;
+        Ok(bytes.into())
+    }
+}

+ 2 - 3
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,