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

This commit is contained in:
debris
2016-08-04 08:41:30 +02:00
66 changed files with 1281 additions and 600 deletions

View File

@@ -25,7 +25,7 @@ semver = "0.2"
bit-set = "0.4"
time = "0.1"
evmjit = { path = "../evmjit", optional = true }
clippy = { version = "0.0.79", optional = true}
clippy = { version = "0.0.80", optional = true}
ethash = { path = "../ethash" }
ethcore-util = { path = "../util" }
ethcore-devtools = { path = "../devtools" }

View File

@@ -20,6 +20,8 @@ use util::*;
use pod_account::*;
use account_db::*;
use std::cell::{Ref, RefCell};
/// Single account in the system.
#[derive(Clone)]
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 \
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()
}
@@ -185,6 +191,12 @@ impl Account {
pub fn is_dirty(&self) -> bool {
self.filth == Filth::Dirty
}
/// Mark account as clean.
pub fn set_clean(&mut self) {
self.filth = Filth::Clean
}
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code.
pub fn cache_code(&mut self, db: &AccountDB) -> bool {
// TODO: fill out self.code_cache;
@@ -243,9 +255,13 @@ impl Account {
if f == &Filth::Dirty {
// cast key and value to trait type,
// so we can call overloaded `to_bytes` method
match v.is_zero() {
true => { t.remove(k); },
false => { t.insert(k, &encode(&U256::from(v.as_slice()))); },
let res = match v.is_zero() {
true => t.remove(k),
false => t.insert(k, &encode(&U256::from(v.as_slice()))),
};
if let Err(e) = res {
warn!("Encountered potential DB corruption: {}", e);
}
*f = Filth::Clean;
}

View File

@@ -193,7 +193,7 @@ pub struct OpenBlock<'x> {
block: ExecutedBlock,
engine: &'x Engine,
vm_factory: &'x EvmFactory,
last_hashes: LastHashes,
last_hashes: Arc<LastHashes>,
}
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
@@ -204,7 +204,7 @@ pub struct OpenBlock<'x> {
pub struct ClosedBlock {
block: ExecutedBlock,
uncle_bytes: Bytes,
last_hashes: LastHashes,
last_hashes: Arc<LastHashes>,
unclosed_state: State,
}
@@ -235,7 +235,7 @@ impl<'x> OpenBlock<'x> {
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
last_hashes: Arc<LastHashes>,
author: Address,
gas_range_target: (U256, U256),
extra_data: Bytes,
@@ -316,7 +316,7 @@ impl<'x> OpenBlock<'x> {
author: self.block.base.header.author.clone(),
timestamp: self.block.base.header.timestamp,
difficulty: self.block.base.header.difficulty.clone(),
last_hashes: self.last_hashes.clone(), // TODO: should be a reference.
last_hashes: self.last_hashes.clone(),
gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
gas_limit: self.block.base.header.gas_limit.clone(),
}
@@ -498,7 +498,7 @@ pub fn enact(
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
@@ -531,7 +531,7 @@ pub fn enact_bytes(
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
@@ -548,7 +548,7 @@ pub fn enact_verified(
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
@@ -564,7 +564,7 @@ pub fn enact_and_seal(
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
last_hashes: LastHashes,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<SealedBlock, Error> {
@@ -586,8 +586,8 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
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 = b.close_and_lock();
@@ -603,17 +603,18 @@ mod tests {
let mut db_result = get_temp_journal_db();
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 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 last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default(), Default::default()).unwrap();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
@@ -631,9 +632,10 @@ mod tests {
let mut db_result = get_temp_journal_db();
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 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 last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new();
@@ -647,8 +649,8 @@ 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 e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], &Default::default(), Default::default()).unwrap();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);

View File

@@ -359,7 +359,7 @@ impl BlockChain {
let batch = DBTransaction::new(&db);
batch.put(DB_COL_HEADERS, &hash, block.header_rlp().as_raw()).unwrap();
batch.put(DB_COL_BODIES, &hash, &Self::block_to_body(&genesis)).unwrap();
batch.put(DB_COL_BODIES, &hash, &Self::block_to_body(genesis)).unwrap();
batch.write(DB_COL_EXTRA, &hash, &details);
batch.write(DB_COL_EXTRA, &header.number(), &hash);
@@ -549,15 +549,11 @@ impl BlockChain {
assert!(self.pending_best_block.read().is_none());
let block_rlp = UntrustedRlp::new(bytes);
let compressed_header = block_rlp.at(0).unwrap().compress(RlpType::Blocks);
let compressed_body = UntrustedRlp::new(&Self::block_to_body(bytes)).compress(RlpType::Blocks);
// store block in db
batch.put(DB_COL_HEADERS, &hash, &compressed_header).unwrap();
batch.put(DB_COL_BODIES, &hash, &compressed_body).unwrap();
batch.put_compressed(DB_COL_HEADERS, &hash, block.header_rlp().as_raw().to_vec()).unwrap();
batch.put_compressed(DB_COL_BODIES, &hash, Self::block_to_body(bytes)).unwrap();
let info = self.block_info(bytes);
let info = self.block_info(&header);
if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location {
info!(target: "reorg", "Reorg to {} ({} {} {})",
@@ -582,10 +578,8 @@ impl BlockChain {
}
/// Get inserted block info which is critical to prepare extras updates.
fn block_info(&self, block_bytes: &[u8]) -> BlockInfo {
let block = BlockView::new(block_bytes);
let header = block.header_view();
let hash = block.sha3();
fn block_info(&self, header: &HeaderView) -> BlockInfo {
let hash = header.sha3();
let number = header.number();
let parent_hash = header.parent_hash();
let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash));
@@ -1056,7 +1050,7 @@ mod tests {
let bc = BlockChain::new(Config::default(), &genesis, db.clone());
let batch = db.transaction();
for b in [&b1a, &b1b, &b2a, &b2b, &b3a, &b3b, &b4a, &b4b, &b5a, &b5b].iter() {
for b in &[&b1a, &b1b, &b2a, &b2b, &b3a, &b3b, &b4a, &b4b, &b5a, &b5b] {
bc.insert_block(&batch, b, vec![]);
bc.commit();
}

View File

@@ -183,7 +183,7 @@ impl Client {
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);
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);
try!(state_db.commit(&batch, 0, &spec.genesis_header().hash(), None));
try!(db.write(batch).map_err(ClientError::Database));
@@ -246,13 +246,13 @@ impl Client {
}
}
fn build_last_hashes(&self, parent_hash: H256) -> LastHashes {
fn build_last_hashes(&self, parent_hash: H256) -> Arc<LastHashes> {
{
let hashes = self.last_hashes.read();
if hashes.front().map_or(false, |h| h == &parent_hash) {
let mut res = Vec::from(hashes.clone());
res.resize(256, H256::default());
return res;
return Arc::new(res);
}
}
let mut last_hashes = LastHashes::new();
@@ -268,7 +268,7 @@ impl Client {
}
let mut cached_hashes = self.last_hashes.write();
*cached_hashes = VecDeque::from(last_hashes.clone());
last_hashes
Arc::new(last_hashes)
}
fn check_and_close_block(&self, block: &PreverifiedBlock) -> Result<LockedBlock, ()> {
@@ -413,6 +413,7 @@ impl Client {
}
}
self.db.flush().expect("DB flush failed.");
imported
}
@@ -440,7 +441,7 @@ impl Client {
// CHECK! I *think* this is fine, even if the state_root is equal to another
// already-imported block of the same number.
// TODO: Prove it with a test.
block.drain().commit(&batch, number, hash, ancient).expect("State DB commit failed.");
block.drain().commit(&batch, number, hash, ancient).expect("DB commit failed.");
let route = self.chain.insert_block(&batch, block_data, receipts);
self.tracedb.import(&batch, TraceImportRequest {
@@ -451,7 +452,7 @@ impl Client {
retracted: route.retracted.len()
});
// Final commit to the DB
self.db.write(batch).expect("State DB write failed.");
self.db.write_buffered(batch).expect("DB write failed.");
self.chain.commit();
self.update_last_hashes(&parent, hash);
@@ -712,7 +713,7 @@ impl BlockChainClient for Client {
x.state_diff = Some(state.diff_from(orig));
}
}
ret.map_err(|ee| ReplayError::Execution(ee))
ret.map_err(ReplayError::Execution)
}
fn keep_alive(&self) {
@@ -975,7 +976,7 @@ impl BlockChainClient for Client {
}
fn last_hashes(&self) -> LastHashes {
self.build_last_hashes(self.chain.best_block_hash())
(*self.build_last_hashes(self.chain.best_block_hash())).clone()
}
fn queue_transactions(&self, transactions: Vec<Bytes>) {
@@ -1059,6 +1060,7 @@ impl MiningBlockChainClient for Client {
precise_time_ns() - start,
);
});
self.db.flush().expect("DB flush failed.");
Ok(h)
}
}

View File

@@ -2,11 +2,15 @@ use trace::Error as TraceError;
use util::UtilError;
use std::fmt::{Display, Formatter, Error as FmtError};
use util::trie::TrieError;
/// Client configuration errors.
#[derive(Debug)]
pub enum Error {
/// TraceDB configuration error.
Trace(TraceError),
/// TrieDB-related error.
Trie(TrieError),
/// Database error
Database(String),
/// 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 {
fn from(err: UtilError) -> Self {
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 {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Error::Trace(ref err) => write!(f, "{}", err),
Error::Trie(ref err) => write!(f, "{}", err),
Error::Util(ref err) => write!(f, "{}", err),
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 mut db_result = get_temp_journal_db();
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 mut open_block = OpenBlock::new(
@@ -272,7 +272,7 @@ impl MiningBlockChainClient for TestBlockChainClient {
false,
db,
&genesis_header,
last_hashes,
Arc::new(last_hashes),
author,
gas_range_target,
extra_data

View File

@@ -202,7 +202,7 @@ mod tests {
author: 0.into(),
timestamp: 0,
difficulty: 0.into(),
last_hashes: vec![],
last_hashes: Arc::new(vec![]),
gas_used: 0.into(),
gas_limit: 0.into(),
});
@@ -250,8 +250,8 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
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 = b.close_and_lock();

View File

@@ -84,8 +84,8 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
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 = b.close_and_lock();

View File

@@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::cmp;
use std::sync::Arc;
use util::{U256, Address, H256, Hashable};
use header::BlockNumber;
use ethjson;
@@ -37,7 +38,7 @@ pub struct EnvInfo {
/// The block gas limit.
pub gas_limit: U256,
/// The last 256 block hashes.
pub last_hashes: LastHashes,
pub last_hashes: Arc<LastHashes>,
/// The gas used.
pub gas_used: U256,
}
@@ -50,7 +51,7 @@ impl Default for EnvInfo {
timestamp: 0,
difficulty: 0.into(),
gas_limit: 0.into(),
last_hashes: vec![],
last_hashes: Arc::new(vec![]),
gas_used: 0.into(),
}
}
@@ -65,8 +66,8 @@ impl From<ethjson::vm::Env> for EnvInfo {
difficulty: e.difficulty.into(),
gas_limit: e.gas_limit.into(),
timestamp: e.timestamp.into(),
last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(),
gas_used: Default::default(),
last_hashes: Arc::new((1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect()),
gas_used: U256::default(),
}
}
}

View File

@@ -258,7 +258,10 @@ pub type ImportResult = Result<H256, Error>;
impl From<ClientError> for 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!(ImportError);
binary_fixed_size!(TransactionError);

View File

@@ -163,7 +163,9 @@ impl Engine for Ethash {
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.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> {
@@ -352,8 +354,8 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
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 = b.close();
@@ -367,8 +369,8 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
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 uncle = Header::new();
@@ -396,7 +398,7 @@ mod tests {
author: 0.into(),
timestamp: 0,
difficulty: 0.into(),
last_hashes: vec![],
last_hashes: Arc::new(vec![]),
gas_used: 0.into(),
gas_limit: 0.into(),
});
@@ -408,7 +410,7 @@ mod tests {
author: 0.into(),
timestamp: 0,
difficulty: 0.into(),
last_hashes: vec![],
last_hashes: Arc::new(vec![]),
gas_used: 0.into(),
gas_limit: 0.into(),
});

View File

@@ -67,7 +67,7 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_journal_db();
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();
assert_eq!(s.balance(&"0000000000000000000000000000000000000001".parse().unwrap()), U256::from(1u64));
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".parse().unwrap()), U256::from(1u64));

View File

@@ -324,7 +324,7 @@ mod tests {
author: 0.into(),
timestamp: 0,
difficulty: 0.into(),
last_hashes: vec![],
last_hashes: Arc::new(vec![]),
gas_used: 0.into(),
gas_limit: 0.into(),
}
@@ -391,7 +391,9 @@ mod tests {
{
let env_info = &mut setup.env_info;
env_info.number = test_env_number;
env_info.last_hashes.push(test_hash.clone());
let mut last_hashes = (*env_info.last_hashes).clone();
last_hashes.push(test_hash.clone());
env_info.last_hashes = Arc::new(last_hashes);
}
let state = setup.state.reference_mut();
let mut tracer = NoopTracer;

View File

@@ -20,6 +20,8 @@ use util::*;
use basic_types::*;
use time::get_time;
use std::cell::RefCell;
/// Type for Block number
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 = state_result.reference_mut();
state.populate_from(pre);
state.commit();
state.commit()
.expect(&format!("State test {} failed due to internal error.", name));
let vm_factory = Default::default();
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/>.
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> {
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() {
let key: Vec<u8> = key.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() {
@@ -46,7 +49,7 @@ fn test_trie(json: &[u8], trie: TrieSpec) -> Vec<String> {
}
mod generic {
use util::TrieSpec;
use util::trie::TrieSpec;
fn do_json_test(json: &[u8]) -> Vec<String> {
super::test_trie(json, TrieSpec::Generic)
@@ -57,7 +60,7 @@ mod generic {
}
mod secure {
use util::TrieSpec;
use util::trie::TrieSpec;
fn do_json_test(json: &[u8]) -> Vec<String> {
super::test_trie(json, TrieSpec::Secure)

View File

@@ -472,7 +472,7 @@ impl MinerService for Miner {
// TODO: merge this code with client.rs's fn call somwhow.
let header = block.header();
let last_hashes = chain.last_hashes();
let last_hashes = Arc::new(chain.last_hashes());
let env_info = EnvInfo {
number: header.number(),
author: *header.author(),

View File

@@ -71,7 +71,9 @@ impl PodAccount {
let mut r = H256::new();
let mut t = SecTrieDBMut::new(db, &mut r);
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);
}
}
}
}
@@ -96,7 +98,7 @@ impl From<ethjson::spec::Account> for PodAccount {
PodAccount {
balance: a.balance.map_or_else(U256::zero, Into::into),
nonce: a.nonce.map_or_else(U256::zero, Into::into),
code: a.code.map(Into::into).or(Some(Vec::new())),
code: a.code.map(Into::into).or_else(|| Some(Vec::new())),
storage: BTreeMap::new()
}
}

View File

@@ -19,7 +19,7 @@
use account_db::{AccountDB, AccountDBMut};
use error::Error;
use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY, TrieDB};
use util::rlp::{DecoderError, Rlp, RlpStream, Stream, UntrustedRlp, View};
use util::rlp::{Rlp, RlpStream, Stream, UntrustedRlp, View};
// An alternate account structure from ::account::Account.
#[derive(PartialEq, Clone, Debug)]
@@ -99,7 +99,7 @@ impl Account {
}
// 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};
let nonce = try!(rlp.val_at(0));
@@ -120,7 +120,7 @@ impl Account {
let k: Bytes = try!(pair_rlp.val_at(0));
let v: Bytes = try!(pair_rlp.val_at(1));
storage_trie.insert(&k, &v);
try!(storage_trie.insert(&k, &v));
}
}
Ok(Account {
@@ -157,7 +157,7 @@ mod tests {
{
let mut trie = SecTrieDBMut::new(&mut db, &mut root);
for (k, v) in map.make() {
trie.insert(&k, &v);
trie.insert(&k, &v).unwrap();
}
}
root

View File

@@ -387,11 +387,11 @@ impl StateRebuilder {
};
for (hash, thin_rlp) in pairs {
account_trie.insert(&hash, &thin_rlp);
try!(account_trie.insert(&hash, &thin_rlp));
}
}
let batch = DBTransaction::new(&self.db.backing());
let batch = DBTransaction::new(self.db.backing());
try!(self.db.commit(&batch, 0, &H256::zero(), None));
try!(self.db.backing().write(batch).map_err(|e| Error::Util(e.into())));
Ok(())

View File

@@ -25,6 +25,8 @@ use super::seal::Generic as GenericSeal;
use ethereum;
use ethjson;
use std::cell::RefCell;
/// Parameters common to all engines.
#[derive(Debug, PartialEq, Clone)]
pub struct CommonParams {
@@ -226,21 +228,21 @@ impl Spec {
}
/// 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()) {
let mut root = H256::new();
{
let mut t = SecTrieDBMut::new(db, &mut root);
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() {
account.insert_additional(&mut AccountDBMut::new(db, address));
}
assert!(db.contains(&self.state_root()));
true
} else { false }
Ok(true)
} else { Ok(false) }
}
/// Loads spec from json file.

View File

@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::cell::{RefCell, RefMut};
use common::*;
use engines::Engine;
use executive::{Executive, TransactOptions};
@@ -71,7 +73,7 @@ impl State {
/// 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> {
if !db.as_hashdb().contains(&root) {
return Err(TrieError::InvalidStateRoot);
return Err(TrieError::InvalidStateRoot(root));
}
let state = State {
@@ -161,8 +163,7 @@ impl State {
/// Determine whether an account exists.
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);
self.cache.borrow().get(a).unwrap_or(&None).is_some() || db.contains(a)
self.ensure_cached(a, false, |a| a.is_some())
}
/// Get the balance of account `a`.
@@ -238,8 +239,7 @@ impl State {
// TODO uncomment once to_pod() works correctly.
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
self.commit();
self.clear();
try!(self.commit());
let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs);
// trace!("Transaction receipt: {:?}", receipt);
Ok(ApplyOutcome{receipt: receipt, trace: e.trace})
@@ -248,7 +248,13 @@ impl State {
/// 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.
#[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.
// 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() {
@@ -264,20 +270,25 @@ impl State {
{
let mut trie = trie_factory.from_existing(db, root).unwrap();
for (address, ref a) in accounts.iter() {
for (address, ref mut a) in accounts.iter_mut() {
match **a {
Some(ref account) if account.is_dirty() => trie.insert(address, &account.rlp()),
None => trie.remove(address),
Some(ref mut account) if account.is_dirty() => {
account.set_clean();
try!(trie.insert(address, &account.rlp()))
},
None => try!(trie.remove(address)),
_ => (),
}
}
}
Ok(())
}
/// 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());
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
@@ -336,7 +347,11 @@ impl State {
let have_key = self.cache.borrow().contains_key(a);
if !have_key {
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 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.
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), |_|{})
}
/// 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`.
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 {
fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&'a self, a: &Address, require_code: bool, default: F, not_default: G)
-> RefMut<'a, Account>
{
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);
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 {
self.note_cache(a);
}
let preexists = self.cache.borrow().get(a).unwrap().is_none();
if preexists {
self.cache.borrow_mut().insert(a.clone(), Some(default()));
} else {
not_default(self.cache.borrow_mut().get_mut(a).unwrap().as_mut().unwrap());
match self.cache.borrow_mut().get_mut(a).unwrap() {
&mut Some(ref mut acc) => not_default(acc),
slot @ &mut None => *slot = Some(default()),
}
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 {
account.cache_code(&AccountDB::new(self.db.as_hashdb(), a));
}
account
}).unwrap()) }
})
}
}
@@ -466,12 +488,12 @@ fn should_work_when_cloned() {
let mut state = get_temp_state_in(temp.as_path());
assert_eq!(state.exists(&a), false);
state.inc_nonce(&a);
state.commit();
state.commit().unwrap();
state.clone()
};
state.inc_nonce(&a);
state.commit();
state.commit().unwrap();
}
#[test]
@@ -1281,7 +1303,7 @@ fn code_from_database() {
state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{});
state.init_code(&a, vec![1, 2, 3]);
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()));
state.drop()
};
@@ -1297,7 +1319,7 @@ fn storage_at_from_database() {
let (root, db) = {
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.commit();
state.commit().unwrap();
state.drop()
};
@@ -1313,7 +1335,7 @@ fn get_from_database() {
let mut state = get_temp_state_in(temp.as_path());
state.inc_nonce(&a);
state.add_balance(&a, &U256::from(69u64));
state.commit();
state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(69u64));
state.drop()
};
@@ -1344,7 +1366,7 @@ fn remove_from_database() {
let (root, db) = {
let mut state = get_temp_state_in(temp.as_path());
state.inc_nonce(&a);
state.commit();
state.commit().unwrap();
assert_eq!(state.exists(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64));
state.drop()
@@ -1355,7 +1377,7 @@ fn remove_from_database() {
assert_eq!(state.exists(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64));
state.kill_account(&a);
state.commit();
state.commit().unwrap();
assert_eq!(state.exists(&a), false);
assert_eq!(state.nonce(&a), U256::from(0u64));
state.drop()
@@ -1374,16 +1396,16 @@ fn alter_balance() {
let b = address_from_u64(1u64);
state.add_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));
state.sub_balance(&a, &U256::from(42u64));
assert_eq!(state.balance(&a), U256::from(27u64));
state.commit();
state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(27u64));
state.transfer_balance(&a, &b, &U256::from(18u64));
assert_eq!(state.balance(&a), U256::from(9u64));
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(&b), U256::from(18u64));
}
@@ -1397,11 +1419,11 @@ fn alter_nonce() {
assert_eq!(state.nonce(&a), U256::from(1u64));
state.inc_nonce(&a);
assert_eq!(state.nonce(&a), U256::from(2u64));
state.commit();
state.commit().unwrap();
assert_eq!(state.nonce(&a), U256::from(2u64));
state.inc_nonce(&a);
assert_eq!(state.nonce(&a), U256::from(3u64));
state.commit();
state.commit().unwrap();
assert_eq!(state.nonce(&a), U256::from(3u64));
}
@@ -1412,7 +1434,7 @@ fn balance_nonce() {
let a = Address::zero();
assert_eq!(state.balance(&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.nonce(&a), U256::from(0u64));
}
@@ -1423,7 +1445,7 @@ fn ensure_cached() {
let mut state = state_result.reference_mut();
let a = Address::zero();
state.require(&a, false);
state.commit();
state.commit().unwrap();
assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785");
}
@@ -1463,7 +1485,7 @@ fn snapshot_nested() {
fn create_empty() {
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
state.commit();
state.commit().unwrap();
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 = 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 genesis_header = test_spec.genesis_header();
@@ -160,7 +160,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
false,
db,
&last_header,
last_hashes.clone(),
Arc::new(last_hashes.clone()),
author.clone(),
(3141562.into(), 31415620.into()),
vec![]