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

This commit is contained in:
aggstam
2022-04-09 14:40:32 +03:00
parent 29e5d4c285
commit 8ea28e752f
10 changed files with 61 additions and 58 deletions

View File

@@ -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"

View File

@@ -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());

View File

@@ -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 {

View File

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

View File

@@ -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>,

View File

@@ -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,

View File

@@ -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"),

View File

@@ -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,
}

View File

@@ -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())
}
}

View File

@@ -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,