diff --git a/ethcore/res/ethereum/metropolis_test.json b/ethcore/res/ethereum/metropolis_test.json index 9b367c9f4..76189e731 100644 --- a/ethcore/res/ethereum/metropolis_test.json +++ b/ethcore/res/ethereum/metropolis_test.json @@ -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": { diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index e19a7e27b..60c7531e4 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -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); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 5c43cee35..4cf1530ea 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -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, diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs index 2fd071062..1cc68596b 100644 --- a/ethcore/src/client/evm_test_client.rs +++ b/ethcore/src/client/evm_test_client.rs @@ -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, diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index bfb62d18c..a823e295f 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -413,7 +413,7 @@ impl BlockChainClient for TestBlockChainClient { fn nonce(&self, address: &Address, id: BlockId) -> Option { 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()) diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index b1e5a6b12..c6c41c5f8 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -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. diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index d38edd8d3..e0000f4cc 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -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) -> 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(block: &mut ExecutedBlock, last_hashes: Arc, 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(()) + } +} diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 87bc06152..98e274e9b 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -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> { diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index de53227de..6e698150b 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -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 { // 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) -> 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."); - } - } -// } + let state = block.fields_mut().state; + for child in &self.ethash_params.dao_hardfork_accounts { + let beneficiary = &self.ethash_params.dao_hardfork_beneficiary; + 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()); diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index 06be23ea5..523f98d18 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -82,16 +82,15 @@ impl From 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), + } } } diff --git a/ethcore/src/evm/ext.rs b/ethcore/src/evm/ext.rs index d2ef23159..fbdc3cec4 100644 --- a/ethcore/src/evm/ext.rs +++ b/ethcore/src/evm/ext.rs @@ -74,7 +74,7 @@ pub trait Ext { fn balance(&self, address: &Address) -> trie::Result; /// 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. /// diff --git a/ethcore/src/evm/interpreter/gasometer.rs b/ethcore/src/evm/interpreter/gasometer.rs index 8f2309fe2..4d8350e91 100644 --- a/ethcore/src/evm/interpreter/gasometer.rs +++ b/ethcore/src/evm/interpreter/gasometer.rs @@ -235,6 +235,9 @@ impl Gasometer { 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), }; diff --git a/ethcore/src/evm/schedule.rs b/ethcore/src/evm/schedule.rs index 2a3d0f70a..7fafb2e12 100644 --- a/ethcore/src/evm/schedule.rs +++ b/ethcore/src/evm/schedule.rs @@ -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, } } } diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 21a0fc378..b6e783c91 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -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, @@ -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(); diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index dd7abc6b5..36efdd2e7 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -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, 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, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory) -> Self { + pub fn new(state: &'a mut State, 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, info: &'a EnvInfo, engine: &'a Engine, vm_factory: &'a Factory, parent_depth: usize) -> Self { + pub fn from_parent(state: &'a mut State, 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(¶ms), 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(¶ms), 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() }; diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index d351f3cc4..25ed0d042 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -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, 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, 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 { 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) } - fn blockhash(&self, number: &U256) -> H256 { - // 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() - }, + 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 => { + 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 } } - 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(); } diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 37c7ebf50..86442179b 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -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 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, 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, 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 { 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 { 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 { 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 { &mut state, &info, &engine, - &vm_factory, 0, OriginInfo::from(¶ms), &mut substate, diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 101f26244..e5edc6d05 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -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 { diff --git a/ethcore/src/snapshot/consensus/authority.rs b/ethcore/src/snapshot/consensus/authority.rs index 4568700b9..0d7595c76 100644 --- a/ethcore/src/snapshot/consensus/authority.rs +++ b/ethcore/src/snapshot/consensus/authority.rs @@ -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)) diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 74805b233..915ff91b0 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -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 for CommonParams { @@ -79,6 +88,12 @@ impl From 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, - /// 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 { 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) } diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 384c0cca9..42289c3f8 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -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 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. // TODO: [rob] find a less hacky way to avoid duplication of `Client::state_at`. pub fn replace_backend(self, backend: T) -> State { @@ -579,6 +585,7 @@ impl State { /// 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 State { -> Result { 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 State { } } - /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// `accounts` is mutable because we may need to commit the code or storage and record that. #[cfg_attr(feature="dev", allow(match_ref_pats))] diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index b86c84a07..6aef92ec5 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -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()); diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 57b0adbea..ed77657ad 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -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); diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index 547be3136..016928a09 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -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. diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs index 5d5367791..e5029f4f2 100644 --- a/json/src/spec/params.rs +++ b/json/src/spec/params.rs @@ -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, + /// See `CommonParams` docs. + #[serde(rename="eip210Transition")] + pub eip210_transition: Option, + /// See `CommonParams` docs. + #[serde(rename="eip210ContractAddress")] + pub eip210_contract_address: Option
, + /// See `CommonParams` docs. + #[serde(rename="eip210ContractCode")] + pub eip210_contract_code: Option, + /// See `CommonParams` docs. + #[serde(rename="eip210ContractGas")] + pub eip210_contract_gas: Option, } #[cfg(test)]