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",
"homesteadTransition": "0x0",
"eip150Transition": "0x0",
"eip155Transition": "0x7fffffffffffffff",
"eip155Transition": "0x0",
"eip160Transition": "0x0",
"eip161abcTransition": "0x0",
"eip161dTransition": "0x0",
@ -24,9 +24,10 @@
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x1",
"eip98Transition": "0x7fffffffffffffff",
"eip98Transition": "0x0",
"eip86Transition": "0x0",
"eip140Transition": "0x0"
"eip140Transition": "0x0",
"eip210Transition": "0x0"
},
"genesis": {
"seal": {

View File

@ -265,7 +265,7 @@ impl<'x> OpenBlock<'x> {
let mut r = OpenBlock {
block: ExecutedBlock::new(state, tracing),
engine: engine,
last_hashes: last_hashes,
last_hashes: last_hashes.clone(),
};
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_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.on_new_block(&mut r.block);
engine.on_new_block(&mut r.block, last_hashes)?;
Ok(r)
}
@ -373,7 +373,9 @@ impl<'x> OpenBlock<'x> {
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() {
warn!("Encountered error on state commit: {}", e);
}
@ -397,7 +399,9 @@ impl<'x> OpenBlock<'x> {
pub fn close_and_lock(self) -> LockedBlock {
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() {
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 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)
.transact_virtual(t, options)?;
let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact_virtual(t, options)?;
// TODO gav move this into Executive.
if let Some(original) = original_state {
@ -1063,7 +1062,7 @@ impl BlockChainClient for Client {
let tx = tx.fake_sign(sender);
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())
.map(|r| r.exception.is_none())
.unwrap_or(false))
@ -1125,13 +1124,13 @@ impl BlockChainClient for Client {
let rest = txs.split_off(address.index);
for t in txs {
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;
}
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 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 {
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 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 {
Err(ExecutionError::Internal(_)) => None,

View File

@ -103,7 +103,7 @@ impl EvmTestClient {
let mut substate = state::Substate::new();
let mut tracer = trace::NoopTracer;
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(
params,
&mut substate,

View File

@ -413,7 +413,7 @@ impl BlockChainClient for TestBlockChainClient {
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> {
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,
}
}
@ -747,7 +747,7 @@ impl BlockChainClient for TestBlockChainClient {
value: U256::default(),
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 signed = SignedTransaction::new(transaction.with_signature(sig, network_id)).unwrap();
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.
fn on_close_block(&self, block: &mut ExecutedBlock) {
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error> {
let fields = block.fields_mut();
// Bestow block reward
let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty)
.map_err(::error::Error::from)
.and_then(|_| fields.state.commit());
// 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);
}
res
}
/// Check the number of seal fields.

View File

@ -40,7 +40,7 @@ use account_provider::AccountProvider;
use block::ExecutedBlock;
use builtin::Builtin;
use client::Client;
use env_info::EnvInfo;
use env_info::{EnvInfo, LastHashes};
use error::Error;
use evm::Schedule;
use header::{Header, BlockNumber};
@ -53,6 +53,10 @@ use evm::CreateContractAddress;
use ethkey::Signature;
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.
#[derive(Debug)]
pub enum EngineError {
@ -159,9 +163,15 @@ pub trait Engine : Sync + Send {
fn account_start_nonce(&self) -> U256 { self.params().account_start_nonce }
/// 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.
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.
/// 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 }
}
}
/// 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.
fn on_close_block(&self, block: &mut ExecutedBlock) {
fn on_close_block(&self, block: &mut ExecutedBlock) -> Result<(), Error>{
let fields = block.fields_mut();
// Bestow block reward
let res = fields.state.add_balance(fields.header.author(), &self.block_reward, CleanupMode::NoEmpty)
.map_err(::error::Error::from)
.and_then(|_| fields.state.commit());
// 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);
}
res
}
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 ethjson;
use rlp::{self, UntrustedRlp};
use env_info::LastHashes;
/// Parity tries to round block.gas_limit to multiple of this constant
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());
}
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 {
// TODO: enable trigger function maybe?
// if block.fields().header.gas_limit() <= 4_000_000.into() {
let state = block.fields_mut().state;
for child in &self.ethash_params.dao_hardfork_accounts {
let beneficiary = &self.ethash_params.dao_hardfork_beneficiary;
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.");
try!(state.balance(child)
.and_then(|b| state.transfer_balance(child, beneficiary, &b, CleanupMode::NoEmpty)));
}
}
// }
}
Ok(())
}
/// 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).
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 fields = block.fields_mut();
// Bestow block reward
let res = fields.state.add_balance(
fields.state.add_balance(
fields.header.author(),
&(reward + reward / U256::from(32) * U256::from(fields.uncles.len())),
CleanupMode::NoEmpty
);
if let Err(e) = res {
warn!("Failed to give block reward: {}", e);
}
)?;
// Bestow uncle rewards
let current_number = fields.header.number();
for u in fields.uncles.iter() {
let res = fields.state.add_balance(
fields.state.add_balance(
u.author(),
&(reward * U256::from(8 + u.number() - current_number) / U256::from(8)),
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.
if let Err(e) = fields.state.commit() {
warn!("Encountered error on state commit: {}", e);
}
fields.state.commit()?;
Ok(())
}
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
@ -741,7 +728,7 @@ mod tests {
fn difficulty_frontier() {
let spec = new_homestead_test();
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();
parent_header.set_number(1000000);
@ -759,7 +746,7 @@ mod tests {
fn difficulty_homestead() {
let spec = new_homestead_test();
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();
parent_header.set_number(1500000);
@ -780,7 +767,7 @@ mod tests {
ecip1010_pause_transition: 3000000,
..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();
parent_header.set_number(3500000);
@ -814,7 +801,7 @@ mod tests {
ecip1010_continue_transition: 5000000,
..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();
parent_header.set_number(5000102);
@ -859,7 +846,7 @@ mod tests {
#[test]
fn gas_limit_is_multiple_of_determinant() {
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 header = Header::new();
header.set_number(1);
@ -903,7 +890,7 @@ mod tests {
fn difficulty_max_timestamp() {
let spec = new_homestead_test();
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();
parent_header.set_number(1000000);
@ -931,7 +918,7 @@ mod tests {
header.set_number(parent_header.number() + 1);
header.set_gas_limit(100_001.into());
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());
parent_header.set_number(9);
@ -986,7 +973,7 @@ mod tests {
nonce: U256::zero(),
}.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(&tx2, &header).is_ok());

View File

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

View File

@ -74,7 +74,7 @@ pub trait Ext {
fn balance(&self, address: &Address) -> trie::Result<U256>;
/// 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.
///

View File

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

View File

@ -103,6 +103,8 @@ pub struct Schedule {
pub no_empty: bool,
/// Kill empty accounts if touched.
pub kill_empty: bool,
/// Blockhash instruction gas cost.
pub blockhash_gas: usize,
}
impl Schedule {
@ -161,6 +163,7 @@ impl Schedule {
sub_gas_cap_divisor: Some(64),
no_empty: no_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,
no_empty: false,
kill_empty: false,
blockhash_gas: 20,
}
}
}

View File

@ -20,6 +20,11 @@ use env_info::EnvInfo;
use types::executed::CallType;
use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress};
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 {
topics: Vec<H256>,
@ -107,7 +112,7 @@ impl Ext for FakeExt {
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()
}
@ -430,6 +435,67 @@ fn test_blockhash(factory: super::Factory) {
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}
fn test_calldataload(factory: super::Factory) {
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();

View File

@ -22,7 +22,7 @@ use engines::Engine;
use types::executed::CallType;
use env_info::EnvInfo;
use error::ExecutionError;
use evm::{self, Ext, Factory, Finalize, CreateContractAddress, FinalizationResult};
use evm::{self, Ext, Finalize, CreateContractAddress, FinalizationResult};
use externalities::*;
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
use transaction::{Action, SignedTransaction};
@ -71,33 +71,30 @@ pub struct TransactOptions {
}
/// 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>,
info: &'a EnvInfo,
engine: &'a Engine,
vm_factory: &'a Factory,
engine: &'a E,
depth: usize,
}
impl<'a, B: 'a + StateBackend> Executive<'a, B> {
impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
/// 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 {
state: state,
info: info,
engine: engine,
vm_factory: vm_factory,
depth: 0,
}
}
/// 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 {
state: state,
info: info,
engine: engine,
vm_factory: vm_factory,
depth: parent_depth + 1,
}
}
@ -110,8 +107,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
output: OutputPolicy<'any, 'any>,
tracer: &'any mut T,
vm_tracer: &'any mut V
) -> Externalities<'any, T, V, B> 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<'any, T, V, B, E> where T: Tracer, V: VMTracer {
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.
@ -252,7 +249,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
// Ordinary execution - keep VM in same thread
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);
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);
@ -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
// https://github.com/aturon/crossbeam/issues/16
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);
scope.spawn(move || {
@ -594,14 +591,14 @@ mod tests {
params.gas = U256::from(100_000);
params.code = Some(Arc::new("3331600055".from_hex().unwrap()));
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();
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();
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()
};
@ -652,14 +649,14 @@ mod tests {
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
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();
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();
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()
};
@ -671,8 +668,6 @@ mod tests {
#[test]
// Tracing is not suported in JIT
fn test_call_to_create() {
let factory = Factory::new(VMType::Interpreter, 1024 * 32);
// code:
//
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
@ -719,7 +714,7 @@ mod tests {
let mut vm_tracer = ExecutiveVMTracer::toplevel();
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]);
ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap()
};
@ -796,7 +791,6 @@ mod tests {
#[test]
fn test_create_contract() {
// Tracing is not supported in JIT
let factory = Factory::new(VMType::Interpreter, 1024 * 32);
// code:
//
// 60 10 - push 16
@ -829,7 +823,7 @@ mod tests {
let mut vm_tracer = ExecutiveVMTracer::toplevel();
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()
};
@ -907,14 +901,14 @@ mod tests {
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
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();
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();
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()
};
@ -958,14 +952,14 @@ mod tests {
params.gas = U256::from(100_000);
params.code = Some(Arc::new(code));
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();
let info = EnvInfo::default();
let engine = TestEngine::new(1024);
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();
}
@ -1015,7 +1009,7 @@ mod tests {
params.code = Some(Arc::new(code_a.clone()));
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_b, code_b.clone()).unwrap();
state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty).unwrap();
@ -1025,7 +1019,7 @@ mod tests {
let mut substate = Substate::new();
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()
};
@ -1062,14 +1056,14 @@ mod tests {
params.address = address.clone();
params.gas = U256::from(100_000);
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();
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();
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()
};
@ -1094,14 +1088,14 @@ mod tests {
let sender = t.sender();
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();
let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0);
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 };
ex.transact(&t, opts).unwrap()
};
@ -1131,14 +1125,14 @@ mod tests {
}.sign(keypair.secret(), None);
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();
let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0);
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 };
ex.transact(&t, opts)
};
@ -1163,7 +1157,7 @@ mod tests {
}.sign(keypair.secret(), None);
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();
let mut info = EnvInfo::default();
info.gas_used = U256::from(20_000);
@ -1171,7 +1165,7 @@ mod tests {
let engine = TestEngine::new(0);
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 };
ex.transact(&t, opts)
};
@ -1197,14 +1191,14 @@ mod tests {
}.sign(keypair.secret(), None);
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();
let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0);
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 };
ex.transact(&t, opts)
};
@ -1231,14 +1225,14 @@ mod tests {
params.gas = U256::from(0x0186a0);
params.code = Some(Arc::new(code));
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();
let info = EnvInfo::default();
let engine = TestEngine::new(0);
let mut substate = Substate::new();
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)
};
@ -1255,7 +1249,7 @@ mod tests {
// EIP-140 test case
let code = "6c726576657274656420646174616000557f726576657274206d657373616765000000000000000000000000000000000000600052600e6000fd".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.commit().unwrap();
@ -1266,7 +1260,7 @@ mod tests {
params.gas = U256::from(20025);
params.code = Some(Arc::new(code));
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();
let info = EnvInfo::default();
let engine = TestEngine::new_metropolis();
@ -1274,7 +1268,7 @@ mod tests {
let mut output = [0u8; 14];
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()
};

View File

@ -21,7 +21,7 @@ use state::{Backend as StateBackend, State, Substate};
use engines::Engine;
use env_info::EnvInfo;
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::transaction::UNSIGNED_SENDER;
use trace::{Tracer, VMTracer};
@ -58,13 +58,12 @@ impl OriginInfo {
}
/// 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
{
state: &'a mut State<B>,
env_info: &'a EnvInfo,
engine: &'a Engine,
vm_factory: &'a Factory,
engine: &'a E,
depth: usize,
origin_info: OriginInfo,
substate: &'a mut Substate,
@ -74,15 +73,14 @@ pub struct Externalities<'a, T: 'a, V: 'a, B: 'a>
vm_tracer: &'a mut V,
}
impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
where T: Tracer, V: VMTracer, B: StateBackend
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E>
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
{
/// Basic `Externalities` constructor.
#[cfg_attr(feature="dev", allow(too_many_arguments))]
pub fn new(state: &'a mut State<B>,
env_info: &'a EnvInfo,
engine: &'a Engine,
vm_factory: &'a Factory,
engine: &'a E,
depth: usize,
origin_info: OriginInfo,
substate: &'a mut Substate,
@ -94,7 +92,6 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B>
state: state,
env_info: env_info,
engine: engine,
vm_factory: vm_factory,
depth: depth,
origin_info: origin_info,
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>
where T: Tracer, V: VMTracer, B: StateBackend
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, E: Engine + ?Sized
{
fn storage_at(&self, key: &H256) -> trie::Result<H256> {
self.state.storage_at(&self.origin_info.address, key)
@ -131,7 +128,37 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
self.state.balance(address)
}
fn blockhash(&self, number: &U256) -> H256 {
fn blockhash(&mut self, number: &U256) -> H256 {
if self.env_info.number + 256 >= self.engine.params().eip210_transition {
let blockhash_contract_address = self.engine.params().eip210_contract_address;
let code_res = self.state.code(&blockhash_contract_address)
.and_then(|code| self.state.code_hash(&blockhash_contract_address).map(|hash| (code, hash)));
let (code, code_hash) = match code_res {
Ok((code, hash)) => (code, hash),
Err(_) => return H256::zero(),
};
let params = ActionParams {
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 => {
@ -147,6 +174,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
},
}
}
}
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], address_scheme: CreateContractAddress) -> ContractCreateResult {
// create new contract address
@ -180,7 +208,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B>
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
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);
}
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) {
Ok(gas_left) => MessageCallResult::Success(gas_left),
@ -406,8 +434,7 @@ mod tests {
let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer;
let vm_factory = Default::default();
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 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);
assert_eq!(ext.env_info().number, 100);
}
@ -419,8 +446,7 @@ mod tests {
let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer;
let vm_factory = Default::default();
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 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 hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
@ -444,8 +470,7 @@ mod tests {
let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer;
let vm_factory = Default::default();
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 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 hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
@ -460,8 +485,7 @@ mod tests {
let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer;
let vm_factory = Default::default();
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 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 output = vec![];
@ -489,8 +513,7 @@ mod tests {
let mut vm_tracer = NoopVMTracer;
{
let vm_factory = Default::default();
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 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);
ext.log(log_topics, &log_data);
}
@ -507,8 +530,7 @@ mod tests {
let mut vm_tracer = NoopVMTracer;
{
let vm_factory = Default::default();
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 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);
ext.suicide(refund_account).unwrap();
}

View File

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

View File

@ -728,7 +728,7 @@ impl MinerService for Miner {
.map_err(ExecutionError::from)?;
}
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.
if let Some(original) = original_state {

View File

@ -470,7 +470,7 @@ impl Rebuilder for ChunkRebuilder {
db.boxed_clone(),
self.manifest.state_root.clone(),
engine.account_start_nonce(),
factories.clone(),
factories,
).map_err(|e| format!("State root mismatch: {}", e))?;
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 };
Executive::new(&mut state, &env_info, engine, &factories.vm)
Executive::new(&mut state, &env_info, engine)
.transact_virtual(&tx, options)
.map(|e| e.output)
.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 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 error::Error;
use ethereum;
@ -39,7 +39,8 @@ use types::executed::CallType;
use util::*;
/// Parameters common to all engines.
#[derive(Debug, PartialEq, Clone, Default)]
#[derive(Debug, PartialEq, Default)]
#[cfg_attr(test, derive(Clone))]
pub struct CommonParams {
/// Account start nonce.
pub account_start_nonce: U256,
@ -63,6 +64,14 @@ pub struct CommonParams {
pub eip86_transition: BlockNumber,
/// Number of first block where EIP-140 (Metropolis: REVERT opcode) rules begin.
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 {
@ -79,6 +88,12 @@ impl From<ethjson::spec::Params> for CommonParams {
validate_receipts_transition: p.validate_receipts_transition.map_or(0, 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),
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.
pub nodes: Vec<String>,
/// Parameters common to all engines.
pub params: CommonParams,
/// The genesis block's parent hash field.
pub parent_hash: H256,
/// The genesis block's author field.
@ -138,7 +150,6 @@ fn load_from(s: ethjson::spec::Spec) -> Result<Spec, Error> {
let mut s = Spec {
name: s.name.clone().into(),
params: params.clone(),
engine: Spec::engine(s.engine, params, builtins),
data_dir: s.data_dir.unwrap_or(s.name).into(),
nodes: s.nodes.unwrap_or_else(Vec::new),
@ -250,7 +261,7 @@ impl Spec {
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) {
warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
}
@ -275,17 +286,20 @@ impl Spec {
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.
pub fn nodes(&self) -> &[String] { &self.nodes }
/// 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.
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.
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.
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
// called anyway.
let db = self.run_constructors(factories, db)?;
Ok(db)
}

View File

@ -36,6 +36,7 @@ use types::executed::{Executed, ExecutionError};
use types::state_diff::StateDiff;
use transaction::SignedTransaction;
use state_db::StateDB;
use evm::{Factory as EvmFactory};
use util::*;
@ -310,6 +311,11 @@ impl<B: Backend> State<B> {
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.
// 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> {
@ -579,6 +585,7 @@ impl<B: Backend> State<B> {
/// 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<()> {
trace!(target: "state", "set_storage({}:{} to {})", a, key.hex(), value.hex());
if self.storage_at(a, &key)? != value {
self.require(a, false)?.set_storage(key, value)
}
@ -625,9 +632,7 @@ impl<B: Backend> State<B> {
-> Result<Executed, ExecutionError>
{
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, &vm_factory);
let mut e = Executive::new(self, env_info, engine);
match virt {
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.
/// `accounts` is mutable because we may need to commit the code or storage and record that.
#[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 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();
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 builtin::Builtin;
use state::*;
use evm::Schedule;
use evm::{Schedule, Factory as EvmFactory};
use factory::Factories;
use engines::Engine;
use ethereum;
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())
}
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 {
let db = new_db();
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.
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)]
#[cfg_attr(feature = "ipc", binary)]
/// Transaction action type.

View File

@ -17,7 +17,8 @@
//! Spec params deserialization.
use uint::Uint;
use hash::H256;
use hash::{H256, Address};
use bytes::Bytes;
/// Spec params.
#[derive(Debug, PartialEq, Deserialize)]
@ -62,6 +63,18 @@ pub struct Params {
/// See `CommonParams` docs.
#[serde(rename="eip140Transition")]
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)]