EIP-210 BLOCKHASH changes (#5505)

* EIP-210

* comment
This commit is contained in:
Arkadiy Paronyan 2017-05-30 11:52:33 +02:00 committed by Gav Wood
parent de4c9507e6
commit e6a31e7543
25 changed files with 382 additions and 191 deletions

View File

@ -11,7 +11,7 @@
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x0", "homesteadTransition": "0x0",
"eip150Transition": "0x0", "eip150Transition": "0x0",
"eip155Transition": "0x7fffffffffffffff", "eip155Transition": "0x0",
"eip160Transition": "0x0", "eip160Transition": "0x0",
"eip161abcTransition": "0x0", "eip161abcTransition": "0x0",
"eip161dTransition": "0x0", "eip161dTransition": "0x0",
@ -24,9 +24,10 @@
"maximumExtraDataSize": "0x20", "maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388", "minGasLimit": "0x1388",
"networkID" : "0x1", "networkID" : "0x1",
"eip98Transition": "0x7fffffffffffffff", "eip98Transition": "0x0",
"eip86Transition": "0x0", "eip86Transition": "0x0",
"eip140Transition": "0x0" "eip140Transition": "0x0",
"eip210Transition": "0x0"
}, },
"genesis": { "genesis": {
"seal": { "seal": {

View File

@ -265,7 +265,7 @@ impl<'x> OpenBlock<'x> {
let mut r = OpenBlock { let mut r = OpenBlock {
block: ExecutedBlock::new(state, tracing), block: ExecutedBlock::new(state, tracing),
engine: engine, engine: engine,
last_hashes: last_hashes, last_hashes: last_hashes.clone(),
}; };
r.block.header.set_parent_hash(parent.hash()); r.block.header.set_parent_hash(parent.hash());
@ -278,7 +278,7 @@ impl<'x> OpenBlock<'x> {
let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit); let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit);
let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target); let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target);
engine.populate_from_parent(&mut r.block.header, parent, gas_floor_target, gas_ceil_target); engine.populate_from_parent(&mut r.block.header, parent, gas_floor_target, gas_ceil_target);
engine.on_new_block(&mut r.block); engine.on_new_block(&mut r.block, last_hashes)?;
Ok(r) Ok(r)
} }
@ -373,7 +373,9 @@ impl<'x> OpenBlock<'x> {
let unclosed_state = s.block.state.clone(); let unclosed_state = s.block.state.clone();
s.engine.on_close_block(&mut s.block); if let Err(e) = s.engine.on_close_block(&mut s.block) {
warn!("Encountered error on closing the block: {}", e);
}
if let Err(e) = s.block.state.commit() { if let Err(e) = s.block.state.commit() {
warn!("Encountered error on state commit: {}", e); warn!("Encountered error on state commit: {}", e);
} }
@ -397,7 +399,9 @@ impl<'x> OpenBlock<'x> {
pub fn close_and_lock(self) -> LockedBlock { pub fn close_and_lock(self) -> LockedBlock {
let mut s = self; let mut s = self;
s.engine.on_close_block(&mut s.block); if let Err(e) = s.engine.on_close_block(&mut s.block) {
warn!("Encountered error on closing the block: {}", e);
}
if let Err(e) = s.block.state.commit() { if let Err(e) = s.block.state.commit() {
warn!("Encountered error on state commit: {}", e); warn!("Encountered error on state commit: {}", e);

View File

@ -1032,8 +1032,7 @@ impl BlockChainClient for Client {
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None }; let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
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, &self.factories.vm) let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact_virtual(t, options)?;
.transact_virtual(t, options)?;
// TODO gav move this into Executive. // TODO gav move this into Executive.
if let Some(original) = original_state { if let Some(original) = original_state {
@ -1063,7 +1062,7 @@ impl BlockChainClient for Client {
let tx = tx.fake_sign(sender); let tx = tx.fake_sign(sender);
let mut state = original_state.clone(); let mut state = original_state.clone();
Ok(Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm) Ok(Executive::new(&mut state, &env_info, &*self.engine)
.transact_virtual(&tx, options.clone()) .transact_virtual(&tx, options.clone())
.map(|r| r.exception.is_none()) .map(|r| r.exception.is_none())
.unwrap_or(false)) .unwrap_or(false))
@ -1125,13 +1124,13 @@ impl BlockChainClient for Client {
let rest = txs.split_off(address.index); let rest = txs.split_off(address.index);
for t in txs { for t in txs {
let t = SignedTransaction::new(t).expect(PROOF); let t = SignedTransaction::new(t).expect(PROOF);
let x = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&t, Default::default())?; let x = Executive::new(&mut state, &env_info, &*self.engine).transact(&t, Default::default())?;
env_info.gas_used = env_info.gas_used + x.gas_used; env_info.gas_used = env_info.gas_used + x.gas_used;
} }
let first = rest.into_iter().next().expect("We split off < `address.index`; Length is checked earlier; qed"); let first = rest.into_iter().next().expect("We split off < `address.index`; Length is checked earlier; qed");
let t = SignedTransaction::new(first).expect(PROOF); let t = SignedTransaction::new(first).expect(PROOF);
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None }; let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
let mut ret = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&t, options)?; let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact(&t, options)?;
if let Some(original) = original_state { if let Some(original) = original_state {
ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?) ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?)
} }
@ -1753,7 +1752,7 @@ impl ProvingBlockChainClient for Client {
let mut state = state.replace_backend(backend); let mut state = state.replace_backend(backend);
let options = TransactOptions { tracing: false, vm_tracing: false, check_nonce: false }; let options = TransactOptions { tracing: false, vm_tracing: false, check_nonce: false };
let res = Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(&transaction, options); let res = Executive::new(&mut state, &env_info, &*self.engine).transact(&transaction, options);
match res { match res {
Err(ExecutionError::Internal(_)) => None, Err(ExecutionError::Internal(_)) => None,

View File

@ -103,7 +103,7 @@ impl EvmTestClient {
let mut substate = state::Substate::new(); let mut substate = state::Substate::new();
let mut tracer = trace::NoopTracer; let mut tracer = trace::NoopTracer;
let mut output = vec![]; let mut output = vec![];
let mut executive = executive::Executive::new(&mut state, &info, &*self.spec.engine, &self.factories.vm); let mut executive = executive::Executive::new(&mut state, &info, &*self.spec.engine);
let gas_left = executive.call( let gas_left = executive.call(
params, params,
&mut substate, &mut substate,

View File

@ -413,7 +413,7 @@ impl BlockChainClient for TestBlockChainClient {
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> { fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> {
match id { match id {
BlockId::Latest => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params.account_start_nonce)), BlockId::Latest => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params().account_start_nonce)),
_ => None, _ => None,
} }
} }
@ -747,7 +747,7 @@ impl BlockChainClient for TestBlockChainClient {
value: U256::default(), value: U256::default(),
data: data, data: data,
}; };
let network_id = Some(self.spec.params.network_id); let network_id = Some(self.spec.params().network_id);
let sig = self.spec.engine.sign(transaction.hash(network_id)).unwrap(); let sig = self.spec.engine.sign(transaction.hash(network_id)).unwrap();
let signed = SignedTransaction::new(transaction.with_signature(sig, network_id)).unwrap(); let signed = SignedTransaction::new(transaction.with_signature(sig, network_id)).unwrap();
self.miner.import_own_transaction(self, signed.into()) self.miner.import_own_transaction(self, signed.into())

View File

@ -340,16 +340,17 @@ impl Engine for AuthorityRound {
} }
/// Apply the block reward on finalisation of the block. /// Apply the block reward on finalisation of the block.
fn on_close_block(&self, block: &mut ExecutedBlock) { fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
let fields = block.fields_mut(); let fields = block.fields_mut();
// Bestow block reward // Bestow block reward
let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty) let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty)
.map_err(::error::Error::from) .map_err(::error::Error::from)
.and_then(|_| fields.state.commit()); .and_then(|_| fields.state.commit());
// Commit state so that we can actually figure out the state root. // Commit state so that we can actually figure out the state root.
if let Err(e) = res { if let Err(ref e) = res {
warn!("Encountered error on closing block: {}", e); warn!("Encountered error on closing block: {}", e);
} }
res
} }
/// Check the number of seal fields. /// Check the number of seal fields.

View File

@ -40,7 +40,7 @@ use account_provider::AccountProvider;
use block::ExecutedBlock; use block::ExecutedBlock;
use builtin::Builtin; use builtin::Builtin;
use client::Client; use client::Client;
use env_info::EnvInfo; use env_info::{EnvInfo, LastHashes};
use error::Error; use error::Error;
use evm::Schedule; use evm::Schedule;
use header::{Header, BlockNumber}; use header::{Header, BlockNumber};
@ -53,6 +53,10 @@ use evm::CreateContractAddress;
use ethkey::Signature; use ethkey::Signature;
use util::*; use util::*;
/// Default EIP-210 contrat code.
/// As defined in https://github.com/ethereum/EIPs/pull/210/commits/9df24a3714af42e3bf350265bdc75b486c909d7f#diff-e02a92c2fb96c1a1bfb05e4c6e2ef5daR49
pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561007a57600143036020526000356101006020510755600061010060205107141561005057600035610100610100602051050761010001555b6000620100006020510714156100755760003561010062010000602051050761020001555b610161565b436000351215801561008c5780610095565b623567e0600035125b9050156100a757600060605260206060f35b610100600035430312156100ca57610100600035075460805260206080f3610160565b62010000600035430312156100e857600061010060003507146100eb565b60005b1561010d576101006101006000350507610100015460a052602060a0f361015f565b63010000006000354303121561012d576000620100006000350714610130565b60005b1561015357610100620100006000350507610200015460c052602060c0f361015e565b600060e052602060e0f35b5b5b5b5b";
/// Voting errors. /// Voting errors.
#[derive(Debug)] #[derive(Debug)]
pub enum EngineError { pub enum EngineError {
@ -159,9 +163,15 @@ pub trait Engine : Sync + Send {
fn account_start_nonce(&self) -> U256 { self.params().account_start_nonce } fn account_start_nonce(&self) -> U256 { self.params().account_start_nonce }
/// Block transformation functions, before the transactions. /// Block transformation functions, before the transactions.
fn on_new_block(&self, _block: &mut ExecutedBlock) {} fn on_new_block(&self, block: &mut ExecutedBlock, last_hashes: Arc<LastHashes>) -> Result<(), Error> {
let parent_hash = block.fields().header.parent_hash().clone();
common::push_last_hash(block, last_hashes, self, &parent_hash)
}
/// Block transformation functions, after the transactions. /// Block transformation functions, after the transactions.
fn on_close_block(&self, _block: &mut ExecutedBlock) {} fn on_close_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> {
Ok(())
}
/// None means that it requires external input (e.g. PoW) to seal a block. /// None means that it requires external input (e.g. PoW) to seal a block.
/// Some(true) means the engine is currently prime for seal generation (i.e. node is the current validator). /// Some(true) means the engine is currently prime for seal generation (i.e. node is the current validator).
@ -314,3 +324,64 @@ pub trait Engine : Sync + Send {
if number >= self.params().eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce } if number >= self.params().eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }
} }
} }
/// Common engine utilities
pub mod common {
use block::ExecutedBlock;
use env_info::{EnvInfo, LastHashes};
use error::Error;
use transaction::SYSTEM_ADDRESS;
use executive::Executive;
use types::executed::CallType;
use action_params::{ActionParams, ActionValue};
use trace::{NoopTracer, NoopVMTracer};
use state::Substate;
use util::*;
use super::Engine;
/// Push last known block hash to the state.
pub fn push_last_hash<E: Engine + ?Sized>(block: &mut ExecutedBlock, last_hashes: Arc<LastHashes>, engine: &E, hash: &H256) -> Result<(), Error> {
if block.fields().header.number() == engine.params().eip210_transition {
let state = block.fields_mut().state;
state.init_code(&engine.params().eip210_contract_address, engine.params().eip210_contract_code.clone())?;
}
if block.fields().header.number() >= engine.params().eip210_transition {
let env_info = {
let header = block.fields().header;
EnvInfo {
number: header.number(),
author: header.author().clone(),
timestamp: header.timestamp(),
difficulty: header.difficulty().clone(),
last_hashes: last_hashes,
gas_used: U256::zero(),
gas_limit: engine.params().eip210_contract_gas,
}
};
let mut state = block.fields_mut().state;
let contract_address = engine.params().eip210_contract_address;
let params = ActionParams {
code_address: contract_address.clone(),
address: contract_address.clone(),
sender: SYSTEM_ADDRESS.clone(),
origin: SYSTEM_ADDRESS.clone(),
gas: engine.params().eip210_contract_gas,
gas_price: 0.into(),
value: ActionValue::Transfer(0.into()),
code: state.code(&contract_address)?,
code_hash: state.code_hash(&contract_address)?,
data: Some(hash.to_vec()),
call_type: CallType::Call,
};
let mut ex = Executive::new(&mut state, &env_info, engine);
let mut substate = Substate::new();
let mut output = [];
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
warn!("Encountered error on updating last hashes: {}", e);
}
}
Ok(())
}
}

View File

@ -482,16 +482,17 @@ impl Engine for Tendermint {
} }
/// Apply the block reward on finalisation of the block. /// Apply the block reward on finalisation of the block.
fn on_close_block(&self, block: &mut ExecutedBlock) { fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error>{
let fields = block.fields_mut(); let fields = block.fields_mut();
// Bestow block reward // Bestow block reward
let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty) let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty)
.map_err(::error::Error::from) .map_err(::error::Error::from)
.and_then(|_| fields.state.commit()); .and_then(|_| fields.state.commit());
// Commit state so that we can actually figure out the state root. // Commit state so that we can actually figure out the state root.
if let Err(e) = res { if let Err(ref e) = res {
warn!("Encountered error on closing block: {}", e); warn!("Encountered error on closing block: {}", e);
} }
res
} }
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {

View File

@ -28,6 +28,7 @@ use engines::Engine;
use evm::Schedule; use evm::Schedule;
use ethjson; use ethjson;
use rlp::{self, UntrustedRlp}; use rlp::{self, UntrustedRlp};
use env_info::LastHashes;
/// Parity tries to round block.gas_limit to multiple of this constant /// Parity tries to round block.gas_limit to multiple of this constant
pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]); pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]);
@ -252,60 +253,46 @@ impl Engine for Arc<Ethash> {
// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number(), header.difficulty(), header.gas_limit()); // info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number(), header.difficulty(), header.gas_limit());
} }
fn on_new_block(&self, block: &mut ExecutedBlock) { fn on_new_block(&self, block: &mut ExecutedBlock, last_hashes: Arc<LastHashes>) -> Result<(), Error> {
let parent_hash = block.fields().header.parent_hash().clone();
try!(::engines::common::push_last_hash(block, last_hashes, self, &parent_hash));
if block.fields().header.number() == self.ethash_params.dao_hardfork_transition { if block.fields().header.number() == self.ethash_params.dao_hardfork_transition {
// TODO: enable trigger function maybe? let state = block.fields_mut().state;
// if block.fields().header.gas_limit() <= 4_000_000.into() { for child in &self.ethash_params.dao_hardfork_accounts {
let state = block.fields_mut().state; let beneficiary = &self.ethash_params.dao_hardfork_beneficiary;
for child in &self.ethash_params.dao_hardfork_accounts { try!(state.balance(child)
let beneficiary = &self.ethash_params.dao_hardfork_beneficiary; .and_then(|b| state.transfer_balance(child, beneficiary, &b, CleanupMode::NoEmpty)));
let res = state.balance(child) }
.and_then(|b| state.transfer_balance(child, beneficiary, &b, CleanupMode::NoEmpty));
if let Err(_) = res {
warn!("Unable to apply DAO hardfork due to database corruption.");
warn!("Your node is now likely out of consensus.");
}
}
// }
} }
Ok(())
} }
/// Apply the block reward on finalisation of the block. /// Apply the block reward on finalisation of the block.
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
fn on_close_block(&self, block: &mut ExecutedBlock) { fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
let reward = self.ethash_params.block_reward; let reward = self.ethash_params.block_reward;
let fields = block.fields_mut(); let fields = block.fields_mut();
// Bestow block reward // Bestow block reward
let res = fields.state.add_balance( fields.state.add_balance(
fields.header.author(), fields.header.author(),
&(reward + reward / U256::from(32) * U256::from(fields.uncles.len())), &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())),
CleanupMode::NoEmpty CleanupMode::NoEmpty
); )?;
if let Err(e) = res {
warn!("Failed to give block reward: {}", e);
}
// Bestow uncle rewards // Bestow uncle rewards
let current_number = fields.header.number(); let current_number = fields.header.number();
for u in fields.uncles.iter() { for u in fields.uncles.iter() {
let res = fields.state.add_balance( fields.state.add_balance(
u.author(), u.author(),
&(reward * U256::from(8 + u.number() - current_number) / U256::from(8)), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)),
CleanupMode::NoEmpty CleanupMode::NoEmpty
); )?;
if let Err(e) = res {
warn!("Failed to give uncle reward: {}", e);
}
} }
// Commit state so that we can actually figure out the state root. // Commit state so that we can actually figure out the state root.
if let Err(e) = fields.state.commit() { fields.state.commit()?;
warn!("Encountered error on state commit: {}", e); Ok(())
}
} }
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
@ -741,7 +728,7 @@ mod tests {
fn difficulty_frontier() { fn difficulty_frontier() {
let spec = new_homestead_test(); let spec = new_homestead_test();
let ethparams = get_default_ethash_params(); let ethparams = get_default_ethash_params();
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
let mut parent_header = Header::default(); let mut parent_header = Header::default();
parent_header.set_number(1000000); parent_header.set_number(1000000);
@ -759,7 +746,7 @@ mod tests {
fn difficulty_homestead() { fn difficulty_homestead() {
let spec = new_homestead_test(); let spec = new_homestead_test();
let ethparams = get_default_ethash_params(); let ethparams = get_default_ethash_params();
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
let mut parent_header = Header::default(); let mut parent_header = Header::default();
parent_header.set_number(1500000); parent_header.set_number(1500000);
@ -780,7 +767,7 @@ mod tests {
ecip1010_pause_transition: 3000000, ecip1010_pause_transition: 3000000,
..get_default_ethash_params() ..get_default_ethash_params()
}; };
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
let mut parent_header = Header::default(); let mut parent_header = Header::default();
parent_header.set_number(3500000); parent_header.set_number(3500000);
@ -814,7 +801,7 @@ mod tests {
ecip1010_continue_transition: 5000000, ecip1010_continue_transition: 5000000,
..get_default_ethash_params() ..get_default_ethash_params()
}; };
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
let mut parent_header = Header::default(); let mut parent_header = Header::default();
parent_header.set_number(5000102); parent_header.set_number(5000102);
@ -859,7 +846,7 @@ mod tests {
#[test] #[test]
fn gas_limit_is_multiple_of_determinant() { fn gas_limit_is_multiple_of_determinant() {
let spec = new_homestead_test(); let spec = new_homestead_test();
let ethash = Ethash::new(spec.params, get_default_ethash_params(), BTreeMap::new()); let ethash = Ethash::new(spec.params().clone(), get_default_ethash_params(), BTreeMap::new());
let mut parent = Header::new(); let mut parent = Header::new();
let mut header = Header::new(); let mut header = Header::new();
header.set_number(1); header.set_number(1);
@ -903,7 +890,7 @@ mod tests {
fn difficulty_max_timestamp() { fn difficulty_max_timestamp() {
let spec = new_homestead_test(); let spec = new_homestead_test();
let ethparams = get_default_ethash_params(); let ethparams = get_default_ethash_params();
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
let mut parent_header = Header::default(); let mut parent_header = Header::default();
parent_header.set_number(1000000); parent_header.set_number(1000000);
@ -931,7 +918,7 @@ mod tests {
header.set_number(parent_header.number() + 1); header.set_number(parent_header.number() + 1);
header.set_gas_limit(100_001.into()); header.set_gas_limit(100_001.into());
header.set_difficulty(ethparams.minimum_difficulty); header.set_difficulty(ethparams.minimum_difficulty);
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok()); assert!(ethash.verify_block_family(&header, &parent_header, None).is_ok());
parent_header.set_number(9); parent_header.set_number(9);
@ -986,7 +973,7 @@ mod tests {
nonce: U256::zero(), nonce: U256::zero(),
}.sign(keypair.secret(), None).into(); }.sign(keypair.secret(), None).into();
let ethash = Ethash::new(spec.params, ethparams, BTreeMap::new()); let ethash = Ethash::new(spec.params().clone(), ethparams, BTreeMap::new());
assert!(ethash.verify_transaction_basic(&tx1, &header).is_ok()); assert!(ethash.verify_transaction_basic(&tx1, &header).is_ok());
assert!(ethash.verify_transaction_basic(&tx2, &header).is_ok()); assert!(ethash.verify_transaction_basic(&tx2, &header).is_ok());

View File

@ -82,16 +82,15 @@ impl From<builtin::Error> for Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*; use self::Error::*;
let message = match *self { match *self {
OutOfGas => "Out of gas", OutOfGas => write!(f, "Out of gas"),
BadJumpDestination { .. } => "Bad jump destination", BadJumpDestination { destination } => write!(f, "Bad jump destination {:x}", destination),
BadInstruction { .. } => "Bad instruction", BadInstruction { instruction } => write!(f, "Bad instruction {:x}", instruction),
StackUnderflow { .. } => "Stack underflow", StackUnderflow { instruction, wanted, on_stack } => write!(f, "Stack underflow {} {}/{}", instruction, wanted, on_stack),
OutOfStack { .. } => "Out of stack", OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit),
BuiltIn { .. } => "Built-in failed", BuiltIn(name) => write!(f, "Built-in failed: {}", name),
Internal(ref msg) => msg, Internal(ref msg) => write!(f, "Internal error: {}", msg),
}; }
message.fmt(f)
} }
} }

View File

@ -74,7 +74,7 @@ pub trait Ext {
fn balance(&self, address: &Address) -> trie::Result<U256>; fn balance(&self, address: &Address) -> trie::Result<U256>;
/// Returns the hash of one of the 256 most recent complete blocks. /// Returns the hash of one of the 256 most recent complete blocks.
fn blockhash(&self, number: &U256) -> H256; fn blockhash(&mut self, number: &U256) -> H256;
/// Creates new contract. /// Creates new contract.
/// ///

View File

@ -235,6 +235,9 @@ impl<Gas: CostType> Gasometer<Gas> {
let gas = Gas::from(schedule.exp_gas + schedule.exp_byte_gas * bytes); let gas = Gas::from(schedule.exp_gas + schedule.exp_byte_gas * bytes);
Request::Gas(gas) Request::Gas(gas)
}, },
instructions::BLOCKHASH => {
Request::Gas(Gas::from(schedule.blockhash_gas))
},
_ => Request::Gas(default_gas), _ => Request::Gas(default_gas),
}; };

View File

@ -103,6 +103,8 @@ pub struct Schedule {
pub no_empty: bool, pub no_empty: bool,
/// Kill empty accounts if touched. /// Kill empty accounts if touched.
pub kill_empty: bool, pub kill_empty: bool,
/// Blockhash instruction gas cost.
pub blockhash_gas: usize,
} }
impl Schedule { impl Schedule {
@ -161,6 +163,7 @@ impl Schedule {
sub_gas_cap_divisor: Some(64), sub_gas_cap_divisor: Some(64),
no_empty: no_empty, no_empty: no_empty,
kill_empty: kill_empty, kill_empty: kill_empty,
blockhash_gas: if have_metropolis_instructions { 350 } else { 20 },
} }
} }
@ -213,6 +216,7 @@ impl Schedule {
sub_gas_cap_divisor: None, sub_gas_cap_divisor: None,
no_empty: false, no_empty: false,
kill_empty: false, kill_empty: false,
blockhash_gas: 20,
} }
} }
} }

View File

@ -20,6 +20,11 @@ use env_info::EnvInfo;
use types::executed::CallType; use types::executed::CallType;
use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress}; use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress};
use std::fmt::Debug; use std::fmt::Debug;
use tests::helpers::*;
use types::transaction::SYSTEM_ADDRESS;
use executive::Executive;
use state::Substate;
use trace::{NoopVMTracer, NoopTracer};
pub struct FakeLogEntry { pub struct FakeLogEntry {
topics: Vec<H256>, topics: Vec<H256>,
@ -107,7 +112,7 @@ impl Ext for FakeExt {
Ok(self.balances[address]) Ok(self.balances[address])
} }
fn blockhash(&self, number: &U256) -> H256 { fn blockhash(&mut self, number: &U256) -> H256 {
self.blockhashes.get(number).unwrap_or(&H256::new()).clone() self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
} }
@ -430,6 +435,67 @@ fn test_blockhash(factory: super::Factory) {
assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash); assert_eq!(ext.store.get(&H256::new()).unwrap(), &blockhash);
} }
evm_test!{test_blockhash_eip210: test_blockhash_eip210_jit, test_blockhash_eip210_int}
fn test_blockhash_eip210(factory: super::Factory) {
let get_prev_hash_code = Arc::new("600143034060205260206020f3".from_hex().unwrap()); // this returns previous block hash
let get_prev_hash_code_hash = get_prev_hash_code.sha3();
// This is same as DEFAULT_BLOCKHASH_CONTRACT except for metropolis transition block check removed.
let test_blockhash_contract = "73fffffffffffffffffffffffffffffffffffffffe33141561007a57600143036020526000356101006020510755600061010060205107141561005057600035610100610100602051050761010001555b6000620100006020510714156100755760003561010062010000602051050761020001555b61014a565b4360003512151561009057600060405260206040f35b610100600035430312156100b357610100600035075460605260206060f3610149565b62010000600035430312156100d157600061010060003507146100d4565b60005b156100f6576101006101006000350507610100015460805260206080f3610148565b630100000060003543031215610116576000620100006000350714610119565b60005b1561013c57610100620100006000350507610200015460a052602060a0f3610147565b600060c052602060c0f35b5b5b5b5b";
let blockhash_contract_code = Arc::new(test_blockhash_contract.from_hex().unwrap());
let blockhash_contract_code_hash = blockhash_contract_code.sha3();
let engine = TestEngine::new_metropolis();
let mut env_info = EnvInfo::default();
// populate state with 256 last hashes
let mut state = get_temp_state_with_factory(factory);
let contract_address: Address = 0xf0.into();
state.init_code(&contract_address, (*blockhash_contract_code).clone()).unwrap();
for i in 1 .. 257 {
env_info.number = i.into();
let params = ActionParams {
code_address: contract_address.clone(),
address: contract_address,
sender: SYSTEM_ADDRESS.clone(),
origin: SYSTEM_ADDRESS.clone(),
gas: 100000.into(),
gas_price: 0.into(),
value: ActionValue::Transfer(0.into()),
code: Some(blockhash_contract_code.clone()),
code_hash: blockhash_contract_code_hash,
data: Some(H256::from(i - 1).to_vec()),
call_type: CallType::Call,
};
let mut ex = Executive::new(&mut state, &env_info, &engine);
let mut substate = Substate::new();
let mut output = [];
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
panic!("Encountered error on updating last hashes: {}", e);
}
}
env_info.number = 256;
let params = ActionParams {
code_address: Address::new(),
address: Address::new(),
sender: Address::new(),
origin: Address::new(),
gas: 100000.into(),
gas_price: 0.into(),
value: ActionValue::Transfer(0.into()),
code: Some(get_prev_hash_code),
code_hash: get_prev_hash_code_hash,
data: None,
call_type: CallType::Call,
};
let mut ex = Executive::new(&mut state, &env_info, &engine);
let mut substate = Substate::new();
let mut output = H256::new();
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
panic!("Encountered error on getting last hash: {}", e);
}
assert_eq!(output, 255.into());
}
evm_test!{test_calldataload: test_calldataload_jit, test_calldataload_int} evm_test!{test_calldataload: test_calldataload_jit, test_calldataload_int}
fn test_calldataload(factory: super::Factory) { fn test_calldataload(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();

View File

@ -22,7 +22,7 @@ use engines::Engine;
use types::executed::CallType; use types::executed::CallType;
use env_info::EnvInfo; use env_info::EnvInfo;
use error::ExecutionError; use error::ExecutionError;
use evm::{self, Ext, Factory, Finalize, CreateContractAddress, FinalizationResult}; use evm::{self, Ext, Finalize, CreateContractAddress, FinalizationResult};
use externalities::*; use externalities::*;
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer}; use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
use transaction::{Action, SignedTransaction}; use transaction::{Action, SignedTransaction};
@ -71,33 +71,30 @@ pub struct TransactOptions {
} }
/// Transaction executor. /// Transaction executor.
pub struct Executive<'a, B: 'a + StateBackend> { pub struct Executive<'a, B: 'a + StateBackend, E: 'a + Engine + ?Sized> {
state: &'a mut State<B>, state: &'a mut State<B>,
info: &'a EnvInfo, info: &'a EnvInfo,
engine: &'a Engine, engine: &'a E,
vm_factory: &'a Factory,
depth: usize, depth: usize,
} }
impl<'a, B: 'a + StateBackend> Executive<'a, B> { impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
/// Basic constructor. /// Basic constructor.
pub fn new(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory) -> Self { pub fn new(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a E) -> Self {
Executive { Executive {
state: state, state: state,
info: info, info: info,
engine: engine, engine: engine,
vm_factory: vm_factory,
depth: 0, depth: 0,
} }
} }
/// Populates executive from parent properties. Increments executive depth. /// Populates executive from parent properties. Increments executive depth.
pub fn from_parent(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, parent_depth: usize) -> Self { pub fn from_parent(state: &'a mut State<B>, info: &'a EnvInfo, engine: &'a E, parent_depth: usize) -> Self {
Executive { Executive {
state: state, state: state,
info: info, info: info,
engine: engine, engine: engine,
vm_factory: vm_factory,
depth: parent_depth + 1, depth: parent_depth + 1,
} }
} }
@ -110,8 +107,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
output: OutputPolicy<'any, 'any>, output: OutputPolicy<'any, 'any>,
tracer: &'any mut T, tracer: &'any mut T,
vm_tracer: &'any mut V vm_tracer: &'any mut V
) -> Externalities<'any, T, V, B> where T: Tracer, V: VMTracer { ) -> Externalities<'any, T, V, B, E> where T: Tracer, V: VMTracer {
Externalities::new(self.state, self.info, self.engine, self.vm_factory, self.depth, origin_info, substate, output, tracer, vm_tracer) Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output, tracer, vm_tracer)
} }
/// This function should be used to execute transaction. /// This function should be used to execute transaction.
@ -252,7 +249,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
// Ordinary execution - keep VM in same thread // Ordinary execution - keep VM in same thread
if (self.depth + 1) % depth_threshold != 0 { if (self.depth + 1) % depth_threshold != 0 {
let vm_factory = self.vm_factory; let vm_factory = self.state.vm_factory();
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer); let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer);
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call);
return vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext); return vm_factory.create(params.gas).exec(params, &mut ext).finalize(ext);
@ -262,7 +259,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
// TODO [todr] No thread builder yet, so we need to reset once for a while // TODO [todr] No thread builder yet, so we need to reset once for a while
// https://github.com/aturon/crossbeam/issues/16 // https://github.com/aturon/crossbeam/issues/16
crossbeam::scope(|scope| { crossbeam::scope(|scope| {
let vm_factory = self.vm_factory; let vm_factory = self.state.vm_factory();
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer); let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer);
scope.spawn(move || { scope.spawn(move || {
@ -594,14 +591,14 @@ mod tests {
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(Arc::new("3331600055".from_hex().unwrap())); params.code = Some(Arc::new("3331600055".from_hex().unwrap()));
params.value = ActionValue::Transfer(U256::from(0x7)); params.value = ActionValue::Transfer(U256::from(0x7));
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty).unwrap();
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();
let gas_left = { let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
@ -652,14 +649,14 @@ mod tests {
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(Arc::new(code)); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();
let gas_left = { let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
@ -671,8 +668,6 @@ mod tests {
#[test] #[test]
// Tracing is not suported in JIT // Tracing is not suported in JIT
fn test_call_to_create() { fn test_call_to_create() {
let factory = Factory::new(VMType::Interpreter, 1024 * 32);
// code: // code:
// //
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes? // 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
@ -719,7 +714,7 @@ mod tests {
let mut vm_tracer = ExecutiveVMTracer::toplevel(); let mut vm_tracer = ExecutiveVMTracer::toplevel();
let gas_left = { let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
let output = BytesRef::Fixed(&mut[0u8;0]); let output = BytesRef::Fixed(&mut[0u8;0]);
ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap() ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap()
}; };
@ -796,7 +791,6 @@ mod tests {
#[test] #[test]
fn test_create_contract() { fn test_create_contract() {
// Tracing is not supported in JIT // Tracing is not supported in JIT
let factory = Factory::new(VMType::Interpreter, 1024 * 32);
// code: // code:
// //
// 60 10 - push 16 // 60 10 - push 16
@ -829,7 +823,7 @@ mod tests {
let mut vm_tracer = ExecutiveVMTracer::toplevel(); let mut vm_tracer = ExecutiveVMTracer::toplevel();
let gas_left = { let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap() ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap()
}; };
@ -907,14 +901,14 @@ mod tests {
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(Arc::new(code)); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();
let gas_left = { let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
@ -958,14 +952,14 @@ mod tests {
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(Arc::new(code)); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap();
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(1024); let engine = TestEngine::new(1024);
let mut substate = Substate::new(); let mut substate = Substate::new();
{ {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap(); ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap();
} }
@ -1015,7 +1009,7 @@ mod tests {
params.code = Some(Arc::new(code_a.clone())); params.code = Some(Arc::new(code_a.clone()));
params.value = ActionValue::Transfer(U256::from(100_000)); params.value = ActionValue::Transfer(U256::from(100_000));
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.init_code(&address_a, code_a.clone()).unwrap(); state.init_code(&address_a, code_a.clone()).unwrap();
state.init_code(&address_b, code_b.clone()).unwrap(); state.init_code(&address_b, code_b.clone()).unwrap();
state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty).unwrap();
@ -1025,7 +1019,7 @@ mod tests {
let mut substate = Substate::new(); let mut substate = Substate::new();
let gas_left = { let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
@ -1062,14 +1056,14 @@ mod tests {
params.address = address.clone(); params.address = address.clone();
params.gas = U256::from(100_000); params.gas = U256::from(100_000);
params.code = Some(Arc::new(code.clone())); params.code = Some(Arc::new(code.clone()));
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.init_code(&address, code).unwrap(); state.init_code(&address, code).unwrap();
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();
let gas_left = { let gas_left = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };
@ -1094,14 +1088,14 @@ mod tests {
let sender = t.sender(); let sender = t.sender();
let contract = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default()); let contract = contract_address(CreateContractAddress::FromSenderAndNonce, &sender, &U256::zero(), &H256::default());
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty).unwrap();
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000); info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let executed = { let executed = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false }; let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
ex.transact(&t, opts).unwrap() ex.transact(&t, opts).unwrap()
}; };
@ -1131,14 +1125,14 @@ mod tests {
}.sign(keypair.secret(), None); }.sign(keypair.secret(), None);
let sender = t.sender(); let sender = t.sender();
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap();
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000); info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false }; let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
ex.transact(&t, opts) ex.transact(&t, opts)
}; };
@ -1163,7 +1157,7 @@ mod tests {
}.sign(keypair.secret(), None); }.sign(keypair.secret(), None);
let sender = t.sender(); let sender = t.sender();
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty).unwrap();
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_used = U256::from(20_000); info.gas_used = U256::from(20_000);
@ -1171,7 +1165,7 @@ mod tests {
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false }; let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
ex.transact(&t, opts) ex.transact(&t, opts)
}; };
@ -1197,14 +1191,14 @@ mod tests {
}.sign(keypair.secret(), None); }.sign(keypair.secret(), None);
let sender = t.sender(); let sender = t.sender();
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty).unwrap();
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000); info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let res = { let res = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false }; let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
ex.transact(&t, opts) ex.transact(&t, opts)
}; };
@ -1231,14 +1225,14 @@ mod tests {
params.gas = U256::from(0x0186a0); params.gas = U256::from(0x0186a0);
params.code = Some(Arc::new(code)); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap()); params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap());
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty).unwrap();
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();
let result = { let result = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer)
}; };
@ -1255,7 +1249,7 @@ mod tests {
// EIP-140 test case // EIP-140 test case
let code = "6c726576657274656420646174616000557f726576657274206d657373616765000000000000000000000000000000000000600052600e6000fd".from_hex().unwrap(); let code = "6c726576657274656420646174616000557f726576657274206d657373616765000000000000000000000000000000000000600052600e6000fd".from_hex().unwrap();
let returns = "726576657274206d657373616765".from_hex().unwrap(); let returns = "726576657274206d657373616765".from_hex().unwrap();
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory.clone());
state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap();
state.commit().unwrap(); state.commit().unwrap();
@ -1266,7 +1260,7 @@ mod tests {
params.gas = U256::from(20025); params.gas = U256::from(20025);
params.code = Some(Arc::new(code)); params.code = Some(Arc::new(code));
params.value = ActionValue::Transfer(U256::zero()); params.value = ActionValue::Transfer(U256::zero());
let mut state = get_temp_state(); let mut state = get_temp_state_with_factory(factory);
state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap(); state.add_balance(&sender, &U256::from_str("152d02c7e14af68000000").unwrap(), CleanupMode::NoEmpty).unwrap();
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new_metropolis(); let engine = TestEngine::new_metropolis();
@ -1274,7 +1268,7 @@ mod tests {
let mut output = [0u8; 14]; let mut output = [0u8; 14];
let result = { let result = {
let mut ex = Executive::new(&mut state, &info, &engine, &factory); let mut ex = Executive::new(&mut state, &info, &engine);
ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap()
}; };

View File

@ -21,7 +21,7 @@ use state::{Backend as StateBackend, State, Substate};
use engines::Engine; use engines::Engine;
use env_info::EnvInfo; use env_info::EnvInfo;
use executive::*; use executive::*;
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, Factory, CreateContractAddress}; use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
use types::executed::CallType; use types::executed::CallType;
use types::transaction::UNSIGNED_SENDER; use types::transaction::UNSIGNED_SENDER;
use trace::{Tracer, VMTracer}; use trace::{Tracer, VMTracer};
@ -58,13 +58,12 @@ impl OriginInfo {
} }
/// Implementation of evm Externalities. /// Implementation of evm Externalities.
pub struct Externalities<'a, T: 'a, V: 'a, B: 'a> pub struct Externalities<'a, T: 'a, V: 'a, B: 'a, E: 'a + Engine + ?Sized>
where T: Tracer, V: VMTracer, B: StateBackend where T: Tracer, V: VMTracer, B: StateBackend
{ {
state: &'a mut State<B>, state: &'a mut State<B>,
env_info: &'a EnvInfo, env_info: &'a EnvInfo,
engine: &'a Engine, engine: &'a E,
vm_factory: &'a Factory,
depth: usize, depth: usize,
origin_info: OriginInfo, origin_info: OriginInfo,
substate: &'a mut Substate, substate: &'a mut Substate,
@ -74,15 +73,14 @@ pub struct Externalities<'a, T: 'a, V: 'a, B: 'a>
vm_tracer: &'a mut V, vm_tracer: &'a mut V,
} }
impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B> impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E>
where T: Tracer, V: VMTracer, B: StateBackend where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
{ {
/// Basic `Externalities` constructor. /// Basic `Externalities` constructor.
#[cfg_attr(feature="dev", allow(too_many_arguments))] #[cfg_attr(feature="dev", allow(too_many_arguments))]
pub fn new(state: &'a mut State<B>, pub fn new(state: &'a mut State<B>,
env_info: &'a EnvInfo, env_info: &'a EnvInfo,
engine: &'a Engine, engine: &'a E,
vm_factory: &'a Factory,
depth: usize, depth: usize,
origin_info: OriginInfo, origin_info: OriginInfo,
substate: &'a mut Substate, substate: &'a mut Substate,
@ -94,7 +92,6 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
state: state, state: state,
env_info: env_info, env_info: env_info,
engine: engine, engine: engine,
vm_factory: vm_factory,
depth: depth, depth: depth,
origin_info: origin_info, origin_info: origin_info,
substate: substate, substate: substate,
@ -106,8 +103,8 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
} }
} }
impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
where T: Tracer, V: VMTracer, B: StateBackend where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
{ {
fn storage_at(&self, key: &H256) -> trie::Result<H256> { fn storage_at(&self, key: &H256) -> trie::Result<H256> {
self.state.storage_at(&self.origin_info.address, key) self.state.storage_at(&self.origin_info.address, key)
@ -131,20 +128,51 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
self.state.balance(address) self.state.balance(address)
} }
fn blockhash(&self, number: &U256) -> H256 { fn blockhash(&mut self, number: &U256) -> H256 {
// TODO: comment out what this function expects from env_info, since it will produce panics if the latter is inconsistent if self.env_info.number + 256 >= self.engine.params().eip210_transition {
match *number < U256::from(self.env_info.number) && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 { let blockhash_contract_address = self.engine.params().eip210_contract_address;
true => { let code_res = self.state.code(&blockhash_contract_address)
let index = self.env_info.number - number.low_u64() - 1; .and_then(|code| self.state.code_hash(&blockhash_contract_address).map(|hash| (code, hash)));
assert!(index < self.env_info.last_hashes.len() as u64, format!("Inconsistent env_info, should contain at least {:?} last hashes", index+1));
let r = self.env_info.last_hashes[index as usize].clone(); let (code, code_hash) = match code_res {
trace!("ext: blockhash({}) -> {} self.env_info.number={}\n", number, r, self.env_info.number); Ok((code, hash)) => (code, hash),
r Err(_) => return H256::zero(),
}, };
false => {
trace!("ext: blockhash({}) -> null self.env_info.number={}\n", number, self.env_info.number); let params = ActionParams {
H256::zero() sender: self.origin_info.address.clone(),
}, address: blockhash_contract_address.clone(),
value: ActionValue::Apparent(self.origin_info.value),
code_address: blockhash_contract_address.clone(),
origin: self.origin_info.origin.clone(),
gas: self.engine.params().eip210_contract_gas,
gas_price: 0.into(),
code: code,
code_hash: code_hash,
data: Some(H256::from(number).to_vec()),
call_type: CallType::Call,
};
let mut output = H256::new();
let mut ex = Executive::new(self.state, self.env_info, self.engine);
let r = ex.call(params, self.substate, BytesRef::Fixed(&mut output), self.tracer, self.vm_tracer);
trace!("ext: blockhash contract({}) -> {:?}({}) self.env_info.number={}\n", number, r, output, self.env_info.number);
output
} else {
// TODO: comment out what this function expects from env_info, since it will produce panics if the latter is inconsistent
match *number < U256::from(self.env_info.number) && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 {
true => {
let index = self.env_info.number - number.low_u64() - 1;
assert!(index < self.env_info.last_hashes.len() as u64, format!("Inconsistent env_info, should contain at least {:?} last hashes", index+1));
let r = self.env_info.last_hashes[index as usize].clone();
trace!("ext: blockhash({}) -> {} self.env_info.number={}\n", number, r, self.env_info.number);
r
},
false => {
trace!("ext: blockhash({}) -> null self.env_info.number={}\n", number, self.env_info.number);
H256::zero()
},
}
} }
} }
@ -180,7 +208,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
return ContractCreateResult::Failed return ContractCreateResult::Failed
} }
} }
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth); let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
// TODO: handle internal error separately // TODO: handle internal error separately
match ex.create(params, self.substate, self.tracer, self.vm_tracer) { match ex.create(params, self.substate, self.tracer, self.vm_tracer) {
@ -230,7 +258,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
params.value = ActionValue::Transfer(value); params.value = ActionValue::Transfer(value);
} }
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.vm_factory, self.depth); let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth);
match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) { match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) {
Ok(gas_left) => MessageCallResult::Success(gas_left), Ok(gas_left) => MessageCallResult::Success(gas_left),
@ -406,8 +434,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let vm_factory = Default::default(); let ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
assert_eq!(ext.env_info().number, 100); assert_eq!(ext.env_info().number, 100);
} }
@ -419,8 +446,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let vm_factory = Default::default(); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
@ -444,8 +470,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let vm_factory = Default::default(); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
let ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap()); let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
@ -460,8 +485,7 @@ mod tests {
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let vm_factory = Default::default(); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
let mut output = vec![]; let mut output = vec![];
@ -489,8 +513,7 @@ mod tests {
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
{ {
let vm_factory = Default::default(); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
ext.log(log_topics, &log_data); ext.log(log_topics, &log_data);
} }
@ -507,8 +530,7 @@ mod tests {
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
{ {
let vm_factory = Default::default(); let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, &vm_factory, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer);
ext.suicide(refund_account).unwrap(); ext.suicide(refund_account).unwrap();
} }

View File

@ -21,7 +21,7 @@ use executive::*;
use engines::Engine; use engines::Engine;
use env_info::EnvInfo; use env_info::EnvInfo;
use evm; use evm;
use evm::{Schedule, Ext, Factory, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress}; use evm::{Schedule, Ext, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress};
use externalities::*; use externalities::*;
use types::executed::CallType; use types::executed::CallType;
use tests::helpers::*; use tests::helpers::*;
@ -51,23 +51,22 @@ impl From<ethjson::vm::Call> for CallCreate {
/// Tiny wrapper around executive externalities. /// Tiny wrapper around executive externalities.
/// Stores callcreates. /// Stores callcreates.
struct TestExt<'a, T: 'a, V: 'a, B: 'a> struct TestExt<'a, T: 'a, V: 'a, B: 'a, E: 'a>
where T: Tracer, V: VMTracer, B: StateBackend where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
{ {
ext: Externalities<'a, T, V, B>, ext: Externalities<'a, T, V, B, E>,
callcreates: Vec<CallCreate>, callcreates: Vec<CallCreate>,
nonce: U256, nonce: U256,
sender: Address, sender: Address,
} }
impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B> impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> TestExt<'a, T, V, B, E>
where T: Tracer, V: VMTracer, B: StateBackend where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
{ {
fn new( fn new(
state: &'a mut State<B>, state: &'a mut State<B>,
info: &'a EnvInfo, info: &'a EnvInfo,
engine: &'a Engine, engine: &'a E,
vm_factory: &'a Factory,
depth: usize, depth: usize,
origin_info: OriginInfo, origin_info: OriginInfo,
substate: &'a mut Substate, substate: &'a mut Substate,
@ -78,15 +77,15 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B>
) -> trie::Result<Self> { ) -> trie::Result<Self> {
Ok(TestExt { Ok(TestExt {
nonce: state.nonce(&address)?, nonce: state.nonce(&address)?,
ext: Externalities::new(state, info, engine, vm_factory, depth, origin_info, substate, output, tracer, vm_tracer), ext: Externalities::new(state, info, engine, depth, origin_info, substate, output, tracer, vm_tracer),
callcreates: vec![], callcreates: vec![],
sender: address, sender: address,
}) })
} }
} }
impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B> impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
where T: Tracer, V: VMTracer, B: StateBackend where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
{ {
fn storage_at(&self, key: &H256) -> trie::Result<H256> { fn storage_at(&self, key: &H256) -> trie::Result<H256> {
self.ext.storage_at(key) self.ext.storage_at(key)
@ -112,7 +111,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
self.ext.origin_balance() self.ext.origin_balance()
} }
fn blockhash(&self, number: &U256) -> H256 { fn blockhash(&mut self, number: &U256) -> H256 {
self.ext.blockhash(number) self.ext.blockhash(number)
} }
@ -222,13 +221,13 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
state.populate_from(From::from(vm.pre_state.clone())); state.populate_from(From::from(vm.pre_state.clone()));
let info = From::from(vm.env); let info = From::from(vm.env);
let engine = TestEngine::new(1); let engine = TestEngine::new(1);
let vm_factory = Factory::new(vm_type.clone(), 1024 * 32);
let params = ActionParams::from(vm.transaction); let params = ActionParams::from(vm.transaction);
let mut substate = Substate::new(); let mut substate = Substate::new();
let mut tracer = NoopTracer; let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer; let mut vm_tracer = NoopVMTracer;
let mut output = vec![]; let mut output = vec![];
let vm_factory = state.vm_factory();
// execute // execute
let (res, callcreates) = { let (res, callcreates) = {
@ -236,7 +235,6 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
&mut state, &mut state,
&info, &info,
&engine, &engine,
&vm_factory,
0, 0,
OriginInfo::from(&params), OriginInfo::from(&params),
&mut substate, &mut substate,

View File

@ -728,7 +728,7 @@ impl MinerService for Miner {
.map_err(ExecutionError::from)?; .map_err(ExecutionError::from)?;
} }
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, client.vm_factory()).transact(t, options)?; let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact(t, options)?;
// TODO gav move this into Executive. // TODO gav move this into Executive.
if let Some(original) = original_state { if let Some(original) = original_state {

View File

@ -470,7 +470,7 @@ impl Rebuilder for ChunkRebuilder {
db.boxed_clone(), db.boxed_clone(),
self.manifest.state_root.clone(), self.manifest.state_root.clone(),
engine.account_start_nonce(), engine.account_start_nonce(),
factories.clone(), factories,
).map_err(|e| format!("State root mismatch: {}", e))?; ).map_err(|e| format!("State root mismatch: {}", e))?;
let (tx, env_info) = make_tx_and_env( let (tx, env_info) = make_tx_and_env(
@ -482,7 +482,7 @@ impl Rebuilder for ChunkRebuilder {
); );
let options = TransactOptions { tracing: false, vm_tracing: false, check_nonce: false }; let options = TransactOptions { tracing: false, vm_tracing: false, check_nonce: false };
Executive::new(&mut state, &env_info, engine, &factories.vm) Executive::new(&mut state, &env_info, engine)
.transact_virtual(&tx, options) .transact_virtual(&tx, options)
.map(|e| e.output) .map(|e| e.output)
.map_err(|e| format!("Error executing: {}", e)) .map_err(|e| format!("Error executing: {}", e))

View File

@ -21,7 +21,7 @@ use super::seal::Generic as GenericSeal;
use action_params::{ActionValue, ActionParams}; use action_params::{ActionValue, ActionParams};
use builtin::Builtin; use builtin::Builtin;
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint}; use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT};
use env_info::EnvInfo; use env_info::EnvInfo;
use error::Error; use error::Error;
use ethereum; use ethereum;
@ -39,7 +39,8 @@ use types::executed::CallType;
use util::*; use util::*;
/// Parameters common to all engines. /// Parameters common to all engines.
#[derive(Debug, PartialEq, Clone, Default)] #[derive(Debug, PartialEq, Default)]
#[cfg_attr(test, derive(Clone))]
pub struct CommonParams { pub struct CommonParams {
/// Account start nonce. /// Account start nonce.
pub account_start_nonce: U256, pub account_start_nonce: U256,
@ -63,6 +64,14 @@ pub struct CommonParams {
pub eip86_transition: BlockNumber, pub eip86_transition: BlockNumber,
/// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin. /// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin.
pub eip140_transition: BlockNumber, pub eip140_transition: BlockNumber,
/// Number of first block where EIP-210 (Metropolis: BLOCKHASH changes) rules begin.
pub eip210_transition: BlockNumber,
/// EIP-210 Blockhash contract address.
pub eip210_contract_address: Address,
/// EIP-210 Blockhash contract code.
pub eip210_contract_code: Bytes,
/// Gas allocated for EIP-210 blockhash update.
pub eip210_contract_gas: U256,
} }
impl From<ethjson::spec::Params> for CommonParams { impl From<ethjson::spec::Params> for CommonParams {
@ -79,6 +88,12 @@ impl From<ethjson::spec::Params> for CommonParams {
validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into), validate_receipts_transition: p.validate_receipts_transition.map_or(0, Into::into),
eip86_transition: p.eip86_transition.map_or(BlockNumber::max_value(), Into::into), eip86_transition: p.eip86_transition.map_or(BlockNumber::max_value(), Into::into),
eip140_transition: p.eip140_transition.map_or(BlockNumber::max_value(), Into::into), eip140_transition: p.eip140_transition.map_or(BlockNumber::max_value(), Into::into),
eip210_transition: p.eip210_transition.map_or(BlockNumber::max_value(), Into::into),
eip210_contract_address: p.eip210_contract_address.map_or(0xf0.into(), Into::into),
eip210_contract_code: p.eip210_contract_code.map_or_else(
|| DEFAULT_BLOCKHASH_CONTRACT.from_hex().expect("Default BLOCKHASH contract is valid"),
Into::into),
eip210_contract_gas: p.eip210_contract_gas.map_or(1000000.into(), Into::into),
} }
} }
} }
@ -96,9 +111,6 @@ pub struct Spec {
/// Known nodes on the network in enode format. /// Known nodes on the network in enode format.
pub nodes: Vec<String>, pub nodes: Vec<String>,
/// Parameters common to all engines.
pub params: CommonParams,
/// The genesis block's parent hash field. /// The genesis block's parent hash field.
pub parent_hash: H256, pub parent_hash: H256,
/// The genesis block's author field. /// The genesis block's author field.
@ -138,7 +150,6 @@ fn load_from(s: ethjson::spec::Spec) -> Result<Spec, Error> {
let mut s = Spec { let mut s = Spec {
name: s.name.clone().into(), name: s.name.clone().into(),
params: params.clone(),
engine: Spec::engine(s.engine, params, builtins), engine: Spec::engine(s.engine, params, builtins),
data_dir: s.data_dir.unwrap_or(s.name).into(), data_dir: s.data_dir.unwrap_or(s.name).into(),
nodes: s.nodes.unwrap_or_else(Vec::new), nodes: s.nodes.unwrap_or_else(Vec::new),
@ -250,7 +261,7 @@ impl Spec {
state.kill_account(&address); state.kill_account(&address);
{ {
let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref(), &factories.vm); let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref());
if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) { if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) {
warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e); warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
} }
@ -275,17 +286,20 @@ impl Spec {
self.state_root_memo.read().clone() self.state_root_memo.read().clone()
} }
/// Get common blockchain parameters.
pub fn params(&self) -> &CommonParams { &self.engine.params() }
/// Get the known knodes of the network in enode format. /// Get the known knodes of the network in enode format.
pub fn nodes(&self) -> &[String] { &self.nodes } pub fn nodes(&self) -> &[String] { &self.nodes }
/// Get the configured Network ID. /// Get the configured Network ID.
pub fn network_id(&self) -> u64 { self.params.network_id } pub fn network_id(&self) -> u64 { self.params().network_id }
/// Get the configured subprotocol name. /// Get the configured subprotocol name.
pub fn subprotocol_name(&self) -> String { self.params.subprotocol_name.clone() } pub fn subprotocol_name(&self) -> String { self.params().subprotocol_name.clone() }
/// Get the configured network fork block. /// Get the configured network fork block.
pub fn fork_block(&self) -> Option<(BlockNumber, H256)> { self.params.fork_block } pub fn fork_block(&self) -> Option<(BlockNumber, H256)> { self.params().fork_block }
/// Get the header of the genesis block. /// Get the header of the genesis block.
pub fn genesis_header(&self) -> Header { pub fn genesis_header(&self) -> Header {
@ -362,7 +376,6 @@ impl Spec {
// TODO: could optimize so we don't re-run, but `ensure_db_good` is barely ever // TODO: could optimize so we don't re-run, but `ensure_db_good` is barely ever
// called anyway. // called anyway.
let db = self.run_constructors(factories, db)?; let db = self.run_constructors(factories, db)?;
Ok(db) Ok(db)
} }

View File

@ -36,6 +36,7 @@ use types::executed::{Executed, ExecutionError};
use types::state_diff::StateDiff; use types::state_diff::StateDiff;
use transaction::SignedTransaction; use transaction::SignedTransaction;
use state_db::StateDB; use state_db::StateDB;
use evm::{Factory as EvmFactory};
use util::*; use util::*;
@ -310,6 +311,11 @@ impl<B: Backend> State<B> {
Ok(state) Ok(state)
} }
/// Get a VM factory that can execute on this state.
pub fn vm_factory(&self) -> EvmFactory {
self.factories.vm.clone()
}
/// Swap the current backend for another. /// Swap the current backend for another.
// TODO: [rob] find a less hacky way to avoid duplication of `Client::state_at`. // TODO: [rob] find a less hacky way to avoid duplication of `Client::state_at`.
pub fn replace_backend<T: Backend>(self, backend: T) -> State<T> { pub fn replace_backend<T: Backend>(self, backend: T) -> State<T> {
@ -579,6 +585,7 @@ impl<B: Backend> State<B> {
/// Mutate storage of account `a` so that it is `value` for `key`. /// Mutate storage of account `a` so that it is `value` for `key`.
pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> trie::Result<()> { pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> trie::Result<()> {
trace!(target: "state", "set_storage({}:{} to {})", a, key.hex(), value.hex());
if self.storage_at(a, &key)? != value { if self.storage_at(a, &key)? != value {
self.require(a, false)?.set_storage(key, value) self.require(a, false)?.set_storage(key, value)
} }
@ -625,9 +632,7 @@ impl<B: Backend> State<B> {
-> Result<Executed, ExecutionError> -> Result<Executed, ExecutionError>
{ {
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true }; let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
let vm_factory = self.factories.vm.clone(); let mut e = Executive::new(self, env_info, engine);
let mut e = Executive::new(self, env_info, engine, &vm_factory);
match virt { match virt {
true => e.transact_virtual(t, options), true => e.transact_virtual(t, options),
@ -635,7 +640,6 @@ impl<B: Backend> State<B> {
} }
} }
/// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit.
/// `accounts` is mutable because we may need to commit the code or storage and record that. /// `accounts` is mutable because we may need to commit the code or storage and record that.
#[cfg_attr(feature="dev", allow(match_ref_pats))] #[cfg_attr(feature="dev", allow(match_ref_pats))]

View File

@ -358,7 +358,7 @@ fn transaction_proof() {
let root = client.best_block_header().state_root(); let root = client.best_block_header().state_root();
let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap(); let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap();
Executive::new(&mut state, &client.latest_env_info(), &*test_spec.engine, &factories.vm) Executive::new(&mut state, &client.latest_env_info(), &*test_spec.engine)
.transact(&transaction, Default::default()).unwrap(); .transact(&transaction, Default::default()).unwrap();
assert_eq!(state.balance(&Address::default()).unwrap(), 5.into()); assert_eq!(state.balance(&Address::default()).unwrap(), 5.into());

View File

@ -25,7 +25,8 @@ use block::{OpenBlock, Drain};
use blockchain::{BlockChain, Config as BlockChainConfig}; use blockchain::{BlockChain, Config as BlockChainConfig};
use builtin::Builtin; use builtin::Builtin;
use state::*; use state::*;
use evm::Schedule; use evm::{Schedule, Factory as EvmFactory};
use factory::Factories;
use engines::Engine; use engines::Engine;
use ethereum; use ethereum;
use ethereum::ethash::EthashParams; use ethereum::ethash::EthashParams;
@ -318,6 +319,13 @@ pub fn get_temp_state() -> State<::state_db::StateDB> {
State::new(journal_db, U256::from(0), Default::default()) State::new(journal_db, U256::from(0), Default::default())
} }
pub fn get_temp_state_with_factory(factory: EvmFactory) -> State<::state_db::StateDB> {
let journal_db = get_temp_state_db();
let mut factories = Factories::default();
factories.vm = factory;
State::new(journal_db, U256::from(0), factories)
}
pub fn get_temp_state_db() -> StateDB { pub fn get_temp_state_db() -> StateDB {
let db = new_db(); let db = new_db();
let journal_db = journaldb::new(db, journaldb::Algorithm::EarlyMerge, ::db::COL_STATE); let journal_db = journaldb::new(db, journaldb::Algorithm::EarlyMerge, ::db::COL_STATE);

View File

@ -29,6 +29,9 @@ use ethjson;
/// Fake address for unsigned transactions as defined by EIP-86. /// Fake address for unsigned transactions as defined by EIP-86.
pub const UNSIGNED_SENDER: Address = ::util::H160([0xff; 20]); pub const UNSIGNED_SENDER: Address = ::util::H160([0xff; 20]);
/// System sender address for internal state updates.
pub const SYSTEM_ADDRESS: Address = ::util::H160([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xff,0xff, 0xff, 0xff, 0xfe]);
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "ipc", binary)] #[cfg_attr(feature = "ipc", binary)]
/// Transaction action type. /// Transaction action type.

View File

@ -17,7 +17,8 @@
//! Spec params deserialization. //! Spec params deserialization.
use uint::Uint; use uint::Uint;
use hash::H256; use hash::{H256, Address};
use bytes::Bytes;
/// Spec params. /// Spec params.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
@ -62,6 +63,18 @@ pub struct Params {
/// See `CommonParams` docs. /// See `CommonParams` docs.
#[serde(rename="eip140Transition")] #[serde(rename="eip140Transition")]
pub eip140_transition: Option<Uint>, pub eip140_transition: Option<Uint>,
/// See `CommonParams` docs.
#[serde(rename="eip210Transition")]
pub eip210_transition: Option<Uint>,
/// See `CommonParams` docs.
#[serde(rename="eip210ContractAddress")]
pub eip210_contract_address: Option<Address>,
/// See `CommonParams` docs.
#[serde(rename="eip210ContractCode")]
pub eip210_contract_code: Option<Bytes>,
/// See `CommonParams` docs.
#[serde(rename="eip210ContractGas")]
pub eip210_contract_gas: Option<Uint>,
} }
#[cfg(test)] #[cfg(test)]