diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index b80d68317..ccf106521 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1354,8 +1354,7 @@ impl BlockChainClient for Client { .collect(); match (transaction, previous_receipts) { (Some(transaction), Some(previous_receipts)) => { - let schedule = self.engine().schedule(block_number); - Some(transaction_receipt(&schedule, transaction, previous_receipts)) + Some(transaction_receipt(self.engine(), transaction, previous_receipts)) }, _ => None, } @@ -1748,7 +1747,7 @@ impl Drop for Client { /// Returns `LocalizedReceipt` given `LocalizedTransaction` /// and a vector of receipts from given block up to transaction index. -fn transaction_receipt(schedule: &Schedule, mut tx: LocalizedTransaction, mut receipts: Vec) -> LocalizedReceipt { +fn transaction_receipt(engine: &Engine, mut tx: LocalizedTransaction, mut receipts: Vec) -> LocalizedReceipt { assert_eq!(receipts.len(), tx.transaction_index + 1, "All previous receipts are provided."); let sender = tx.sender(); @@ -1772,7 +1771,7 @@ fn transaction_receipt(schedule: &Schedule, mut tx: LocalizedTransaction, mut re gas_used: receipt.gas_used - prior_gas_used, contract_address: match tx.action { Action::Call(_) => None, - Action::Create => Some(contract_address(schedule.create_address, &sender, &tx.nonce, &tx.data.sha3())) + Action::Create => Some(contract_address(engine.create_address_scheme(block_number), &sender, &tx.nonce, &tx.data.sha3())) }, logs: receipt.logs.into_iter().enumerate().map(|(i, log)| LocalizedLogEntry { entry: log, @@ -1827,17 +1826,17 @@ mod tests { #[test] fn should_return_correct_log_index() { use super::transaction_receipt; - use evm::schedule::Schedule; use ethkey::KeyPair; use log_entry::{LogEntry, LocalizedLogEntry}; use receipt::{Receipt, LocalizedReceipt}; use transaction::{Transaction, LocalizedTransaction, Action}; use util::Hashable; + use tests::helpers::TestEngine; // given let key = KeyPair::from_secret_slice(&"test".sha3()).unwrap(); let secret = key.secret(); - let schedule = Schedule::new_homestead(); + let engine = TestEngine::new(0); let block_number = 1; let block_hash = 5.into(); @@ -1881,7 +1880,7 @@ mod tests { }]; // when - let receipt = transaction_receipt(&schedule, transaction, receipts); + let receipt = transaction_receipt(&engine, transaction, receipts); // then assert_eq!(receipt, LocalizedReceipt { diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index ae57976b4..7041048b8 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -48,6 +48,7 @@ use receipt::Receipt; use snapshot::SnapshotComponents; use spec::CommonParams; use transaction::{UnverifiedTransaction, SignedTransaction}; +use evm::CreateContractAddress; use ethkey::Signature; use util::*; @@ -294,4 +295,9 @@ pub trait Engine : Sync + Send { fn snapshot_components(&self) -> Option> { None } + + /// Returns new contract address generation scheme at given block number. + fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress { + if number >= self.params().eip86_transition { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce } + } } diff --git a/ethcore/src/evm/instructions.rs b/ethcore/src/evm/instructions.rs index 41c9e1ea1..eef1a9e3b 100644 --- a/ethcore/src/evm/instructions.rs +++ b/ethcore/src/evm/instructions.rs @@ -278,7 +278,7 @@ lazy_static! { arr[RETURN as usize] = InstructionInfo::new("RETURN", 0, 2, 0, true, GasPriceTier::Zero); arr[DELEGATECALL as usize] = InstructionInfo::new("DELEGATECALL", 0, 6, 1, true, GasPriceTier::Special); arr[SUICIDE as usize] = InstructionInfo::new("SUICIDE", 0, 1, 0, true, GasPriceTier::Special); - arr[CREATE_P2SH as usize] = InstructionInfo::new("CREATE_P2SH", 0, 3, 1, true, GasPriceTier::Special); + arr[CREATE2 as usize] = InstructionInfo::new("CREATE2", 0, 3, 1, true, GasPriceTier::Special); arr }; } @@ -555,7 +555,7 @@ pub const RETURN: Instruction = 0xf3; /// like CALLCODE but keeps caller's value and sender pub const DELEGATECALL: Instruction = 0xf4; /// create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160 -pub const CREATE_P2SH: Instruction = 0xfb; +pub const CREATE2: Instruction = 0xfb; /// halt execution and register account for later deletion pub const SUICIDE: Instruction = 0xff; diff --git a/ethcore/src/evm/interpreter/gasometer.rs b/ethcore/src/evm/interpreter/gasometer.rs index fb0c86d35..246c93bad 100644 --- a/ethcore/src/evm/interpreter/gasometer.rs +++ b/ethcore/src/evm/interpreter/gasometer.rs @@ -223,7 +223,7 @@ impl Gasometer { Request::GasMemProvide(gas, mem, Some(requested)) }, - instructions::CREATE | instructions::CREATE_P2SH => { + instructions::CREATE | instructions::CREATE2 => { let gas = Gas::from(schedule.create_gas); let mem = mem_needed(stack.peek(1), stack.peek(2))?; diff --git a/ethcore/src/evm/interpreter/mod.rs b/ethcore/src/evm/interpreter/mod.rs index 7fbab7ebc..f08737d24 100644 --- a/ethcore/src/evm/interpreter/mod.rs +++ b/ethcore/src/evm/interpreter/mod.rs @@ -183,7 +183,7 @@ impl Interpreter { let schedule = ext.schedule(); if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) || - (instruction == instructions::CREATE_P2SH && !schedule.have_create_p2sh) { + (instruction == instructions::CREATE2 && !schedule.have_create2) { return Err(evm::Error::BadInstruction { instruction: instruction @@ -268,12 +268,12 @@ impl Interpreter { instructions::JUMPDEST => { // ignore }, - instructions::CREATE | instructions::CREATE_P2SH => { + instructions::CREATE | instructions::CREATE2 => { let endowment = stack.pop_back(); let init_off = stack.pop_back(); let init_size = stack.pop_back(); - let address_scheme = if instruction == instructions::CREATE { ext.schedule().create_address } else { CreateContractAddress::FromSenderAndCodeHash }; + let address_scheme = if instruction == instructions::CREATE { CreateContractAddress::FromSenderAndNonce } else { CreateContractAddress::FromSenderAndCodeHash }; let create_gas = provided.expect("`provided` comes through Self::exec from `Gasometer::get_gas_cost_mem`; `gas_gas_mem_cost` guarantees `Some` when instruction is `CALL`/`CALLCODE`/`DELEGATECALL`/`CREATE`; this is `CREATE`; qed"); let contract_code = self.mem.read_slice(init_off, init_size); diff --git a/ethcore/src/evm/schedule.rs b/ethcore/src/evm/schedule.rs index 97df4d784..3e01f3925 100644 --- a/ethcore/src/evm/schedule.rs +++ b/ethcore/src/evm/schedule.rs @@ -15,7 +15,6 @@ // along with Parity. If not, see . //! Cost schedule and other parameterisations for the EVM. -use evm::CreateContractAddress; /// Definition of the cost schedule and other parameterisations for the EVM. pub struct Schedule { @@ -24,7 +23,7 @@ pub struct Schedule { /// Does it have a delegate cal pub have_delegate_call: bool, /// Does it have a CREATE_P2SH instruction - pub have_create_p2sh: bool, + pub have_create2: bool, /// VM stack limit pub stack_limit: usize, /// Max number of nested calls/creates @@ -102,8 +101,6 @@ pub struct Schedule { pub no_empty: bool, /// Kill empty accounts if touched. pub kill_empty: bool, - /// Contract address generation scheme - pub create_address: CreateContractAddress, } impl Schedule { @@ -118,11 +115,11 @@ impl Schedule { } /// Schedule for the post-EIP-150-era of the Ethereum main net. - pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, have_create_p2sh: bool) -> Schedule { + pub fn new_post_eip150(max_code_size: usize, fix_exp: bool, no_empty: bool, kill_empty: bool, have_metropolis_instructions: bool) -> Schedule { Schedule { exceptional_failed_code_deposit: true, have_delegate_call: true, - have_create_p2sh: have_create_p2sh, + have_create2: have_metropolis_instructions, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -161,7 +158,6 @@ impl Schedule { sub_gas_cap_divisor: Some(64), no_empty: no_empty, kill_empty: kill_empty, - create_address: if have_create_p2sh { CreateContractAddress::FromCodeHash } else { CreateContractAddress::FromSenderAndNonce }, } } @@ -174,7 +170,7 @@ impl Schedule { Schedule { exceptional_failed_code_deposit: efcd, have_delegate_call: hdc, - have_create_p2sh: false, + have_create2: false, stack_limit: 1024, max_depth: 1024, tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], @@ -213,7 +209,6 @@ impl Schedule { sub_gas_cap_divisor: None, no_empty: false, kill_empty: false, - create_address: CreateContractAddress::FromSenderAndNonce, } } } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 494d59db9..1974a6c8d 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -185,7 +185,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let (gas_left, output) = match t.action { Action::Create => { let code_hash = t.data.sha3(); - let new_address = contract_address(schedule.create_address, &sender, &nonce, &code_hash); + let new_address = contract_address(self.engine.create_address_scheme(self.info.number), &sender, &nonce, &code_hash); let params = ActionParams { code_address: new_address.clone(), code_hash: code_hash, @@ -386,8 +386,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { vm_tracer: &mut V, ) -> evm::Result where T: Tracer, V: VMTracer { - let schedule = self.engine.schedule(self.info.number); - if schedule.create_address != CreateContractAddress::FromSenderAndNonce && self.state.exists(¶ms.address)? { + let scheme = self.engine.create_address_scheme(self.info.number); + if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(¶ms.address)? { return Err(evm::Error::OutOfGas); } @@ -398,6 +398,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let mut unconfirmed_substate = Substate::new(); // create contract and transfer value to it if necessary + let schedule = self.engine.schedule(self.info.number); let nonce_offset = if schedule.no_empty {1} else {0}.into(); let prev_bal = self.state.balance(¶ms.address)?; if let ActionValue::Transfer(val) = params.value { diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index ed551e2f3..38e97f683 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1048,7 +1048,7 @@ impl MinerService for Miner { Action::Call(_) => None, Action::Create => { let sender = tx.sender(); - Some(contract_address(self.engine.schedule(pending.header().number()).create_address, &sender, &tx.nonce, &tx.data.sha3())) + Some(contract_address(self.engine.create_address_scheme(pending.header().number()), &sender, &tx.nonce, &tx.data.sha3())) } }, logs: receipt.logs.clone(), diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 639fac053..11ca9154f 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -433,6 +433,11 @@ impl State { self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null())) } + /// Determine whether an account exists and has code. + pub fn exists_and_has_code(&self, a: &Address) -> trie::Result { + self.ensure_cached(a, RequireCache::CodeSize, false, |a| a.map_or(false, |a| a.code_size().map_or(false, |size| size != 0))) + } + /// Get the balance of account `a`. pub fn balance(&self, a: &Address) -> trie::Result { self.ensure_cached(a, RequireCache::None, true,