diff --git a/Cargo.lock b/Cargo.lock index 5dd7011c..4561e958 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -262,6 +262,7 @@ dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lru 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "patricia-trie 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "persistence 0.1.0", "quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/chain/Cargo.toml b/src/chain/Cargo.toml index 8e1255ad..cd23e93c 100644 --- a/src/chain/Cargo.toml +++ b/src/chain/Cargo.toml @@ -13,6 +13,7 @@ lru = "0.1.13" rlp = "0.3.0" parking_lot = "0.7.1" hex = "0.3.2" +patricia-trie = "0.3.0" account = { path = "../account" } crypto = { path = "../crypto" } events = { path = "../events" } diff --git a/src/chain/src/state_chain/block.rs b/src/chain/src/state_chain/block.rs index 2db3c337..56dd87c6 100644 --- a/src/chain/src/state_chain/block.rs +++ b/src/chain/src/state_chain/block.rs @@ -38,6 +38,9 @@ use std::sync::Arc; use std::net::SocketAddr; use std::str; use rlp::{Rlp, RlpStream}; +use persistence::{Codec, BlakeDbHasher}; +use patricia_trie::TrieDBMut; +use hashdb::HashDB; lazy_static! { /// Atomic reference count to state chain genesis block @@ -147,7 +150,43 @@ impl Block for StateBlock { Some(Box::new(fun)) } - fn append_condition(_block: Arc, chain_state: Self::ChainState) -> Result { + fn append_condition(block: Arc, mut chain_state: Self::ChainState) -> Result { + let pool_state = &mut chain_state.pool_state; + + if block.epoch != pool_state.epoch { + return Err(ChainErr::BadAppendCondition); + } + + // Validate and apply each event in the block + for event in block.events.iter().cloned() { + let node_id = event.node_id(); + + // TODO: Handle different errors + if pool_state.account_sent_by_validator(&node_id).is_err() { + return Err(ChainErr::BadAppendCondition); + } + + let raw_root_hash = chain_state.db.retrieve(PersistentDb::ROOT_HASH_KEY).unwrap(); + let mut root_hash_slice = [0; 32]; + + root_hash_slice.copy_from_slice(&raw_root_hash); + + let mut root = Hash(root_hash_slice); + + { + let mut trie = TrieDBMut::::new(&mut chain_state.db, &mut root); + + if event.validate_apply(&mut trie).is_err() { + return Err(ChainErr::BadAppendCondition); + } + } + + let root = root.0.to_vec(); + + // Update root hash entry + chain_state.db.put(PersistentDb::ROOT_HASH_KEY, &root); + } + Ok(chain_state) } diff --git a/src/crypto/src/hash.rs b/src/crypto/src/hash.rs index 03380557..71477380 100644 --- a/src/crypto/src/hash.rs +++ b/src/crypto/src/hash.rs @@ -16,9 +16,8 @@ along with the Purple Library. If not, see . */ -use blake2_rfc::blake2b::{blake2b, Blake2b}; +use blake2_rfc::blake2b::blake2b; use blake_hasher::BlakeHasher; -use byteorder::{LittleEndian, WriteBytesExt}; use crc32fast::Hasher as CrcHasher; use hashdb::Hasher; use quickcheck::Arbitrary; diff --git a/src/events/src/lib.rs b/src/events/src/lib.rs index db278868..0971283c 100644 --- a/src/events/src/lib.rs +++ b/src/events/src/lib.rs @@ -50,6 +50,9 @@ use crypto::Hash; use crypto::NodeId; use std::hash::Hash as HashTrait; use std::hash::Hasher; +use persistence::Codec; +use patricia_trie::TrieDBMut; +use persistence::BlakeDbHasher; #[derive(Clone, Debug)] pub enum Event { @@ -84,6 +87,10 @@ impl HashTrait for Event { } impl Event { + pub fn validate_apply(&self, trie: &mut TrieDBMut) -> Result<(), ()> { + unimplemented!(); + } + pub fn stamp(&self) -> Stamp { match *self { Event::Heartbeat(ref event) => event.stamp.clone(), diff --git a/src/persistence/src/persistent_db.rs b/src/persistence/src/persistent_db.rs index 010ae709..9fb025bf 100644 --- a/src/persistence/src/persistent_db.rs +++ b/src/persistence/src/persistent_db.rs @@ -98,6 +98,8 @@ pub struct PersistentDb { } impl PersistentDb { + pub const ROOT_HASH_KEY: &'static [u8] = b"root_hash"; + pub fn new(db_ref: Arc, cf_name: Option<&'static str>) -> PersistentDb { if !is_initialized() { panic!("Persistence module not initialized! Call `persistence::init()` before using anything"); @@ -203,7 +205,13 @@ impl PersistentDb { Operation::Put(ref val) => Some(val.clone()), Operation::Remove => None, }, - None => self.get_db(key), + None => match self.get_db(key) { + Some(res) => Some(res), + None => match key { + Self::ROOT_HASH_KEY => Some(Hash::NULL_RLP.0.to_vec()), + _ => None + } + }, } } else { let result = self.memory_db.get(key);