Remove (almost all) panickers from trie module (#1776)

* memorydb ub patch and other cleanup

* fix denote invocations

* move trie traits into trie module

* replace "denote" with shim

* triedb returns results and no longer panics

* fix warnings

* get ethcore compiling

* warn on trie errors in ethcore

* remove unsafety from node decoder

* restore broken denote behavior for this branch

* fix overlayrecent fallout

* fix triedb tests

* remove unwrap in state

* alter Trie::get to return Result<Option<_>>

* fix refcell error in require

* fix test warnings

* fix json tests

* whitespace

[ci:skip]

* Avoid unneeded match/indentation

* whitespace

* prettify map_or_else

* remove test warning
This commit is contained in:
Robert Habermeier 2016-08-03 18:35:48 +02:00 committed by Gav Wood
parent 40a304b177
commit 11b65ce53d
37 changed files with 496 additions and 402 deletions

View File

@ -20,6 +20,8 @@ use util::*;
use pod_account::*; use pod_account::*;
use account_db::*; use account_db::*;
use std::cell::{Ref, RefCell};
/// Single account in the system. /// Single account in the system.
#[derive(Clone)] #[derive(Clone)]
pub struct Account { pub struct Account {
@ -136,7 +138,11 @@ impl Account {
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \ SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail."); using it will not fail.");
(Filth::Clean, H256::from(db.get(key).map_or(U256::zero(), |v| -> U256 {decode(v)}))) let item: U256 = match db.get(key){
Ok(x) => x.map_or_else(U256::zero, decode),
Err(e) => panic!("Encountered potential DB corruption: {}", e),
};
(Filth::Clean, item.into())
}).1.clone() }).1.clone()
} }
@ -243,9 +249,13 @@ impl Account {
if f == &Filth::Dirty { if f == &Filth::Dirty {
// cast key and value to trait type, // cast key and value to trait type,
// so we can call overloaded `to_bytes` method // so we can call overloaded `to_bytes` method
match v.is_zero() { let res = match v.is_zero() {
true => { t.remove(k); }, true => t.remove(k),
false => { t.insert(k, &encode(&U256::from(v.as_slice()))); }, false => t.insert(k, &encode(&U256::from(v.as_slice()))),
};
if let Err(e) = res {
warn!("Encountered potential DB corruption: {}", e);
} }
*f = Filth::Clean; *f = Filth::Clean;
} }

View File

@ -586,7 +586,7 @@ mod tests {
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
@ -603,7 +603,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let vm_factory = Default::default(); let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap() let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine.deref(), vec![]).unwrap(); .close_and_lock().seal(engine.deref(), vec![]).unwrap();
@ -612,7 +612,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default(), Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default(), Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes); assert_eq!(e.rlp_bytes(), orig_bytes);
@ -631,7 +631,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let vm_factory = Default::default(); let vm_factory = Default::default();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle1_header = Header::new(); let mut uncle1_header = Header::new();
@ -647,7 +647,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default(), Default::default()).unwrap(); let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default(), Default::default()).unwrap();
let bytes = e.rlp_bytes(); let bytes = e.rlp_bytes();

View File

@ -183,7 +183,7 @@ impl Client {
let tracedb = Arc::new(try!(TraceDB::new(config.tracing, db.clone(), chain.clone()))); let tracedb = Arc::new(try!(TraceDB::new(config.tracing, db.clone(), chain.clone())));
let mut state_db = journaldb::new(db.clone(), config.pruning, DB_COL_STATE); let mut state_db = journaldb::new(db.clone(), config.pruning, DB_COL_STATE);
if state_db.is_empty() && spec.ensure_db_good(state_db.as_hashdb_mut()) { if state_db.is_empty() && try!(spec.ensure_db_good(state_db.as_hashdb_mut())) {
let batch = DBTransaction::new(&db); let batch = DBTransaction::new(&db);
try!(state_db.commit(&batch, 0, &spec.genesis_header().hash(), None)); try!(state_db.commit(&batch, 0, &spec.genesis_header().hash(), None));
try!(db.write(batch).map_err(ClientError::Database)); try!(db.write(batch).map_err(ClientError::Database));

View File

@ -2,11 +2,15 @@ use trace::Error as TraceError;
use util::UtilError; use util::UtilError;
use std::fmt::{Display, Formatter, Error as FmtError}; use std::fmt::{Display, Formatter, Error as FmtError};
use util::trie::TrieError;
/// Client configuration errors. /// Client configuration errors.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// TraceDB configuration error. /// TraceDB configuration error.
Trace(TraceError), Trace(TraceError),
/// TrieDB-related error.
Trie(TrieError),
/// Database error /// Database error
Database(String), Database(String),
/// Util error /// Util error
@ -19,16 +23,29 @@ impl From<TraceError> for Error {
} }
} }
impl From<TrieError> for Error {
fn from(err: TrieError) -> Self {
Error::Trie(err)
}
}
impl From<UtilError> for Error { impl From<UtilError> for Error {
fn from(err: UtilError) -> Self { fn from(err: UtilError) -> Self {
Error::Util(err) Error::Util(err)
} }
} }
impl<E> From<Box<E>> for Error where Error: From<E> {
fn from(err: Box<E>) -> Self {
Error::from(*err)
}
}
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self { match *self {
Error::Trace(ref err) => write!(f, "{}", err), Error::Trace(ref err) => write!(f, "{}", err),
Error::Trie(ref err) => write!(f, "{}", err),
Error::Util(ref err) => write!(f, "{}", err), Error::Util(ref err) => write!(f, "{}", err),
Error::Database(ref s) => write!(f, "Database error: {}", s), Error::Database(ref s) => write!(f, "Database error: {}", s),
} }

View File

@ -262,7 +262,7 @@ impl MiningBlockChainClient for TestBlockChainClient {
let genesis_header = self.spec.genesis_header(); let genesis_header = self.spec.genesis_header();
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
self.spec.ensure_db_good(db.as_hashdb_mut()); self.spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let mut open_block = OpenBlock::new( let mut open_block = OpenBlock::new(

View File

@ -250,7 +250,7 @@ mod tests {
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();

View File

@ -84,7 +84,7 @@ mod tests {
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();

View File

@ -258,7 +258,10 @@ pub type ImportResult = Result<H256, Error>;
impl From<ClientError> for Error { impl From<ClientError> for Error {
fn from(err: ClientError) -> Error { fn from(err: ClientError) -> Error {
Error::Client(err) match err {
ClientError::Trie(err) => Error::Trie(err),
_ => Error::Client(err)
}
} }
} }
@ -338,6 +341,12 @@ impl From<BlockImportError> for Error {
} }
} }
impl<E> From<Box<E>> for Error where Error: From<E> {
fn from(err: Box<E>) -> Error {
Error::from(*err)
}
}
binary_fixed_size!(BlockError); binary_fixed_size!(BlockError);
binary_fixed_size!(ImportError); binary_fixed_size!(ImportError);
binary_fixed_size!(TransactionError); binary_fixed_size!(TransactionError);

View File

@ -163,7 +163,9 @@ impl Engine for Ethash {
for u in fields.uncles.iter() { for u in fields.uncles.iter() {
fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8))); fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)));
} }
fields.state.commit(); if let Err(e) = fields.state.commit() {
warn!("Encountered error on state commit: {}", e);
}
} }
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
@ -352,7 +354,7 @@ mod tests {
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
@ -367,7 +369,7 @@ mod tests {
let genesis_header = spec.genesis_header(); let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); let vm_factory = Default::default();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();

View File

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

View File

@ -20,6 +20,8 @@ use util::*;
use basic_types::*; use basic_types::*;
use time::get_time; use time::get_time;
use std::cell::RefCell;
/// Type for Block number /// Type for Block number
pub type BlockNumber = u64; pub type BlockNumber = u64;

View File

@ -62,7 +62,8 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.populate_from(pre); state.populate_from(pre);
state.commit(); state.commit()
.expect(&format!("State test {} failed due to internal error.", name));
let vm_factory = Default::default(); let vm_factory = Default::default();
let res = state.apply(&env, engine.deref(), &vm_factory, &transaction, false); let res = state.apply(&env, engine.deref(), &vm_factory, &transaction, false);

View File

@ -15,7 +15,9 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use ethjson; use ethjson;
use util::{H256, MemoryDB, TrieSpec, TrieFactory}; use util::trie::{TrieFactory, TrieSpec};
use util::hash::H256;
use util::memorydb::MemoryDB;
fn test_trie(json: &[u8], trie: TrieSpec) -> Vec<String> { fn test_trie(json: &[u8], trie: TrieSpec) -> Vec<String> {
let tests = ethjson::trie::Test::load(json).unwrap(); let tests = ethjson::trie::Test::load(json).unwrap();
@ -30,7 +32,8 @@ fn test_trie(json: &[u8], trie: TrieSpec) -> Vec<String> {
for (key, value) in test.input.data.into_iter() { for (key, value) in test.input.data.into_iter() {
let key: Vec<u8> = key.into(); let key: Vec<u8> = key.into();
let value: Vec<u8> = value.map_or_else(Vec::new, Into::into); let value: Vec<u8> = value.map_or_else(Vec::new, Into::into);
t.insert(&key, &value); t.insert(&key, &value)
.expect(&format!("Trie test '{:?}' failed due to internal error", name))
} }
if *t.root() != test.root.into() { if *t.root() != test.root.into() {
@ -46,7 +49,7 @@ fn test_trie(json: &[u8], trie: TrieSpec) -> Vec<String> {
} }
mod generic { mod generic {
use util::TrieSpec; use util::trie::TrieSpec;
fn do_json_test(json: &[u8]) -> Vec<String> { fn do_json_test(json: &[u8]) -> Vec<String> {
super::test_trie(json, TrieSpec::Generic) super::test_trie(json, TrieSpec::Generic)
@ -57,7 +60,7 @@ mod generic {
} }
mod secure { mod secure {
use util::TrieSpec; use util::trie::TrieSpec;
fn do_json_test(json: &[u8]) -> Vec<String> { fn do_json_test(json: &[u8]) -> Vec<String> {
super::test_trie(json, TrieSpec::Secure) super::test_trie(json, TrieSpec::Secure)

View File

@ -71,7 +71,9 @@ impl PodAccount {
let mut r = H256::new(); let mut r = H256::new();
let mut t = SecTrieDBMut::new(db, &mut r); let mut t = SecTrieDBMut::new(db, &mut r);
for (k, v) in &self.storage { for (k, v) in &self.storage {
t.insert(k, &encode(&U256::from(v.as_slice()))); if let Err(e) = t.insert(k, &encode(&U256::from(v.as_slice()))) {
warn!("Encountered potential DB corruption: {}", e);
}
} }
} }
} }

View File

@ -22,7 +22,7 @@ use error::Error;
use util::{Bytes, HashDB, SHA3_EMPTY, TrieDB}; use util::{Bytes, HashDB, SHA3_EMPTY, TrieDB};
use util::hash::{FixedHash, H256}; use util::hash::{FixedHash, H256};
use util::numbers::U256; use util::numbers::U256;
use util::rlp::{DecoderError, Rlp, RlpStream, Stream, UntrustedRlp, View}; use util::rlp::{Rlp, RlpStream, Stream, UntrustedRlp, View};
// An alternate account structure from ::account::Account. // An alternate account structure from ::account::Account.
#[derive(PartialEq, Clone, Debug)] #[derive(PartialEq, Clone, Debug)]
@ -102,7 +102,7 @@ impl Account {
} }
// decode a fat rlp, and rebuild the storage trie as we go. // decode a fat rlp, and rebuild the storage trie as we go.
pub fn from_fat_rlp(acct_db: &mut AccountDBMut, rlp: UntrustedRlp) -> Result<Self, DecoderError> { pub fn from_fat_rlp(acct_db: &mut AccountDBMut, rlp: UntrustedRlp) -> Result<Self, Error> {
use util::{TrieDBMut, TrieMut}; use util::{TrieDBMut, TrieMut};
let nonce = try!(rlp.val_at(0)); let nonce = try!(rlp.val_at(0));
@ -123,7 +123,7 @@ impl Account {
let k: Bytes = try!(pair_rlp.val_at(0)); let k: Bytes = try!(pair_rlp.val_at(0));
let v: Bytes = try!(pair_rlp.val_at(1)); let v: Bytes = try!(pair_rlp.val_at(1));
storage_trie.insert(&k, &v); try!(storage_trie.insert(&k, &v));
} }
} }
Ok(Account { Ok(Account {
@ -160,7 +160,7 @@ mod tests {
{ {
let mut trie = SecTrieDBMut::new(&mut db, &mut root); let mut trie = SecTrieDBMut::new(&mut db, &mut root);
for (k, v) in map.make() { for (k, v) in map.make() {
trie.insert(&k, &v); trie.insert(&k, &v).unwrap();
} }
} }
root root

View File

@ -387,7 +387,7 @@ impl StateRebuilder {
}; };
for (hash, thin_rlp) in pairs { for (hash, thin_rlp) in pairs {
account_trie.insert(&hash, &thin_rlp); try!(account_trie.insert(&hash, &thin_rlp));
} }
} }

View File

@ -25,6 +25,8 @@ use super::seal::Generic as GenericSeal;
use ethereum; use ethereum;
use ethjson; use ethjson;
use std::cell::RefCell;
/// Parameters common to all engines. /// Parameters common to all engines.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct CommonParams { pub struct CommonParams {
@ -226,21 +228,21 @@ impl Spec {
} }
/// Ensure that the given state DB has the trie nodes in for the genesis state. /// Ensure that the given state DB has the trie nodes in for the genesis state.
pub fn ensure_db_good(&self, db: &mut HashDB) -> bool { pub fn ensure_db_good(&self, db: &mut HashDB) -> Result<bool, Box<TrieError>> {
if !db.contains(&self.state_root()) { if !db.contains(&self.state_root()) {
let mut root = H256::new(); let mut root = H256::new();
{ {
let mut t = SecTrieDBMut::new(db, &mut root); let mut t = SecTrieDBMut::new(db, &mut root);
for (address, account) in self.genesis_state.get().iter() { for (address, account) in self.genesis_state.get().iter() {
t.insert(address.as_slice(), &account.rlp()); try!(t.insert(address.as_slice(), &account.rlp()));
} }
} }
for (address, account) in self.genesis_state.get().iter() { for (address, account) in self.genesis_state.get().iter() {
account.insert_additional(&mut AccountDBMut::new(db, address)); account.insert_additional(&mut AccountDBMut::new(db, address));
} }
assert!(db.contains(&self.state_root())); assert!(db.contains(&self.state_root()));
true Ok(true)
} else { false } } else { Ok(false) }
} }
/// Loads spec from json file. /// Loads spec from json file.

View File

@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::cell::{RefCell, RefMut};
use common::*; use common::*;
use engines::Engine; use engines::Engine;
use executive::{Executive, TransactOptions}; use executive::{Executive, TransactOptions};
@ -71,7 +73,7 @@ impl State {
/// Creates new state with existing state root /// Creates new state with existing state root
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256, trie_factory: TrieFactory) -> Result<State, TrieError> { pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256, trie_factory: TrieFactory) -> Result<State, TrieError> {
if !db.as_hashdb().contains(&root) { if !db.as_hashdb().contains(&root) {
return Err(TrieError::InvalidStateRoot); return Err(TrieError::InvalidStateRoot(root));
} }
let state = State { let state = State {
@ -162,7 +164,8 @@ impl State {
/// Determine whether an account exists. /// Determine whether an account exists.
pub fn exists(&self, a: &Address) -> bool { pub fn exists(&self, a: &Address) -> bool {
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let db = self.trie_factory.readonly(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) self.cache.borrow().get(&a).unwrap_or(&None).is_some() ||
db.contains(a).unwrap_or_else(|e| { warn!("Potential DB corruption encountered: {}", e); false })
} }
/// Get the balance of account `a`. /// Get the balance of account `a`.
@ -238,7 +241,7 @@ impl State {
// TODO uncomment once to_pod() works correctly. // TODO uncomment once to_pod() works correctly.
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod())); // trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
self.commit(); try!(self.commit());
self.clear(); self.clear();
let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs); let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs);
// trace!("Transaction receipt: {:?}", receipt); // trace!("Transaction receipt: {:?}", receipt);
@ -248,7 +251,13 @@ impl State {
/// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit.
/// `accounts` is mutable because we may need to commit the code or storage and record that. /// `accounts` is mutable because we may need to commit the code or storage and record that.
#[cfg_attr(feature="dev", allow(match_ref_pats))] #[cfg_attr(feature="dev", allow(match_ref_pats))]
pub fn commit_into(trie_factory: &TrieFactory, db: &mut HashDB, root: &mut H256, accounts: &mut HashMap<Address, Option<Account>>) { pub fn commit_into(
trie_factory: &TrieFactory,
db: &mut HashDB,
root: &mut H256,
accounts: &mut HashMap<Address,
Option<Account>>
) -> Result<(), Error> {
// first, commit the sub trees. // first, commit the sub trees.
// TODO: is this necessary or can we dispense with the `ref mut a` for just `a`? // TODO: is this necessary or can we dispense with the `ref mut a` for just `a`?
for (address, ref mut a) in accounts.iter_mut() { for (address, ref mut a) in accounts.iter_mut() {
@ -266,18 +275,20 @@ impl State {
let mut trie = trie_factory.from_existing(db, root).unwrap(); let mut trie = trie_factory.from_existing(db, root).unwrap();
for (address, ref a) in accounts.iter() { for (address, ref a) in accounts.iter() {
match **a { match **a {
Some(ref account) if account.is_dirty() => trie.insert(address, &account.rlp()), Some(ref account) if account.is_dirty() => try!(trie.insert(address, &account.rlp())),
None => trie.remove(address), None => try!(trie.remove(address)),
_ => (), _ => (),
} }
} }
} }
Ok(())
} }
/// Commits our cached account changes into the trie. /// Commits our cached account changes into the trie.
pub fn commit(&mut self) { pub fn commit(&mut self) -> Result<(), Error> {
assert!(self.snapshots.borrow().is_empty()); assert!(self.snapshots.borrow().is_empty());
Self::commit_into(&self.trie_factory, self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut()); Self::commit_into(&self.trie_factory, self.db.as_hashdb_mut(), &mut self.root, &mut *self.cache.borrow_mut())
} }
/// Clear state cache /// Clear state cache
@ -336,7 +347,11 @@ impl State {
let have_key = self.cache.borrow().contains_key(a); let have_key = self.cache.borrow().contains_key(a);
if !have_key { if !have_key {
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.insert_cache(a, db.get(a).map(Account::from_rlp)) let maybe_acc = match db.get(&a) {
Ok(acc) => acc.map(Account::from_rlp),
Err(e) => panic!("Potential DB corruption encountered: {}", e),
};
self.insert_cache(a, maybe_acc);
} }
if require_code { if require_code {
if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() { if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() {
@ -348,33 +363,40 @@ impl State {
} }
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
fn require<'a>(&'a self, a: &Address, require_code: bool) -> &'a mut Account { fn require<'a>(&'a self, a: &Address, require_code: bool) -> RefMut<'a, Account> {
self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8), self.account_start_nonce), |_|{}) self.require_or_from(a, require_code, || Account::new_basic(U256::from(0u8), self.account_start_nonce), |_|{})
} }
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
/// If it doesn't exist, make account equal the evaluation of `default`. /// If it doesn't exist, make account equal the evaluation of `default`.
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 { fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&'a self, a: &Address, require_code: bool, default: F, not_default: G)
let have_key = self.cache.borrow().contains_key(a); -> RefMut<'a, Account>
if !have_key { {
let contains_key = self.cache.borrow().contains_key(a);
if !contains_key {
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.insert_cache(a, db.get(a).map(Account::from_rlp)) let maybe_acc = match db.get(&a) {
Ok(acc) => acc.map(Account::from_rlp),
Err(e) => panic!("Potential DB corruption encountered: {}", e),
};
self.insert_cache(a, maybe_acc);
} else { } else {
self.note_cache(a); self.note_cache(a);
} }
let preexists = self.cache.borrow().get(a).unwrap().is_none();
if preexists { match self.cache.borrow_mut().get_mut(a).unwrap() {
self.cache.borrow_mut().insert(a.clone(), Some(default())); &mut Some(ref mut acc) => not_default(acc),
} else { slot @ &mut None => *slot = Some(default()),
not_default(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().unwrap());
} }
unsafe { ::std::mem::transmute(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().map(|account| { RefMut::map(self.cache.borrow_mut(), |c| {
let account = c.get_mut(a).unwrap().as_mut().unwrap();
if require_code { if require_code {
account.cache_code(&AccountDB::new(self.db.as_hashdb(), a)); account.cache_code(&AccountDB::new(self.db.as_hashdb(), a));
} }
account account
}).unwrap()) } })
} }
} }
@ -466,12 +488,12 @@ fn should_work_when_cloned() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
assert_eq!(state.exists(&a), false); assert_eq!(state.exists(&a), false);
state.inc_nonce(&a); state.inc_nonce(&a);
state.commit(); state.commit().unwrap();
state.clone() state.clone()
}; };
state.inc_nonce(&a); state.inc_nonce(&a);
state.commit(); state.commit().unwrap();
} }
#[test] #[test]
@ -1281,7 +1303,7 @@ fn code_from_database() {
state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{}); state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{});
state.init_code(&a, vec![1, 2, 3]); state.init_code(&a, vec![1, 2, 3]);
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
state.commit(); state.commit().unwrap();
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec())); assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
state.drop() state.drop()
}; };
@ -1297,7 +1319,7 @@ fn storage_at_from_database() {
let (root, db) = { let (root, db) = {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
state.set_storage(&a, H256::from(&U256::from(01u64)), H256::from(&U256::from(69u64))); state.set_storage(&a, H256::from(&U256::from(01u64)), H256::from(&U256::from(69u64)));
state.commit(); state.commit().unwrap();
state.drop() state.drop()
}; };
@ -1313,7 +1335,7 @@ fn get_from_database() {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
state.inc_nonce(&a); state.inc_nonce(&a);
state.add_balance(&a, &U256::from(69u64)); state.add_balance(&a, &U256::from(69u64));
state.commit(); state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
state.drop() state.drop()
}; };
@ -1344,7 +1366,7 @@ fn remove_from_database() {
let (root, db) = { let (root, db) = {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
state.inc_nonce(&a); state.inc_nonce(&a);
state.commit(); state.commit().unwrap();
assert_eq!(state.exists(&a), true); assert_eq!(state.exists(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64)); assert_eq!(state.nonce(&a), U256::from(1u64));
state.drop() state.drop()
@ -1355,7 +1377,7 @@ fn remove_from_database() {
assert_eq!(state.exists(&a), true); assert_eq!(state.exists(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64)); assert_eq!(state.nonce(&a), U256::from(1u64));
state.kill_account(&a); state.kill_account(&a);
state.commit(); state.commit().unwrap();
assert_eq!(state.exists(&a), false); assert_eq!(state.exists(&a), false);
assert_eq!(state.nonce(&a), U256::from(0u64)); assert_eq!(state.nonce(&a), U256::from(0u64));
state.drop() state.drop()
@ -1374,16 +1396,16 @@ fn alter_balance() {
let b = address_from_u64(1u64); let b = address_from_u64(1u64);
state.add_balance(&a, &U256::from(69u64)); state.add_balance(&a, &U256::from(69u64));
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
state.commit(); state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
state.sub_balance(&a, &U256::from(42u64)); state.sub_balance(&a, &U256::from(42u64));
assert_eq!(state.balance(&a), U256::from(27u64)); assert_eq!(state.balance(&a), U256::from(27u64));
state.commit(); state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(27u64)); assert_eq!(state.balance(&a), U256::from(27u64));
state.transfer_balance(&a, &b, &U256::from(18u64)); state.transfer_balance(&a, &b, &U256::from(18u64));
assert_eq!(state.balance(&a), U256::from(9u64)); assert_eq!(state.balance(&a), U256::from(9u64));
assert_eq!(state.balance(&b), U256::from(18u64)); assert_eq!(state.balance(&b), U256::from(18u64));
state.commit(); state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(9u64)); assert_eq!(state.balance(&a), U256::from(9u64));
assert_eq!(state.balance(&b), U256::from(18u64)); assert_eq!(state.balance(&b), U256::from(18u64));
} }
@ -1397,11 +1419,11 @@ fn alter_nonce() {
assert_eq!(state.nonce(&a), U256::from(1u64)); assert_eq!(state.nonce(&a), U256::from(1u64));
state.inc_nonce(&a); state.inc_nonce(&a);
assert_eq!(state.nonce(&a), U256::from(2u64)); assert_eq!(state.nonce(&a), U256::from(2u64));
state.commit(); state.commit().unwrap();
assert_eq!(state.nonce(&a), U256::from(2u64)); assert_eq!(state.nonce(&a), U256::from(2u64));
state.inc_nonce(&a); state.inc_nonce(&a);
assert_eq!(state.nonce(&a), U256::from(3u64)); assert_eq!(state.nonce(&a), U256::from(3u64));
state.commit(); state.commit().unwrap();
assert_eq!(state.nonce(&a), U256::from(3u64)); assert_eq!(state.nonce(&a), U256::from(3u64));
} }
@ -1412,7 +1434,7 @@ fn balance_nonce() {
let a = Address::zero(); let a = Address::zero();
assert_eq!(state.balance(&a), U256::from(0u64)); assert_eq!(state.balance(&a), U256::from(0u64));
assert_eq!(state.nonce(&a), U256::from(0u64)); assert_eq!(state.nonce(&a), U256::from(0u64));
state.commit(); state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(0u64)); assert_eq!(state.balance(&a), U256::from(0u64));
assert_eq!(state.nonce(&a), U256::from(0u64)); assert_eq!(state.nonce(&a), U256::from(0u64));
} }
@ -1423,7 +1445,7 @@ fn ensure_cached() {
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
let a = Address::zero(); let a = Address::zero();
state.require(&a, false); state.require(&a, false);
state.commit(); state.commit().unwrap();
assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785"); assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785");
} }
@ -1463,7 +1485,7 @@ fn snapshot_nested() {
fn create_empty() { fn create_empty() {
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.commit(); state.commit().unwrap();
assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421");
} }

View File

@ -137,7 +137,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
test_spec.ensure_db_good(db.as_hashdb_mut()); test_spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let vm_factory = Default::default(); let vm_factory = Default::default();
let genesis_header = test_spec.genesis_header(); let genesis_header = test_spec.genesis_header();

View File

@ -20,7 +20,7 @@ use bytes::*;
use std::collections::HashMap; use std::collections::HashMap;
/// Trait modelling datastore keyed by a 32-byte Keccak hash. /// Trait modelling datastore keyed by a 32-byte Keccak hash.
pub trait HashDB: AsHashDB { pub trait HashDB: AsHashDB + Send + Sync {
/// Get the keys in the database together with number of underlying references. /// Get the keys in the database together with number of underlying references.
fn keys(&self) -> HashMap<H256, i32>; fn keys(&self) -> HashMap<H256, i32>;

View File

@ -88,10 +88,10 @@ impl HashDB for ArchiveDB {
fn get(&self, key: &H256) -> Option<&[u8]> { fn get(&self, key: &H256) -> Option<&[u8]> {
let k = self.overlay.raw(key); let k = self.overlay.raw(key);
match k { match k {
Some(&(ref d, rc)) if rc > 0 => Some(d), Some((d, rc)) if rc > 0 => Some(d),
_ => { _ => {
if let Some(x) = self.payload(key) { if let Some(x) = self.payload(key) {
Some(&self.overlay.denote(key, x).0) Some(self.overlay.denote(key, x).0)
} }
else { else {
None None

View File

@ -277,10 +277,10 @@ impl HashDB for EarlyMergeDB {
fn get(&self, key: &H256) -> Option<&[u8]> { fn get(&self, key: &H256) -> Option<&[u8]> {
let k = self.overlay.raw(key); let k = self.overlay.raw(key);
match k { match k {
Some(&(ref d, rc)) if rc > 0 => Some(d), Some((d, rc)) if rc > 0 => Some(d),
_ => { _ => {
if let Some(x) = self.payload(key) { if let Some(x) = self.payload(key) {
Some(&self.overlay.denote(key, x).0) Some(self.overlay.denote(key, x).0)
} }
else { else {
None None

View File

@ -266,9 +266,9 @@ impl JournalDB for OverlayRecentDB {
{ {
if canon_id == journal.id { if canon_id == journal.id {
for h in &journal.insertions { for h in &journal.insertions {
if let Some(&(ref d, rc)) = journal_overlay.backing_overlay.raw(&to_short_key(h)) { if let Some((d, rc)) = journal_overlay.backing_overlay.raw(&to_short_key(h)) {
if rc > 0 { if rc > 0 {
canon_insertions.push((h.clone(), d.clone())); //TODO: optimize this to avoid data copy canon_insertions.push((h.clone(), d.to_owned())); //TODO: optimize this to avoid data copy
} }
} }
} }
@ -343,7 +343,7 @@ impl HashDB for OverlayRecentDB {
fn get(&self, key: &H256) -> Option<&[u8]> { fn get(&self, key: &H256) -> Option<&[u8]> {
let k = self.transaction_overlay.raw(key); let k = self.transaction_overlay.raw(key);
match k { match k {
Some(&(ref d, rc)) if rc > 0 => Some(d), Some((d, rc)) if rc > 0 => Some(d),
_ => { _ => {
let v = self.journal_overlay.read().backing_overlay.get(&to_short_key(key)).map(|v| v.to_vec()); let v = self.journal_overlay.read().backing_overlay.get(&to_short_key(key)).map(|v| v.to_vec());
match v { match v {
@ -920,4 +920,4 @@ mod tests {
assert!(jdb.get(&key).is_none()); assert!(jdb.get(&key).is_none());
} }
} }

View File

@ -22,7 +22,7 @@ use kvdb::{Database, DBTransaction};
/// A `HashDB` which can manage a short-term journal potentially containing many forks of mutually /// A `HashDB` which can manage a short-term journal potentially containing many forks of mutually
/// exclusive actions. /// exclusive actions.
pub trait JournalDB : HashDB + Send + Sync { pub trait JournalDB: HashDB {
/// Return a copy of ourself, in a box. /// Return a copy of ourself, in a box.
fn boxed_clone(&self) -> Box<JournalDB>; fn boxed_clone(&self) -> Box<JournalDB>;

View File

@ -163,7 +163,7 @@ pub use journaldb::JournalDB;
pub use math::*; pub use math::*;
pub use crypto::*; pub use crypto::*;
pub use triehash::*; pub use triehash::*;
pub use trie::*; pub use trie::{Trie, TrieMut, TrieDB, TrieDBMut, TrieFactory, TrieError, SecTrieDB, SecTrieDBMut};
pub use nibbleslice::*; pub use nibbleslice::*;
pub use semantic_version::*; pub use semantic_version::*;
pub use network::*; pub use network::*;

View File

@ -24,10 +24,10 @@ use hashdb::*;
use heapsize::*; use heapsize::*;
use std::mem; use std::mem;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::default::Default;
#[derive(Debug,Clone)] const STATIC_NULL_RLP: (&'static [u8], i32) = (&[0x80; 1], 1);
use std::collections::hash_map::Entry;
/// Reference-counted memory-based `HashDB` implementation. /// Reference-counted memory-based `HashDB` implementation.
/// ///
/// Use `new()` to create a new database. Insert items with `insert()`, remove items /// Use `new()` to create a new database. Insert items with `insert()`, remove items
@ -71,25 +71,17 @@ use std::default::Default;
/// assert!(!m.contains(&k)); /// assert!(!m.contains(&k));
/// } /// }
/// ``` /// ```
#[derive(PartialEq)] #[derive(Default, Clone, PartialEq)]
pub struct MemoryDB { pub struct MemoryDB {
data: HashMap<H256, (Bytes, i32)>, data: HashMap<H256, (Bytes, i32)>,
static_null_rlp: (Bytes, i32),
aux: HashMap<Bytes, Bytes>, aux: HashMap<Bytes, Bytes>,
} }
impl Default for MemoryDB {
fn default() -> Self {
MemoryDB::new()
}
}
impl MemoryDB { impl MemoryDB {
/// Create a new instance of the memory DB. /// Create a new instance of the memory DB.
pub fn new() -> MemoryDB { pub fn new() -> MemoryDB {
MemoryDB { MemoryDB {
data: HashMap::new(), data: HashMap::new(),
static_null_rlp: (vec![0x80u8; 1], 1),
aux: HashMap::new(), aux: HashMap::new(),
} }
} }
@ -123,18 +115,6 @@ impl MemoryDB {
for empty in empties { self.data.remove(&empty); } for empty in empties { self.data.remove(&empty); }
} }
/// Grab the raw information associated with a key. Returns None if the key
/// doesn't exist.
///
/// Even when Some is returned, the data is only guaranteed to be useful
/// when the refs > 0.
pub fn raw(&self, key: &H256) -> Option<&(Bytes, i32)> {
if key == &SHA3_NULL_RLP {
return Some(&self.static_null_rlp);
}
self.data.get(key)
}
/// Return the internal map of hashes to data, clearing the current state. /// Return the internal map of hashes to data, clearing the current state.
pub fn drain(&mut self) -> HashMap<H256, (Bytes, i32)> { pub fn drain(&mut self) -> HashMap<H256, (Bytes, i32)> {
mem::replace(&mut self.data, HashMap::new()) mem::replace(&mut self.data, HashMap::new())
@ -145,11 +125,23 @@ impl MemoryDB {
mem::replace(&mut self.aux, HashMap::new()) mem::replace(&mut self.aux, HashMap::new())
} }
/// Grab the raw information associated with a key. Returns None if the key
/// doesn't exist.
///
/// Even when Some is returned, the data is only guaranteed to be useful
/// when the refs > 0.
pub fn raw(&self, key: &H256) -> Option<(&[u8], i32)> {
if key == &SHA3_NULL_RLP {
return Some(STATIC_NULL_RLP.clone());
}
self.data.get(key).map(|&(ref v, x)| (&v[..], x))
}
/// Denote than an existing value has the given key. Used when a key gets removed without /// Denote than an existing value has the given key. Used when a key gets removed without
/// a prior insert and thus has a negative reference with no value. /// a prior insert and thus has a negative reference with no value.
/// ///
/// May safely be called even if the key's value is known, in which case it will be a no-op. /// May safely be called even if the key's value is known, in which case it will be a no-op.
pub fn denote(&self, key: &H256, value: Bytes) -> &(Bytes, i32) { pub fn denote(&self, key: &H256, value: Bytes) -> (&[u8], i32) {
if self.raw(key) == None { if self.raw(key) == None {
unsafe { unsafe {
let p = &self.data as *const HashMap<H256, (Bytes, i32)> as *mut HashMap<H256, (Bytes, i32)>; let p = &self.data as *const HashMap<H256, (Bytes, i32)> as *mut HashMap<H256, (Bytes, i32)>;
@ -162,6 +154,7 @@ impl MemoryDB {
/// Returns the size of allocated heap memory /// Returns the size of allocated heap memory
pub fn mem_used(&self) -> usize { pub fn mem_used(&self) -> usize {
self.data.heap_size_of_children() self.data.heap_size_of_children()
+ self.aux.heap_size_of_children()
} }
/// Remove an element and delete it from storage if reference count reaches zero. /// Remove an element and delete it from storage if reference count reaches zero.
@ -190,6 +183,7 @@ impl HashDB for MemoryDB {
if key == &SHA3_NULL_RLP { if key == &SHA3_NULL_RLP {
return Some(&NULL_RLP_STATIC); return Some(&NULL_RLP_STATIC);
} }
match self.data.get(key) { match self.data.get(key) {
Some(&(ref d, rc)) if rc > 0 => Some(d), Some(&(ref d, rc)) if rc > 0 => Some(d),
_ => None _ => None
@ -204,6 +198,7 @@ impl HashDB for MemoryDB {
if key == &SHA3_NULL_RLP { if key == &SHA3_NULL_RLP {
return true; return true;
} }
match self.data.get(key) { match self.data.get(key) {
Some(&(_, x)) if x > 0 => true, Some(&(_, x)) if x > 0 => true,
_ => false _ => false
@ -217,14 +212,14 @@ impl HashDB for MemoryDB {
let key = value.sha3(); let key = value.sha3();
if match self.data.get_mut(&key) { if match self.data.get_mut(&key) {
Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => { Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => {
*old_value = From::from(value); *old_value = value.into();
*rc += 1; *rc += 1;
false false
}, },
Some(&mut (_, ref mut x)) => { *x += 1; false } , Some(&mut (_, ref mut x)) => { *x += 1; false } ,
None => true, None => true,
}{ // ... None falls through into... }{ // ... None falls through into...
self.data.insert(key.clone(), (From::from(value), 1)); self.data.insert(key.clone(), (value.into(), 1));
} }
key key
} }
@ -233,6 +228,7 @@ impl HashDB for MemoryDB {
if value == &NULL_RLP { if value == &NULL_RLP {
return; return;
} }
match self.data.get_mut(&key) { match self.data.get_mut(&key) {
Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => { Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => {
*old_value = value; *old_value = value;
@ -250,6 +246,7 @@ impl HashDB for MemoryDB {
if key == &SHA3_NULL_RLP { if key == &SHA3_NULL_RLP {
return; return;
} }
if match self.data.get_mut(key) { if match self.data.get_mut(key) {
Some(&mut (_, ref mut x)) => { *x -= 1; false } Some(&mut (_, ref mut x)) => { *x -= 1; false }
None => true None => true
@ -281,9 +278,9 @@ fn memorydb_denote() {
for _ in 0..1000 { for _ in 0..1000 {
let r = H256::random(); let r = H256::random();
let k = r.sha3(); let k = r.sha3();
let &(ref v, ref rc) = m.denote(&k, r.to_bytes()); let (v, rc) = m.denote(&k, r.to_bytes());
assert_eq!(v.as_slice(), r.as_slice()); assert_eq!(v, r.as_slice());
assert_eq!(*rc, 0); assert_eq!(rc, 0);
} }
assert_eq!(m.get(&hash).unwrap(), b"Hello world!"); assert_eq!(m.get(&hash).unwrap(), b"Hello world!");

View File

@ -99,7 +99,7 @@ impl OverlayDB {
pub fn revert(&mut self) { self.overlay.clear(); } pub fn revert(&mut self) { self.overlay.clear(); }
/// Get the number of references that would be committed. /// Get the number of references that would be committed.
pub fn commit_refs(&self, key: &H256) -> i32 { self.overlay.raw(key).map_or(0, |&(_, refs)| refs) } pub fn commit_refs(&self, key: &H256) -> i32 { self.overlay.raw(key).map_or(0, |(_, refs)| refs) }
/// Get the refs and value of the given key. /// Get the refs and value of the given key.
fn payload(&self, key: &H256) -> Option<(Bytes, u32)> { fn payload(&self, key: &H256) -> Option<(Bytes, u32)> {
@ -146,14 +146,14 @@ impl HashDB for OverlayDB {
// it positive again. // it positive again.
let k = self.overlay.raw(key); let k = self.overlay.raw(key);
match k { match k {
Some(&(ref d, rc)) if rc > 0 => Some(d), Some((d, rc)) if rc > 0 => Some(d),
_ => { _ => {
let memrc = k.map_or(0, |&(_, rc)| rc); let memrc = k.map_or(0, |(_, rc)| rc);
match self.payload(key) { match self.payload(key) {
Some(x) => { Some(x) => {
let (d, rc) = x; let (d, rc) = x;
if rc as i32 + memrc > 0 { if rc as i32 + memrc > 0 {
Some(&self.overlay.denote(key, d).0) Some(self.overlay.denote(key, d).0)
} }
else { else {
None None
@ -171,9 +171,9 @@ impl HashDB for OverlayDB {
// it positive again. // it positive again.
let k = self.overlay.raw(key); let k = self.overlay.raw(key);
match k { match k {
Some(&(_, rc)) if rc > 0 => true, Some((_, rc)) if rc > 0 => true,
_ => { _ => {
let memrc = k.map_or(0, |&(_, rc)| rc); let memrc = k.map_or(0, |(_, rc)| rc);
match self.payload(key) { match self.payload(key) {
Some(x) => { Some(x) => {
let (_, rc) = x; let (_, rc) = x;

View File

@ -37,7 +37,6 @@ pub use std::error::Error as StdError;
pub use std::ops::*; pub use std::ops::*;
pub use std::cmp::*; pub use std::cmp::*;
pub use std::sync::Arc; pub use std::sync::Arc;
pub use std::cell::*;
pub use std::collections::*; pub use std::collections::*;
pub use rustc_serialize::json::Json; pub use rustc_serialize::json::Json;

View File

@ -17,8 +17,7 @@
use hash::H256; use hash::H256;
use sha3::Hashable; use sha3::Hashable;
use hashdb::HashDB; use hashdb::HashDB;
use super::{TrieDB, Trie, TrieDBIterator, TrieError}; use super::{TrieDB, Trie, TrieDBIterator, TrieItem};
use trie::trietraits::TrieItem;
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
/// Additionaly it stores inserted hash-key mappings for later retrieval. /// Additionaly it stores inserted hash-key mappings for later retrieval.
@ -32,7 +31,7 @@ impl<'db> FatDB<'db> {
/// Create a new trie with the backing database `db` and empty `root` /// Create a new trie with the backing database `db` and empty `root`
/// Initialise to the state entailed by the genesis block. /// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly. /// This guarantees the trie is built correctly.
pub fn new(db: &'db HashDB, root: &'db H256) -> Result<Self, TrieError> { pub fn new(db: &'db HashDB, root: &'db H256) -> super::Result<Self> {
let fatdb = FatDB { let fatdb = FatDB {
raw: try!(TrieDB::new(db, root)) raw: try!(TrieDB::new(db, root))
}; };
@ -60,11 +59,13 @@ impl<'db> Trie for FatDB<'db> {
self.raw.root() self.raw.root()
} }
fn contains(&self, key: &[u8]) -> bool { fn contains(&self, key: &[u8]) -> super::Result<bool> {
self.raw.contains(&key.sha3()) self.raw.contains(&key.sha3())
} }
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key { fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result<Option<&'a [u8]>>
where 'a: 'key
{
self.raw.get(&key.sha3()) self.raw.get(&key.sha3())
} }
} }
@ -105,9 +106,9 @@ fn fatdb_to_trie() {
let mut root = H256::default(); let mut root = H256::default();
{ {
let mut t = FatDBMut::new(&mut memdb, &mut root); let mut t = FatDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
} }
let t = FatDB::new(&memdb, &root).unwrap(); let t = FatDB::new(&memdb, &root).unwrap();
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap(), &[0x01u8, 0x23]); assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), &[0x01u8, 0x23]);
assert_eq!(t.iter().collect::<Vec<_>>(), vec![(vec![0x01u8, 0x23], &[0x01u8, 0x23] as &[u8])]); assert_eq!(t.iter().collect::<Vec<_>>(), vec![(vec![0x01u8, 0x23], &[0x01u8, 0x23] as &[u8])]);
} }

View File

@ -17,7 +17,7 @@
use hash::H256; use hash::H256;
use sha3::Hashable; use sha3::Hashable;
use hashdb::HashDB; use hashdb::HashDB;
use super::{TrieDBMut, TrieMut, TrieError}; use super::{TrieDBMut, TrieMut};
/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
/// Additionaly it stores inserted hash-key mappings for later retrieval. /// Additionaly it stores inserted hash-key mappings for later retrieval.
@ -38,7 +38,7 @@ impl<'db> FatDBMut<'db> {
/// Create a new trie with the backing database `db` and `root`. /// Create a new trie with the backing database `db` and `root`.
/// ///
/// Returns an error if root does not exist. /// Returns an error if root does not exist.
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Result<Self, TrieError> { pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> super::Result<Self> {
Ok(FatDBMut { raw: try!(TrieDBMut::from_existing(db, root)) }) Ok(FatDBMut { raw: try!(TrieDBMut::from_existing(db, root)) })
} }
@ -62,23 +62,26 @@ impl<'db> TrieMut for FatDBMut<'db> {
self.raw.is_empty() self.raw.is_empty()
} }
fn contains(&self, key: &[u8]) -> bool { fn contains(&self, key: &[u8]) -> super::Result<bool> {
self.raw.contains(&key.sha3()) self.raw.contains(&key.sha3())
} }
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key { fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result<Option<&'a [u8]>>
where 'a: 'key
{
self.raw.get(&key.sha3()) self.raw.get(&key.sha3())
} }
fn insert(&mut self, key: &[u8], value: &[u8]) { fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result<()> {
let hash = key.sha3(); let hash = key.sha3();
self.raw.insert(&hash, value); try!(self.raw.insert(&hash, value));
let db = self.raw.db_mut(); let db = self.raw.db_mut();
db.insert_aux(hash.to_vec(), key.to_vec()); db.insert_aux(hash.to_vec(), key.to_vec());
Ok(())
} }
fn remove(&mut self, key: &[u8]) { fn remove(&mut self, key: &[u8]) -> super::Result<()> {
self.raw.remove(&key.sha3()); self.raw.remove(&key.sha3())
} }
} }
@ -92,8 +95,8 @@ fn fatdb_to_trie() {
let mut root = H256::default(); let mut root = H256::default();
{ {
let mut t = FatDBMut::new(&mut memdb, &mut root); let mut t = FatDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
} }
let t = TrieDB::new(&memdb, &root).unwrap(); let t = TrieDB::new(&memdb, &root).unwrap();
assert_eq!(t.get(&(&[0x01u8, 0x23]).sha3()).unwrap(), &[0x01u8, 0x23]); assert_eq!(t.get(&(&[0x01u8, 0x23]).sha3()).unwrap().unwrap(), &[0x01u8, 0x23]);
} }

View File

@ -20,8 +20,6 @@ use std::fmt;
use hash::H256; use hash::H256;
use hashdb::HashDB; use hashdb::HashDB;
/// Export the trietraits module.
pub mod trietraits;
/// Export the standardmap module. /// Export the standardmap module.
pub mod standardmap; pub mod standardmap;
/// Export the journal module. /// Export the journal module.
@ -40,7 +38,6 @@ pub mod sectriedbmut;
mod fatdb; mod fatdb;
mod fatdbmut; mod fatdbmut;
pub use self::trietraits::{Trie, TrieMut};
pub use self::standardmap::{Alphabet, StandardMap, ValueMode}; pub use self::standardmap::{Alphabet, StandardMap, ValueMode};
pub use self::triedbmut::TrieDBMut; pub use self::triedbmut::TrieDBMut;
pub use self::triedb::{TrieDB, TrieDBIterator}; pub use self::triedb::{TrieDB, TrieDBIterator};
@ -49,19 +46,80 @@ pub use self::sectriedb::SecTrieDB;
pub use self::fatdb::{FatDB, FatDBIterator}; pub use self::fatdb::{FatDB, FatDBIterator};
pub use self::fatdbmut::FatDBMut; pub use self::fatdbmut::FatDBMut;
/// Trie Errors /// Trie Errors.
#[derive(Debug)] ///
/// These borrow the data within them to avoid excessive copying on every
/// trie operation.
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum TrieError { pub enum TrieError {
/// Attempted to create a trie with a state root not in the DB. /// Attempted to create a trie with a state root not in the DB.
InvalidStateRoot, InvalidStateRoot(H256),
/// Trie item not found in the database,
IncompleteDatabase(H256),
} }
impl fmt::Display for TrieError { impl fmt::Display for TrieError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Trie Error: Invalid state root.") match *self {
TrieError::InvalidStateRoot(ref root) => write!(f, "Invalid state root: {}", root),
TrieError::IncompleteDatabase(ref missing) =>
write!(f, "Database missing expected key: {}", missing),
}
} }
} }
/// Trie-Item type.
pub type TrieItem<'a> = (Vec<u8>, &'a [u8]);
/// Trie result type. Boxed to avoid copying around extra space for `H256`s on successful queries.
pub type Result<T> = ::std::result::Result<T, Box<TrieError>>;
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait Trie {
/// Return the root of the trie.
fn root(&self) -> &H256;
/// Is the trie empty?
fn is_empty(&self) -> bool { *self.root() == ::rlp::SHA3_NULL_RLP }
/// Does the trie contain a given key?
fn contains(&self, key: &[u8]) -> Result<bool> {
self.get(key).map(|x| x.is_some())
}
/// What is the value of the given key in this trie?
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result<Option<&'a [u8]>> where 'a: 'key;
/// Returns an iterator over elements of trie.
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a>;
}
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait TrieMut {
/// Return the root of the trie.
fn root(&mut self) -> &H256;
/// Is the trie empty?
fn is_empty(&self) -> bool;
/// Does the trie contain a given key?
fn contains(&self, key: &[u8]) -> Result<bool> {
self.get(key).map(|x| x.is_some())
}
/// What is the value of the given key in this trie?
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result<Option<&'a [u8]>> where 'a: 'key;
/// Insert a `key`/`value` pair into the trie. An `empty` value is equivalent to removing
/// `key` from the trie.
fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<()>;
/// Remove a `key` from the trie. Equivalent to making it equal to the empty
/// value.
fn remove(&mut self, key: &[u8]) -> Result<()>;
}
/// Trie types /// Trie types
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum TrieSpec { pub enum TrieSpec {
@ -95,7 +153,7 @@ impl TrieFactory {
} }
/// Create new immutable instance of Trie. /// Create new immutable instance of Trie.
pub fn readonly<'db>(&self, db: &'db HashDB, root: &'db H256) -> Result<Box<Trie + 'db>, TrieError> { pub fn readonly<'db>(&self, db: &'db HashDB, root: &'db H256) -> Result<Box<Trie + 'db>> {
match self.spec { match self.spec {
TrieSpec::Generic => Ok(Box::new(try!(TrieDB::new(db, root)))), TrieSpec::Generic => Ok(Box::new(try!(TrieDB::new(db, root)))),
TrieSpec::Secure => Ok(Box::new(try!(SecTrieDB::new(db, root)))), TrieSpec::Secure => Ok(Box::new(try!(SecTrieDB::new(db, root)))),
@ -113,7 +171,7 @@ impl TrieFactory {
} }
/// Create new mutable instance of trie and check for errors. /// Create new mutable instance of trie and check for errors.
pub fn from_existing<'db>(&self, db: &'db mut HashDB, root: &'db mut H256) -> Result<Box<TrieMut + 'db>, TrieError> { pub fn from_existing<'db>(&self, db: &'db mut HashDB, root: &'db mut H256) -> Result<Box<TrieMut + 'db>> {
match self.spec { match self.spec {
TrieSpec::Generic => Ok(Box::new(try!(TrieDBMut::from_existing(db, root)))), TrieSpec::Generic => Ok(Box::new(try!(TrieDBMut::from_existing(db, root)))),
TrieSpec::Secure => Ok(Box::new(try!(SecTrieDBMut::from_existing(db, root)))), TrieSpec::Secure => Ok(Box::new(try!(SecTrieDBMut::from_existing(db, root)))),

View File

@ -48,7 +48,7 @@ impl<'a> Node<'a> {
}, },
// branch - first 16 are nodes, 17th is a value (or empty). // branch - first 16 are nodes, 17th is a value (or empty).
Prototype::List(17) => { Prototype::List(17) => {
let mut nodes: [&'a [u8]; 16] = unsafe { ::std::mem::uninitialized() }; let mut nodes: [&'a [u8]; 16] = [&[], &[], &[], &[], &[], &[], &[], &[], &[], &[], &[], &[], &[], &[], &[], &[]];
for i in 0..16 { for i in 0..16 {
nodes[i] = r.at(i).as_raw(); nodes[i] = r.at(i).as_raw();
} }

View File

@ -18,8 +18,7 @@ use hash::H256;
use sha3::Hashable; use sha3::Hashable;
use hashdb::HashDB; use hashdb::HashDB;
use super::triedb::TrieDB; use super::triedb::TrieDB;
use super::trietraits::{Trie, TrieItem}; use super::{Trie, TrieItem};
use super::TrieError;
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
/// ///
@ -34,7 +33,7 @@ impl<'db> SecTrieDB<'db> {
/// Initialise to the state entailed by the genesis block. /// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly. /// This guarantees the trie is built correctly.
/// Returns an error if root does not exist. /// Returns an error if root does not exist.
pub fn new(db: &'db HashDB, root: &'db H256) -> Result<Self, TrieError> { pub fn new(db: &'db HashDB, root: &'db H256) -> super::Result<Self> {
Ok(SecTrieDB { raw: try!(TrieDB::new(db, root)) }) Ok(SecTrieDB { raw: try!(TrieDB::new(db, root)) })
} }
@ -56,11 +55,13 @@ impl<'db> Trie for SecTrieDB<'db> {
fn root(&self) -> &H256 { self.raw.root() } fn root(&self) -> &H256 { self.raw.root() }
fn contains(&self, key: &[u8]) -> bool { fn contains(&self, key: &[u8]) -> super::Result<bool> {
self.raw.contains(&key.sha3()) self.raw.contains(&key.sha3())
} }
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key { fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result<Option<&'a [u8]>>
where 'a: 'key
{
self.raw.get(&key.sha3()) self.raw.get(&key.sha3())
} }
} }
@ -69,14 +70,14 @@ impl<'db> Trie for SecTrieDB<'db> {
fn trie_to_sectrie() { fn trie_to_sectrie() {
use memorydb::MemoryDB; use memorydb::MemoryDB;
use super::triedbmut::TrieDBMut; use super::triedbmut::TrieDBMut;
use super::trietraits::TrieMut; use super::super::TrieMut;
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::default(); let mut root = H256::default();
{ {
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&(&[0x01u8, 0x23]).sha3(), &[0x01u8, 0x23]); t.insert(&(&[0x01u8, 0x23]).sha3(), &[0x01u8, 0x23]).unwrap();
} }
let t = SecTrieDB::new(&memdb, &root).unwrap(); let t = SecTrieDB::new(&memdb, &root).unwrap();
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap(), &[0x01u8, 0x23]); assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), &[0x01u8, 0x23]);
} }

View File

@ -18,8 +18,7 @@ use hash::H256;
use sha3::Hashable; use sha3::Hashable;
use hashdb::HashDB; use hashdb::HashDB;
use super::triedbmut::TrieDBMut; use super::triedbmut::TrieDBMut;
use super::trietraits::TrieMut; use super::TrieMut;
use super::TrieError;
/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
/// ///
@ -39,7 +38,7 @@ impl<'db> SecTrieDBMut<'db> {
/// Create a new trie with the backing database `db` and `root`. /// Create a new trie with the backing database `db` and `root`.
/// ///
/// Returns an error if root does not exist. /// Returns an error if root does not exist.
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Result<Self, TrieError> { pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> super::Result<Self> {
Ok(SecTrieDBMut { raw: try!(TrieDBMut::from_existing(db, root)) }) Ok(SecTrieDBMut { raw: try!(TrieDBMut::from_existing(db, root)) })
} }
@ -59,20 +58,22 @@ impl<'db> TrieMut for SecTrieDBMut<'db> {
self.raw.is_empty() self.raw.is_empty()
} }
fn contains(&self, key: &[u8]) -> bool { fn contains(&self, key: &[u8]) -> super::Result<bool> {
self.raw.contains(&key.sha3()) self.raw.contains(&key.sha3())
} }
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key { fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result<Option<&'a [u8]>>
where 'a: 'key
{
self.raw.get(&key.sha3()) self.raw.get(&key.sha3())
} }
fn insert(&mut self, key: &[u8], value: &[u8]) { fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result<()> {
self.raw.insert(&key.sha3(), value); self.raw.insert(&key.sha3(), value)
} }
fn remove(&mut self, key: &[u8]) { fn remove(&mut self, key: &[u8]) -> super::Result<()> {
self.raw.remove(&key.sha3()); self.raw.remove(&key.sha3())
} }
} }
@ -86,8 +87,8 @@ fn sectrie_to_trie() {
let mut root = H256::default(); let mut root = H256::default();
{ {
let mut t = SecTrieDBMut::new(&mut memdb, &mut root); let mut t = SecTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
} }
let t = TrieDB::new(&memdb, &root).unwrap(); let t = TrieDB::new(&memdb, &root).unwrap();
assert_eq!(t.get(&(&[0x01u8, 0x23]).sha3()).unwrap(), &[0x01u8, 0x23]); assert_eq!(t.get(&(&[0x01u8, 0x23]).sha3()).unwrap().unwrap(), &[0x01u8, 0x23]);
} }

View File

@ -18,9 +18,8 @@ use common::*;
use hashdb::*; use hashdb::*;
use nibbleslice::*; use nibbleslice::*;
use rlp::*; use rlp::*;
use super::trietraits::{Trie, TrieItem};
use super::node::Node; use super::node::Node;
use super::TrieError; use super::{Trie, TrieItem, TrieError};
/// A `Trie` implementation using a generic `HashDB` backing database. /// A `Trie` implementation using a generic `HashDB` backing database.
/// ///
@ -41,11 +40,11 @@ use super::TrieError;
/// fn main() { /// fn main() {
/// let mut memdb = MemoryDB::new(); /// let mut memdb = MemoryDB::new();
/// let mut root = H256::new(); /// let mut root = H256::new();
/// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar"); /// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap();
/// let t = TrieDB::new(&memdb, &root).unwrap(); /// let t = TrieDB::new(&memdb, &root).unwrap();
/// assert!(t.contains(b"foo")); /// assert!(t.contains(b"foo").unwrap());
/// assert_eq!(t.get(b"foo").unwrap(), b"bar"); /// assert_eq!(t.get(b"foo").unwrap().unwrap(), b"bar");
/// assert!(t.db_items_remaining().is_empty()); /// assert!(t.db_items_remaining().unwrap().is_empty());
/// } /// }
/// ``` /// ```
pub struct TrieDB<'db> { pub struct TrieDB<'db> {
@ -59,9 +58,9 @@ pub struct TrieDB<'db> {
impl<'db> TrieDB<'db> { impl<'db> TrieDB<'db> {
/// Create a new trie with the backing database `db` and `root` /// Create a new trie with the backing database `db` and `root`
/// Returns an error if `root` does not exist /// Returns an error if `root` does not exist
pub fn new(db: &'db HashDB, root: &'db H256) -> Result<Self, TrieError> { pub fn new(db: &'db HashDB, root: &'db H256) -> super::Result<Self> {
if !db.contains(root) { if !db.contains(root) {
Err(TrieError::InvalidStateRoot) Err(Box::new(TrieError::InvalidStateRoot(*root)))
} else { } else {
Ok(TrieDB { Ok(TrieDB {
db: db, db: db,
@ -77,11 +76,11 @@ impl<'db> TrieDB<'db> {
} }
/// Determine all the keys in the backing database that belong to the trie. /// Determine all the keys in the backing database that belong to the trie.
pub fn keys(&self) -> Vec<H256> { pub fn keys(&self) -> super::Result<Vec<H256>> {
let mut ret: Vec<H256> = Vec::new(); let mut ret: Vec<H256> = Vec::new();
ret.push(self.root.clone()); ret.push(self.root.clone());
self.accumulate_keys(self.root_node(), &mut ret); try!(self.accumulate_keys(try!(self.root_node()), &mut ret));
ret Ok(ret)
} }
/// Convert a vector of hashes to a hashmap of hash to occurrences. /// Convert a vector of hashes to a hashmap of hash to occurrences.
@ -95,49 +94,51 @@ impl<'db> TrieDB<'db> {
/// Determine occurrences of items in the backing database which are not related to this /// Determine occurrences of items in the backing database which are not related to this
/// trie. /// trie.
pub fn db_items_remaining(&self) -> HashMap<H256, i32> { pub fn db_items_remaining(&self) -> super::Result<HashMap<H256, i32>> {
let mut ret = self.db.keys(); let mut ret = self.db.keys();
for (k, v) in Self::to_map(self.keys()).into_iter() { for (k, v) in Self::to_map(try!(self.keys())).into_iter() {
let keycount = *ret.get(&k).unwrap_or(&0); let keycount = *ret.get(&k).unwrap_or(&0);
match keycount <= v as i32 { match keycount <= v as i32 {
true => ret.remove(&k), true => ret.remove(&k),
_ => ret.insert(k, keycount - v as i32), _ => ret.insert(k, keycount - v as i32),
}; };
} }
ret Ok(ret)
} }
/// Recursion helper for `keys`. /// Recursion helper for `keys`.
fn accumulate_keys(&self, node: Node, acc: &mut Vec<H256>) { fn accumulate_keys(&self, node: Node, acc: &mut Vec<H256>) -> super::Result<()> {
let mut handle_payload = |payload| { let mut handle_payload = |payload| {
let p = Rlp::new(payload); let p = Rlp::new(payload);
if p.is_data() && p.size() == 32 { if p.is_data() && p.size() == 32 {
acc.push(p.as_val()); acc.push(p.as_val());
} }
self.accumulate_keys(self.get_node(payload), acc); self.accumulate_keys(try!(self.get_node(payload)), acc)
}; };
match node { match node {
Node::Extension(_, payload) => handle_payload(payload), Node::Extension(_, payload) => try!(handle_payload(payload)),
Node::Branch(payloads, _) => for payload in &payloads { handle_payload(payload) }, Node::Branch(payloads, _) => for payload in &payloads { try!(handle_payload(payload)) },
_ => {}, _ => {},
} }
Ok(())
} }
/// Get the root node's RLP. /// Get the root node's RLP.
fn root_node(&self) -> Node { fn root_node(&self) -> super::Result<Node> {
Node::decoded(self.root_data()) self.root_data().map(Node::decoded)
} }
/// Get the data of the root node. /// Get the data of the root node.
fn root_data(&self) -> &[u8] { fn root_data(&self) -> super::Result<&[u8]> {
self.db.get(self.root).expect("Trie root not found!") self.db.get(self.root).ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root)))
} }
/// Get the root node as a `Node`. /// Get the root node as a `Node`.
fn get_node<'a>(&'a self, node: &'a [u8]) -> Node { fn get_node(&'db self, node: &'db [u8]) -> super::Result<Node> {
Node::decoded(self.get_raw_or_lookup(node)) self.get_raw_or_lookup(node).map(Node::decoded)
} }
/// Indentation helper for `formal_all`. /// Indentation helper for `formal_all`.
@ -154,7 +155,9 @@ impl<'db> TrieDB<'db> {
Node::Leaf(slice, value) => try!(writeln!(f, "'{:?}: {:?}.", slice, value.pretty())), Node::Leaf(slice, value) => try!(writeln!(f, "'{:?}: {:?}.", slice, value.pretty())),
Node::Extension(ref slice, ref item) => { Node::Extension(ref slice, ref item) => {
try!(write!(f, "'{:?} ", slice)); try!(write!(f, "'{:?} ", slice));
try!(self.fmt_all(self.get_node(item), f, deepness)); if let Ok(node) = self.get_node(item) {
try!(self.fmt_all(node, f, deepness));
}
}, },
Node::Branch(ref nodes, ref value) => { Node::Branch(ref nodes, ref value) => {
try!(writeln!(f, "")); try!(writeln!(f, ""));
@ -164,12 +167,15 @@ impl<'db> TrieDB<'db> {
} }
for i in 0..16 { for i in 0..16 {
match self.get_node(nodes[i]) { match self.get_node(nodes[i]) {
Node::Empty => {}, Ok(Node::Empty) => {},
n => { Ok(n) => {
try!(self.fmt_indent(f, deepness + 1)); try!(self.fmt_indent(f, deepness + 1));
try!(write!(f, "'{:x} ", i)); try!(write!(f, "'{:x} ", i));
try!(self.fmt_all(n, f, deepness + 1)); try!(self.fmt_all(n, f, deepness + 1));
} }
Err(e) => {
try!(write!(f, "ERROR: {}", e));
}
} }
} }
}, },
@ -182,38 +188,46 @@ impl<'db> TrieDB<'db> {
} }
/// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists. /// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists.
fn do_lookup<'a, 'key>(&'a self, key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key { fn do_lookup<'key>(&'db self, key: &NibbleSlice<'key>) -> super::Result<Option<&'db [u8]>>
let root_rlp = self.root_data(); where 'db: 'key
self.get_from_node(root_rlp, key) {
let root_rlp = try!(self.root_data());
self.get_from_node(&root_rlp, key)
} }
/// Recursible function to retrieve the value given a `node` and a partial `key`. `None` if no /// Recursible function to retrieve the value given a `node` and a partial `key`. `None` if no
/// value exists for the key. /// value exists for the key.
/// ///
/// Note: Not a public API; use Trie trait functions. /// Note: Not a public API; use Trie trait functions.
fn get_from_node<'a, 'key>(&'a self, node: &'a [u8], key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key { fn get_from_node<'key>(&'db self, node: &'db [u8], key: &NibbleSlice<'key>) -> super::Result<Option<&'db [u8]>>
where 'db: 'key
{
match Node::decoded(node) { match Node::decoded(node) {
Node::Leaf(ref slice, ref value) if key == slice => Some(value), Node::Leaf(ref slice, ref value) if key == slice => Ok(Some(value)),
Node::Extension(ref slice, ref item) if key.starts_with(slice) => { Node::Extension(ref slice, ref item) if key.starts_with(slice) => {
self.get_from_node(self.get_raw_or_lookup(item), &key.mid(slice.len())) let data = try!(self.get_raw_or_lookup(item));
self.get_from_node(data, &key.mid(slice.len()))
}, },
Node::Branch(ref nodes, value) => match key.is_empty() { Node::Branch(ref nodes, value) => match key.is_empty() {
true => value, true => Ok(value),
false => self.get_from_node(self.get_raw_or_lookup(nodes[key.at(0) as usize]), &key.mid(1)) false => self.get_from_node(try!(self.get_raw_or_lookup(nodes[key.at(0) as usize])), &key.mid(1))
}, },
_ => None _ => Ok(None)
} }
} }
/// Given some node-describing data `node`, return the actual node RLP. /// Given some node-describing data `node`, return the actual node RLP.
/// This could be a simple identity operation in the case that the node is sufficiently small, but /// This could be a simple identity operation in the case that the node is sufficiently small, but
/// may require a database lookup. /// may require a database lookup.
fn get_raw_or_lookup<'a>(&'a self, node: &'a [u8]) -> &'a [u8] { fn get_raw_or_lookup(&'db self, node: &'db [u8]) -> super::Result<&'db [u8]> {
// check if its sha3 + len // check if its sha3 + len
let r = Rlp::new(node); let r = Rlp::new(node);
match r.is_data() && r.size() == 32 { match r.is_data() && r.size() == 32 {
true => self.db.get(&r.as_val::<H256>()).unwrap_or_else(|| panic!("Not found! {:?}", r.as_val::<H256>())), true => {
false => node let key = r.as_val::<H256>();
self.db.get(&key).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(key)))
}
false => Ok(node)
} }
} }
} }
@ -229,7 +243,6 @@ enum Status {
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
struct Crumb<'a> { struct Crumb<'a> {
node: Node<'a>, node: Node<'a>,
// key: &'a[u8],
status: Status, status: Status,
} }
@ -262,7 +275,7 @@ impl<'a> TrieDBIterator<'a> {
trail: vec![], trail: vec![],
key_nibbles: Vec::new(), key_nibbles: Vec::new(),
}; };
r.descend(db.root_data()); r.descend(db.root_data().unwrap());
r r
} }
@ -270,7 +283,7 @@ impl<'a> TrieDBIterator<'a> {
fn descend(&mut self, d: &'a [u8]) { fn descend(&mut self, d: &'a [u8]) {
self.trail.push(Crumb { self.trail.push(Crumb {
status: Status::Entering, status: Status::Entering,
node: self.db.get_node(d) node: self.db.get_node(d).unwrap(),
}); });
match self.trail.last().unwrap().node { match self.trail.last().unwrap().node {
Node::Leaf(n, _) | Node::Extension(n, _) => { self.key_nibbles.extend(n.iter()); }, Node::Leaf(n, _) | Node::Extension(n, _) => { self.key_nibbles.extend(n.iter()); },
@ -342,11 +355,9 @@ impl<'db> Trie for TrieDB<'db> {
fn root(&self) -> &H256 { self.root } fn root(&self) -> &H256 { self.root }
fn contains(&self, key: &[u8]) -> bool { fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result<Option<&'a [u8]>>
self.get(key).is_some() where 'a: 'key
} {
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.do_lookup(&NibbleSlice::new(key)) self.do_lookup(&NibbleSlice::new(key))
} }
} }
@ -362,8 +373,8 @@ impl<'db> fmt::Debug for TrieDB<'db> {
#[test] #[test]
fn iterator() { fn iterator() {
use super::trietraits::TrieMut;
use memorydb::*; use memorydb::*;
use super::TrieMut;
use super::triedbmut::*; use super::triedbmut::*;
let d = vec![ &b"A"[..], &b"AA"[..], &b"AB"[..], &b"B"[..] ]; let d = vec![ &b"A"[..], &b"AA"[..], &b"AB"[..], &b"B"[..] ];
@ -373,7 +384,7 @@ fn iterator() {
{ {
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
for x in &d { for x in &d {
t.insert(x, x); t.insert(x, x).unwrap();
} }
} }
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.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), TrieDB::new(&memdb, &root).unwrap().iter().map(|x|x.0).collect::<Vec<_>>());

View File

@ -273,11 +273,11 @@ impl<'a> Index<&'a StorageHandle> for NodeStorage {
/// let mut t = TrieDBMut::new(&mut memdb, &mut root); /// let mut t = TrieDBMut::new(&mut memdb, &mut root);
/// assert!(t.is_empty()); /// assert!(t.is_empty());
/// assert_eq!(*t.root(), SHA3_NULL_RLP); /// assert_eq!(*t.root(), SHA3_NULL_RLP);
/// t.insert(b"foo", b"bar"); /// t.insert(b"foo", b"bar").unwrap();
/// assert!(t.contains(b"foo")); /// assert!(t.contains(b"foo").unwrap());
/// assert_eq!(t.get(b"foo").unwrap(), b"bar"); /// assert_eq!(t.get(b"foo").unwrap().unwrap(), b"bar");
/// t.remove(b"foo"); /// t.remove(b"foo").unwrap();
/// assert!(!t.contains(b"foo")); /// assert!(!t.contains(b"foo").unwrap());
/// } /// }
/// ``` /// ```
pub struct TrieDBMut<'a> { pub struct TrieDBMut<'a> {
@ -309,9 +309,9 @@ impl<'a> TrieDBMut<'a> {
/// Create a new trie with the backing database `db` and `root. /// Create a new trie with the backing database `db` and `root.
/// Returns an error if `root` does not exist. /// Returns an error if `root` does not exist.
pub fn from_existing(db: &'a mut HashDB, root: &'a mut H256) -> Result<Self, TrieError> { pub fn from_existing(db: &'a mut HashDB, root: &'a mut H256) -> super::Result<Self> {
if !db.contains(root) { if !db.contains(root) {
return Err(TrieError::InvalidStateRoot); return Err(Box::new(TrieError::InvalidStateRoot(*root)));
} }
let root_handle = NodeHandle::Hash(*root); let root_handle = NodeHandle::Hash(*root);
@ -335,23 +335,23 @@ impl<'a> TrieDBMut<'a> {
} }
// cache a node by hash // cache a node by hash
fn cache(&mut self, hash: H256) -> StorageHandle { fn cache(&mut self, hash: H256) -> super::Result<StorageHandle> {
let node_rlp = self.db.get(&hash).expect("Not found!"); let node_rlp = try!(self.db.get(&hash).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(hash))));
let node = Node::from_rlp(node_rlp, &*self.db, &mut self.storage); let node = Node::from_rlp(node_rlp, &*self.db, &mut self.storage);
self.storage.alloc(Stored::Cached(node, hash)) Ok(self.storage.alloc(Stored::Cached(node, hash)))
} }
// inspect a node, choosing either to replace, restore, or delete it. // inspect a node, choosing either to replace, restore, or delete it.
// if restored or replaced, returns the new node along with a flag of whether it was changed. // if restored or replaced, returns the new node along with a flag of whether it was changed.
fn inspect<F>(&mut self, stored: Stored, inspector: F) -> Option<(Stored, bool)> fn inspect<F>(&mut self, stored: Stored, inspector: F) -> super::Result<Option<(Stored, bool)>>
where F: FnOnce(&mut Self, Node) -> Action { where F: FnOnce(&mut Self, Node) -> super::Result<Action> {
match stored { Ok(match stored {
Stored::New(node) => match inspector(self, node) { Stored::New(node) => match try!(inspector(self, node)) {
Action::Restore(node) => Some((Stored::New(node), false)), Action::Restore(node) => Some((Stored::New(node), false)),
Action::Replace(node) => Some((Stored::New(node), true)), Action::Replace(node) => Some((Stored::New(node), true)),
Action::Delete => None, Action::Delete => None,
}, },
Stored::Cached(node, hash) => match inspector(self, node) { Stored::Cached(node, hash) => match try!(inspector(self, node)) {
Action::Restore(node) => Some((Stored::Cached(node, hash), false)), Action::Restore(node) => Some((Stored::Cached(node, hash), false)),
Action::Replace(node) => { Action::Replace(node) => {
self.death_row.insert(hash); self.death_row.insert(hash);
@ -362,21 +362,22 @@ impl<'a> TrieDBMut<'a> {
None None
} }
}, },
} })
} }
// walk the trie, attempting to find the key's node. // walk the trie, attempting to find the key's node.
fn lookup<'x, 'key>(&'x self, partial: NibbleSlice<'key>, handle: &NodeHandle) -> Option<&'x [u8]> fn lookup<'x, 'key>(&'x self, partial: NibbleSlice<'key>, handle: &NodeHandle) -> super::Result<Option<&'x [u8]>>
where 'x: 'key { where 'x: 'key
{
match *handle { match *handle {
NodeHandle::Hash(ref hash) => self.do_db_lookup(hash, partial), NodeHandle::Hash(ref hash) => self.do_db_lookup(hash, partial),
NodeHandle::InMemory(ref handle) => match self.storage[handle] { NodeHandle::InMemory(ref handle) => match self.storage[handle] {
Node::Empty => None, Node::Empty => Ok(None),
Node::Leaf(ref key, ref value) => { Node::Leaf(ref key, ref value) => {
if NibbleSlice::from_encoded(key).0 == partial { if NibbleSlice::from_encoded(key).0 == partial {
Some(value) Ok(Some(value))
} else { } else {
None Ok(None)
} }
} }
Node::Extension(ref slice, ref child) => { Node::Extension(ref slice, ref child) => {
@ -384,15 +385,18 @@ impl<'a> TrieDBMut<'a> {
if partial.starts_with(&slice) { if partial.starts_with(&slice) {
self.lookup(partial.mid(slice.len()), child) self.lookup(partial.mid(slice.len()), child)
} else { } else {
None Ok(None)
} }
} }
Node::Branch(ref children, ref value) => { Node::Branch(ref children, ref value) => {
if partial.is_empty() { if partial.is_empty() {
value.as_ref().map(|v| &v[..]) Ok(value.as_ref().map(|v| &v[..]))
} else { } else {
let idx = partial.at(0); let idx = partial.at(0);
(&children[idx as usize]).as_ref().and_then(|child| self.lookup(partial.mid(1), child)) match children[idx as usize].as_ref() {
Some(child) => self.lookup(partial.mid(1), child),
None => Ok(None),
}
} }
} }
} }
@ -400,60 +404,68 @@ impl<'a> TrieDBMut<'a> {
} }
/// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists. /// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists.
fn do_db_lookup<'x, 'key>(&'x self, hash: &H256, key: NibbleSlice<'key>) -> Option<&'x [u8]> where 'x: 'key { fn do_db_lookup<'x, 'key>(&'x self, hash: &H256, key: NibbleSlice<'key>) -> super::Result<Option<&'x [u8]>>
self.db.get(hash).and_then(|node_rlp| self.get_from_db_node(node_rlp, key)) where 'x: 'key
{
self.db.get(hash).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(*hash)))
.and_then(|node_rlp| self.get_from_db_node(node_rlp, key))
} }
/// Recursible function to retrieve the value given a `node` and a partial `key`. `None` if no /// Recursible function to retrieve the value given a `node` and a partial `key`. `None` if no
/// value exists for the key. /// value exists for the key.
/// ///
/// Note: Not a public API; use Trie trait functions. /// Note: Not a public API; use Trie trait functions.
fn get_from_db_node<'x, 'key>(&'x self, node: &'x [u8], key: NibbleSlice<'key>) -> Option<&'x [u8]> where 'x: 'key { fn get_from_db_node<'x, 'key>(&'x self, node: &'x [u8], key: NibbleSlice<'key>) -> super::Result<Option<&'x [u8]>>
where 'x: 'key
{
match RlpNode::decoded(node) { match RlpNode::decoded(node) {
RlpNode::Leaf(ref slice, ref value) if &key == slice => Some(value), RlpNode::Leaf(ref slice, ref value) if &key == slice => Ok(Some(value)),
RlpNode::Extension(ref slice, ref item) if key.starts_with(slice) => { RlpNode::Extension(ref slice, ref item) if key.starts_with(slice) => {
self.get_from_db_node(self.get_raw_or_lookup(item), key.mid(slice.len())) self.get_from_db_node(try!(self.get_raw_or_lookup(item)), key.mid(slice.len()))
}, },
RlpNode::Branch(ref nodes, value) => match key.is_empty() { RlpNode::Branch(ref nodes, value) => match key.is_empty() {
true => value, true => Ok(value),
false => self.get_from_db_node(self.get_raw_or_lookup(nodes[key.at(0) as usize]), key.mid(1)) false => self.get_from_db_node(try!(self.get_raw_or_lookup(nodes[key.at(0) as usize])), key.mid(1))
}, },
_ => None _ => Ok(None),
} }
} }
/// Given some node-describing data `node`, return the actual node RLP. /// Given some node-describing data `node`, return the actual node RLP.
/// This could be a simple identity operation in the case that the node is sufficiently small, but /// This could be a simple identity operation in the case that the node is sufficiently small, but
/// may require a database lookup. /// may require a database lookup.
fn get_raw_or_lookup<'x>(&'x self, node: &'x [u8]) -> &'x [u8] { fn get_raw_or_lookup<'x>(&'x self, node: &'x [u8]) -> super::Result<&'x [u8]> {
// check if its sha3 + len // check if its sha3 + len
let r = Rlp::new(node); let r = Rlp::new(node);
match r.is_data() && r.size() == 32 { match r.is_data() && r.size() == 32 {
true => self.db.get(&r.as_val::<H256>()).expect("Not found!"), true => {
false => node let key = r.as_val::<H256>();
self.db.get(&key).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(key)))
}
false => Ok(node)
} }
} }
/// insert a key, value pair into the trie, creating new nodes if necessary. /// insert a key, value pair into the trie, creating new nodes if necessary.
fn insert_at(&mut self, handle: NodeHandle, partial: NibbleSlice, value: Bytes) -> (StorageHandle, bool) { fn insert_at(&mut self, handle: NodeHandle, partial: NibbleSlice, value: Bytes) -> super::Result<(StorageHandle, bool)> {
let h = match handle { let h = match handle {
NodeHandle::InMemory(h) => h, NodeHandle::InMemory(h) => h,
NodeHandle::Hash(h) => self.cache(h) NodeHandle::Hash(h) => try!(self.cache(h)),
}; };
let stored = self.storage.destroy(h); let stored = self.storage.destroy(h);
let (new_stored, changed) = self.inspect(stored, move |trie, stored| { let (new_stored, changed) = try!(self.inspect(stored, move |trie, stored| {
trie.insert_inspector(stored, partial, value).into_action() trie.insert_inspector(stored, partial, value).map(|a| a.into_action())
}).expect("Insertion never deletes."); })).expect("Insertion never deletes.");
(self.storage.alloc(new_stored), changed) Ok((self.storage.alloc(new_stored), changed))
} }
/// the insertion inspector. /// the insertion inspector.
#[cfg_attr(feature = "dev", allow(cyclomatic_complexity))] #[cfg_attr(feature = "dev", allow(cyclomatic_complexity))]
fn insert_inspector(&mut self, node: Node, partial: NibbleSlice, value: Bytes) -> InsertAction { fn insert_inspector(&mut self, node: Node, partial: NibbleSlice, value: Bytes) -> super::Result<InsertAction> {
trace!(target: "trie", "augmented (partial: {:?}, value: {:?})", partial, value.pretty()); trace!(target: "trie", "augmented (partial: {:?}, value: {:?})", partial, value.pretty());
match node { Ok(match node {
Node::Empty => { Node::Empty => {
trace!(target: "trie", "empty: COMPOSE"); trace!(target: "trie", "empty: COMPOSE");
InsertAction::Replace(Node::Leaf(partial.encoded(true), value)) InsertAction::Replace(Node::Leaf(partial.encoded(true), value))
@ -473,11 +485,11 @@ impl<'a> TrieDBMut<'a> {
let partial = partial.mid(1); let partial = partial.mid(1);
if let Some(child) = children[idx].take() { if let Some(child) = children[idx].take() {
// original had something there. recurse down into it. // original had something there. recurse down into it.
let (new_child, changed) = self.insert_at(child, partial, value); let (new_child, changed) = try!(self.insert_at(child, partial, value));
children[idx] = Some(new_child.into()); children[idx] = Some(new_child.into());
if !changed { if !changed {
// the new node we composed didn't change. that means our branch is untouched too. // the new node we composed didn't change. that means our branch is untouched too.
return InsertAction::Restore(Node::Branch(children, stored_value)); return Ok(InsertAction::Restore(Node::Branch(children, stored_value)));
} }
} else { } else {
// original had nothing there. compose a leaf. // original had nothing there. compose a leaf.
@ -516,7 +528,8 @@ impl<'a> TrieDBMut<'a> {
}; };
// always replace because whatever we get out here is not the branch we started with. // always replace because whatever we get out here is not the branch we started with.
InsertAction::Replace(self.insert_inspector(branch, partial, value).unwrap_node()) let branch_action = try!(self.insert_inspector(branch, partial, value)).unwrap_node();
InsertAction::Replace(branch_action)
} else if cp == existing_key.len() { } else if cp == existing_key.len() {
trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp);
@ -524,7 +537,7 @@ impl<'a> TrieDBMut<'a> {
// make a stub branch and an extension. // make a stub branch and an extension.
let branch = Node::Branch(empty_children(), Some(stored_value)); let branch = Node::Branch(empty_children(), Some(stored_value));
// augment the new branch. // augment the new branch.
let branch = self.insert_inspector(branch, partial.mid(cp), value).unwrap_node(); let branch = try!(self.insert_inspector(branch, partial.mid(cp), value)).unwrap_node();
// always replace since we took a leaf and made an extension. // always replace since we took a leaf and made an extension.
let branch_handle = self.storage.alloc(Stored::New(branch)).into(); let branch_handle = self.storage.alloc(Stored::New(branch)).into();
@ -537,7 +550,7 @@ impl<'a> TrieDBMut<'a> {
let low = Node::Leaf(existing_key.mid(cp).encoded(true), stored_value); let low = Node::Leaf(existing_key.mid(cp).encoded(true), stored_value);
// augment it. this will result in the Leaf -> cp == 0 routine, // augment it. this will result in the Leaf -> cp == 0 routine,
// which creates a branch. // which creates a branch.
let augmented_low = self.insert_inspector(low, partial.mid(cp), value).unwrap_node(); let augmented_low = try!(self.insert_inspector(low, partial.mid(cp), value)).unwrap_node();
// make an extension using it. this is a replacement. // make an extension using it. this is a replacement.
InsertAction::Replace(Node::Extension( InsertAction::Replace(Node::Extension(
@ -568,14 +581,15 @@ impl<'a> TrieDBMut<'a> {
}; };
// continue inserting. // continue inserting.
InsertAction::Replace(self.insert_inspector(Node::Branch(children, None), partial, value).unwrap_node()) let branch_action = try!(self.insert_inspector(Node::Branch(children, None), partial, value)).unwrap_node();
InsertAction::Replace(branch_action)
} else if cp == existing_key.len() { } else if cp == existing_key.len() {
trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp);
// fully-shared prefix. // fully-shared prefix.
// insert into the child node. // insert into the child node.
let (new_child, changed) = self.insert_at(child_branch, partial.mid(cp), value); let (new_child, changed) = try!(self.insert_at(child_branch, partial.mid(cp), value));
let new_ext = Node::Extension(existing_key.encoded(false), new_child.into()); let new_ext = Node::Extension(existing_key.encoded(false), new_child.into());
// if the child branch wasn't changed, meaning this extension remains the same. // if the child branch wasn't changed, meaning this extension remains the same.
@ -589,7 +603,7 @@ impl<'a> TrieDBMut<'a> {
// partially-shared. // partially-shared.
let low = Node::Extension(existing_key.mid(cp).encoded(false), child_branch); let low = Node::Extension(existing_key.mid(cp).encoded(false), child_branch);
// augment the extension. this will take the cp == 0 path, creating a branch. // augment the extension. this will take the cp == 0 path, creating a branch.
let augmented_low = self.insert_inspector(low, partial.mid(cp), value).unwrap_node(); let augmented_low = try!(self.insert_inspector(low, partial.mid(cp), value)).unwrap_node();
// always replace, since this extension is not the one we started with. // always replace, since this extension is not the one we started with.
// this is known because the partial key is only the common prefix. // this is known because the partial key is only the common prefix.
@ -599,37 +613,38 @@ impl<'a> TrieDBMut<'a> {
)) ))
} }
} }
} })
} }
/// Remove a node from the trie based on key. /// Remove a node from the trie based on key.
fn remove_at(&mut self, handle: NodeHandle, partial: NibbleSlice) -> Option<(StorageHandle, bool)> { fn remove_at(&mut self, handle: NodeHandle, partial: NibbleSlice) -> super::Result<Option<(StorageHandle, bool)>> {
let stored = match handle { let stored = match handle {
NodeHandle::InMemory(h) => self.storage.destroy(h), NodeHandle::InMemory(h) => self.storage.destroy(h),
NodeHandle::Hash(h) => { NodeHandle::Hash(h) => {
let handle = self.cache(h); let handle = try!(self.cache(h));
self.storage.destroy(handle) self.storage.destroy(handle)
} }
}; };
self.inspect(stored, move |trie, node| trie.remove_inspector(node, partial)) let opt = try!(self.inspect(stored, move |trie, node| trie.remove_inspector(node, partial)));
.map(|(new, changed)| (self.storage.alloc(new), changed))
Ok(opt.map(|(new, changed)| (self.storage.alloc(new), changed)))
} }
/// the removal inspector /// the removal inspector
fn remove_inspector(&mut self, node: Node, partial: NibbleSlice) -> Action { fn remove_inspector(&mut self, node: Node, partial: NibbleSlice) -> super::Result<Action> {
match (node, partial.is_empty()) { Ok(match (node, partial.is_empty()) {
(Node::Empty, _) => Action::Delete, (Node::Empty, _) => Action::Delete,
(Node::Branch(c, None), true) => Action::Restore(Node::Branch(c, None)), (Node::Branch(c, None), true) => Action::Restore(Node::Branch(c, None)),
(Node::Branch(children, _), true) => { (Node::Branch(children, _), true) => {
// always replace since we took the value out. // always replace since we took the value out.
Action::Replace(self.fix(Node::Branch(children, None))) Action::Replace(try!(self.fix(Node::Branch(children, None))))
} }
(Node::Branch(mut children, value), false) => { (Node::Branch(mut children, value), false) => {
let idx = partial.at(0) as usize; let idx = partial.at(0) as usize;
if let Some(child) = children[idx].take() { if let Some(child) = children[idx].take() {
trace!(target: "trie", "removing value out of branch child, partial={:?}", partial); trace!(target: "trie", "removing value out of branch child, partial={:?}", partial);
match self.remove_at(child, partial.mid(1)) { match try!(self.remove_at(child, partial.mid(1))) {
Some((new, changed)) => { Some((new, changed)) => {
children[idx] = Some(new.into()); children[idx] = Some(new.into());
let branch = Node::Branch(children, value); let branch = Node::Branch(children, value);
@ -644,7 +659,7 @@ impl<'a> TrieDBMut<'a> {
// the child we took was deleted. // the child we took was deleted.
// the node may need fixing. // the node may need fixing.
trace!(target: "trie", "branch child deleted, partial={:?}", partial); trace!(target: "trie", "branch child deleted, partial={:?}", partial);
Action::Replace(self.fix(Node::Branch(children, value))) Action::Replace(try!(self.fix(Node::Branch(children, value))))
} }
} }
} else { } else {
@ -670,14 +685,14 @@ impl<'a> TrieDBMut<'a> {
if cp == existing_len { if cp == existing_len {
// try to remove from the child branch. // try to remove from the child branch.
trace!(target: "trie", "removing from extension child, partial={:?}", partial); trace!(target: "trie", "removing from extension child, partial={:?}", partial);
match self.remove_at(child_branch, partial.mid(cp)) { match try!(self.remove_at(child_branch, partial.mid(cp))) {
Some((new_child, changed)) => { Some((new_child, changed)) => {
let new_child = new_child.into(); let new_child = new_child.into();
// if the child branch was unchanged, then the extension is too. // if the child branch was unchanged, then the extension is too.
// otherwise, this extension may need fixing. // otherwise, this extension may need fixing.
match changed { match changed {
true => Action::Replace(self.fix(Node::Extension(encoded, new_child))), true => Action::Replace(try!(self.fix(Node::Extension(encoded, new_child)))),
false => Action::Restore(Node::Extension(encoded, new_child)), false => Action::Restore(Node::Extension(encoded, new_child)),
} }
} }
@ -692,7 +707,7 @@ impl<'a> TrieDBMut<'a> {
Action::Restore(Node::Extension(encoded, child_branch)) Action::Restore(Node::Extension(encoded, child_branch))
} }
} }
} })
} }
/// Given a node which may be in an _invalid state_, fix it such that it is then in a valid /// Given a node which may be in an _invalid state_, fix it such that it is then in a valid
@ -701,7 +716,7 @@ impl<'a> TrieDBMut<'a> {
/// _invalid state_ means: /// _invalid state_ means:
/// - Branch node where there is only a single entry; /// - Branch node where there is only a single entry;
/// - Extension node followed by anything other than a Branch node. /// - Extension node followed by anything other than a Branch node.
fn fix(&mut self, node: Node) -> Node { fn fix(&mut self, node: Node) -> super::Result<Node> {
match node { match node {
Node::Branch(mut children, value) => { Node::Branch(mut children, value) => {
// if only a single value, transmute to leaf/extension and feed through fixed. // if only a single value, transmute to leaf/extension and feed through fixed.
@ -734,12 +749,12 @@ impl<'a> TrieDBMut<'a> {
(UsedIndex::None, Some(value)) => { (UsedIndex::None, Some(value)) => {
// make a leaf. // make a leaf.
trace!(target: "trie", "fixing: branch -> leaf"); trace!(target: "trie", "fixing: branch -> leaf");
Node::Leaf(NibbleSlice::new(&[]).encoded(true), value) Ok(Node::Leaf(NibbleSlice::new(&[]).encoded(true), value))
} }
(_, value) => { (_, value) => {
// all is well. // all is well.
trace!(target: "trie", "fixing: restoring branch"); trace!(target: "trie", "fixing: restoring branch");
Node::Branch(children, value) Ok(Node::Branch(children, value))
} }
} }
} }
@ -747,7 +762,7 @@ impl<'a> TrieDBMut<'a> {
let stored = match child { let stored = match child {
NodeHandle::InMemory(h) => self.storage.destroy(h), NodeHandle::InMemory(h) => self.storage.destroy(h),
NodeHandle::Hash(h) => { NodeHandle::Hash(h) => {
let handle = self.cache(h); let handle = try!(self.cache(h));
self.storage.destroy(handle) self.storage.destroy(handle)
} }
}; };
@ -782,7 +797,7 @@ impl<'a> TrieDBMut<'a> {
let new_partial = NibbleSlice::new_composed(&partial, &sub_partial); let new_partial = NibbleSlice::new_composed(&partial, &sub_partial);
trace!(target: "trie", "fixing: extension -> leaf. new_partial={:?}", new_partial); trace!(target: "trie", "fixing: extension -> leaf. new_partial={:?}", new_partial);
Node::Leaf(new_partial.encoded(true), value) Ok(Node::Leaf(new_partial.encoded(true), value))
} }
child_node => { child_node => {
trace!(target: "trie", "fixing: restoring extension"); trace!(target: "trie", "fixing: restoring extension");
@ -794,11 +809,11 @@ impl<'a> TrieDBMut<'a> {
Stored::New(child_node) Stored::New(child_node)
}; };
Node::Extension(partial, self.storage.alloc(stored).into()) Ok(Node::Extension(partial, self.storage.alloc(stored).into()))
} }
} }
} }
other => other, // only ext and branch need fixing. other => Ok(other), // only ext and branch need fixing.
} }
} }
@ -881,29 +896,27 @@ impl<'a> TrieMut for TrieDBMut<'a> {
} }
} }
fn get<'b, 'key>(&'b self, key: &'key [u8]) -> Option<&'b [u8]> where 'b: 'key { fn get<'x, 'key>(&'x self, key: &'key [u8]) -> super::Result<Option<&'x [u8]>> where 'x: 'key {
self.lookup(NibbleSlice::new(key), &self.root_handle) self.lookup(NibbleSlice::new(key), &self.root_handle)
} }
fn contains(&self, key: &[u8]) -> bool {
self.get(key).is_some()
}
fn insert(&mut self, key: &[u8], value: &[u8]) { fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result<()> {
if value.is_empty() { if value.is_empty() {
self.remove(key); return self.remove(key);
return;
} }
let root_handle = self.root_handle(); let root_handle = self.root_handle();
let (new_handle, _) = self.insert_at(root_handle, NibbleSlice::new(key), value.to_owned()); let (new_handle, _) = try!(self.insert_at(root_handle, NibbleSlice::new(key), value.to_owned()));
self.root_handle = NodeHandle::InMemory(new_handle); self.root_handle = NodeHandle::InMemory(new_handle);
Ok(())
} }
fn remove(&mut self, key: &[u8]) { fn remove(&mut self, key: &[u8]) -> super::Result<()> {
let root_handle = self.root_handle(); let root_handle = self.root_handle();
let key = NibbleSlice::new(key); let key = NibbleSlice::new(key);
match self.remove_at(root_handle, key) { match try!(self.remove_at(root_handle, key)) {
Some((handle, _)) => { Some((handle, _)) => {
self.root_handle = NodeHandle::InMemory(handle); self.root_handle = NodeHandle::InMemory(handle);
} }
@ -912,6 +925,8 @@ impl<'a> TrieMut for TrieDBMut<'a> {
*self.root = SHA3_NULL_RLP; *self.root = SHA3_NULL_RLP;
} }
}; };
Ok(())
} }
} }
@ -930,7 +945,7 @@ mod tests {
use super::*; use super::*;
use rlp::*; use rlp::*;
use bytes::ToPretty; use bytes::ToPretty;
use super::super::trietraits::*; use super::super::TrieMut;
use super::super::standardmap::*; use super::super::standardmap::*;
fn populate_trie<'db>(db: &'db mut HashDB, root: &'db mut H256, v: &[(Vec<u8>, Vec<u8>)]) -> TrieDBMut<'db> { fn populate_trie<'db>(db: &'db mut HashDB, root: &'db mut H256, v: &[(Vec<u8>, Vec<u8>)]) -> TrieDBMut<'db> {
@ -938,7 +953,7 @@ mod tests {
for i in 0..v.len() { for i in 0..v.len() {
let key: &[u8]= &v[i].0; let key: &[u8]= &v[i].0;
let val: &[u8] = &v[i].1; let val: &[u8] = &v[i].1;
t.insert(key, val); t.insert(key, val).unwrap();
} }
t t
} }
@ -946,7 +961,7 @@ mod tests {
fn unpopulate_trie<'db>(t: &mut TrieDBMut<'db>, v: &[(Vec<u8>, Vec<u8>)]) { fn unpopulate_trie<'db>(t: &mut TrieDBMut<'db>, v: &[(Vec<u8>, Vec<u8>)]) {
for i in v { for i in v {
let key: &[u8]= &i.0; let key: &[u8]= &i.0;
t.remove(key); t.remove(key).unwrap();
} }
} }
@ -1009,7 +1024,7 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x01u8, 0x23]) ])); assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x01u8, 0x23]) ]));
} }
@ -1020,15 +1035,15 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t1 = TrieDBMut::new(&mut memdb, &mut root); let mut t1 = TrieDBMut::new(&mut memdb, &mut root);
t1.insert(&[0x01, 0x23], &big_value.to_vec()); t1.insert(&[0x01, 0x23], &big_value.to_vec()).unwrap();
t1.insert(&[0x01, 0x34], &big_value.to_vec()); t1.insert(&[0x01, 0x34], &big_value.to_vec()).unwrap();
let mut memdb2 = MemoryDB::new(); let mut memdb2 = MemoryDB::new();
let mut root2 = H256::new(); let mut root2 = H256::new();
let mut t2 = TrieDBMut::new(&mut memdb2, &mut root2); let mut t2 = TrieDBMut::new(&mut memdb2, &mut root2);
t2.insert(&[0x01], &big_value.to_vec()); t2.insert(&[0x01], &big_value.to_vec()).unwrap();
t2.insert(&[0x01, 0x23], &big_value.to_vec()); t2.insert(&[0x01, 0x23], &big_value.to_vec()).unwrap();
t2.insert(&[0x01, 0x34], &big_value.to_vec()); t2.insert(&[0x01, 0x34], &big_value.to_vec()).unwrap();
t2.remove(&[0x01]); t2.remove(&[0x01]).unwrap();
} }
#[test] #[test]
@ -1036,8 +1051,8 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]); t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]).unwrap();
assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x23u8, 0x45]) ])); assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x23u8, 0x45]) ]));
} }
@ -1046,8 +1061,8 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]); t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]).unwrap();
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]), (vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x11u8, 0x23], vec![0x11u8, 0x23]) (vec![0x11u8, 0x23], vec![0x11u8, 0x23])
@ -1059,9 +1074,9 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]); t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap();
t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]); t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap();
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]), (vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x81u8, 0x23], vec![0x81u8, 0x23]), (vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
@ -1074,8 +1089,8 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[], &[0x0]); t.insert(&[], &[0x0]).unwrap();
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
(vec![], vec![0x0]), (vec![], vec![0x0]),
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]), (vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
@ -1087,8 +1102,8 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]); t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]).unwrap();
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]), (vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x01u8, 0x34], vec![0x01u8, 0x34]), (vec![0x01u8, 0x34], vec![0x01u8, 0x34]),
@ -1100,9 +1115,9 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01, 0x23, 0x45], &[0x01]); t.insert(&[0x01, 0x23, 0x45], &[0x01]).unwrap();
t.insert(&[0x01, 0xf3, 0x45], &[0x02]); t.insert(&[0x01, 0xf3, 0x45], &[0x02]).unwrap();
t.insert(&[0x01, 0xf3, 0xf5], &[0x03]); t.insert(&[0x01, 0xf3, 0xf5], &[0x03]).unwrap();
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
(vec![0x01, 0x23, 0x45], vec![0x01]), (vec![0x01, 0x23, 0x45], vec![0x01]),
(vec![0x01, 0xf3, 0x45], vec![0x02]), (vec![0x01, 0xf3, 0x45], vec![0x02]),
@ -1118,8 +1133,8 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], big_value0); t.insert(&[0x01u8, 0x23], big_value0).unwrap();
t.insert(&[0x11u8, 0x23], big_value1); t.insert(&[0x11u8, 0x23], big_value1).unwrap();
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
(vec![0x01u8, 0x23], big_value0.to_vec()), (vec![0x01u8, 0x23], big_value0.to_vec()),
(vec![0x11u8, 0x23], big_value1.to_vec()) (vec![0x11u8, 0x23], big_value1.to_vec())
@ -1133,8 +1148,8 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], big_value); t.insert(&[0x01u8, 0x23], big_value).unwrap();
t.insert(&[0x11u8, 0x23], big_value); t.insert(&[0x11u8, 0x23], big_value).unwrap();
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
(vec![0x01u8, 0x23], big_value.to_vec()), (vec![0x01u8, 0x23], big_value.to_vec()),
(vec![0x11u8, 0x23], big_value.to_vec()) (vec![0x11u8, 0x23], big_value.to_vec())
@ -1146,7 +1161,7 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let t = TrieDBMut::new(&mut memdb, &mut root); let t = TrieDBMut::new(&mut memdb, &mut root);
assert_eq!(t.get(&[0x5]), None); assert_eq!(t.get(&[0x5]), Ok(None));
} }
#[test] #[test]
@ -1154,10 +1169,10 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
assert_eq!(t.get(&[0x1, 0x23]).unwrap(), &[0x1u8, 0x23]); assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), &[0x1u8, 0x23]);
t.commit(); t.commit();
assert_eq!(t.get(&[0x1, 0x23]).unwrap(), &[0x1u8, 0x23]); assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), &[0x1u8, 0x23]);
} }
#[test] #[test]
@ -1165,18 +1180,18 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]); t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap();
t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]); t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap();
assert_eq!(t.get(&[0x01, 0x23]).unwrap(), &[0x01u8, 0x23]); assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), &[0x01u8, 0x23]);
assert_eq!(t.get(&[0xf1, 0x23]).unwrap(), &[0xf1u8, 0x23]); assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), &[0xf1u8, 0x23]);
assert_eq!(t.get(&[0x81, 0x23]).unwrap(), &[0x81u8, 0x23]); assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), &[0x81u8, 0x23]);
assert_eq!(t.get(&[0x82, 0x23]), None); assert_eq!(t.get(&[0x82, 0x23]), Ok(None));
t.commit(); t.commit();
assert_eq!(t.get(&[0x01, 0x23]).unwrap(), &[0x01u8, 0x23]); assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), &[0x01u8, 0x23]);
assert_eq!(t.get(&[0xf1, 0x23]).unwrap(), &[0xf1u8, 0x23]); assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), &[0xf1u8, 0x23]);
assert_eq!(t.get(&[0x81, 0x23]).unwrap(), &[0x81u8, 0x23]); assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), &[0x81u8, 0x23]);
assert_eq!(t.get(&[0x82, 0x23]), None); assert_eq!(t.get(&[0x82, 0x23]), Ok(None));
} }
#[test] #[test]
@ -1223,7 +1238,7 @@ mod tests {
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
{ {
let mut t = TrieDBMut::new(&mut db, &mut root); let mut t = TrieDBMut::new(&mut db, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
} }
{ {
@ -1246,13 +1261,13 @@ mod tests {
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDBMut::new(&mut db, &mut root); let mut t = TrieDBMut::new(&mut db, &mut root);
for &(ref key, ref value) in &x { for &(ref key, ref value) in &x {
t.insert(key, value); t.insert(key, value).unwrap();
} }
assert_eq!(*t.root(), trie_root(x.clone())); assert_eq!(*t.root(), trie_root(x.clone()));
for &(ref key, _) in &x { for &(ref key, _) in &x {
t.insert(key, &[]); t.insert(key, &[]).unwrap();
} }
assert!(t.is_empty()); assert!(t.is_empty());

View File

@ -1,62 +0,0 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity 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 General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use hash::H256;
use rlp::SHA3_NULL_RLP;
/// Trie-Item type.
pub type TrieItem<'a> = (Vec<u8>, &'a [u8]);
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait Trie {
/// Return the root of the trie.
fn root(&self) -> &H256;
/// Is the trie empty?
fn is_empty(&self) -> bool { *self.root() == SHA3_NULL_RLP }
/// Does the trie contain a given key?
fn contains(&self, key: &[u8]) -> bool;
/// What is the value of the given key in this trie?
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key;
/// Returns an iterator over elements of trie.
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a>;
}
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait TrieMut {
/// Return the root of the trie.
fn root(&mut self) -> &H256;
/// Is the trie empty?
fn is_empty(&self) -> bool;
/// Does the trie contain a given key?
fn contains(&self, key: &[u8]) -> bool;
/// What is the value of the given key in this trie?
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key;
/// Insert a `key`/`value` pair into the trie. An `empty` value is equivalent to removing
/// `key` from the trie.
fn insert(&mut self, key: &[u8], value: &[u8]);
/// Remove a `key` from the trie. Equivalent to making it equal to the empty
/// value.
fn remove(&mut self, key: &[u8]);
}