Refactor triedb constructors to error on invalid state root (#1230)
* add TrieError, refactor Trie DB creation * remove Result type alias due to glob import conflicts * fix fallout in state.rs * add debug, display impl for TrieError * fix fallout in account.rs * ethcore::Error::TrieError variant * fix remaining fallout in ethcore crate * added From<TrieError> impl for Error, removed map_err calls * fix test breakages * fix doc tests * update docs [ci skip]
This commit is contained in:
parent
fdc22db3f4
commit
13968aaa38
@ -116,7 +116,12 @@ impl Account {
|
|||||||
/// Get (and cache) the contents of the trie's storage at `key`.
|
/// Get (and cache) the contents of the trie's storage at `key`.
|
||||||
pub fn storage_at(&self, db: &AccountDB, key: &H256) -> H256 {
|
pub fn storage_at(&self, db: &AccountDB, key: &H256) -> H256 {
|
||||||
self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
|
self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
|
||||||
(Filth::Clean, H256::from(SecTrieDB::new(db, &self.storage_root).get(key.bytes()).map_or(U256::zero(), |v| -> U256 {decode(v)})))
|
let db = SecTrieDB::new(db, &self.storage_root)
|
||||||
|
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
|
||||||
|
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
|
||||||
|
using it will not fail.");
|
||||||
|
|
||||||
|
(Filth::Clean, H256::from(db.get(key.bytes()).map_or(U256::zero(), |v| -> U256 {decode(v)})))
|
||||||
}).1.clone()
|
}).1.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +209,10 @@ impl Account {
|
|||||||
|
|
||||||
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
|
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
|
||||||
pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
|
pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
|
||||||
let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root);
|
let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root)
|
||||||
|
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
|
||||||
|
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
|
||||||
|
using it will not fail.");
|
||||||
for (k, &mut (ref mut f, ref mut v)) in self.storage_overlay.borrow_mut().iter_mut() {
|
for (k, &mut (ref mut f, ref mut v)) in self.storage_overlay.borrow_mut().iter_mut() {
|
||||||
if f == &Filth::Dirty {
|
if f == &Filth::Dirty {
|
||||||
// cast key and value to trait type,
|
// cast key and value to trait type,
|
||||||
|
@ -278,7 +278,7 @@ mod tests {
|
|||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
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, false, db, &genesis_header, last_hashes, addr.clone(), 3141562.into(), vec![]);
|
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, addr.clone(), 3141562.into(), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
let b = b.close_and_lock();
|
||||||
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
|
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
|
||||||
|
|
||||||
|
@ -228,9 +228,20 @@ pub struct SealedBlock {
|
|||||||
impl<'x> OpenBlock<'x> {
|
impl<'x> OpenBlock<'x> {
|
||||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||||
/// Create a new `OpenBlock` ready for transaction pushing.
|
/// Create a new `OpenBlock` ready for transaction pushing.
|
||||||
pub fn new(engine: &'x Engine, vm_factory: &'x EvmFactory, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self {
|
pub fn new(
|
||||||
|
engine: &'x Engine,
|
||||||
|
vm_factory: &'x EvmFactory,
|
||||||
|
tracing: bool,
|
||||||
|
db: Box<JournalDB>,
|
||||||
|
parent: &Header,
|
||||||
|
last_hashes: LastHashes,
|
||||||
|
author: Address,
|
||||||
|
gas_floor_target: U256,
|
||||||
|
extra_data: Bytes
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
|
||||||
let mut r = OpenBlock {
|
let mut r = OpenBlock {
|
||||||
block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()), tracing),
|
block: ExecutedBlock::new(state, tracing),
|
||||||
engine: engine,
|
engine: engine,
|
||||||
vm_factory: vm_factory,
|
vm_factory: vm_factory,
|
||||||
last_hashes: last_hashes,
|
last_hashes: last_hashes,
|
||||||
@ -245,7 +256,7 @@ impl<'x> OpenBlock<'x> {
|
|||||||
|
|
||||||
engine.populate_from_parent(&mut r.block.base.header, parent, gas_floor_target);
|
engine.populate_from_parent(&mut r.block.base.header, parent, gas_floor_target);
|
||||||
engine.on_new_block(&mut r.block);
|
engine.on_new_block(&mut r.block);
|
||||||
r
|
Ok(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alter the author for the block.
|
/// Alter the author for the block.
|
||||||
@ -464,12 +475,12 @@ impl IsBlock for SealedBlock {
|
|||||||
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
|
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
|
||||||
{
|
{
|
||||||
if ::log::max_log_level() >= ::log::LogLevel::Trace {
|
if ::log::max_log_level() >= ::log::LogLevel::Trace {
|
||||||
let s = State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce());
|
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce()));
|
||||||
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
|
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut b = OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone());
|
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone()));
|
||||||
b.set_difficulty(*header.difficulty());
|
b.set_difficulty(*header.difficulty());
|
||||||
b.set_gas_limit(*header.gas_limit());
|
b.set_gas_limit(*header.gas_limit());
|
||||||
b.set_timestamp(header.timestamp());
|
b.set_timestamp(header.timestamp());
|
||||||
@ -514,7 +525,7 @@ mod tests {
|
|||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
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, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
|
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
let b = b.close_and_lock();
|
||||||
let _ = b.seal(engine.deref(), vec![]);
|
let _ = b.seal(engine.deref(), vec![]);
|
||||||
}
|
}
|
||||||
@ -530,7 +541,8 @@ mod tests {
|
|||||||
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());
|
||||||
let vm_factory = Default::default();
|
let vm_factory = Default::default();
|
||||||
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).close_and_lock().seal(engine.deref(), vec![]).unwrap();
|
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap()
|
||||||
|
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
|
||||||
let orig_bytes = b.rlp_bytes();
|
let orig_bytes = b.rlp_bytes();
|
||||||
let orig_db = b.drain();
|
let orig_db = b.drain();
|
||||||
|
|
||||||
@ -557,7 +569,7 @@ mod tests {
|
|||||||
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());
|
||||||
let vm_factory = Default::default();
|
let vm_factory = Default::default();
|
||||||
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]);
|
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap();
|
||||||
let mut uncle1_header = Header::new();
|
let mut uncle1_header = Header::new();
|
||||||
uncle1_header.extra_data = b"uncle1".to_vec();
|
uncle1_header.extra_data = b"uncle1".to_vec();
|
||||||
let mut uncle2_header = Header::new();
|
let mut uncle2_header = Header::new();
|
||||||
|
@ -386,18 +386,14 @@ impl<V> Client<V> where V: Verifier {
|
|||||||
|
|
||||||
let root = HeaderView::new(&header).state_root();
|
let root = HeaderView::new(&header).state_root();
|
||||||
|
|
||||||
// TODO [rob]: refactor State::from_existing so we avoid doing redundant lookups.
|
State::from_existing(db, root, self.engine.account_start_nonce()).ok()
|
||||||
if !db.contains(&root) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(State::from_existing(db, root, self.engine.account_start_nonce()))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a copy of the best block's state.
|
/// Get a copy of the best block's state.
|
||||||
pub fn state(&self) -> State {
|
pub fn state(&self) -> State {
|
||||||
State::from_existing(self.state_db.lock().unwrap().boxed_clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce())
|
State::from_existing(self.state_db.lock().unwrap().boxed_clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce())
|
||||||
|
.expect("State root of best block header always valid.")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get info on the cache.
|
/// Get info on the cache.
|
||||||
@ -481,7 +477,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
|
|||||||
}
|
}
|
||||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||||
let mut ret = Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, options);
|
let mut ret = Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, options);
|
||||||
|
|
||||||
// TODO gav move this into Executive.
|
// TODO gav move this into Executive.
|
||||||
if analytics.state_diffing {
|
if analytics.state_diffing {
|
||||||
if let Ok(ref mut x) = ret {
|
if let Ok(ref mut x) = ret {
|
||||||
@ -776,7 +772,8 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
|
|||||||
author,
|
author,
|
||||||
gas_floor_target,
|
gas_floor_target,
|
||||||
extra_data,
|
extra_data,
|
||||||
);
|
).expect("OpenBlock::new only fails if parent state root invalid. State root of best block's header is never invalid. \
|
||||||
|
Therefore creating an OpenBlock with the best block's header will not fail.");
|
||||||
|
|
||||||
// Add uncles
|
// Add uncles
|
||||||
self.chain
|
self.chain
|
||||||
|
@ -224,6 +224,8 @@ pub enum Error {
|
|||||||
PowHashInvalid,
|
PowHashInvalid,
|
||||||
/// The value of the nonce or mishash is invalid.
|
/// The value of the nonce or mishash is invalid.
|
||||||
PowInvalid,
|
PowInvalid,
|
||||||
|
/// Error concerning TrieDBs
|
||||||
|
TrieError(TrieError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@ -239,6 +241,7 @@ impl fmt::Display for Error {
|
|||||||
f.write_fmt(format_args!("Unknown engine name ({})", name)),
|
f.write_fmt(format_args!("Unknown engine name ({})", name)),
|
||||||
Error::PowHashInvalid => f.write_str("Invalid or out of date PoW hash."),
|
Error::PowHashInvalid => f.write_str("Invalid or out of date PoW hash."),
|
||||||
Error::PowInvalid => f.write_str("Invalid nonce or mishash"),
|
Error::PowInvalid => f.write_str("Invalid nonce or mishash"),
|
||||||
|
Error::TrieError(ref err) => f.write_fmt(format_args!("{}", err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,6 +303,12 @@ impl From<IoError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<TrieError> for Error {
|
||||||
|
fn from(err: TrieError) -> Error {
|
||||||
|
Error::TrieError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted.
|
// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted.
|
||||||
/*#![feature(concat_idents)]
|
/*#![feature(concat_idents)]
|
||||||
macro_rules! assimilate {
|
macro_rules! assimilate {
|
||||||
|
@ -308,7 +308,7 @@ mod tests {
|
|||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
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, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
|
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
|
||||||
let b = b.close();
|
let b = b.close();
|
||||||
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
|
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
|
||||||
}
|
}
|
||||||
@ -323,7 +323,7 @@ mod tests {
|
|||||||
spec.ensure_db_good(db.as_hashdb_mut());
|
spec.ensure_db_good(db.as_hashdb_mut());
|
||||||
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, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
|
let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
|
||||||
let mut uncle = Header::new();
|
let mut uncle = Header::new();
|
||||||
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
|
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
|
||||||
uncle.author = uncle_author.clone();
|
uncle.author = uncle_author.clone();
|
||||||
|
@ -62,7 +62,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());
|
||||||
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce());
|
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce()).unwrap();
|
||||||
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64));
|
assert_eq!(s.balance(&address_from_hex("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));
|
||||||
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000003")), U256::from(1u64));
|
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000003")), U256::from(1u64));
|
||||||
|
@ -44,6 +44,9 @@ pub struct State {
|
|||||||
account_start_nonce: U256,
|
account_start_nonce: U256,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
|
||||||
|
Therefore creating a SecTrieDB with this state's root will not fail.";
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
/// Creates new state with empty state root
|
/// Creates new state with empty state root
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -64,18 +67,17 @@ 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) -> State {
|
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256) -> Result<State, TrieError> {
|
||||||
{
|
if !db.as_hashdb().contains(&root) {
|
||||||
// trie should panic! if root does not exist
|
Err(TrieError::InvalidStateRoot)
|
||||||
let _ = SecTrieDB::new(db.as_hashdb(), &root);
|
} else {
|
||||||
}
|
Ok(State {
|
||||||
|
db: db,
|
||||||
State {
|
root: root,
|
||||||
db: db,
|
cache: RefCell::new(HashMap::new()),
|
||||||
root: root,
|
snapshots: RefCell::new(Vec::new()),
|
||||||
cache: RefCell::new(HashMap::new()),
|
account_start_nonce: account_start_nonce,
|
||||||
snapshots: RefCell::new(Vec::new()),
|
})
|
||||||
account_start_nonce: account_start_nonce,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +156,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 {
|
||||||
self.cache.borrow().get(&a).unwrap_or(&None).is_some() || SecTrieDB::new(self.db.as_hashdb(), &self.root).contains(&a)
|
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||||
|
self.cache.borrow().get(&a).unwrap_or(&None).is_some() || db.contains(&a)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the balance of account `a`.
|
/// Get the balance of account `a`.
|
||||||
@ -245,7 +248,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut trie = SecTrieDBMut::from_existing(db, root);
|
let mut trie = SecTrieDBMut::from_existing(db, root).unwrap();
|
||||||
for (address, ref a) in accounts.iter() {
|
for (address, ref a) in accounts.iter() {
|
||||||
match **a {
|
match **a {
|
||||||
Some(ref account) => trie.insert(address, &account.rlp()),
|
Some(ref account) => trie.insert(address, &account.rlp()),
|
||||||
@ -308,7 +311,8 @@ impl State {
|
|||||||
fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option<Account> {
|
fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option<Account> {
|
||||||
let have_key = self.cache.borrow().contains_key(a);
|
let have_key = self.cache.borrow().contains_key(a);
|
||||||
if !have_key {
|
if !have_key {
|
||||||
self.insert_cache(a, SecTrieDB::new(self.db.as_hashdb(), &self.root).get(&a).map(Account::from_rlp))
|
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||||
|
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
|
||||||
}
|
}
|
||||||
if require_code {
|
if 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() {
|
||||||
@ -328,7 +332,8 @@ impl State {
|
|||||||
fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account {
|
fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account {
|
||||||
let have_key = self.cache.borrow().contains_key(a);
|
let have_key = self.cache.borrow().contains_key(a);
|
||||||
if !have_key {
|
if !have_key {
|
||||||
self.insert_cache(a, SecTrieDB::new(self.db.as_hashdb(), &self.root).get(&a).map(Account::from_rlp))
|
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
|
||||||
|
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
|
||||||
} else {
|
} else {
|
||||||
self.note_cache(a);
|
self.note_cache(a);
|
||||||
}
|
}
|
||||||
@ -1145,7 +1150,7 @@ fn code_from_database() {
|
|||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = State::from_existing(db, root, U256::from(0u8));
|
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||||
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
|
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1160,7 +1165,7 @@ fn storage_at_from_database() {
|
|||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
|
|
||||||
let s = State::from_existing(db, root, U256::from(0u8));
|
let s = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||||
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64)));
|
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1177,7 +1182,7 @@ fn get_from_database() {
|
|||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = State::from_existing(db, root, U256::from(0u8));
|
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||||
assert_eq!(state.nonce(&a), U256::from(1u64));
|
assert_eq!(state.nonce(&a), U256::from(1u64));
|
||||||
}
|
}
|
||||||
@ -1210,7 +1215,7 @@ fn remove_from_database() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (root, db) = {
|
let (root, db) = {
|
||||||
let mut state = State::from_existing(db, root, U256::from(0u8));
|
let mut state = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||||
assert_eq!(state.exists(&a), true);
|
assert_eq!(state.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);
|
||||||
@ -1220,7 +1225,7 @@ fn remove_from_database() {
|
|||||||
state.drop()
|
state.drop()
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = State::from_existing(db, root, U256::from(0u8));
|
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
|
||||||
assert_eq!(state.exists(&a), false);
|
assert_eq!(state.exists(&a), false);
|
||||||
assert_eq!(state.nonce(&a), U256::from(0u64));
|
assert_eq!(state.nonce(&a), U256::from(0u64));
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
//! Trie interface and implementation.
|
//! Trie interface and implementation.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
/// Export the trietraits module.
|
/// Export the trietraits module.
|
||||||
pub mod trietraits;
|
pub mod trietraits;
|
||||||
/// Export the standardmap module.
|
/// Export the standardmap module.
|
||||||
@ -33,9 +35,22 @@ pub mod sectriedb;
|
|||||||
/// Export the sectriedbmut module.
|
/// Export the sectriedbmut module.
|
||||||
pub mod sectriedbmut;
|
pub mod sectriedbmut;
|
||||||
|
|
||||||
pub use self::trietraits::*;
|
pub use self::trietraits::{Trie, TrieMut};
|
||||||
pub use self::standardmap::*;
|
pub use self::standardmap::{Alphabet, StandardMap, ValueMode};
|
||||||
pub use self::triedbmut::*;
|
pub use self::triedbmut::TrieDBMut;
|
||||||
pub use self::triedb::*;
|
pub use self::triedb::TrieDB;
|
||||||
pub use self::sectriedbmut::*;
|
pub use self::sectriedbmut::SecTrieDBMut;
|
||||||
pub use self::sectriedb::*;
|
pub use self::sectriedb::SecTrieDB;
|
||||||
|
|
||||||
|
/// Trie Errors
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum TrieError {
|
||||||
|
/// Attempted to create a trie with a state root not in the DB.
|
||||||
|
InvalidStateRoot,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TrieError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Trie Error: Invalid state root.")
|
||||||
|
}
|
||||||
|
}
|
@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
use hash::*;
|
use hash::*;
|
||||||
use sha3::*;
|
use sha3::*;
|
||||||
use hashdb::*;
|
use hashdb::HashDB;
|
||||||
use super::triedb::*;
|
use super::triedb::TrieDB;
|
||||||
use super::trietraits::*;
|
use super::trietraits::Trie;
|
||||||
|
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.
|
||||||
///
|
///
|
||||||
@ -29,10 +30,12 @@ pub struct SecTrieDB<'db> {
|
|||||||
|
|
||||||
impl<'db> SecTrieDB<'db> {
|
impl<'db> SecTrieDB<'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) -> Self {
|
/// Returns an error if root does not exist.
|
||||||
SecTrieDB { raw: TrieDB::new(db, root) }
|
pub fn new(db: &'db HashDB, root: &'db H256) -> Result<Self, TrieError> {
|
||||||
|
Ok(SecTrieDB { raw: try!(TrieDB::new(db, root)) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the underlying raw `TrieDB` struct.
|
/// Get a reference to the underlying raw `TrieDB` struct.
|
||||||
@ -60,8 +63,9 @@ impl<'db> Trie for SecTrieDB<'db> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn trie_to_sectrie() {
|
fn trie_to_sectrie() {
|
||||||
use memorydb::*;
|
use memorydb::MemoryDB;
|
||||||
use super::triedbmut::*;
|
use super::triedbmut::TrieDBMut;
|
||||||
|
use super::trietraits::TrieMut;
|
||||||
|
|
||||||
let mut memdb = MemoryDB::new();
|
let mut memdb = MemoryDB::new();
|
||||||
let mut root = H256::new();
|
let mut root = H256::new();
|
||||||
@ -69,6 +73,6 @@ fn trie_to_sectrie() {
|
|||||||
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]);
|
||||||
}
|
}
|
||||||
let t = SecTrieDB::new(&memdb, &root);
|
let t = SecTrieDB::new(&memdb, &root).unwrap();
|
||||||
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap(), &[0x01u8, 0x23]);
|
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap(), &[0x01u8, 0x23]);
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
use hash::*;
|
use hash::*;
|
||||||
use sha3::*;
|
use sha3::*;
|
||||||
use hashdb::*;
|
use hashdb::HashDB;
|
||||||
use super::triedbmut::*;
|
use super::triedbmut::TrieDBMut;
|
||||||
use super::trietraits::*;
|
use super::trietraits::{Trie, 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.
|
||||||
///
|
///
|
||||||
@ -35,10 +36,11 @@ impl<'db> SecTrieDBMut<'db> {
|
|||||||
SecTrieDBMut { raw: TrieDBMut::new(db, root) }
|
SecTrieDBMut { raw: TrieDBMut::new(db, root) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new trie with the backing database `db` and `root`
|
/// Create a new trie with the backing database `db` and `root`.
|
||||||
/// Panics, if `root` does not exist
|
///
|
||||||
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self {
|
/// Returns an error if root does not exist.
|
||||||
SecTrieDBMut { raw: TrieDBMut::from_existing(db, root) }
|
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Result<Self, TrieError> {
|
||||||
|
Ok(SecTrieDBMut { raw: try!(TrieDBMut::from_existing(db, root)) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the backing database.
|
/// Get the backing database.
|
||||||
@ -81,6 +83,6 @@ fn sectrie_to_trie() {
|
|||||||
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]);
|
||||||
}
|
}
|
||||||
let t = TrieDB::new(&memdb, &root);
|
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(), &[0x01u8, 0x23]);
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,9 @@ use common::*;
|
|||||||
use hashdb::*;
|
use hashdb::*;
|
||||||
use nibbleslice::*;
|
use nibbleslice::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use super::trietraits::*;
|
use super::trietraits::Trie;
|
||||||
use super::node::*;
|
use super::node::Node;
|
||||||
|
use super::TrieError;
|
||||||
|
|
||||||
/// A `Trie` implementation using a generic `HashDB` backing database.
|
/// A `Trie` implementation using a generic `HashDB` backing database.
|
||||||
///
|
///
|
||||||
@ -41,7 +42,7 @@ use super::node::*;
|
|||||||
/// 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");
|
||||||
/// let t = TrieDB::new(&memdb, &root);
|
/// let t = TrieDB::new(&memdb, &root).unwrap();
|
||||||
/// assert!(t.contains(b"foo"));
|
/// assert!(t.contains(b"foo"));
|
||||||
/// assert_eq!(t.get(b"foo").unwrap(), b"bar");
|
/// assert_eq!(t.get(b"foo").unwrap(), b"bar");
|
||||||
/// assert!(t.db_items_remaining().is_empty());
|
/// assert!(t.db_items_remaining().is_empty());
|
||||||
@ -57,16 +58,16 @@ pub struct TrieDB<'db> {
|
|||||||
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
|
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
|
||||||
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`
|
||||||
/// Panics, if `root` does not exist
|
/// Returns an error if `root` does not exist
|
||||||
pub fn new(db: &'db HashDB, root: &'db H256) -> Self {
|
pub fn new(db: &'db HashDB, root: &'db H256) -> Result<Self, TrieError> {
|
||||||
if !db.contains(root) {
|
if !db.contains(root) {
|
||||||
flushln!("TrieDB::new({}): Trie root not found!", root);
|
Err(TrieError::InvalidStateRoot)
|
||||||
panic!("Trie root not found!");
|
} else {
|
||||||
}
|
Ok(TrieDB {
|
||||||
TrieDB {
|
db: db,
|
||||||
db: db,
|
root: root,
|
||||||
root: root,
|
hash_count: 0
|
||||||
hash_count: 0
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,6 +357,7 @@ impl<'db> fmt::Debug for TrieDB<'db> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iterator() {
|
fn iterator() {
|
||||||
|
use super::trietraits::TrieMut;
|
||||||
use memorydb::*;
|
use memorydb::*;
|
||||||
use super::triedbmut::*;
|
use super::triedbmut::*;
|
||||||
|
|
||||||
@ -369,6 +371,6 @@ fn iterator() {
|
|||||||
t.insert(&x, &x);
|
t.insert(&x, &x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), TrieDB::new(&memdb, &root).iter().map(|x|x.0).collect::<Vec<_>>());
|
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), TrieDB::new(&memdb, &root).unwrap().iter().map(|x|x.0).collect::<Vec<_>>());
|
||||||
assert_eq!(d, TrieDB::new(&memdb, &root).iter().map(|x|x.1).collect::<Vec<_>>());
|
assert_eq!(d, TrieDB::new(&memdb, &root).unwrap().iter().map(|x|x.1).collect::<Vec<_>>());
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,10 @@ use common::*;
|
|||||||
use hashdb::*;
|
use hashdb::*;
|
||||||
use nibbleslice::*;
|
use nibbleslice::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use super::node::*;
|
use super::node::Node;
|
||||||
use super::journal::*;
|
use super::journal::Journal;
|
||||||
use super::trietraits::*;
|
use super::trietraits::{Trie, TrieMut};
|
||||||
|
use super::TrieError;
|
||||||
|
|
||||||
/// A `Trie` implementation using a generic `HashDB` backing database.
|
/// A `Trie` implementation using a generic `HashDB` backing database.
|
||||||
///
|
///
|
||||||
@ -84,17 +85,16 @@ impl<'db> TrieDBMut<'db> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new trie with the backing database `db` and `root`.
|
/// Create a new trie with the backing database `db` and `root`.
|
||||||
/// Panics, if `root` does not exist.
|
/// Returns an error if `root` does not exist.
|
||||||
// TODO: return Result<Self, TrieError>
|
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) -> Self {
|
|
||||||
if !db.exists(root) {
|
if !db.exists(root) {
|
||||||
flushln!("Trie root not found {}", root);
|
Err(TrieError::InvalidStateRoot)
|
||||||
panic!("Trie root not found!");
|
} else {
|
||||||
}
|
Ok(TrieDBMut {
|
||||||
TrieDBMut {
|
db: db,
|
||||||
db: db,
|
root: root,
|
||||||
root: root,
|
hash_count: 0
|
||||||
hash_count: 0
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user