Merge branch 'master' into jsonsertests

This commit is contained in:
Gav Wood 2016-06-08 06:18:44 -07:00
commit becf1d7b28
19 changed files with 268 additions and 97 deletions

View File

@ -116,7 +116,12 @@ impl Account {
/// Get (and cache) the contents of the trie's storage at `key`.
pub fn storage_at(&self, db: &AccountDB, key: &H256) -> H256 {
self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
(Filth::Clean, H256::from(SecTrieDB::new(db, &self.storage_root).get(key.bytes()).map_or(U256::zero(), |v| -> U256 {decode(v)})))
let db = SecTrieDB::new(db, &self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
(Filth::Clean, H256::from(db.get(key.bytes()).map_or(U256::zero(), |v| -> U256 {decode(v)})))
}).1.clone()
}
@ -204,7 +209,10 @@ impl Account {
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root);
let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
for (k, &mut (ref mut f, ref mut v)) in self.storage_overlay.borrow_mut().iter_mut() {
if f == &Filth::Dirty {
// cast key and value to trait type,

View File

@ -278,7 +278,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, addr.clone(), 3141562.into(), vec![]);
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, addr.clone(), 3141562.into(), vec![]).unwrap();
let b = b.close_and_lock();
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();

View File

@ -212,9 +212,20 @@ pub struct SealedBlock {
impl<'x> OpenBlock<'x> {
#[cfg_attr(feature="dev", allow(too_many_arguments))]
/// Create a new `OpenBlock` ready for transaction pushing.
pub fn new(engine: &'x Engine, vm_factory: &'x EvmFactory, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self {
pub fn new(
engine: &'x Engine,
vm_factory: &'x EvmFactory,
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
author: Address,
gas_floor_target: U256,
extra_data: Bytes
) -> Result<Self, Error> {
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
let mut r = OpenBlock {
block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()), tracing),
block: ExecutedBlock::new(state, tracing),
engine: engine,
vm_factory: vm_factory,
last_hashes: last_hashes,
@ -229,7 +240,7 @@ impl<'x> OpenBlock<'x> {
engine.populate_from_parent(&mut r.block.base.header, parent, gas_floor_target);
engine.on_new_block(&mut r.block);
r
Ok(r)
}
/// Alter the author for the block.
@ -448,12 +459,12 @@ impl IsBlock for SealedBlock {
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
{
if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce());
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce()));
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
}
}
let mut b = OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone());
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone()));
b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp());
@ -498,7 +509,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
let b = b.close_and_lock();
let _ = b.seal(engine.deref(), vec![]);
}
@ -514,7 +525,8 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).close_and_lock().seal(engine.deref(), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap()
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
@ -541,7 +553,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]);
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap();
let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new();

View File

@ -386,18 +386,14 @@ impl<V> Client<V> where V: Verifier {
let root = HeaderView::new(&header).state_root();
// TODO [rob]: refactor State::from_existing so we avoid doing redundant lookups.
if !db.contains(&root) {
return None;
}
Some(State::from_existing(db, root, self.engine.account_start_nonce()))
State::from_existing(db, root, self.engine.account_start_nonce()).ok()
})
}
/// Get a copy of the best block's state.
pub fn state(&self) -> State {
State::from_existing(self.state_db.lock().unwrap().boxed_clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce())
.expect("State root of best block header always valid.")
}
/// Get info on the cache.
@ -776,7 +772,8 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
author,
gas_floor_target,
extra_data,
);
).expect("OpenBlock::new only fails if parent state root invalid. State root of best block's header is never invalid. \
Therefore creating an OpenBlock with the best block's header will not fail.");
// Add uncles
self.chain

View File

@ -224,6 +224,8 @@ pub enum Error {
PowHashInvalid,
/// The value of the nonce or mishash is invalid.
PowInvalid,
/// Error concerning TrieDBs
TrieError(TrieError),
}
impl fmt::Display for Error {
@ -239,6 +241,7 @@ impl fmt::Display for Error {
f.write_fmt(format_args!("Unknown engine name ({})", name)),
Error::PowHashInvalid => f.write_str("Invalid or out of date PoW hash."),
Error::PowInvalid => f.write_str("Invalid nonce or mishash"),
Error::TrieError(ref err) => f.write_fmt(format_args!("{}", err)),
}
}
}
@ -300,6 +303,12 @@ impl From<IoError> for Error {
}
}
impl From<TrieError> for Error {
fn from(err: TrieError) -> Error {
Error::TrieError(err)
}
}
// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted.
/*#![feature(concat_idents)]
macro_rules! assimilate {

View File

@ -308,7 +308,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
}
@ -323,7 +323,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
let mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone();

View File

@ -62,7 +62,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce());
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce()).unwrap();
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000003")), U256::from(1u64));

View File

@ -44,6 +44,9 @@ pub struct State {
account_start_nonce: U256,
}
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
Therefore creating a SecTrieDB with this state's root will not fail.";
impl State {
/// Creates new state with empty state root
#[cfg(test)]
@ -64,18 +67,17 @@ impl State {
}
/// Creates new state with existing state root
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256) -> State {
{
// trie should panic! if root does not exist
let _ = SecTrieDB::new(db.as_hashdb(), &root);
}
State {
db: db,
root: root,
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256) -> Result<State, TrieError> {
if !db.as_hashdb().contains(&root) {
Err(TrieError::InvalidStateRoot)
} else {
Ok(State {
db: db,
root: root,
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
})
}
}
@ -154,7 +156,8 @@ impl State {
/// Determine whether an account exists.
pub fn exists(&self, a: &Address) -> bool {
self.cache.borrow().get(&a).unwrap_or(&None).is_some() || SecTrieDB::new(self.db.as_hashdb(), &self.root).contains(&a)
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.cache.borrow().get(&a).unwrap_or(&None).is_some() || db.contains(&a)
}
/// Get the balance of account `a`.
@ -245,7 +248,7 @@ impl State {
}
{
let mut trie = SecTrieDBMut::from_existing(db, root);
let mut trie = SecTrieDBMut::from_existing(db, root).unwrap();
for (address, ref a) in accounts.iter() {
match **a {
Some(ref account) => trie.insert(address, &account.rlp()),
@ -308,7 +311,8 @@ impl State {
fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option<Account> {
let have_key = self.cache.borrow().contains_key(a);
if !have_key {
self.insert_cache(a, SecTrieDB::new(self.db.as_hashdb(), &self.root).get(&a).map(Account::from_rlp))
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
}
if require_code {
if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() {
@ -328,7 +332,8 @@ impl State {
fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account {
let have_key = self.cache.borrow().contains_key(a);
if !have_key {
self.insert_cache(a, SecTrieDB::new(self.db.as_hashdb(), &self.root).get(&a).map(Account::from_rlp))
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
} else {
self.note_cache(a);
}
@ -1145,7 +1150,7 @@ fn code_from_database() {
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8));
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
}
@ -1160,7 +1165,7 @@ fn storage_at_from_database() {
state.drop()
};
let s = State::from_existing(db, root, U256::from(0u8));
let s = State::from_existing(db, root, U256::from(0u8)).unwrap();
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64)));
}
@ -1177,7 +1182,7 @@ fn get_from_database() {
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8));
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
assert_eq!(state.balance(&a), U256::from(69u64));
assert_eq!(state.nonce(&a), U256::from(1u64));
}
@ -1210,7 +1215,7 @@ fn remove_from_database() {
};
let (root, db) = {
let mut state = State::from_existing(db, root, U256::from(0u8));
let mut state = State::from_existing(db, root, U256::from(0u8)).unwrap();
assert_eq!(state.exists(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64));
state.kill_account(&a);
@ -1220,7 +1225,7 @@ fn remove_from_database() {
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8));
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
assert_eq!(state.exists(&a), false);
assert_eq!(state.nonce(&a), U256::from(0u64));
}

View File

@ -23,7 +23,8 @@ Parity. Ethereum Client.
Usage:
parity daemon <pid-file> [options]
parity account (new | list) [options]
parity account (new | list ) [options]
parity account import <path>... [options]
parity import [ <file> ] [options]
parity export [ <file> ] [options]
parity signer new-token [options]
@ -212,6 +213,7 @@ pub struct Args {
pub cmd_new_token: bool,
pub arg_pid_file: String,
pub arg_file: Option<String>,
pub arg_path: Vec<String>,
pub flag_chain: String,
pub flag_db_path: String,
pub flag_identity: String,

View File

@ -482,6 +482,11 @@ fn execute_account_cli(conf: Configuration) {
for &(addr, _) in &secret_store.accounts().unwrap() {
println!("{:?}", addr);
}
return;
}
if conf.args.cmd_import {
let imported = util::keys::import_keys_paths(&mut secret_store, &conf.args.arg_path).unwrap();
println!("Imported {} keys", imported);
}
}

21
util/res/pat/p1.json Normal file
View File

@ -0,0 +1,21 @@
{
"address": "3f49624084b67849c7b4e805c5988c21a430f9d9",
"Crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "9f27e3dd4fc73e7103ed61e5493662189a3eb52223ae49e3d1deacc04c889eae",
"cipherparams": {
"iv": "457494bf05f2618c397dc74dbb5181c0"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "db14edb18c41ee7f5ec4397df89c3a2ae4d0af60884c52bb54ce490574f8df33"
},
"mac": "572d24532438d31fdf513c744a3ff26c933ffda5744ee42bc71661cbe3f2112e"
},
"id": "62a0ad73-556d-496a-8e1c-0783d30d3ace",
"version": 3
}

21
util/res/pat/p2.json Normal file
View File

@ -0,0 +1,21 @@
{
"address": "5ba4dcf897e97c2bdf8315b9ef26c13c085988cf",
"Crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "d4a08ec930163778273920f6ad1d49b71836337be6fd9863993ac700a612fddd",
"cipherparams": {
"iv": "89ce5ec129fc27cd5bcbeb8c92bdad50"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "612ab108dc37e69ee8af37a7b24bf7f2234086d7bbf945bacdeccce331f7f84a"
},
"mac": "4152caa7444e06784223d735cea80cd2690b4c587ad8db3d5529442227b25695"
},
"id": "35086353-fb12-4029-b56b-033cd61ce35b",
"version": 3
}

View File

@ -80,9 +80,10 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path)
}
/// Imports all geth keys in the directory
pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> {
pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<usize, ImportError> {
use std::path::PathBuf;
let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory));
let mut total = 0;
for &(ref address, ref file_path) in &geth_files {
let mut path = PathBuf::new();
path.push(geth_keyfiles_directory);
@ -90,18 +91,45 @@ pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory:
if let Err(e) = import_geth_key(secret_store, Path::new(&path)) {
warn!("Skipped geth address {}, error importing: {:?}", address, e)
}
else { total = total + 1}
}
Ok(())
Ok(total)
}
/// Gets the default geth keystore directory.
///
/// Based on https://github.com/ethereum/go-ethereum/blob/e553215/common/path.go#L75
pub fn keystore_dir(is_testnet: bool) -> PathBuf {
path::ethereum::with_default(if is_testnet {"testnet/keystore"} else {"keystore"})
}
/// Imports key(s) from provided file/directory
pub fn import_keys_path(secret_store: &mut SecretStore, path: &str) -> Result<usize, ImportError> {
// check if it is just one file or directory
if let Ok(meta) = fs::metadata(path) {
if meta.is_file() {
try!(import_geth_key(secret_store, Path::new(path)));
return Ok(1);
}
else if meta.is_dir() {
return Ok(try!(fs::read_dir(path)).fold(
0,
|total, p|
total +
match p {
Ok(dir_entry) => import_keys_path(secret_store, dir_entry.path().to_str().unwrap()).unwrap_or_else(|_| 0),
Err(e) => { warn!("Error importing dir entry: {:?}", e); 0 },
}
))
}
}
Ok(0)
}
/// Imports all keys from list of provided files/directories
pub fn import_keys_paths(secret_store: &mut SecretStore, path: &[String]) -> Result<usize, ImportError> {
Ok(path.iter().fold(0, |total, ref p| total + import_keys_path(secret_store, &p).unwrap_or_else(|_| 0)))
}
#[cfg(test)]
mod tests {
use super::*;
@ -115,10 +143,21 @@ mod tests {
}
}
fn pat_path() -> &'static str {
match ::std::fs::metadata("res") {
Ok(_) => "res/pat",
Err(_) => "util/res/pat"
}
}
fn test_path_param(param_val: &'static str) -> String {
test_path().to_owned() + param_val
}
fn pat_path_param(param_val: &'static str) -> String {
pat_path().to_owned() + param_val
}
#[test]
fn can_enumerate() {
let keys = enumerate_geth_keys(Path::new(test_path())).unwrap();
@ -191,4 +230,32 @@ mod tests {
assert!(val.is_ok());
assert_eq!(32, val.unwrap().len());
}
#[test]
fn can_import_by_filename() {
let temp = ::devtools::RandomTempPath::create_dir();
let mut secret_store = SecretStore::new_in(temp.as_path());
let amount = import_keys_path(&mut secret_store, &pat_path_param("/p1.json")).unwrap();
assert_eq!(1, amount);
}
#[test]
fn can_import_by_dir() {
let temp = ::devtools::RandomTempPath::create_dir();
let mut secret_store = SecretStore::new_in(temp.as_path());
let amount = import_keys_path(&mut secret_store, pat_path()).unwrap();
assert_eq!(2, amount);
}
#[test]
fn can_import_mulitple() {
let temp = ::devtools::RandomTempPath::create_dir();
let mut secret_store = SecretStore::new_in(temp.as_path());
let amount = import_keys_paths(&mut secret_store, &[pat_path_param("/p1.json"), pat_path_param("/p2.json")]).unwrap();
assert_eq!(2, amount);
}
}

View File

@ -23,3 +23,4 @@ mod test_account_provider;
pub use self::store::AccountProvider;
pub use self::test_account_provider::{TestAccount, TestAccountProvider};
pub use self::geth_import::import_keys_paths;

View File

@ -16,6 +16,8 @@
//! Trie interface and implementation.
use std::fmt;
/// Export the trietraits module.
pub mod trietraits;
/// Export the standardmap module.
@ -33,9 +35,22 @@ pub mod sectriedb;
/// Export the sectriedbmut module.
pub mod sectriedbmut;
pub use self::trietraits::*;
pub use self::standardmap::*;
pub use self::triedbmut::*;
pub use self::triedb::*;
pub use self::sectriedbmut::*;
pub use self::sectriedb::*;
pub use self::trietraits::{Trie, TrieMut};
pub use self::standardmap::{Alphabet, StandardMap, ValueMode};
pub use self::triedbmut::TrieDBMut;
pub use self::triedb::TrieDB;
pub use self::sectriedbmut::SecTrieDBMut;
pub use self::sectriedb::SecTrieDB;
/// Trie Errors
#[derive(Debug)]
pub enum TrieError {
/// Attempted to create a trie with a state root not in the DB.
InvalidStateRoot,
}
impl fmt::Display for TrieError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Trie Error: Invalid state root.")
}
}

View File

@ -16,9 +16,10 @@
use hash::*;
use sha3::*;
use hashdb::*;
use super::triedb::*;
use super::trietraits::*;
use hashdb::HashDB;
use super::triedb::TrieDB;
use super::trietraits::Trie;
use super::TrieError;
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
///
@ -29,10 +30,12 @@ pub struct SecTrieDB<'db> {
impl<'db> SecTrieDB<'db> {
/// Create a new trie with the backing database `db` and empty `root`
///
/// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly.
pub fn new(db: &'db HashDB, root: &'db H256) -> Self {
SecTrieDB { raw: TrieDB::new(db, root) }
/// Returns an error if root does not exist.
pub fn new(db: &'db HashDB, root: &'db H256) -> Result<Self, TrieError> {
Ok(SecTrieDB { raw: try!(TrieDB::new(db, root)) })
}
/// Get a reference to the underlying raw `TrieDB` struct.
@ -60,8 +63,9 @@ impl<'db> Trie for SecTrieDB<'db> {
#[test]
fn trie_to_sectrie() {
use memorydb::*;
use super::triedbmut::*;
use memorydb::MemoryDB;
use super::triedbmut::TrieDBMut;
use super::trietraits::TrieMut;
let mut memdb = MemoryDB::new();
let mut root = H256::new();
@ -69,6 +73,6 @@ fn trie_to_sectrie() {
let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&(&[0x01u8, 0x23]).sha3(), &[0x01u8, 0x23]);
}
let t = SecTrieDB::new(&memdb, &root);
let t = SecTrieDB::new(&memdb, &root).unwrap();
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap(), &[0x01u8, 0x23]);
}

View File

@ -16,9 +16,10 @@
use hash::*;
use sha3::*;
use hashdb::*;
use super::triedbmut::*;
use super::trietraits::*;
use hashdb::HashDB;
use super::triedbmut::TrieDBMut;
use super::trietraits::{Trie, TrieMut};
use super::TrieError;
/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
///
@ -35,10 +36,11 @@ impl<'db> SecTrieDBMut<'db> {
SecTrieDBMut { raw: TrieDBMut::new(db, root) }
}
/// Create a new trie with the backing database `db` and `root`
/// Panics, if `root` does not exist
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self {
SecTrieDBMut { raw: TrieDBMut::from_existing(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: &'db mut HashDB, root: &'db mut H256) -> Result<Self, TrieError> {
Ok(SecTrieDBMut { raw: try!(TrieDBMut::from_existing(db, root)) })
}
/// Get the backing database.
@ -81,6 +83,6 @@ fn sectrie_to_trie() {
let mut t = SecTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
}
let t = TrieDB::new(&memdb, &root);
let t = TrieDB::new(&memdb, &root).unwrap();
assert_eq!(t.get(&(&[0x01u8, 0x23]).sha3()).unwrap(), &[0x01u8, 0x23]);
}

View File

@ -18,8 +18,9 @@ use common::*;
use hashdb::*;
use nibbleslice::*;
use rlp::*;
use super::trietraits::*;
use super::node::*;
use super::trietraits::Trie;
use super::node::Node;
use super::TrieError;
/// A `Trie` implementation using a generic `HashDB` backing database.
///
@ -41,7 +42,7 @@ use super::node::*;
/// let mut memdb = MemoryDB::new();
/// let mut root = H256::new();
/// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar");
/// let t = TrieDB::new(&memdb, &root);
/// let t = TrieDB::new(&memdb, &root).unwrap();
/// assert!(t.contains(b"foo"));
/// assert_eq!(t.get(b"foo").unwrap(), b"bar");
/// assert!(t.db_items_remaining().is_empty());
@ -57,16 +58,16 @@ pub struct TrieDB<'db> {
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
impl<'db> TrieDB<'db> {
/// Create a new trie with the backing database `db` and `root`
/// Panics, if `root` does not exist
pub fn new(db: &'db HashDB, root: &'db H256) -> Self {
/// Returns an error if `root` does not exist
pub fn new(db: &'db HashDB, root: &'db H256) -> Result<Self, TrieError> {
if !db.contains(root) {
flushln!("TrieDB::new({}): Trie root not found!", root);
panic!("Trie root not found!");
}
TrieDB {
db: db,
root: root,
hash_count: 0
Err(TrieError::InvalidStateRoot)
} else {
Ok(TrieDB {
db: db,
root: root,
hash_count: 0
})
}
}
@ -356,6 +357,7 @@ impl<'db> fmt::Debug for TrieDB<'db> {
#[test]
fn iterator() {
use super::trietraits::TrieMut;
use memorydb::*;
use super::triedbmut::*;
@ -369,6 +371,6 @@ fn iterator() {
t.insert(&x, &x);
}
}
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), TrieDB::new(&memdb, &root).iter().map(|x|x.0).collect::<Vec<_>>());
assert_eq!(d, TrieDB::new(&memdb, &root).iter().map(|x|x.1).collect::<Vec<_>>());
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), TrieDB::new(&memdb, &root).unwrap().iter().map(|x|x.0).collect::<Vec<_>>());
assert_eq!(d, TrieDB::new(&memdb, &root).unwrap().iter().map(|x|x.1).collect::<Vec<_>>());
}

View File

@ -18,9 +18,10 @@ use common::*;
use hashdb::*;
use nibbleslice::*;
use rlp::*;
use super::node::*;
use super::journal::*;
use super::trietraits::*;
use super::node::Node;
use super::journal::Journal;
use super::trietraits::{Trie, TrieMut};
use super::TrieError;
/// A `Trie` implementation using a generic `HashDB` backing database.
///
@ -84,17 +85,16 @@ impl<'db> TrieDBMut<'db> {
}
/// Create a new trie with the backing database `db` and `root`.
/// Panics, if `root` does not exist.
// TODO: return Result<Self, TrieError>
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self {
/// Returns an error if `root` does not exist.
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Result<Self, TrieError> {
if !db.exists(root) {
flushln!("Trie root not found {}", root);
panic!("Trie root not found!");
}
TrieDBMut {
db: db,
root: root,
hash_count: 0
Err(TrieError::InvalidStateRoot)
} else {
Ok(TrieDBMut {
db: db,
root: root,
hash_count: 0
})
}
}