From e9f777baa59b2bf3c067e4172b2df5a09fa5b020 Mon Sep 17 00:00:00 2001 From: Seulgi Kim Date: Fri, 3 Jan 2020 15:58:22 +0900 Subject: [PATCH] Export the codechain-merkle module to the merkle-trie package --- Cargo.lock | 36 +- Cargo.toml | 1 - core/Cargo.toml | 2 +- core/src/block.rs | 2 +- core/src/client/client.rs | 2 +- core/src/client/mod.rs | 2 +- core/src/client/test_client.rs | 2 +- core/src/error.rs | 2 +- core/src/lib.rs | 1 - core/src/scheme/scheme.rs | 2 +- core/src/verification/verification.rs | 2 +- state/Cargo.toml | 2 +- state/src/cache/shard_cache.rs | 2 +- state/src/cache/top_cache.rs | 2 +- state/src/cache/write_back.rs | 8 +- state/src/error.rs | 2 +- state/src/impls/shard_level.rs | 16 +- state/src/impls/top_level.rs | 2 +- state/src/lib.rs | 1 - state/src/tests.rs | 2 +- state/src/traits.rs | 2 +- sync/Cargo.toml | 2 +- sync/src/lib.rs | 1 - sync/src/snapshot/snapshot.rs | 4 +- util/merkle/Cargo.toml | 18 - util/merkle/benches/triedb.rs | 164 ------ util/merkle/src/lib.rs | 113 ---- util/merkle/src/nibbleslice.rs | 272 ---------- util/merkle/src/node.rs | 115 ---- util/merkle/src/skewed.rs | 130 ----- util/merkle/src/triedb.rs | 141 ----- util/merkle/src/triedbmut.rs | 719 -------------------------- util/merkle/src/triehash.rs | 248 --------- 33 files changed, 47 insertions(+), 1973 deletions(-) delete mode 100644 util/merkle/Cargo.toml delete mode 100644 util/merkle/benches/triedb.rs delete mode 100644 util/merkle/src/lib.rs delete mode 100644 util/merkle/src/nibbleslice.rs delete mode 100644 util/merkle/src/node.rs delete mode 100644 util/merkle/src/skewed.rs delete mode 100644 util/merkle/src/triedb.rs delete mode 100644 util/merkle/src/triedbmut.rs delete mode 100644 util/merkle/src/triehash.rs diff --git a/Cargo.lock b/Cargo.lock index 3f2530addd..ae9071f4f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,7 +261,6 @@ dependencies = [ "codechain-key", "codechain-keystore", "codechain-logger", - "codechain-merkle", "codechain-network", "codechain-rpc", "codechain-state", @@ -303,7 +302,6 @@ dependencies = [ "codechain-key", "codechain-keystore", "codechain-logger", - "codechain-merkle", "codechain-network", "codechain-state", "codechain-stratum", @@ -319,6 +317,7 @@ dependencies = [ "linked-hash-map", "log 0.4.6", "lru-cache", + "merkle-trie", "num-rational", "parking_lot 0.6.4", "primitives", @@ -457,21 +456,6 @@ dependencies = [ "time", ] -[[package]] -name = "codechain-merkle" -version = "0.1.0" -dependencies = [ - "codechain-crypto", - "codechain-db", - "kvdb", - "kvdb-rocksdb", - "primitives", - "rand 0.6.1", - "rlp", - "tempfile", - "trie-standardmap", -] - [[package]] name = "codechain-network" version = "0.1.0" @@ -544,13 +528,13 @@ dependencies = [ "codechain-db", "codechain-key", "codechain-logger", - "codechain-merkle", "codechain-types", "codechain-vm", "kvdb", "kvdb-memorydb", "log 0.4.6", "lru-cache", + "merkle-trie", "parking_lot 0.6.4", "primitives", "rlp", @@ -584,7 +568,6 @@ dependencies = [ "codechain-db", "codechain-key", "codechain-logger", - "codechain-merkle", "codechain-network", "codechain-state", "codechain-timer", @@ -592,6 +575,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "log 0.4.6", + "merkle-trie", "never-type", "parking_lot 0.6.4", "primitives", @@ -1575,6 +1559,20 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +[[package]] +name = "merkle-trie" +version = "0.1.0" +source = "git+https://github.com/CodeChain-io/rust-merkle-trie.git#a6e067fe71c232d9024952ee63905ab4f5c4407d" +dependencies = [ + "codechain-crypto", + "codechain-db", + "primitives", + "rand 0.6.1", + "rlp", + "rlp_derive", + "snap", +] + [[package]] name = "mime" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index 70a4c7352f..753c49c770 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ codechain-discovery = { path = "discovery" } codechain-logger = { path = "util/logger" } codechain-key = { path = "key" } codechain-keystore = { path = "keystore" } -codechain-merkle = { path = "util/merkle" } codechain-network = { path = "network" } codechain-rpc = { path = "rpc" } codechain-state = { path = "state" } diff --git a/core/Cargo.toml b/core/Cargo.toml index 85fbb765f1..ee8ec36be0 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -12,7 +12,6 @@ codechain-json = { path = "../json" } codechain-key = { path = "../key" } codechain-keystore = { path="../keystore" } codechain-logger = { path = "../util/logger" } -codechain-merkle = { path = "../util/merkle" } codechain-network = { path = "../network" } codechain-state = { path = "../state" } codechain-timer = { path = "../util/timer" } @@ -28,6 +27,7 @@ kvdb-memorydb = "0.1" linked-hash-map = "0.5" log = "0.4.6" lru-cache = "0.1.2" +merkle-trie = { git = "https://github.com/CodeChain-io/rust-merkle-trie.git", version = "0.1" } num-rational = "0.2.1" parking_lot = "0.6.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } diff --git a/core/src/block.rs b/core/src/block.rs index d5ac1a9185..18ced1bf3c 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -18,13 +18,13 @@ use std::collections::HashSet; use ccrypto::BLAKE_NULL_RLP; use ckey::Address; -use cmerkle::skewed_merkle_root; use cstate::{FindActionHandler, StateDB, StateError, StateWithCache, TopLevelState}; use ctypes::errors::HistoryError; use ctypes::header::{Header, Seal}; use ctypes::util::unexpected::Mismatch; use ctypes::{BlockNumber, CommonParams, TxHash}; use cvm::ChainTimeInfo; +use merkle_trie::skewed_merkle_root; use primitives::{Bytes, H256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; diff --git a/core/src/client/client.rs b/core/src/client/client.rs index b0787d5bf6..2fa7b004e6 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -21,7 +21,6 @@ use std::sync::{Arc, Weak}; use cdb::{new_journaldb, Algorithm, AsHashDB, DatabaseError}; use cio::IoChannel; use ckey::{Address, NetworkId, PlatformAddress, Public}; -use cmerkle::Result as TrieResult; use cnetwork::NodeId; use cstate::{ ActionHandler, AssetScheme, FindActionHandler, OwnedAsset, StateDB, StateResult, Text, TopLevelState, TopStateView, @@ -31,6 +30,7 @@ use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction}; use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash}; use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig}; use kvdb::{DBTransaction, KeyValueDB}; +use merkle_trie::Result as TrieResult; use parking_lot::{Mutex, RwLock, RwLockReadGuard}; use primitives::{Bytes, H160, H256, U256}; use rlp::Rlp; diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 79343c6f25..0f1e600306 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -32,13 +32,13 @@ use std::sync::Arc; use cdb::DatabaseError; use ckey::{Address, NetworkId, PlatformAddress, Public}; -use cmerkle::Result as TrieResult; use cnetwork::NodeId; use cstate::{AssetScheme, FindActionHandler, OwnedAsset, StateResult, Text, TopLevelState, TopStateView}; use ctypes::transaction::{AssetTransferInput, PartialHashing, ShardTransaction}; use ctypes::{BlockHash, BlockNumber, CommonParams, ShardId, Tracker, TxHash}; use cvm::ChainTimeInfo; use kvdb::KeyValueDB; +use merkle_trie::Result as TrieResult; use primitives::{Bytes, H160, H256, U256}; use crate::block::{ClosedBlock, OpenBlock, SealedBlock}; diff --git a/core/src/client/test_client.rs b/core/src/client/test_client.rs index 905b9992b3..95ea2d19fe 100644 --- a/core/src/client/test_client.rs +++ b/core/src/client/test_client.rs @@ -38,7 +38,6 @@ use std::sync::Arc; use cdb; use ckey::{public_to_address, Address, Generator, KeyPair, NetworkId, PlatformAddress, Private, Public, Random}; -use cmerkle::skewed_merkle_root; use cnetwork::NodeId; use cstate::tests::helpers::empty_top_state; use cstate::{FindActionHandler, StateDB, TopLevelState}; @@ -48,6 +47,7 @@ use ctypes::{BlockHash, BlockNumber, CommonParams, Header as BlockHeader, Tracke use cvm::ChainTimeInfo; use kvdb::KeyValueDB; use kvdb_memorydb; +use merkle_trie::skewed_merkle_root; use parking_lot::RwLock; use primitives::{Bytes, H256, U256}; use rlp::*; diff --git a/core/src/error.rs b/core/src/error.rs index 36eef08b8c..e8f8b5284f 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -20,11 +20,11 @@ use std::io::Error as StdIoError; use cdb::DatabaseError; use cio::IoError; use ckey::{Address, Error as KeyError}; -use cmerkle::TrieError; use cstate::StateError; use ctypes::errors::{HistoryError, RuntimeError, SyntaxError}; use ctypes::util::unexpected::{Mismatch, OutOfBounds}; use ctypes::{BlockHash, BlockNumber}; +use merkle_trie::TrieError; use primitives::{H256, U256}; use rlp::DecoderError; diff --git a/core/src/lib.rs b/core/src/lib.rs index b3e1a55d99..b648f0744c 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -24,7 +24,6 @@ extern crate codechain_key as ckey; extern crate codechain_keystore as ckeystore; #[macro_use] extern crate codechain_logger as clogger; -extern crate codechain_merkle as cmerkle; extern crate codechain_network as cnetwork; extern crate codechain_state as cstate; extern crate codechain_stratum as cstratum; diff --git a/core/src/scheme/scheme.rs b/core/src/scheme/scheme.rs index 64c427131b..6f075aa947 100644 --- a/core/src/scheme/scheme.rs +++ b/core/src/scheme/scheme.rs @@ -21,10 +21,10 @@ use ccrypto::{blake256, BLAKE_NULL_RLP}; use cdb::{AsHashDB, HashDB}; use cjson; use ckey::Address; -use cmerkle::{TrieFactory, TrieMut}; use cstate::{Metadata, MetadataAddress, Shard, ShardAddress, StateDB, StateResult, StateWithCache, TopLevelState}; use ctypes::errors::SyntaxError; use ctypes::{BlockHash, CommonParams, Header, ShardId}; +use merkle_trie::{TrieFactory, TrieMut}; use parking_lot::RwLock; use primitives::{Bytes, H256, U256}; use rlp::{Encodable, Rlp, RlpStream}; diff --git a/core/src/verification/verification.rs b/core/src/verification/verification.rs index 5ad32138f6..a8cb57d129 100644 --- a/core/src/verification/verification.rs +++ b/core/src/verification/verification.rs @@ -16,9 +16,9 @@ use std::time::{SystemTime, UNIX_EPOCH}; -use cmerkle::skewed_merkle_root; use ctypes::util::unexpected::{Mismatch, OutOfBounds}; use ctypes::{BlockNumber, CommonParams, Header}; +use merkle_trie::skewed_merkle_root; use primitives::{Bytes, H256}; use rlp::Rlp; diff --git a/state/Cargo.toml b/state/Cargo.toml index 97a34ed845..6124dd69d5 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -8,7 +8,6 @@ edition = "2018" codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } codechain-db = { git = "https://github.com/CodeChain-io/rust-codechain-db.git", version = "0.1" } codechain-logger = { path = "../util/logger" } -codechain-merkle = { path = "../util/merkle" } codechain-key = { path = "../key" } codechain-types = { path = "../types" } codechain-vm = { path = "../vm" } @@ -16,6 +15,7 @@ kvdb = "0.1" kvdb-memorydb = "0.1" log = "0.4.6" lru-cache = "0.1.1" +merkle-trie = { git = "https://github.com/CodeChain-io/rust-merkle-trie.git", version = "0.1" } parking_lot = "0.6.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } diff --git a/state/src/cache/shard_cache.rs b/state/src/cache/shard_cache.rs index ae76ef8b65..d0b18e5812 100644 --- a/state/src/cache/shard_cache.rs +++ b/state/src/cache/shard_cache.rs @@ -16,7 +16,7 @@ use std::cell::RefMut; -use cmerkle::{Result as TrieResult, Trie, TrieMut}; +use merkle_trie::{Result as TrieResult, Trie, TrieMut}; use super::WriteBack; use crate::{AssetScheme, AssetSchemeAddress, OwnedAsset, OwnedAssetAddress}; diff --git a/state/src/cache/top_cache.rs b/state/src/cache/top_cache.rs index 1b592f6d0c..225734f2fe 100644 --- a/state/src/cache/top_cache.rs +++ b/state/src/cache/top_cache.rs @@ -17,7 +17,7 @@ use std::cell::RefMut; use ckey::Address; -use cmerkle::{Result as TrieResult, Trie, TrieMut}; +use merkle_trie::{Result as TrieResult, Trie, TrieMut}; use primitives::H256; use super::WriteBack; diff --git a/state/src/cache/write_back.rs b/state/src/cache/write_back.rs index 07b3c0a213..b4123fd4b0 100644 --- a/state/src/cache/write_back.rs +++ b/state/src/cache/write_back.rs @@ -22,7 +22,7 @@ use std::fmt; use std::sync::atomic::{AtomicUsize, Ordering}; use std::vec::Vec; -use cmerkle::{self, Result as TrieResult, Trie, TrieMut}; +use merkle_trie::{Result as TrieResult, Trie, TrieMut}; use super::CacheableItem; @@ -195,7 +195,7 @@ where /// Check caches for required data /// First searches for account in the local, then the shared cache. /// Populates local cache if nothing found. - pub fn get(&self, a: &Item::Address, db: &dyn Trie) -> cmerkle::Result> { + pub fn get(&self, a: &Item::Address, db: &dyn Trie) -> TrieResult> { // check local cache first if let Some(cached_item) = self.cache.borrow_mut().get_mut(a) { cached_item.touched = touched_count(); @@ -210,7 +210,7 @@ where /// Pull item `a` in our cache from the trie DB. /// If it doesn't exist, make item equal the evaluation of `default`. - pub fn get_mut(&self, a: &Item::Address, db: &dyn Trie) -> cmerkle::Result> { + pub fn get_mut(&self, a: &Item::Address, db: &dyn Trie) -> TrieResult> { let contains_key = self.cache.borrow().contains_key(a); if !contains_key { let maybe_item = db.get(a.as_ref())?.map(|bytes| ::rlp::decode::(&bytes).unwrap()); @@ -234,7 +234,7 @@ where })) } - pub fn create Item>(&self, a: &Item::Address, f: F) -> cmerkle::Result { + pub fn create Item>(&self, a: &Item::Address, f: F) -> TrieResult { if let Some(cached) = self.cache.borrow().get(a) { assert!(cached.item.is_none()); } diff --git a/state/src/error.rs b/state/src/error.rs index d2a0161b8c..df758320b0 100644 --- a/state/src/error.rs +++ b/state/src/error.rs @@ -16,8 +16,8 @@ use std::fmt; -use cmerkle::TrieError; use ctypes::errors::RuntimeError; +use merkle_trie::TrieError; #[derive(Clone, Debug, PartialEq)] pub enum Error { diff --git a/state/src/impls/shard_level.rs b/state/src/impls/shard_level.rs index f5f83ade78..41ce943b0a 100644 --- a/state/src/impls/shard_level.rs +++ b/state/src/impls/shard_level.rs @@ -21,7 +21,6 @@ use std::iter::{once, FromIterator}; use ccrypto::{Blake, BLAKE_NULL_RLP}; use cdb::AsHashDB; use ckey::Address; -use cmerkle::{self, TrieError, TrieFactory}; use ctypes::errors::{RuntimeError, UnlockFailureReason}; use ctypes::transaction::{ AssetMintOutput, AssetOutPoint, AssetTransferInput, AssetTransferOutput, AssetWrapCCCOutput, PartialHashing, @@ -30,6 +29,7 @@ use ctypes::transaction::{ use ctypes::util::unexpected::Mismatch; use ctypes::{BlockNumber, ShardId, Tracker}; use cvm::{decode, execute, ChainTimeInfo, ScriptResult, VMConfig}; +use merkle_trie::{Result as TrieResult, TrieError, TrieFactory}; use primitives::{Bytes, H160, H256}; use crate::cache::ShardCache; @@ -65,7 +65,7 @@ impl<'db> ShardLevelState<'db> { db: &'db mut RefCell, root: H256, cache: &'db mut ShardCache, - ) -> cmerkle::Result { + ) -> TrieResult { if !db.borrow().as_hashdb().contains(&root) { return Err(TrieError::InvalidStateRoot(root)) } @@ -85,7 +85,7 @@ impl<'db> ShardLevelState<'db> { db: &RefCell, root: H256, cache: ShardCache, - ) -> cmerkle::Result { + ) -> TrieResult { if !db.borrow().as_hashdb().contains(&root) { return Err(TrieError::InvalidStateRoot(root)) } @@ -661,13 +661,13 @@ impl<'db> ShardLevelState<'db> { registrar: Option
, allowed_script_hashes: Vec, pool: Vec, - ) -> cmerkle::Result { + ) -> TrieResult { self.cache.create_asset_scheme(&AssetSchemeAddress::new(asset_type, shard_id), || { AssetScheme::new_with_pool(metadata, supply, approver, registrar, allowed_script_hashes, pool) }) } - fn get_asset_scheme_mut(&self, shard_id: ShardId, asset_type: H160) -> cmerkle::Result> { + fn get_asset_scheme_mut(&self, shard_id: ShardId, asset_type: H160) -> TrieResult> { let db = self.db.borrow(); let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; self.cache.asset_scheme_mut(&AssetSchemeAddress::new(asset_type, shard_id), &trie) @@ -681,7 +681,7 @@ impl<'db> ShardLevelState<'db> { lock_script_hash: H160, parameters: Vec, quantity: u64, - ) -> cmerkle::Result { + ) -> TrieResult { self.cache.create_asset(&OwnedAssetAddress::new(tracker, index, self.shard_id), || { OwnedAsset::new(asset_type, lock_script_hash, parameters, quantity) }) @@ -694,7 +694,7 @@ impl<'db> ShardLevelState<'db> { } impl<'db> ShardStateView for ShardLevelState<'db> { - fn asset_scheme(&self, asset_type: H160) -> cmerkle::Result> { + fn asset_scheme(&self, asset_type: H160) -> TrieResult> { let db = self.db.borrow(); let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; self.cache.asset_scheme(&AssetSchemeAddress::new(asset_type, self.shard_id), &trie) @@ -777,7 +777,7 @@ pub struct ReadOnlyShardLevelState<'db> { } impl<'db> ShardStateView for ReadOnlyShardLevelState<'db> { - fn asset_scheme(&self, asset_type: H160) -> cmerkle::Result> { + fn asset_scheme(&self, asset_type: H160) -> TrieResult> { let db = self.db.borrow(); let trie = TrieFactory::readonly(db.as_hashdb(), &self.root)?; self.cache.asset_scheme(&AssetSchemeAddress::new(asset_type, self.shard_id), &trie) diff --git a/state/src/impls/top_level.rs b/state/src/impls/top_level.rs index 0e5b1abfb9..8f6db4d858 100644 --- a/state/src/impls/top_level.rs +++ b/state/src/impls/top_level.rs @@ -41,7 +41,6 @@ use std::collections::HashMap; use ccrypto::BLAKE_NULL_RLP; use cdb::{AsHashDB, DatabaseError}; use ckey::{public_to_address, recover, verify_address, Address, NetworkId, Public, Signature}; -use cmerkle::{Result as TrieResult, TrieError, TrieFactory}; use ctypes::errors::RuntimeError; use ctypes::transaction::{ Action, AssetOutPoint, AssetTransferInput, AssetWrapCCCOutput, ShardTransaction, Transaction, @@ -52,6 +51,7 @@ use ctypes::Tracker; use ctypes::{BlockNumber, CommonParams, ShardId, TxHash}; use cvm::ChainTimeInfo; use kvdb::DBTransaction; +use merkle_trie::{Result as TrieResult, TrieError, TrieFactory}; #[cfg(test)] use primitives::H160; use primitives::{Bytes, H256}; diff --git a/state/src/lib.rs b/state/src/lib.rs index eb81b3373e..0b58f222ef 100644 --- a/state/src/lib.rs +++ b/state/src/lib.rs @@ -16,7 +16,6 @@ extern crate codechain_crypto as ccrypto; extern crate codechain_db as cdb; -extern crate codechain_merkle as cmerkle; #[macro_use] extern crate codechain_logger as clogger; extern crate codechain_key as ckey; diff --git a/state/src/tests.rs b/state/src/tests.rs index 00c7a04d11..ee0bc9adcd 100644 --- a/state/src/tests.rs +++ b/state/src/tests.rs @@ -18,11 +18,11 @@ pub mod helpers { use std::sync::Arc; use cdb::AsHashDB; - use cmerkle::{TrieFactory, TrieMut}; use ctypes::{BlockNumber, Tracker}; use cvm::ChainTimeInfo; use kvdb::KeyValueDB; use kvdb_memorydb; + use merkle_trie::{TrieFactory, TrieMut}; use primitives::H256; use rlp::Encodable; diff --git a/state/src/traits.rs b/state/src/traits.rs index 40d94688f7..de89768396 100644 --- a/state/src/traits.rs +++ b/state/src/traits.rs @@ -15,10 +15,10 @@ // along with this program. If not, see . use ckey::{public_to_address, Address, Public, Signature}; -use cmerkle::Result as TrieResult; use ctypes::transaction::ShardTransaction; use ctypes::{BlockNumber, CommonParams, ShardId, Tracker, TxHash}; use cvm::ChainTimeInfo; +use merkle_trie::Result as TrieResult; use primitives::{Bytes, H160, H256}; use crate::{ diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 7cdef063e3..d5d9a5d5b5 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -11,13 +11,13 @@ codechain-core = { path = "../core" } codechain-db = { git = "https://github.com/CodeChain-io/rust-codechain-db.git", version = "0.1" } codechain-key = { path = "../key" } codechain-logger = { path = "../util/logger" } -codechain-merkle = { path = "../util/merkle" } codechain-network = { path = "../network" } codechain-state = { path = "../state" } codechain-timer = { path = "../util/timer" } codechain-types = { path = "../types" } kvdb = "0.1" log = "0.4.6" +merkle-trie = { git = "https://github.com/CodeChain-io/rust-merkle-trie.git", version = "0.1" } never-type = "0.1.0" parking_lot = "0.6.0" primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 54d28314a7..8792691242 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -18,7 +18,6 @@ extern crate parking_lot; extern crate codechain_core as ccore; extern crate codechain_db as cdb; -extern crate codechain_merkle as cmerkle; #[macro_use] extern crate codechain_logger as clogger; extern crate codechain_network as cnetwork; diff --git a/sync/src/snapshot/snapshot.rs b/sync/src/snapshot/snapshot.rs index 3d2a5e099f..645fd5f312 100644 --- a/sync/src/snapshot/snapshot.rs +++ b/sync/src/snapshot/snapshot.rs @@ -24,8 +24,8 @@ use std::sync::Arc; use ccore::COL_STATE; use cdb::{new_journaldb, Algorithm, JournalDB}; -use cmerkle::Node; use kvdb::KeyValueDB; +use merkle_trie::Node; use primitives::H256; use rlp::{Rlp, RlpStream}; use snap; @@ -296,8 +296,8 @@ mod tests { use ccore::COL_STATE; - use cmerkle::{Trie, TrieFactory, TrieMut}; use kvdb_memorydb; + use merkle_trie::{Trie, TrieFactory, TrieMut}; use primitives::H256; use tempfile::tempdir; use trie_standardmap::{Alphabet, StandardMap, ValueMode}; diff --git a/util/merkle/Cargo.toml b/util/merkle/Cargo.toml deleted file mode 100644 index e7e0d1197a..0000000000 --- a/util/merkle/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "codechain-merkle" -version = "0.1.0" -authors = ["CodeChain Team "] -edition = "2018" - -[dependencies] -rand = "0.6.1" -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } -codechain-db = { git = "https://github.com/CodeChain-io/rust-codechain-db.git", version = "0.1" } -primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } -rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" } - -[dev-dependencies] -kvdb = "0.1" -kvdb-rocksdb = "0.1" -tempfile = "3.1.0" -trie-standardmap = { git = "https://github.com/CodeChain-io/trie-standardmap.git", version = "0.2" } diff --git a/util/merkle/benches/triedb.rs b/util/merkle/benches/triedb.rs deleted file mode 100644 index 02b2727152..0000000000 --- a/util/merkle/benches/triedb.rs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -#![feature(test)] - -extern crate codechain_db as cdb; -extern crate codechain_merkle as cmerkle; -extern crate kvdb; -extern crate kvdb_rocksdb as rocksdb; -extern crate primitives; -extern crate rand; -extern crate tempfile; -extern crate test; - -use std::path::Path; -use std::sync::Arc; - -use cdb::{new_journaldb, Algorithm, JournalDB}; -use cmerkle::{Trie, TrieFactory, TrieMut}; -use kvdb::DBTransaction; -use primitives::H256; -use rand::random; -use rocksdb::{CompactionProfile, Database, DatabaseConfig}; -use tempfile::{tempdir, TempDir}; -use test::Bencher; - -struct TestDB { - _dir: TempDir, - db: Arc, - journal: Box, - root: H256, -} - -impl TestDB { - // Replicate CodeChain's db config - fn config(path: &Path) -> DatabaseConfig { - let mut config = DatabaseConfig::with_columns(Some(1)); - config.memory_budget = Default::default(); - config.compaction = CompactionProfile::auto(path); - config - } - - fn populate(path: &Path, size: usize) -> H256 { - // Create database - let config = Self::config(path); - let db = Arc::new(Database::open(&config, path.to_str().unwrap()).unwrap()); - let mut journal = new_journaldb(db.clone(), Algorithm::Archive, Some(0)); - let mut root = H256::new(); - { - let hashdb = journal.as_hashdb_mut(); - let mut trie = TrieFactory::create(hashdb, &mut root); - for i in 0..size { - trie.insert(&i.to_be_bytes(), &i.to_be_bytes()).unwrap(); - } - } - let mut batch = DBTransaction::new(); - journal.journal_under(&mut batch, 0, &H256::new()).unwrap(); - db.write_buffered(batch); - db.flush().unwrap(); - - root - } - - fn new(size: usize) -> Self { - // Create temporary directory - let dir = tempdir().unwrap(); - let root = Self::populate(dir.path(), size); - - // Create database - let config = Self::config(dir.path()); - let db = Arc::new(Database::open(&config, dir.path().to_str().unwrap()).unwrap()); - let journal = new_journaldb(db.clone(), Algorithm::Archive, Some(0)); - - Self { - _dir: dir, - db, - journal, - root, - } - } - - fn trie<'db>(&'db self) -> impl Trie + 'db { - let hashdb = self.journal.as_hashdb(); - TrieFactory::readonly(hashdb, &self.root).unwrap() - } - - fn trie_mut<'db>(&'db mut self) -> impl TrieMut + 'db { - let hashdb = self.journal.as_hashdb_mut(); - TrieFactory::create(hashdb, &mut self.root) - } - - fn flush(&mut self) { - let mut batch = DBTransaction::new(); - self.journal.journal_under(&mut batch, 0, &H256::new()).unwrap(); - self.db.write_buffered(batch); - self.db.flush().unwrap(); - } -} - -const DB_SIZE: usize = 10000; -const BATCH: usize = 10000; - -#[bench] -fn bench_read_single(b: &mut Bencher) { - let db = TestDB::new(DB_SIZE); - b.iter(|| { - let trie = db.trie(); - let item = random::() % DB_SIZE; - let _ = trie.get(&item.to_be_bytes()).unwrap().unwrap(); - }); -} - -#[bench] -fn bench_read_multiple(b: &mut Bencher) { - let db = TestDB::new(DB_SIZE); - b.iter(|| { - let trie = db.trie(); - for _ in 0..BATCH { - let item = random::() % DB_SIZE; - let _ = trie.get(&item.to_be_bytes()).unwrap().unwrap(); - } - }); -} - -#[bench] -fn bench_write_single(b: &mut Bencher) { - let mut db = TestDB::new(DB_SIZE); - b.iter(|| { - { - let mut trie = db.trie_mut(); - let item = random::() % DB_SIZE + DB_SIZE; - let _ = trie.insert(&item.to_be_bytes(), &item.to_be_bytes()).unwrap(); - } - db.flush(); - }); -} - -#[bench] -fn bench_write_multiple(b: &mut Bencher) { - let mut db = TestDB::new(DB_SIZE); - b.iter(|| { - { - let mut trie = db.trie_mut(); - for _ in 0..BATCH { - let item = random::() % DB_SIZE + DB_SIZE; - let _ = trie.insert(&item.to_be_bytes(), &item.to_be_bytes()).unwrap(); - } - } - db.flush(); - }); -} diff --git a/util/merkle/src/lib.rs b/util/merkle/src/lib.rs deleted file mode 100644 index f3bf4a6bd5..0000000000 --- a/util/merkle/src/lib.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -extern crate codechain_crypto as ccrypto; -extern crate codechain_db as cdb; -extern crate primitives; -extern crate rlp; - -#[cfg(test)] -extern crate trie_standardmap as standardmap; - -use std::fmt; - -use ccrypto::BLAKE_NULL_RLP; -use cdb::{DBValue, HashDB}; -use primitives::H256; - -mod nibbleslice; -pub mod node; -mod skewed; -pub mod triedb; -pub mod triedbmut; -pub mod triehash; - -pub use crate::node::Node; -pub use crate::skewed::skewed_merkle_root; -use crate::triedb::TrieDB; -use crate::triedbmut::TrieDBMut; - -/// Trie Errors. -/// -/// These borrow the data within them to avoid excessive copying on every -/// trie operation. -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum TrieError { - /// Attempted to create a trie with a state root not in the DB. - InvalidStateRoot(H256), - /// Trie item not found in the database, - IncompleteDatabase(H256), -} - -impl fmt::Display for TrieError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - TrieError::InvalidStateRoot(root) => write!(f, "Invalid state root: {}", root), - TrieError::IncompleteDatabase(missing) => write!(f, "Database missing expected key: {}", missing), - } - } -} - -pub type Result = ::std::result::Result; - -/// A key-value datastore implemented as a database-backed Merkle trie. -pub trait Trie { - /// Return the root of the trie. - fn root(&self) -> &H256; - - /// Is the trie empty? - fn is_empty(&self) -> bool { - *self.root() == BLAKE_NULL_RLP - } - - /// Does the trie contain a given key? - fn contains(&self, key: &[u8]) -> Result { - self.get(key).map(|x| x.is_some()) - } - - /// What is the value of the given key in this trie? - fn get(&self, key: &[u8]) -> Result>; -} - -/// A key-value datastore implemented as a database-backed modified Merkle tree. -pub trait TrieMut: Trie { - /// Insert a `key`/`value` pair into the trie. An empty value is equivalent to removing - /// `key` from the trie. Returns the old value associated with this key, if it existed. - fn insert(&mut self, key: &[u8], value: &[u8]) -> Result>; - - /// Remove a `key` from the trie. Equivalent to making it equal to the empty - /// value. Returns the old value associated with this key, if it existed. - fn remove(&mut self, key: &[u8]) -> Result>; -} - -pub enum TrieFactory {} - -impl TrieFactory { - /// Create new immutable instance of Trie. - pub fn readonly<'db>(db: &'db dyn HashDB, root: &'db H256) -> Result { - Ok(TrieDB::try_new(db, root)?) - } - - /// Create new mutable instance of Trie. - pub fn create<'db>(db: &'db mut dyn HashDB, root: &'db mut H256) -> impl TrieMut + 'db { - TrieDBMut::new(db, root) - } - - /// Create new mutable instance of trie and check for errors. - pub fn from_existing<'db>(db: &'db mut dyn HashDB, root: &'db mut H256) -> Result { - Ok(TrieDBMut::from_existing(db, root)?) - } -} diff --git a/util/merkle/src/nibbleslice.rs b/util/merkle/src/nibbleslice.rs deleted file mode 100644 index d39714c21d..0000000000 --- a/util/merkle/src/nibbleslice.rs +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -use std::cmp::*; -use std::fmt; - - -#[derive(Eq, Ord)] -pub struct NibbleSlice<'a> { - pub data: &'a [u8], - pub offset: usize, -} - -impl<'a, 'view> NibbleSlice<'a> -where - 'a: 'view, -{ - /// Create a new nibble slice with the given byte-slice. - pub fn new(data: &'a [u8]) -> Self { - NibbleSlice::new_offset(data, 0) - } - - /// Create a new nibble slice with the given byte-slice with a nibble offset. - pub fn new_offset(data: &'a [u8], offset: usize) -> Self { - NibbleSlice { - data, - offset, - } - } - - /// Create a new nibble slice from the given HPE encoded data (e.g. output of `encoded()`). - pub fn from_encoded(data: &'a [u8]) -> NibbleSlice { - let offset = if (data[0] & 0b1_0000) == 0b1_0000 { - 1 - } else { - 2 - }; - Self::new_offset(data, offset) - } - - /// Is this an empty slice? - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Get the length (in nibbles, naturally) of this slice. - pub fn len(&self) -> usize { - self.data.len() * 2 - self.offset - } - - /// Get the nibble at position `i`. - pub fn at(&self, i: usize) -> u8 { - let word = self.data[(self.offset + i) >> 1]; - if (self.offset + i) & 1 == 1 { - word & 0b1111 - } else { - word >> 4 - } - } - - /// Return object which represents a view on to this slice (further) offset by `i` nibbles. - pub fn mid(&'view self, i: usize) -> NibbleSlice<'a> { - NibbleSlice { - data: self.data, - offset: self.offset + i, - } - } - - /// Do we start with the same nibbles as the whole of `them`? - pub fn starts_with(&self, them: &Self) -> bool { - self.common_prefix(them) == them.len() - } - - /// How many of the same nibbles at the beginning do we match with `them`? - pub fn common_prefix(&self, them: &Self) -> usize { - let s = min(self.len(), them.len()); - let mut i = 0usize; - while i < s { - if self.at(i) != them.at(i) { - break - } - i += 1; - } - i - } - - /// Encode while nibble slice in prefixed hex notation, noting whether it `is_leaf`. - pub fn encoded(&self) -> Vec { - let l = self.len(); - let mut r = Vec::new(); - let mut i = l % 2; - r.push(if i == 1 { - 0b1_0000 + self.at(0) - } else { - 0 - }); - while i < l { - r.push((self.at(i) << 4) + self.at(i + 1)); - i += 2; - } - r - } - - - /// Encode only the leftmost `n` bytes of the nibble slice in prefixed hex notation, - /// noting whether it `is_leaf`. - pub fn encoded_leftmost(&self, n: usize) -> Vec { - let l = min(self.len(), n); - let mut r = Vec::new(); - let mut i = l % 2; - r.push(if i == 1 { - 0b1_0000 + self.at(0) - } else { - 0 - }); - while i < l { - r.push((self.at(i) << 4) + self.at(i + 1)); - i += 2; - } - r - } - - pub fn to_vec(&self) -> Vec { - let mut vec: Vec = Vec::new(); - for i in 0..self.len() { - vec.push(self.at(i)); - } - vec - } - - pub fn from_vec(v: &[u8]) -> (Vec, usize) { - let mut r = Vec::new(); - let l = v.len(); - let mut i = l % 2; - r.push(if i == 1 { - 0b1_0000 + (v[0] & 0b1111) - } else { - 0 - }); - while i < l { - r.push(((v[i] & 0b1111) << 4) + (v[i + 1] & 0b1111)); - i += 2; - } - (r, 2 - (l % 2)) - } -} - -impl<'a> PartialEq for NibbleSlice<'a> { - fn eq(&self, them: &Self) -> bool { - self.len() == them.len() && self.starts_with(them) - } -} - -impl<'a> PartialOrd for NibbleSlice<'a> { - fn partial_cmp(&self, them: &Self) -> Option { - let s = min(self.len(), them.len()); - let mut i = 0usize; - while i < s { - match self.at(i).partial_cmp(&them.at(i)).unwrap() { - Ordering::Less => return Some(Ordering::Less), - Ordering::Greater => return Some(Ordering::Greater), - _ => i += 1, - } - } - self.len().partial_cmp(&them.len()) - } -} - -impl<'a> fmt::Debug for NibbleSlice<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for i in 0..self.len() { - match i { - 0 => write!(f, "{:01x}", self.at(i))?, - _ => write!(f, "'{:01x}", self.at(i))?, - } - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::NibbleSlice; - - static D: &[u8; 3] = &[0x01u8, 0x23, 0x45]; - - #[test] - fn basics() { - let n = NibbleSlice::new(D); - assert_eq!(n.len(), 6); - assert!(!n.is_empty()); - - let n = NibbleSlice::new_offset(D, 6); - assert!(n.is_empty()); - - let n = NibbleSlice::new_offset(D, 3); - assert_eq!(n.len(), 3); - for i in 0..3 { - assert_eq!(n.at(i), i as u8 + 3); - } - } - - #[test] - fn mid() { - let n = NibbleSlice::new(D); - let m = n.mid(2); - for i in 0..4 { - assert_eq!(m.at(i), i as u8 + 2); - } - let m = n.mid(3); - for i in 0..3 { - assert_eq!(m.at(i), i as u8 + 3); - } - } - - #[test] - fn encoded() { - let n = NibbleSlice::new(D); - assert_eq!(n.encoded(), vec![0x00, 0x01, 0x23, 0x45]); - assert_eq!(n.mid(1).encoded(), vec![0x11, 0x23, 0x45]); - } - - #[test] - fn from_encoded() { - let n = NibbleSlice::new(D); - assert_eq!(n, NibbleSlice::from_encoded(&[0x00, 0x01, 0x23, 0x45])); - assert_eq!(n.mid(1), NibbleSlice::from_encoded(&[0x11, 0x23, 0x45])); - } - - #[test] - fn shared() { - let n = NibbleSlice::new(D); - - let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45, 0x67]; - let m = NibbleSlice::new(other); - - assert_eq!(n.common_prefix(&m), 4); - assert_eq!(m.common_prefix(&n), 4); - assert_eq!(n.mid(1).common_prefix(&m.mid(1)), 3); - assert_eq!(n.mid(1).common_prefix(&m.mid(2)), 0); - assert_eq!(n.common_prefix(&m.mid(4)), 6); - assert!(!n.starts_with(&m.mid(4))); - assert!(m.mid(4).starts_with(&n)); - } - - #[test] - fn compare() { - let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45]; - let n = NibbleSlice::new(D); - let m = NibbleSlice::new(other); - - assert!(n != m); - assert!(n > m); - assert!(m < n); - - assert!(n == m.mid(4)); - assert!(n >= m.mid(4)); - assert!(n <= m.mid(4)); - } -} diff --git a/util/merkle/src/node.rs b/util/merkle/src/node.rs deleted file mode 100644 index 66f2704808..0000000000 --- a/util/merkle/src/node.rs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use primitives::H256; -use rlp::*; - -use crate::nibbleslice::NibbleSlice; - - -#[derive(Eq, PartialEq, Debug)] -pub enum Node<'a> { - Leaf(NibbleSlice<'a>, &'a [u8]), - - Branch(NibbleSlice<'a>, Box<[Option; 16]>), -} - -impl<'a> Node<'a> { - /// Decode the `node_rlp` and return the Node. - pub fn decoded(node_rlp: &'a [u8]) -> Option { - let r = Rlp::new(node_rlp); - match r.prototype().unwrap() { - // Empty node - Prototype::Data(0) => None, - // leaf node - first is nibbles and second is value - Prototype::List(2) => { - let slice = NibbleSlice::from_encoded(r.at(0).unwrap().data().unwrap()); - - Some(Node::Leaf(slice, r.at(1).unwrap().data().unwrap())) - } - // branch node - first is nibbles (or empty), the rest 16 are nodes. - Prototype::List(17) => { - let mut nodes = [None; 16]; - debug_assert_eq!(16, nodes.len()); - for (i, node) in nodes.iter_mut().enumerate().map(|(i, node)| (i + 1, node)) { - *node = if r.at(i).unwrap().is_empty() { - None - } else { - Some(r.val_at::(i).unwrap()) - }; - } - - Some(Node::Branch(NibbleSlice::from_encoded(r.at(0).unwrap().data().unwrap()), nodes.into())) - } - - // something went wrong. - _ => panic!("Rlp data is not valid."), - } - } - - /// Encode the node into RLP. - pub fn encoded(node: Self) -> Vec { - match node { - Node::Leaf(slice, value) => { - let mut stream = RlpStream::new_list(2); - stream.append(&&*slice.encoded()); - stream.append(&value); - stream.drain() - } - Node::Branch(slice, nodes) => { - let mut stream = RlpStream::new_list(17); - - stream.append(&&*slice.encoded()); - - for child in nodes.iter() { - if let Some(hash) = child { - stream.append(hash); - } else { - stream.append_empty_data(); - } - } - stream.drain() - } - } - } - - /// Encode the node into RLP. - /// What the difference with above `encoded()` is length of nibblepath encoded - pub fn encoded_until(node: Self, size: usize) -> Vec { - match node { - Node::Leaf(slice, value) => { - let mut stream = RlpStream::new_list(2); - stream.append(&&*slice.encoded_leftmost(size)); - stream.append(&&*value); - stream.drain() - } - Node::Branch(slice, nodes) => { - let mut stream = RlpStream::new_list(17); - - stream.append(&&*slice.encoded_leftmost(size)); - - for child in nodes.iter() { - if let Some(hash) = child { - stream.append(hash); - } else { - stream.append_empty_data(); - } - } - stream.drain() - } - } - } -} diff --git a/util/merkle/src/skewed.rs b/util/merkle/src/skewed.rs deleted file mode 100644 index 2e5ecaac3c..0000000000 --- a/util/merkle/src/skewed.rs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2018 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use std::ops::BitXor; - -use ccrypto::Blake; - -// skewed_merkle_root(base, vec![input0, input1, input2, input3]) -// will creates the tree as below -// -// root -// / \ -// h0 input3 -// / \ -// h1 input2 -// / \ -// h2 input1 -// / \ -// base input0 -// -// and returns the root. -// This function calls hash function twice per depth. One is hashing input. This hashing makes input -// to the fixed size. And the other is for merkling. - -pub fn skewed_merkle_root(base: Out, inputs: Iter) -> Out -where - Iter: IntoIterator, - In: AsRef<[u8]>, - Xor: AsRef<[u8]>, - Out: BitXor + Blake, { - inputs.into_iter().fold(base, |acc, input| { - let xor = acc ^ Blake::blake(input); - Blake::blake(&xor) - }) -} - -#[cfg(test)] -mod tests { - use std::vec::Vec; - - use primitives::H256; - - use super::*; - - #[test] - fn empty_is_zero() { - let result = skewed_merkle_root::, _, _, _>(H256::zero(), vec![]); - assert_eq!(H256::zero(), result); - } - - #[test] - fn one_is_hash_of_blake() { - let item: H256 = 1000.into(); - let result = skewed_merkle_root(H256::zero(), vec![item]); - assert_eq!(H256::blake(H256::blake(item)), result); - } - - #[test] - fn skewed_merkle_trie_of_two_elements() { - let item0: H256 = 1000.into(); - let item1: H256 = 1001.into(); - let expected = H256::blake(H256::blake(H256::blake(&item0)) ^ H256::blake(&item1)); - let result = skewed_merkle_root(H256::zero(), vec![item0, item1]); - assert_eq!(expected, result); - } - - #[test] - fn skewed_merkle_trie_of_three_elements() { - let item0 = vec![0xCA, 0xFE]; - let item2 = vec![ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, - 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, - 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, - 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, - 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, - 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, - 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, - 0xFC, 0xFD, 0xFE, 0xFF, - ]; - let item1 = vec![0xBE, 0xBE]; - let expected = - H256::blake(H256::blake(H256::blake(H256::blake(&item0)) ^ H256::blake(&item1)) ^ H256::blake(&item2)); - let result = skewed_merkle_root(H256::zero(), vec![item0, item1, item2]); - assert_eq!(expected, result); - } - - #[test] - fn skewed_merkle_trie_is_incremental() { - let total: Vec = vec![ - 0xCAFE.into(), - 0xDEAD.into(), - 0xBEEF_CAFE.into(), - 0xDEAD_BEEF.into(), - 0xDEAD_BEEF_CAFE.into(), - 0xBEEF.into(), - 0xBEBE.into(), - 0xFEED.into(), - ]; - - let parent: Vec = total.iter().take(4).map(Clone::clone).collect(); - let parent_output = skewed_merkle_root(H256::zero(), parent); - - let current: Vec = total.iter().skip(4).map(Clone::clone).collect(); - let calculated: H256 = skewed_merkle_root(parent_output, current); - - let expected: H256 = skewed_merkle_root(H256::zero(), total); - - assert_eq!(calculated, expected); - } -} diff --git a/util/merkle/src/triedb.rs b/util/merkle/src/triedb.rs deleted file mode 100644 index 725bdf4e43..0000000000 --- a/util/merkle/src/triedb.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use ccrypto::blake256; -use cdb::HashDB; -use primitives::H256; - -use crate::nibbleslice::NibbleSlice; -use crate::node::Node as RlpNode; -use crate::{Trie, TrieError}; -/// A `Trie` implementation using a generic `HashDB` backing database. -/// -/// Use it as a `Trie` trait object. You can use `db()` to get the backing database object. -/// Use `get` and `contains` to query values associated with keys in the trie. -/// -/// # Example -/// ``` -/// extern crate codechain_db as cdb; -/// extern crate primitives; -/// extern crate codechain_merkle as cmerkle; -/// -/// use cmerkle::*; -/// use cdb::*; -/// use primitives::H256; -/// -/// let mut memdb = MemoryDB::new(); -/// let mut root = H256::new(); -/// TrieFactory::create(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap(); -/// let t = TrieFactory::readonly(&memdb, &root).unwrap(); -/// assert!(t.contains(b"foo").unwrap()); -/// assert_eq!(t.get(b"foo").unwrap().unwrap(), b"bar".to_vec()); -/// ``` -pub(crate) struct TrieDB<'db> { - db: &'db dyn HashDB, - root: &'db H256, -} - -/// Description of what kind of query will be made to the trie. -type Query = dyn Fn(&[u8]) -> T; - -impl<'db> TrieDB<'db> { - /// Create a new trie with the backing database `db` and `root` - /// Returns an error if `root` does not exist - pub fn try_new(db: &'db dyn HashDB, root: &'db H256) -> crate::Result { - if !db.contains(root) { - Err(TrieError::InvalidStateRoot(*root)) - } else { - Ok(TrieDB { - db, - root, - }) - } - } - - /// Get auxiliary - fn get_aux( - &self, - path: &NibbleSlice, - cur_node_hash: Option, - query: &Query, - ) -> crate::Result> { - match cur_node_hash { - Some(hash) => { - let node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?; - - match RlpNode::decoded(&node_rlp) { - Some(RlpNode::Leaf(partial, value)) => { - if &partial == path { - Ok(Some(query(value))) - } else { - Ok(None) - } - } - Some(RlpNode::Branch(partial, children)) => { - if path.starts_with(&partial) { - self.get_aux( - &path.mid(partial.len() + 1), - children[path.mid(partial.len()).at(0) as usize], - query, - ) - } else { - Ok(None) - } - } - None => Ok(None), - } - } - None => Ok(None), - } - } -} - -impl<'db> Trie for TrieDB<'db> { - fn root(&self) -> &H256 { - self.root - } - - fn get(&self, key: &[u8]) -> Result>, TrieError> { - let path = blake256(key); - let root = *self.root; - - self.get_aux(&NibbleSlice::new(&path), Some(root), &|bytes| bytes.to_vec()) - } -} - -#[cfg(test)] -mod tests { - use cdb::MemoryDB; - - use super::*; - use crate::*; - - #[test] - fn get() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(b"A", b"ABC").unwrap(); - t.insert(b"B", b"ABCBA").unwrap(); - } - - let t = TrieDB::try_new(&memdb, &root).unwrap(); - assert_eq!(t.get(b"A"), Ok(Some(b"ABC".to_vec()))); - assert_eq!(t.get(b"B"), Ok(Some(b"ABCBA".to_vec()))); - assert_eq!(t.get(b"C"), Ok(None)); - } -} diff --git a/util/merkle/src/triedbmut.rs b/util/merkle/src/triedbmut.rs deleted file mode 100644 index 80f819681b..0000000000 --- a/util/merkle/src/triedbmut.rs +++ /dev/null @@ -1,719 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -use std::fmt; - -use ccrypto::{blake256, BLAKE_NULL_RLP}; -use cdb::{DBValue, HashDB}; -use primitives::H256; - -use crate::nibbleslice::NibbleSlice; -use crate::node::Node as RlpNode; -use crate::triedb::TrieDB; -use crate::{Trie, TrieError, TrieMut}; - -fn empty_children() -> [Option; 16] { - [None; 16] -} - -pub(crate) struct TrieDBMut<'a> { - db: &'a mut dyn HashDB, - // When Trie is empty, root has None. - root: &'a mut H256, -} - -impl<'a> TrieDBMut<'a> { - /// Create a new trie with backing database `db` and empty `root`. - pub fn new(db: &'a mut dyn HashDB, root: &'a mut H256) -> Self { - *root = BLAKE_NULL_RLP; - - TrieDBMut { - db, - root, - } - } - - /// Create a new trie with the backing database `db` and `root. - /// Returns an error if `root` does not exist. - pub fn from_existing(db: &'a mut dyn HashDB, root: &'a mut H256) -> crate::Result { - if !db.contains(root) { - return Err(TrieError::InvalidStateRoot(*root)) - } - - Ok(TrieDBMut { - db, - root, - }) - } - - /// Insert auxiliary - fn insert_aux( - &mut self, - path: NibbleSlice, - insert_value: &[u8], - cur_node_hash: Option, - old_val: &mut Option, - ) -> crate::Result { - match cur_node_hash { - Some(hash) => { - let node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?; - - match RlpNode::decoded(&node_rlp) { - Some(RlpNode::Leaf(partial, value)) => { - // Renew the Leaf - if partial == path { - let node = RlpNode::Leaf(path, insert_value); - let node_rlp = RlpNode::encoded(node); - let hash = self.db.insert(&node_rlp); - - *old_val = Some(value.to_vec()); - - Ok(hash) - } else { - // Make branch node and insert Leaves - let common = partial.common_prefix(&path); - let mut new_child = empty_children(); - let new_partial = partial.mid(common); - let new_path = path.mid(common); - - new_child[new_partial.at(0) as usize] = Some(self.insert_aux( - new_partial.mid(1), - value, - new_child[new_partial.at(0) as usize], - old_val, - )?); - new_child[new_path.at(0) as usize] = Some(self.insert_aux( - new_path.mid(1), - insert_value, - new_child[new_path.at(0) as usize], - old_val, - )?); - - let node_rlp = RlpNode::encoded_until(RlpNode::Branch(partial, new_child.into()), common); - let hash = self.db.insert(&node_rlp); - - Ok(hash) - } - } - Some(RlpNode::Branch(partial, mut children)) => { - let common = partial.common_prefix(&path); - - // Make new branch node and insert leaf and branch with new path - if common < partial.len() { - let mut new_child = empty_children(); - let new_partial = partial.mid(common); - let new_path = path.mid(common); - let o_branch = RlpNode::Branch(new_partial.mid(1), children); - - let mut node_rlp = RlpNode::encoded(o_branch); - let b_hash = self.db.insert(&node_rlp); - - new_child[new_partial.at(0) as usize] = Some(b_hash); - new_child[new_path.at(0) as usize] = Some(self.insert_aux( - new_path.mid(1), - insert_value, - new_child[new_path.at(0) as usize], - old_val, - )?); - - node_rlp = RlpNode::encoded_until(RlpNode::Branch(partial, new_child.into()), common); - let hash = self.db.insert(&node_rlp); - - Ok(hash) - } else { - // Insert leaf into the branch node - let new_path = path.mid(common); - - children[new_path.at(0) as usize] = Some(self.insert_aux( - new_path.mid(1), - insert_value, - children[new_path.at(0) as usize], - old_val, - )?); - - let new_branch = RlpNode::Branch(partial, children); - let node_rlp = RlpNode::encoded(new_branch); - let hash = self.db.insert(&node_rlp); - - Ok(hash) - } - } - None => { - let node = RlpNode::Leaf(path, insert_value); - let node_rlp = RlpNode::encoded(node); - let hash = self.db.insert(&node_rlp); - - Ok(hash) - } - } - } - None => { - let node = RlpNode::Leaf(path, insert_value); - let node_rlp = RlpNode::encoded(node); - let hash = self.db.insert(&node_rlp); - - Ok(hash) - } - } - } - - /// Remove auxiliary - fn remove_aux( - &mut self, - path: &NibbleSlice, - cur_node_hash: Option, - old_val: &mut Option, - ) -> crate::Result> { - match cur_node_hash { - Some(hash) => { - let node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?; - - match RlpNode::decoded(&node_rlp) { - Some(RlpNode::Leaf(partial, value)) => { - if path == &partial { - *old_val = Some(value.to_vec()); - - Ok(None) - } else { - Ok(cur_node_hash) - } - } - Some(RlpNode::Branch(partial, mut children)) => { - if path.starts_with(&partial) { - let new_path = path.mid(partial.len()); - children[new_path.at(0) as usize] = - self.remove_aux(&new_path.mid(1), children[new_path.at(0) as usize], old_val)?; - - if children[new_path.at(0) as usize] == None { - // Fix the node - let child_count = children.iter().filter(|x| x.is_none()).count(); - - match child_count { - 16 => { - // Branch can be removed - Ok(None) - } - 15 => { - // Transform the branch into Leaf - let index = children - .iter() - .position(Option::is_some) - .expect("Can not find leaf in the branch"); - let new_leaf_hash = children[index].expect("Index is wrong"); - let new_leaf_data = self - .db - .get(&new_leaf_hash) - .ok_or_else(|| TrieError::IncompleteDatabase(hash))?; - let new_leaf_node = RlpNode::decoded(&new_leaf_data); - - match new_leaf_node { - None => Err(TrieError::IncompleteDatabase(hash)), - Some(RlpNode::Leaf(child_partial, child_value)) => { - let mut vec = partial.to_vec(); - vec.push(index as u8); - vec.append(&mut child_partial.to_vec()); - - let (new_partial, offset) = NibbleSlice::from_vec(&vec); - let new_leaf = RlpNode::Leaf( - NibbleSlice::new_offset(&new_partial, offset), - child_value, - ); - let node_rlp = RlpNode::encoded(new_leaf); - let new_hash = self.db.insert(&node_rlp); - - Ok(Some(new_hash)) - } - Some(RlpNode::Branch(child_partial, children)) => { - let mut vec = partial.to_vec(); - vec.push(index as u8); - vec.append(&mut child_partial.to_vec()); - - let (new_partial, offset) = NibbleSlice::from_vec(&vec); - let new_branch = RlpNode::Branch( - NibbleSlice::new_offset(&new_partial, offset), - children, - ); - let node_rlp = RlpNode::encoded(new_branch); - let new_hash = self.db.insert(&node_rlp); - - Ok(Some(new_hash)) - } - } - } - _ => { - let new_branch = RlpNode::Branch(partial, children); - let node_rlp = RlpNode::encoded(new_branch); - let new_hash = self.db.insert(&node_rlp); - - Ok(Some(new_hash)) - } - } - } else { - let new_branch = RlpNode::Branch(partial, children); - let node_rlp = RlpNode::encoded(new_branch); - let new_hash = self.db.insert(&node_rlp); - - Ok(Some(new_hash)) - } - } else { - Ok(cur_node_hash) - } - } - None => Ok(cur_node_hash), - } - } - None => Ok(cur_node_hash), - } - } -} - -impl<'a> fmt::Display for RlpNode<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - RlpNode::Leaf(partial, value) => writeln!(f, "Leaf - key({:?}), value({:?})", partial, value), - RlpNode::Branch(partial, children) => { - writeln!(f, "Branch - path({:?})", partial)?; - - debug_assert_eq!(16, children.len()); - for (i, child) in children.iter().enumerate() { - writeln!(f, "child {} - hash({:?})", i, child)?; - } - Ok(()) - } - } - } -} - -impl<'a> Trie for TrieDBMut<'a> { - fn root(&self) -> &H256 { - self.root - } - - fn is_empty(&self) -> bool { - *self.root == BLAKE_NULL_RLP - } - - fn get(&self, key: &[u8]) -> crate::Result> { - let t = TrieDB::try_new(self.db, self.root)?; - - t.get(key) - } -} - -impl<'a> TrieMut for TrieDBMut<'a> { - fn insert(&mut self, key: &[u8], value: &[u8]) -> crate::Result> { - let path = blake256(key); - let mut old_val = None; - let cur_hash = *self.root; - *self.root = self.insert_aux(NibbleSlice::new(&path), value, Some(cur_hash), &mut old_val)?; - - Ok(old_val) - } - - fn remove(&mut self, key: &[u8]) -> crate::Result> { - let path = blake256(key); - let mut old_val = None; - let cur_hash = *self.root; - - *self.root = match self.remove_aux(&NibbleSlice::new(&path), Some(cur_hash), &mut old_val)? { - Some(hash) => hash, - None => BLAKE_NULL_RLP, - }; - - Ok(old_val) - } -} - - -#[cfg(test)] -mod tests { - use ccrypto::BLAKE_NULL_RLP; - use cdb::*; - use standardmap::*; - - use crate::triehash::trie_root; - use crate::TrieMut; - - use super::*; - - fn populate_trie<'db>(db: &'db mut dyn HashDB, root: &'db mut H256, v: &[(Vec, Vec)]) -> TrieDBMut<'db> { - let mut t = TrieDBMut::new(db, root); - for (key, val) in v { - t.insert(key, val).unwrap(); - } - t - } - - fn unpopulate_trie(t: &mut TrieDBMut, v: &[(Vec, Vec)]) { - for i in v { - let key: &[u8] = &i.0; - t.remove(key).unwrap(); - } - } - - #[test] - fn playpen() { - let mut seed = H256::new(); - for test_i in 0..10 { - if test_i % 50 == 0 { - println!("{:?} of 10000 stress tests done", test_i); - } - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 100, - } - .make_with(&mut seed); - - let real = trie_root(x.clone()); - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut memtrie = populate_trie(&mut memdb, &mut root, &x); - - if *memtrie.root() != real { - println!("TRIE MISMATCH"); - println!(); - println!("{:?} vs {:?}", memtrie.root(), real); - for i in &x { - println!("{:?} -> {:?}", i.0, i.1); - } - } - assert_eq!(*memtrie.root(), real); - unpopulate_trie(&mut memtrie, &x); - - if *memtrie.root() != BLAKE_NULL_RLP { - println!("- TRIE MISMATCH"); - println!(); - println!("{:?} vs {:?}", memtrie.root(), real); - for i in &x { - println!("{:?} -> {:?}", i.0, i.1); - } - } - assert_eq!(*memtrie.root(), BLAKE_NULL_RLP); - } - } - - #[test] - fn init() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let t = TrieDBMut::new(&mut memdb, &mut root); - assert_eq!(*t.root(), BLAKE_NULL_RLP); - } - - #[test] - fn insert_on_empty() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - assert_eq!(*t.root(), trie_root(vec![(vec![0x01u8, 0x23], vec![0x01u8, 0x23])])); - } - - #[test] - fn remove_to_empty() { - let big_value = b"00000000000000000000000000000000"; - - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t1 = TrieDBMut::new(&mut memdb, &mut root); - t1.insert(&[0x01, 0x23], big_value).unwrap(); - t1.insert(&[0x01, 0x34], big_value).unwrap(); - let mut memdb2 = MemoryDB::new(); - let mut root2 = H256::new(); - let mut t2 = TrieDBMut::new(&mut memdb2, &mut root2); - t2.insert(&[0x01], big_value).unwrap(); - t2.insert(&[0x01, 0x23], big_value).unwrap(); - t2.insert(&[0x01, 0x34], big_value).unwrap(); - t2.remove(&[0x01]).unwrap(); - } - - #[test] - fn insert_replace_root() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]).unwrap(); - assert_eq!(*t.root(), trie_root(vec![(vec![0x01u8, 0x23], vec![0x23u8, 0x45])])); - } - - #[test] - fn insert_make_branch_root() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]).unwrap(); - assert_eq!( - *t.root(), - trie_root(vec![(vec![0x01u8, 0x23], vec![0x01u8, 0x23]), (vec![0x11u8, 0x23], vec![0x11u8, 0x23])]) - ); - } - - #[test] - fn insert_into_branch_root() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap(); - t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap(); - assert_eq!( - *t.root(), - trie_root(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), - (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), - ]) - ); - } - - #[test] - fn insert_value_into_branch_root() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[], &[0x0]).unwrap(); - assert_eq!(*t.root(), trie_root(vec![(vec![], vec![0x0]), (vec![0x01u8, 0x23], vec![0x01u8, 0x23])])); - } - - #[test] - fn insert_split_leaf() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]).unwrap(); - assert_eq!( - *t.root(), - trie_root(vec![(vec![0x01u8, 0x23], vec![0x01u8, 0x23]), (vec![0x01u8, 0x34], vec![0x01u8, 0x34])]) - ); - } - - #[test] - fn insert_split_extenstion() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01, 0x23, 0x45], &[0x01]).unwrap(); - t.insert(&[0x01, 0xf3, 0x45], &[0x02]).unwrap(); - t.insert(&[0x01, 0xf3, 0xf5], &[0x03]).unwrap(); - assert_eq!( - *t.root(), - trie_root(vec![ - (vec![0x01, 0x23, 0x45], vec![0x01]), - (vec![0x01, 0xf3, 0x45], vec![0x02]), - (vec![0x01, 0xf3, 0xf5], vec![0x03]), - ]) - ); - } - - #[test] - fn insert_big_value() { - let big_value0 = b"00000000000000000000000000000000"; - let big_value1 = b"11111111111111111111111111111111"; - - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], big_value0).unwrap(); - t.insert(&[0x11u8, 0x23], big_value1).unwrap(); - assert_eq!( - *t.root(), - trie_root(vec![(vec![0x01u8, 0x23], big_value0.to_vec()), (vec![0x11u8, 0x23], big_value1.to_vec())]) - ); - } - - #[test] - fn insert_duplicate_value() { - let big_value = b"00000000000000000000000000000000"; - - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], big_value).unwrap(); - t.insert(&[0x11u8, 0x23], big_value).unwrap(); - assert_eq!( - *t.root(), - trie_root(vec![(vec![0x01u8, 0x23], big_value.to_vec()), (vec![0x11u8, 0x23], big_value.to_vec())]) - ); - } - - #[test] - fn empty() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let t = TrieDBMut::new(&mut memdb, &mut root); - assert_eq!(t.get(&[0x5]), Ok(None)); - } - - #[test] - fn one() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), vec![0x1u8, 0x23]); - - assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), vec![0x1u8, 0x23]); - } - - #[test] - fn three() { - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap(); - t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap(); - assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), vec![0x01u8, 0x23]); - assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), vec![0xf1u8, 0x23]); - assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), vec![0x81u8, 0x23]); - assert_eq!(t.get(&[0x82, 0x23]), Ok(None)); - - assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), vec![0x01u8, 0x23]); - assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), vec![0xf1u8, 0x23]); - assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), vec![0x81u8, 0x23]); - assert_eq!(t.get(&[0x82, 0x23]), Ok(None)); - } - - #[test] - fn stress() { - let mut seed = H256::new(); - for _ in 0..50 { - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 4, - } - .make_with(&mut seed); - - let real = trie_root(x.clone()); - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let memtrie = populate_trie(&mut memdb, &mut root, &x); - let mut y = x.clone(); - y.sort_by(|ref a, ref b| a.0.cmp(&b.0)); - let mut memdb2 = MemoryDB::new(); - let mut root2 = H256::new(); - let memtrie_sorted = populate_trie(&mut memdb2, &mut root2, &y); - if *memtrie.root() != real || *memtrie_sorted.root() != real { - println!("TRIE MISMATCH"); - println!(); - println!("ORIGINAL... {:?}", memtrie.root()); - for i in &x { - println!("{:?} -> {:?}", i.0, i.1); - } - println!("SORTED... {:?}", memtrie_sorted.root()); - for i in &y { - println!("{:?} -> {:?}", i.0, i.1); - } - } - assert_eq!(*memtrie.root(), real); - assert_eq!(*memtrie_sorted.root(), real); - } - } - - #[test] - fn trie_existing() { - let mut root = H256::new(); - let mut db = MemoryDB::new(); - { - let mut t = TrieDBMut::new(&mut db, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - } - - { - let _ = TrieDBMut::from_existing(&mut db, &mut root); - } - } - - #[test] - fn from_null_rlp_succeeds() { - let mut root = BLAKE_NULL_RLP; - let mut db = MemoryDB::new(); - TrieDBMut::from_existing(&mut db, &mut root).unwrap(); - } - - #[test] - #[should_panic] - fn from_zero_fails() { - let mut root = H256::zero(); - let mut db = MemoryDB::new(); - TrieDBMut::from_existing(&mut db, &mut root).unwrap(); - } - - #[test] - #[ignore] - fn insert_empty() { - let mut seed = H256::new(); - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 4, - } - .make_with(&mut seed); - - let mut db = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut db, &mut root); - for &(ref key, ref value) in &x { - t.insert(key, value).unwrap(); - } - - assert_eq!(*t.root(), trie_root(x.clone())); - - for &(ref key, _) in &x { - t.insert(key, &[]).unwrap(); - } - - assert!(t.is_empty()); - assert_eq!(*t.root(), BLAKE_NULL_RLP); - } - - #[test] - fn return_old_values() { - let mut seed = H256::new(); - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 4, - } - .make_with(&mut seed); - - let mut db = MemoryDB::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut db, &mut root); - for &(ref key, ref value) in &x { - assert!(t.insert(key, value).unwrap().is_none()); - assert_eq!(t.insert(key, value).unwrap(), Some(value.clone())); - } - - for (key, value) in x { - assert_eq!(t.remove(&key).unwrap(), Some(value)); - assert!(t.remove(&key).unwrap().is_none()); - } - } -} diff --git a/util/merkle/src/triehash.rs b/util/merkle/src/triehash.rs deleted file mode 100644 index 43699d9e6b..0000000000 --- a/util/merkle/src/triehash.rs +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright 2018 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -//! Generetes trie root. -//! -//! This module should be used to generate trie root hash. - -use std::cmp; -use std::collections::BTreeMap; - -use ccrypto::blake256; -use primitives::H256; -use rlp::RlpStream; - -fn shared_prefix_len(first: &[T], second: &[T]) -> usize { - let len = cmp::min(first.len(), second.len()); - (0..len).take_while(|&i| first[i] == second[i]).count() -} - -/// Generates a trie root hash for a vector of key-values -pub fn trie_root(input: I) -> H256 -where - I: IntoIterator, - A: AsRef<[u8]> + Ord, - B: AsRef<[u8]>, { - // Make key into hash value, which is blake256(key) - let gen_input: Vec<_> = input.into_iter().map(|(k, v)| (blake256(k), v)).collect(); - let gen_input: Vec<_> = gen_input - // first put elements into btree to sort them and to remove duplicates - .into_iter() - .collect::>() - // then move them to a vector - .into_iter() - .map(|(k, v)| (as_nibbles(k.as_ref()), v) ) - .collect(); - - gen_trie_root(&gen_input) -} - -fn gen_trie_root, B: AsRef<[u8]>>(input: &[(A, B)]) -> H256 { - let mut stream = RlpStream::new(); - hash256rlp(input, 0, &mut stream); - blake256(stream.out()) -} - -/// Hex-prefix Notation. First nibble has flags: oddness = 2^0 -/// -/// Input values are in range `[0, 0xf]`. -/// -/// ```markdown -/// [0,0,1,2,3,4,5] 0x10012345 // 7 > 4 -/// [0,1,2,3,4,5] 0x00012345 // 6 > 4 -/// [1,2,3,4,5] 0x112345 // 5 > 3 -/// [0,0,1,2,3,4] 0x00001234 // 6 > 3 -/// [0,1,2,3,4] 0x101234 // 5 > 3 -/// [1,2,3,4] 0x001234 // 4 > 3 -/// ``` -fn hex_prefix_encode(nibbles: &[u8]) -> Vec { - let inlen = nibbles.len(); - let oddness_factor = inlen % 2; - // next even number divided by two - let reslen = (inlen + 2) >> 1; - let mut res = Vec::with_capacity(reslen); - - let first_byte = { - let mut bits = (oddness_factor as u8) << 4; - if oddness_factor == 1 { - bits += nibbles[0]; - } - bits - }; - - res.push(first_byte); - - let mut offset = oddness_factor; - while offset < inlen { - let byte = (nibbles[offset] << 4) + nibbles[offset + 1]; - res.push(byte); - offset += 2; - } - - res -} - -/// Converts slice of bytes to nibbles. -fn as_nibbles(bytes: &[u8]) -> Vec { - let mut res = Vec::with_capacity(bytes.len() * 2); - for byte in bytes { - res.push(*byte >> 4); - res.push(*byte & 0b1111); - } - res -} - -fn hash256rlp, B: AsRef<[u8]>>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream) { - let inlen = input.len(); - - // in case of empty slice, just append empty data - if inlen == 0 { - stream.append_empty_data(); - return - } - - // take slices - let key: &[u8] = &input[0].0.as_ref(); - let value: &[u8] = &input[0].1.as_ref(); - - // if the slice contains just one item, append the suffix of the key - // and then append value - if inlen == 1 { - stream.begin_list(2); - stream.append(&hex_prefix_encode(&key[pre_len..])); - stream.append(&value); - return - } - - // get length of the longest shared prefix in slice keys - let shared_prefix = input.iter() - // skip first element - .skip(1) - // get minimum number of shared nibbles between first and each successive - .fold(key.len(), | acc, &(ref k, _) | { - cmp::min(shared_prefix_len(key, k.as_ref()), acc) - }); - - // an item for every possible nibble/suffix - // + 1 for data - stream.begin_list(17); - - // Append partial path as a first element of branch - stream.append(&hex_prefix_encode(&key[pre_len..shared_prefix])); - - let mut begin: usize = 0; - - // iterate over all possible nibbles - for i in 0..16 { - // count how many successive elements have same next nibble - let len = if begin < input.len() { - input[begin..].iter().take_while(|pair| pair.0.as_ref()[shared_prefix] == i).count() - } else { - 0 - }; - - // if at least 1 successive element has the same nibble - // append their suffixes - match len { - 0 => { - stream.append_empty_data(); - } - _ => hash256aux(&input[begin..(begin + len)], shared_prefix + 1, stream), - } - begin += len; - } -} - -fn hash256aux, B: AsRef<[u8]>>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream) { - let mut s = RlpStream::new(); - hash256rlp(input, pre_len, &mut s); - let out = s.out(); - - stream.append(&blake256(out)); -} - - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn nibbles() { - let v = vec![0x31, 0x23, 0x45]; - let e = vec![3, 1, 2, 3, 4, 5]; - assert_eq!(as_nibbles(&v), e); - - // A => 65 => 0x41 => [4, 1] - let v: Vec = From::from("A"); - let e = vec![4, 1]; - assert_eq!(as_nibbles(&v), e); - } - - #[test] - fn _hex_prefix_encode() { - let v = vec![0, 0, 1, 2, 3, 4, 5]; - let e = vec![0x10, 0x01, 0x23, 0x45]; - let h = hex_prefix_encode(&v); - assert_eq!(h, e); - - let v = vec![0, 1, 2, 3, 4, 5]; - let e = vec![0x00, 0x01, 0x23, 0x45]; - let h = hex_prefix_encode(&v); - assert_eq!(h, e); - - let v = vec![1, 2, 3, 4]; - let e = vec![0x00, 0x12, 0x34]; - let h = hex_prefix_encode(&v); - assert_eq!(h, e); - } - - #[test] - fn triehash_out_of_order() { - assert_eq!( - trie_root(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), - (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), - ]), - trie_root(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), - (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), - ]) - ); - } - - #[test] - fn shared_prefix() { - let a = vec![1, 2, 3, 4, 5, 6]; - let b = vec![4, 2, 3, 4, 5, 6]; - assert_eq!(shared_prefix_len(&a, &b), 0); - } - - #[test] - fn shared_prefix2() { - let a = vec![1, 2, 3, 3, 5]; - let b = vec![1, 2, 3]; - assert_eq!(shared_prefix_len(&a, &b), 3); - } - - #[test] - fn shared_prefix3() { - let a = vec![1, 2, 3, 4, 5, 6]; - let b = vec![1, 2, 3, 4, 5, 6]; - assert_eq!(shared_prefix_len(&a, &b), 6); - } -}