Merge remote-tracking branch 'origin/master' into rpc-middleware

This commit is contained in:
Gav Wood
2016-12-01 19:43:31 -08:00
222 changed files with 3180 additions and 1695 deletions

View File

@@ -29,7 +29,7 @@ byteorder = "0.5"
transient-hashmap = "0.1"
linked-hash-map = "0.3.0"
evmjit = { path = "../evmjit", optional = true }
clippy = { version = "0.0.96", optional = true}
clippy = { version = "0.0.103", optional = true}
ethash = { path = "../ethash" }
ethcore-util = { path = "../util" }
ethcore-io = { path = "../util/io" }

View File

@@ -121,10 +121,6 @@ impl<'db> HashDB for AccountDB<'db>{
fn remove(&mut self, _key: &H256) {
unimplemented!()
}
fn get_aux(&self, hash: &[u8]) -> Option<DBValue> {
self.db.get_aux(hash)
}
}
/// DB backend wrapper for Account trie
@@ -197,18 +193,6 @@ impl<'db> HashDB for AccountDBMut<'db>{
let key = combine_key(&self.address_hash, key);
self.db.remove(&key)
}
fn insert_aux(&mut self, hash: Vec<u8>, value: Vec<u8>) {
self.db.insert_aux(hash, value);
}
fn get_aux(&self, hash: &[u8]) -> Option<DBValue> {
self.db.get_aux(hash)
}
fn remove_aux(&mut self, hash: &[u8]) {
self.db.remove_aux(hash);
}
}
struct Wrapping<'db>(&'db HashDB);

View File

@@ -594,9 +594,9 @@ mod tests {
use factory::Factories;
use state_db::StateDB;
use views::BlockView;
use util::Address;
use util::{Address, TrieFactory};
use util::hash::FixedHash;
use util::trie::TrieSpec;
use std::sync::Arc;
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
@@ -637,7 +637,7 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
@@ -653,7 +653,7 @@ mod tests {
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine, vec![]).unwrap();
@@ -662,7 +662,7 @@ mod tests {
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
@@ -681,7 +681,7 @@ mod tests {
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle1_header = Header::new();
@@ -697,7 +697,7 @@ mod tests {
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap();
let bytes = e.rlp_bytes();

View File

@@ -22,7 +22,7 @@ use std::time::{Instant};
use time::precise_time_ns;
// util
use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock};
use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock, Hashable};
use util::{journaldb, TrieFactory, Trie};
use util::trie::TrieSpec;
use util::{U256, H256, Address, H2048, Uint, FixedHash};
@@ -172,9 +172,10 @@ impl Client {
false => TrieSpec::Secure,
};
let trie_factory = TrieFactory::new(trie_spec);
let journal_db = journaldb::new(db.clone(), config.pruning, ::db::COL_STATE);
let mut state_db = StateDB::new(journal_db, config.state_cache_size);
if state_db.journal_db().is_empty() && try!(spec.ensure_db_good(&mut state_db)) {
if state_db.journal_db().is_empty() && try!(spec.ensure_db_good(&mut state_db, &trie_factory)) {
let mut batch = DBTransaction::new(&db);
try!(state_db.journal_under(&mut batch, 0, &spec.genesis_header().hash()));
try!(db.write(batch).map_err(ClientError::Database));
@@ -216,7 +217,7 @@ impl Client {
let factories = Factories {
vm: EvmFactory::new(config.vm_type.clone(), config.jump_table_size),
trie: TrieFactory::new(trie_spec),
trie: trie_factory,
accountdb: Default::default(),
};
@@ -869,8 +870,8 @@ impl BlockChainClient for Client {
}
fn keep_alive(&self) {
let should_wake = match &*self.mode.lock() {
&Mode::Dark(..) | &Mode::Passive(..) => true,
let should_wake = match *self.mode.lock() {
Mode::Dark(..) | Mode::Passive(..) => true,
_ => false,
};
if should_wake {
@@ -952,6 +953,10 @@ impl BlockChainClient for Client {
self.state_at(id).map(|s| s.nonce(address))
}
fn storage_root(&self, address: &Address, id: BlockID) -> Option<H256> {
self.state_at(id).and_then(|s| s.storage_root(address))
}
fn block_hash(&self, id: BlockID) -> Option<H256> {
let chain = self.chain.read();
Self::block_hash(&chain, id)
@@ -969,7 +974,7 @@ impl BlockChainClient for Client {
self.state_at(id).map(|s| s.storage_at(address, position))
}
fn list_accounts(&self, id: BlockID) -> Option<Vec<Address>> {
fn list_accounts(&self, id: BlockID, after: Option<&Address>, count: u64) -> Option<Vec<Address>> {
if !self.factories.trie.is_fat() {
trace!(target: "fatdb", "list_accounts: Not a fat DB");
return None;
@@ -989,18 +994,68 @@ impl BlockChainClient for Client {
}
};
let iter = match trie.iter() {
let mut iter = match trie.iter() {
Ok(iter) => iter,
_ => return None,
};
if let Some(after) = after {
if let Err(e) = iter.seek(after) {
trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e);
}
}
let accounts = iter.filter_map(|item| {
item.ok().map(|(addr, _)| Address::from_slice(&addr))
}).collect();
}).take(count as usize).collect();
Some(accounts)
}
fn list_storage(&self, id: BlockID, account: &Address, after: Option<&H256>, count: u64) -> Option<Vec<H256>> {
if !self.factories.trie.is_fat() {
trace!(target: "fatdb", "list_stroage: Not a fat DB");
return None;
}
let state = match self.state_at(id) {
Some(state) => state,
_ => return None,
};
let root = match state.storage_root(account) {
Some(root) => root,
_ => return None,
};
let (_, db) = state.drop();
let account_db = self.factories.accountdb.readonly(db.as_hashdb(), account.sha3());
let trie = match self.factories.trie.readonly(account_db.as_hashdb(), &root) {
Ok(trie) => trie,
_ => {
trace!(target: "fatdb", "list_storage: Couldn't open the DB");
return None;
}
};
let mut iter = match trie.iter() {
Ok(iter) => iter,
_ => return None,
};
if let Some(after) = after {
if let Err(e) = iter.seek(after) {
trace!(target: "fatdb", "list_accounts: Couldn't seek the DB: {:?}", e);
}
}
let keys = iter.filter_map(|item| {
item.ok().map(|(key, _)| H256::from_slice(&key))
}).take(count as usize).collect();
Some(keys)
}
fn transaction(&self, id: TransactionID) -> Option<LocalizedTransaction> {
self.transaction_address(id).and_then(|address| self.chain.read().transaction(&address))
}

View File

@@ -333,7 +333,7 @@ impl MiningBlockChainClient for TestBlockChainClient {
let genesis_header = self.spec.genesis_header();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
self.spec.ensure_db_good(&mut db).unwrap();
self.spec.ensure_db_good(&mut db, &TrieFactory::default()).unwrap();
let last_hashes = vec![genesis_header.hash()];
let mut open_block = OpenBlock::new(
@@ -385,6 +385,10 @@ impl BlockChainClient for TestBlockChainClient {
}
}
fn storage_root(&self, _address: &Address, _id: BlockID) -> Option<H256> {
None
}
fn latest_nonce(&self, address: &Address) -> U256 {
self.nonce(address, BlockID::Latest).unwrap()
}
@@ -416,10 +420,13 @@ impl BlockChainClient for TestBlockChainClient {
}
}
fn list_accounts(&self, _id: BlockID) -> Option<Vec<Address>> {
fn list_accounts(&self, _id: BlockID, _after: Option<&Address>, _count: u64) -> Option<Vec<Address>> {
None
}
fn list_storage(&self, _id: BlockID, _account: &Address, _after: Option<&H256>, _count: u64) -> Option<Vec<H256>> {
None
}
fn transaction(&self, _id: TransactionID) -> Option<LocalizedTransaction> {
None // Simple default.
}

View File

@@ -68,6 +68,10 @@ pub trait BlockChainClient : Sync + Send {
/// May not fail on BlockID::Latest.
fn nonce(&self, address: &Address, id: BlockID) -> Option<U256>;
/// Attempt to get address storage root at given block.
/// May not fail on BlockID::Latest.
fn storage_root(&self, address: &Address, id: BlockID) -> Option<H256>;
/// Get address nonce at the latest block's state.
fn latest_nonce(&self, address: &Address) -> U256 {
self.nonce(address, BlockID::Latest)
@@ -114,7 +118,12 @@ pub trait BlockChainClient : Sync + Send {
}
/// Get a list of all accounts in the block `id`, if fat DB is in operation, otherwise `None`.
fn list_accounts(&self, id: BlockID) -> Option<Vec<Address>>;
/// If `after` is set the list starts with the following item.
fn list_accounts(&self, id: BlockID, after: Option<&Address>, count: u64) -> Option<Vec<Address>>;
/// Get a list of all storage keys in the block `id`, if fat DB is in operation, otherwise `None`.
/// If `after` is set the list starts with the following item.
fn list_storage(&self, id: BlockID, account: &Address, after: Option<&H256>, count: u64) -> Option<Vec<H256>>;
/// Get transaction with given hash.
fn transaction(&self, id: TransactionID) -> Option<LocalizedTransaction>;

View File

@@ -124,7 +124,7 @@ impl AuthorityRound {
}
fn step_proposer(&self, step: usize) -> &Address {
let ref p = self.our_params;
let p = &self.our_params;
p.authorities.get(step % p.authority_n).expect("There are authority_n authorities; taking number modulo authority_n gives number in authority_n range; qed")
}
@@ -211,7 +211,7 @@ impl Engine for AuthorityRound {
fn on_close_block(&self, _block: &mut ExecutedBlock) {}
fn is_sealer(&self, author: &Address) -> Option<bool> {
let ref p = self.our_params;
let p = &self.our_params;
Some(p.authorities.contains(author))
}
@@ -279,7 +279,7 @@ impl Engine for AuthorityRound {
let step = try!(header_step(header));
// Check if parent is from a previous step.
if step == try!(header_step(parent)) {
if step == try!(header_step(parent)) {
trace!(target: "poa", "Multiple blocks proposed for step {}.", step);
try!(Err(BlockError::DoubleVote(header.author().clone())));
}
@@ -315,6 +315,7 @@ impl Engine for AuthorityRound {
#[cfg(test)]
mod tests {
use util::*;
use util::trie::TrieSpec;
use env_info::EnvInfo;
use header::Header;
use error::{Error, BlockError};
@@ -384,9 +385,9 @@ mod tests {
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let mut db1 = get_temp_state_db().take();
spec.ensure_db_good(&mut db1).unwrap();
spec.ensure_db_good(&mut db1, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let mut db2 = get_temp_state_db().take();
spec.ensure_db_good(&mut db2).unwrap();
spec.ensure_db_good(&mut db2, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b1 = b1.close_and_lock();

View File

@@ -184,6 +184,7 @@ impl Engine for BasicAuthority {
#[cfg(test)]
mod tests {
use util::*;
use util::trie::TrieSpec;
use block::*;
use env_info::EnvInfo;
use error::{BlockError, Error};
@@ -256,7 +257,7 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();

View File

@@ -68,6 +68,7 @@ impl Engine for InstantSeal {
#[cfg(test)]
mod tests {
use util::*;
use util::trie::TrieSpec;
use tests::helpers::*;
use account_provider::AccountProvider;
use spec::Spec;
@@ -84,7 +85,7 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();

View File

@@ -422,6 +422,7 @@ impl Header {
#[cfg(test)]
mod tests {
use util::*;
use util::trie::TrieSpec;
use block::*;
use tests::helpers::*;
use env_info::EnvInfo;
@@ -438,7 +439,7 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close();
@@ -452,7 +453,7 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle = Header::new();

View File

@@ -72,6 +72,7 @@ pub fn new_morden() -> Spec { load(include_bytes!("../../res/ethereum/morden.jso
#[cfg(test)]
mod tests {
use util::*;
use util::trie::TrieSpec;
use state::*;
use super::*;
use tests::helpers::*;
@@ -84,7 +85,7 @@ mod tests {
let genesis_header = spec.genesis_header();
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
spec.ensure_db_good(&mut db).unwrap();
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), Default::default()).unwrap();
assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()), 1u64.into());
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()), 1u64.into());

View File

@@ -197,19 +197,17 @@ impl<Gas: CostType> Gasometer<Gas> {
let address = u256_to_address(stack.peek(1));
let is_value_transfer = !stack.peek(2).is_zero();
if instruction == instructions::CALL {
if (
!schedule.no_empty && !ext.exists(&address)
) || (
schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)
) {
gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into()));
}
};
if instruction == instructions::CALL && (
(!schedule.no_empty && !ext.exists(&address))
||
(schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address))
) {
gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into()));
}
if is_value_transfer {
gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into()));
};
}
let requested = *stack.peek(0);
@@ -347,7 +345,7 @@ fn test_mem_gas_cost() {
let result = gasometer.mem_gas_cost(&schedule, current_mem_size, &mem_size);
// then
if let Ok(_) = result {
if result.is_ok() {
assert!(false, "Should fail with OutOfGas");
}
}

View File

@@ -95,7 +95,7 @@ impl Ext for FakeExt {
}
fn exists_and_not_null(&self, address: &Address) -> bool {
self.balances.get(address).map_or(false, |b| !b.is_zero())
self.balances.get(address).map_or(false, |b| !b.is_zero())
}
fn origin_balance(&self) -> U256 {
@@ -103,7 +103,7 @@ impl Ext for FakeExt {
}
fn balance(&self, address: &Address) -> U256 {
*self.balances.get(address).unwrap()
self.balances[address]
}
fn blockhash(&self, number: &U256) -> H256 {

View File

@@ -445,7 +445,7 @@ impl<'a> Executive<'a> {
trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, sender);
// Below: NoEmpty is safe since the sender must already be non-null to have sent this transaction
self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty);
self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty);
trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author);
self.state.add_balance(&self.info.author, &fees_value, substate.to_cleanup_mode(&schedule));
@@ -514,9 +514,11 @@ impl<'a> Executive<'a> {
#[cfg(test)]
#[allow(dead_code)]
mod tests {
use std::sync::Arc;
use ethkey::{Generator, Random};
use super::*;
use util::*;
use util::{H256, U256, U512, Address, Uint, FixedHash, FromHex, FromStr};
use util::bytes::BytesRef;
use action_params::{ActionParams, ActionValue};
use env_info::EnvInfo;
use evm::{Factory, VMType};

View File

@@ -151,7 +151,7 @@ impl GasPriceCalibrator {
if Instant::now() >= self.next_calibration {
let usd_per_tx = self.options.usd_per_tx;
trace!(target: "miner", "Getting price info");
if let Ok(_) = PriceInfo::get(move |price: PriceInfo| {
let price_info = PriceInfo::get(move |price: PriceInfo| {
trace!(target: "miner", "Price info arrived: {:?}", price);
let usd_per_eth = price.ethusd;
let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
@@ -159,7 +159,9 @@ impl GasPriceCalibrator {
let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx;
info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas)));
set_price(U256::from(wei_per_gas as u64));
}) {
});
if price_info.is_ok() {
self.next_calibration = Instant::now() + self.options.recalibration_period;
} else {
warn!(target: "miner", "Unable to update Ether price.");
@@ -1139,15 +1141,16 @@ impl MinerService for Miner {
#[cfg(test)]
mod tests {
use std::sync::Arc;
use std::time::Duration;
use super::super::{MinerService, PrioritizationStrategy};
use super::*;
use util::*;
use block::IsBlock;
use util::{U256, Uint, FromHex};
use ethkey::{Generator, Random};
use client::{BlockChainClient, TestBlockChainClient, EachBlockWith, TransactionImportResult};
use header::BlockNumber;
use types::transaction::{Transaction, SignedTransaction, Action};
use block::*;
use spec::Spec;
use tests::helpers::{generate_dummy_client};

View File

@@ -990,7 +990,7 @@ impl TransactionQueue {
let mut update_last_nonce_to = None;
{
let by_nonce = self.future.by_address.row_mut(&address);
if let None = by_nonce {
if by_nonce.is_none() {
return;
}
let mut by_nonce = by_nonce.expect("None is tested in early-exit condition above; qed");
@@ -1212,12 +1212,12 @@ mod test {
use util::table::*;
use util::*;
use ethkey::{Random, Generator};
use transaction::*;
use error::{Error, TransactionError};
use super::*;
use super::{TransactionSet, TransactionOrder, VerifiedTransaction};
use miner::local_transactions::LocalTransactionsList;
use client::TransactionImportResult;
use transaction::{SignedTransaction, Transaction, Action};
fn unwrap_tx_err(err: Result<TransactionImportResult, Error>) -> TransactionError {
match err.unwrap_err() {

View File

@@ -64,13 +64,13 @@ impl PodAccount {
}
/// Place additional data into given hash DB.
pub fn insert_additional(&self, db: &mut AccountDBMut) {
pub fn insert_additional(&self, db: &mut AccountDBMut, factory: &TrieFactory) {
match self.code {
Some(ref c) if !c.is_empty() => { db.insert(c); }
_ => {}
}
let mut r = H256::new();
let mut t = SecTrieDBMut::new(db, &mut r);
let mut t = factory.create(db, &mut r);
for (k, v) in &self.storage {
if let Err(e) = t.insert(k, &rlp::encode(&U256::from(&**v))) {
warn!("Encountered potential DB corruption: {}", e);

View File

@@ -552,11 +552,11 @@ const POW_VERIFY_RATE: f32 = 0.02;
pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &Engine, chain: &BlockChain, body: Option<&[u8]>, always: bool) -> Result<(), ::error::Error> {
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
match chain.block_header(header.parent_hash()) {
Some(parent) => engine.verify_block_family(&header, &parent, body),
None => engine.verify_block_seal(&header),
Some(parent) => engine.verify_block_family(header, &parent, body),
None => engine.verify_block_seal(header),
}
} else {
engine.verify_block_basic(&header, body)
engine.verify_block_basic(header, body)
}
}

View File

@@ -244,13 +244,13 @@ 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 StateDB) -> Result<bool, Box<TrieError>> {
pub fn ensure_db_good(&self, db: &mut StateDB, factory: &TrieFactory) -> Result<bool, Box<TrieError>> {
if !db.as_hashdb().contains(&self.state_root()) {
trace!(target: "spec", "ensure_db_good: Fresh database? Cannot find state root {}", self.state_root());
let mut root = H256::new();
{
let mut t = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root);
let mut t = factory.create(db.as_hashdb_mut(), &mut root);
for (address, account) in self.genesis_state.get().iter() {
try!(t.insert(&**address, &account.rlp()));
}
@@ -258,7 +258,7 @@ impl Spec {
trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root);
for (address, account) in self.genesis_state.get().iter() {
db.note_non_null_account(address);
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address));
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address), factory);
}
assert!(db.as_hashdb().contains(&self.state_root()));
Ok(true)

View File

@@ -314,11 +314,10 @@ impl Account {
self.code_hash == SHA3_EMPTY
}
#[cfg(test)]
/// return the storage root associated with this account or None if it has been altered via the overlay.
/// Return the storage root associated with this account or None if it has been altered via the overlay.
pub fn storage_root(&self) -> Option<&H256> { if self.storage_is_clean() {Some(&self.storage_root)} else {None} }
/// return the storage overlay.
/// Return the storage overlay.
pub fn storage_changes(&self) -> &HashMap<H256, H256> { &self.storage_changes }
/// Increment the nonce of the account by one.
@@ -445,11 +444,10 @@ impl fmt::Debug for Account {
#[cfg(test)]
mod tests {
use rlp::{UntrustedRlp, RlpType, View, Compressible};
use util::*;
use super::*;
use account_db::*;
use rlp::*;
#[test]
fn account_compress() {

View File

@@ -369,6 +369,12 @@ impl State {
|a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce()))
}
/// Get the storage root of account `a`.
pub fn storage_root(&self, a: &Address) -> Option<H256> {
self.ensure_cached(a, RequireCache::None, true,
|a| a.as_ref().and_then(|account| account.storage_root().cloned()))
}
/// Mutate storage of account `address` so that it is `value` for `key`.
pub fn storage_at(&self, address: &Address, key: &H256) -> H256 {
// Storage key search and update works like this:
@@ -445,6 +451,7 @@ impl State {
}
/// Add `incr` to the balance of account `a`.
#[cfg_attr(feature="dev", allow(single_match))]
pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) {
trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a));
let is_value_transfer = !incr.is_zero();

View File

@@ -57,6 +57,7 @@ impl Substate {
}
/// Get the cleanup mode object from this.
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
pub fn to_cleanup_mode(&mut self, schedule: &Schedule) -> CleanupMode {
match (schedule.no_empty, schedule.kill_empty) {
(false, _) => CleanupMode::ForceCreate,

View File

@@ -397,6 +397,7 @@ impl StateDB {
}
/// Get cached code based on hash.
#[cfg_attr(feature="dev", allow(map_clone))]
pub fn get_cached_code(&self, hash: &H256) -> Option<Arc<Vec<u8>>> {
let mut cache = self.code_cache.lock();

View File

@@ -62,7 +62,7 @@ fn should_return_registrar() {
&db_config
).unwrap();
let params = client.additional_params();
let address = params.get("registrar").unwrap();
let address = &params["registrar"];
assert_eq!(address.len(), 40);
assert!(U256::from_str(address).is_ok());
@@ -93,7 +93,7 @@ fn imports_good_block() {
&db_config
).unwrap();
let good_block = get_good_dummy_block();
if let Err(_) = client.import_block(good_block) {
if client.import_block(good_block).is_err() {
panic!("error importing block being good by definition");
}
client.flush_queue();
@@ -203,18 +203,18 @@ fn can_collect_garbage() {
#[test]
fn can_generate_gas_price_median() {
let client_result = generate_dummy_client_with_data(3, 1, &vec_into![1, 2, 3]);
let client_result = generate_dummy_client_with_data(3, 1, slice_into![1, 2, 3]);
let client = client_result.reference();
assert_eq!(Some(U256::from(2)), client.gas_price_median(3));
let client_result = generate_dummy_client_with_data(4, 1, &vec_into![1, 4, 3, 2]);
let client_result = generate_dummy_client_with_data(4, 1, slice_into![1, 4, 3, 2]);
let client = client_result.reference();
assert_eq!(Some(U256::from(3)), client.gas_price_median(4));
}
#[test]
fn can_generate_gas_price_histogram() {
let client_result = generate_dummy_client_with_data(20, 1, &vec_into![6354,8593,6065,4842,7845,7002,689,4958,4250,6098,5804,4320,643,8895,2296,8589,7145,2000,2512,1408]);
let client_result = generate_dummy_client_with_data(20, 1, slice_into![6354,8593,6065,4842,7845,7002,689,4958,4250,6098,5804,4320,643,8895,2296,8589,7145,2000,2512,1408]);
let client = client_result.reference();
let hist = client.gas_price_histogram(20, 5).unwrap();
@@ -224,7 +224,7 @@ fn can_generate_gas_price_histogram() {
#[test]
fn empty_gas_price_histogram() {
let client_result = generate_dummy_client_with_data(20, 0, &vec_into![]);
let client_result = generate_dummy_client_with_data(20, 0, slice_into![]);
let client = client_result.reference();
assert!(client.gas_price_histogram(20, 5).is_none());

View File

@@ -18,6 +18,7 @@ use ethkey::KeyPair;
use io::*;
use client::{BlockChainClient, Client, ClientConfig};
use util::*;
use util::trie::TrieSpec;
use spec::*;
use state_db::StateDB;
use block::{OpenBlock, Drain};
@@ -157,7 +158,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
let mut db_result = get_temp_state_db();
let mut db = db_result.take();
test_spec.ensure_db_good(&mut db).unwrap();
test_spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
let genesis_header = test_spec.genesis_header();
let mut rolling_timestamp = 40;
@@ -262,7 +263,7 @@ pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> GuardedTempResult<Arc<
).unwrap();
for block in &blocks {
if let Err(_) = client.import_block(block.clone()) {
if client.import_block(block.clone()).is_err() {
panic!("panic importing block which is well-formed");
}
}

View File

@@ -19,16 +19,16 @@
pub use std::time::Duration;
use client::Mode as ClientMode;
/// IPC-capable shadow-type for client::config::Mode
/// IPC-capable shadow-type for `client::config::Mode`
#[derive(Clone, Binary, Debug)]
pub enum Mode {
/// Same as ClientMode::Off.
/// Same as `ClientMode::Off`.
Off,
/// Same as ClientMode::Dark; values in seconds.
/// Same as `ClientMode::Dark`; values in seconds.
Dark(u64),
/// Same as ClientMode::Passive; values in seconds.
/// Same as `ClientMode::Passive`; values in seconds.
Passive(u64, u64),
/// Same as ClientMode::Active.
/// Same as `ClientMode::Active`.
Active,
}
@@ -52,4 +52,4 @@ impl From<Mode> for ClientMode {
Mode::Active => ClientMode::Active,
}
}
}
}

View File

@@ -73,7 +73,7 @@ pub struct Transaction {
impl Transaction {
/// Append object with a without signature into RLP stream
pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option<u8>) {
s.begin_list(if let None = network_id { 6 } else { 9 });
s.begin_list(if network_id.is_none() { 6 } else { 9 });
s.append(&self.nonce);
s.append(&self.gas_price);
s.append(&self.gas);
@@ -210,7 +210,7 @@ pub struct SignedTransaction {
/// Plain Transaction.
unsigned: Transaction,
/// The V field of the signature; the LS bit described which half of the curve our point falls
/// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks.
/// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks.
v: u8,
/// The R field of the signature; helps describe the point on the curve.
r: U256,
@@ -304,7 +304,7 @@ impl SignedTransaction {
/// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid.
pub fn standard_v(&self) -> u8 { match self.v { v if v == 27 || v == 28 || v > 36 => (v - 1) % 2, _ => 4 } }
/// The network ID, or `None` if this is a global transaction.
/// The network ID, or `None` if this is a global transaction.
pub fn network_id(&self) -> Option<u8> {
match self.v {
v if v > 36 => Some((v - 35) / 2),
@@ -461,7 +461,7 @@ fn should_agree_with_vitalik() {
let signed: SignedTransaction = decode(&FromHex::from_hex(tx_data).unwrap());
signed.check_low_s().unwrap();
assert_eq!(signed.sender().unwrap(), address.into());
flushln!("networkid: {:?}", signed.network_id());
flushln!("networkid: {:?}", signed.network_id());
};
test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce")
@@ -474,4 +474,4 @@ fn should_agree_with_vitalik() {
test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332")
test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029")
test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f")
}
}

View File

@@ -29,6 +29,7 @@ use header::{BlockNumber, Header};
use rlp::{UntrustedRlp, View};
use transaction::SignedTransaction;
use views::BlockView;
use time::get_time;
/// Preprocessed block data gathered in `verify_block_unordered` call
pub struct PreverifiedBlock {
@@ -209,6 +210,10 @@ pub fn verify_header_params(header: &Header, engine: &Engine) -> Result<(), Erro
if header.number() != 0 && header.extra_data().len() > maximum_extra_data_size {
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds { min: None, max: Some(maximum_extra_data_size), found: header.extra_data().len() })));
}
let max_time = get_time().sec as u64 + 30;
if header.timestamp() > max_time {
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: header.timestamp() })))
}
Ok(())
}
@@ -258,6 +263,7 @@ mod tests {
use tests::helpers::*;
use types::log_entry::{LogEntry, LocalizedLogEntry};
use rlp::View;
use time::get_time;
fn check_ok(result: Result<(), Error>) {
result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e));
@@ -271,6 +277,14 @@ mod tests {
}
}
fn check_fail_timestamp(result: Result<(), Error>) {
match result {
Err(Error::Block(BlockError::InvalidTimestamp(_))) => (),
Err(other) => panic!("Block verification failed.\nExpected: InvalidTimestamp\nGot: {:?}", other),
Ok(_) => panic!("Block verification failed.\nExpected: InvalidTimestamp\nGot: Ok"),
}
}
struct TestBlockChain {
blocks: HashMap<H256, Bytes>,
numbers: HashMap<BlockNumber, H256>,
@@ -515,6 +529,14 @@ mod tests {
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
InvalidTimestamp(OutOfBounds { max: None, min: Some(parent.timestamp() + 1), found: header.timestamp() }));
header = good.clone();
header.set_timestamp(2450000000);
check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
header = good.clone();
header.set_timestamp(get_time().sec as u64 + 40);
check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
header = good.clone();
header.set_number(9);
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),