Merge branch 'master' of github.com:ethcore/parity into simplified_block_opening

This commit is contained in:
debris
2016-06-09 11:09:12 -07:00
53 changed files with 1220 additions and 397 deletions

View File

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

View File

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

View File

@@ -38,23 +38,7 @@ pub struct Block {
impl Block {
/// Returns true if the given bytes form a valid encoding of a block in RLP.
// TODO: implement Decoder for this and have this use that.
pub fn is_good(b: &[u8]) -> bool {
/*
let urlp = UntrustedRlp::new(&b);
if !urlp.is_list() || urlp.item_count() != 3 || urlp.size() != b.len() { return false; }
if urlp.val_at::<Header>(0).is_err() { return false; }
if !urlp.at(1).unwrap().is_list() { return false; }
if urlp.at(1).unwrap().iter().find(|i| i.as_val::<Transaction>().is_err()).is_some() {
return false;
}
if !urlp.at(2).unwrap().is_list() { return false; }
if urlp.at(2).unwrap().iter().find(|i| i.as_val::<Header>().is_err()).is_some() {
return false;
}
true*/
UntrustedRlp::new(b).as_val::<Block>().is_ok()
}
}
@@ -228,9 +212,20 @@ pub struct SealedBlock {
impl<'x> OpenBlock<'x> {
#[cfg_attr(feature="dev", allow(too_many_arguments))]
/// Create a new `OpenBlock` ready for transaction pushing.
pub fn new(engine: &'x Engine, vm_factory: &'x EvmFactory, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self {
pub fn new(
engine: &'x Engine,
vm_factory: &'x EvmFactory,
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
author: Address,
gas_floor_target: U256,
extra_data: Bytes
) -> Result<Self, Error> {
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
let mut r = OpenBlock {
block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()), tracing),
block: ExecutedBlock::new(state, tracing),
engine: engine,
vm_factory: vm_factory,
last_hashes: last_hashes,
@@ -245,7 +240,7 @@ impl<'x> OpenBlock<'x> {
engine.populate_from_parent(&mut r.block.base.header, parent, gas_floor_target);
engine.on_new_block(&mut r.block);
r
Ok(r)
}
/// Alter the author for the block.
@@ -464,12 +459,12 @@ impl IsBlock for SealedBlock {
pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box<JournalDB>, parent: &Header, last_hashes: LastHashes, vm_factory: &EvmFactory) -> Result<LockedBlock, Error> {
{
if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce());
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce()));
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
}
}
let mut b = OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone());
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, header.author().clone(), 3141562.into(), header.extra_data().clone()));
b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp());
@@ -514,7 +509,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]);
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, Address::zero(), 3141562.into(), vec![]).unwrap();
let b = b.close_and_lock();
let _ = b.seal(engine.deref(), vec![]);
}
@@ -530,7 +525,8 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).close_and_lock().seal(engine.deref(), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap()
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
@@ -557,7 +553,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]);
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], Address::zero(), 3141562.into(), vec![]).unwrap();
let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new();

View File

@@ -386,18 +386,14 @@ impl<V> Client<V> where V: Verifier {
let root = HeaderView::new(&header).state_root();
// TODO [rob]: refactor State::from_existing so we avoid doing redundant lookups.
if !db.contains(&root) {
return None;
}
Some(State::from_existing(db, root, self.engine.account_start_nonce()))
State::from_existing(db, root, self.engine.account_start_nonce()).ok()
})
}
/// Get a copy of the best block's state.
pub fn state(&self) -> State {
State::from_existing(self.state_db.lock().unwrap().boxed_clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce())
.expect("State root of best block header always valid.")
}
/// Get info on the cache.
@@ -479,7 +475,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
// give the sender a sufficient balance
state.add_balance(&sender, &(needed_balance - balance));
}
let options = TransactOptions { tracing: false, 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);
// TODO gav move this into Executive.
@@ -774,7 +770,8 @@ impl<V> MiningBlockChainClient for Client<V> where V: Verifier {
author,
gas_floor_target,
extra_data,
);
).expect("OpenBlock::new only fails if parent state root invalid. State root of best block's header is never invalid. \
Therefore creating an OpenBlock with the best block's header will not fail.");
// Add uncles
self.chain

View File

@@ -51,6 +51,8 @@ use error::Error as EthError;
/// Options concerning what analytics we run on the call.
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)]
pub struct CallAnalytics {
/// Make a transaction trace.
pub transaction_tracing: bool,
/// Make a VM trace.
pub vm_tracing: bool,
/// Make a diff.

View File

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

View File

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

View File

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

View File

@@ -20,7 +20,7 @@ use std::sync::atomic::AtomicBool;
use util::*;
use util::keys::store::{AccountProvider};
use views::{BlockView, HeaderView};
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockChainClient, BlockID, CallAnalytics};
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
use block::{ClosedBlock, IsBlock};
use error::*;
use transaction::SignedTransaction;
@@ -279,7 +279,7 @@ impl MinerService for Miner {
// give the sender a sufficient balance
state.add_balance(&sender, &(needed_balance - balance));
}
let options = TransactOptions { tracing: false, 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(), chain.vm_factory()).transact(t, options);
// TODO gav move this into Executive.

View File

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