From 4848c384cd22f35b89690b2b427f2ad9b1db189e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Mon, 23 Jul 2018 21:48:01 +0800 Subject: [PATCH] Avoid schedule copying in nested call/create (#9190) * Avoid schedule copying in nested call/create * Fix tests * fix test: wrong Schedule used * Fix private-tx test * Fix jsontests compilation --- ethcore/private-tx/src/lib.rs | 4 +- ethcore/src/client/client.rs | 11 +++- ethcore/src/client/evm_test_client.rs | 4 +- ethcore/src/executive.rs | 90 +++++++++++++++++---------- ethcore/src/externalities.rs | 39 +++++++----- ethcore/src/factory.rs | 6 +- ethcore/src/json_tests/executive.rs | 9 ++- ethcore/src/machine.rs | 3 +- ethcore/src/spec/spec.rs | 4 +- ethcore/src/state/mod.rs | 3 +- ethcore/src/tests/client.rs | 5 +- ethcore/src/tests/evm.rs | 6 +- 12 files changed, 117 insertions(+), 67 deletions(-) diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 0700a428b..a661197da 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -435,7 +435,9 @@ impl Provider where { let (new_address, _) = ethcore_contract_address(engine.create_address_scheme(env_info.number), &sender, &nonce, &transaction.data); Some(new_address) }); - let result = Executive::new(&mut state, &env_info, engine.machine()).transact_virtual(transaction, options)?; + let machine = engine.machine(); + let schedule = machine.schedule(env_info.number); + let result = Executive::new(&mut state, &env_info, &machine, &schedule).transact_virtual(transaction, options)?; let (encrypted_code, encrypted_storage) = match contract_address { None => bail!(ErrorKind::ContractDoesNotExist), Some(address) => { diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 56c71a86e..f8990e9c7 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -616,7 +616,9 @@ impl Importer { ).expect("state known to be available for just-imported block; qed"); let options = TransactOptions::with_no_tracing().dont_check_nonce(); - let res = Executive::new(&mut state, &env_info, self.engine.machine()) + let machine = self.engine.machine(); + let schedule = machine.schedule(env_info.number); + let res = Executive::new(&mut state, &env_info, &machine, &schedule) .transact(&transaction, options); let res = match res { @@ -1232,8 +1234,9 @@ impl Client { .dont_check_nonce() .save_output_from_contract(); let original_state = if state_diff { Some(state.clone()) } else { None }; + let schedule = machine.schedule(env_info.number); - let mut ret = Executive::new(state, env_info, machine).transact_virtual(transaction, options)?; + let mut ret = Executive::new(state, env_info, &machine, &schedule).transact_virtual(transaction, options)?; if let Some(original) = original_state { ret.state_diff = Some(state.diff_from(original).map_err(ExecutionError::from)?); @@ -1486,7 +1489,9 @@ impl Call for Client { let tx = tx.fake_sign(sender); let mut clone = state.clone(); - Ok(Executive::new(&mut clone, &env_info, self.engine.machine()) + let machine = self.engine.machine(); + let schedule = machine.schedule(env_info.number); + Ok(Executive::new(&mut clone, &env_info, &machine, &schedule) .transact_virtual(&tx, options()) .map(|r| r.exception.is_none()) .unwrap_or(false)) diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs index f11cae3b0..ace761723 100644 --- a/ethcore/src/client/evm_test_client.rs +++ b/ethcore/src/client/evm_test_client.rs @@ -184,7 +184,9 @@ impl<'a> EvmTestClient<'a> { }; let mut substate = state::Substate::new(); let mut output = vec![]; - let mut executive = executive::Executive::new(&mut self.state, &info, self.spec.engine.machine()); + let machine = self.spec.engine.machine(); + let schedule = machine.schedule(info.number); + let mut executive = executive::Executive::new(&mut self.state, &info, &machine, &schedule); executive.call( params, &mut substate, diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 37dc03dee..1243eeea3 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -21,11 +21,11 @@ use hash::keccak; use ethereum_types::{H256, U256, U512, Address}; use bytes::{Bytes, BytesRef}; use state::{Backend as StateBackend, State, Substate, CleanupMode}; -use machine::EthereumMachine as Machine; use error::ExecutionError; +use machine::EthereumMachine as Machine; use evm::{CallType, Finalize, FinalizationResult}; use vm::{ - self, Ext, EnvInfo, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, + self, EnvInfo, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, ActionValue, Schedule, }; use externalities::*; @@ -167,28 +167,31 @@ pub struct Executive<'a, B: 'a> { state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, + schedule: &'a Schedule, depth: usize, static_flag: bool, } impl<'a, B: 'a + StateBackend> Executive<'a, B> { /// Basic constructor. - pub fn new(state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine) -> Self { + pub fn new(state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, schedule: &'a Schedule) -> Self { Executive { state: state, info: info, machine: machine, + schedule: schedule, depth: 0, static_flag: false, } } /// Populates executive from parent properties. Increments executive depth. - pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, parent_depth: usize, static_flag: bool) -> Self { + pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, schedule: &'a Schedule, parent_depth: usize, static_flag: bool) -> Self { Executive { state: state, info: info, machine: machine, + schedule: schedule, depth: parent_depth + 1, static_flag: static_flag, } @@ -205,7 +208,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { static_call: bool, ) -> Externalities<'any, T, V, B> where T: Tracer, V: VMTracer { let is_static = self.static_flag || static_call; - Externalities::new(self.state, self.info, self.machine, self.depth, origin_info, substate, output, tracer, vm_tracer, is_static) + Externalities::new(self.state, self.info, self.machine, self.schedule, self.depth, origin_info, substate, output, tracer, vm_tracer, is_static) } /// This function should be used to execute transaction. @@ -244,7 +247,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let sender = t.sender(); let nonce = self.state.nonce(&sender)?; - let schedule = self.machine.schedule(self.info.number); + let schedule = self.schedule; let base_gas_required = U256::from(t.gas_required(&schedule)); if t.gas < base_gas_required { @@ -336,7 +339,6 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { fn exec_vm( &mut self, - schedule: Schedule, params: ActionParams, unconfirmed_substate: &mut Substate, output_policy: OutputPolicy, @@ -350,19 +352,22 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { // Ordinary execution - keep VM in same thread if self.depth != depth_threshold { let vm_factory = self.state.vm_factory(); + let wasm = self.schedule.wasm.is_some(); + trace!(target: "executive", "ext.schedule.have_delegate_call: {}", self.schedule.have_delegate_call); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); - trace!(target: "executive", "ext.schedule.have_delegate_call: {}", ext.schedule().have_delegate_call); - let mut vm = vm_factory.create(¶ms, &schedule); + let mut vm = vm_factory.create(¶ms, wasm); return vm.exec(params, &mut ext).finalize(ext); } // Start in new thread with stack size needed up to max depth crossbeam::scope(|scope| { let vm_factory = self.state.vm_factory(); + let max_depth = self.schedule.max_depth; + let wasm = self.schedule.wasm.is_some(); let mut ext = self.as_externalities(OriginInfo::from(¶ms), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); - scope.builder().stack_size(::std::cmp::max(schedule.max_depth.saturating_sub(depth_threshold) * STACK_SIZE_PER_DEPTH, local_stack_size)).spawn(move || { - let mut vm = vm_factory.create(¶ms, &schedule); + scope.builder().stack_size(::std::cmp::max(max_depth.saturating_sub(depth_threshold) * STACK_SIZE_PER_DEPTH, local_stack_size)).spawn(move || { + let mut vm = vm_factory.create(¶ms, wasm); vm.exec(params, &mut ext).finalize(ext) }).expect("Sub-thread creation cannot fail; the host might run out of resources; qed") }).join() @@ -392,7 +397,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { // backup used in case of running out of gas self.state.checkpoint(); - let schedule = self.machine.schedule(self.info.number); + let schedule = self.schedule; // at first, transfer value to destination if let ActionValue::Transfer(val) = params.value { @@ -479,7 +484,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("scope is conditional on params.code.is_some(); qed")); let res = { - self.exec_vm(schedule, params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer) + self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()), &mut subtracer, &mut subvmtracer) }; vm_tracer.done_subtrace(subvmtracer); @@ -552,7 +557,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.machine.schedule(self.info.number); + let schedule = self.schedule; 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 { @@ -571,7 +576,6 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed")); let res = self.exec_vm( - schedule, params, &mut unconfirmed_substate, OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), @@ -607,7 +611,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { trace: Vec, vm_trace: Option ) -> Result, ExecutionError> { - let schedule = self.machine.schedule(self.info.number); + let schedule = self.schedule; // refunds from SSTORE nonzero -> zero let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.sstore_clears_count; @@ -756,10 +760,11 @@ mod tests { state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -813,10 +818,11 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -855,11 +861,12 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_byzantium_machine(5); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap(); @@ -939,12 +946,13 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(5); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap() }; @@ -1055,12 +1063,13 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = ::ethereum::new_byzantium_test_machine(); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let output = BytesRef::Fixed(&mut[0u8;0]); ex.call(params, &mut substate, output, &mut tracer, &mut vm_tracer).unwrap() }; @@ -1127,12 +1136,13 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(5); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut tracer = ExecutiveTracer::default(); let mut vm_tracer = ExecutiveVMTracer::toplevel(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params.clone(), &mut substate, &mut None, &mut tracer, &mut vm_tracer).unwrap() }; @@ -1214,10 +1224,11 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1265,10 +1276,11 @@ mod tests { state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(1024); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap(); } @@ -1325,10 +1337,11 @@ mod tests { let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1369,10 +1382,11 @@ mod tests { state.init_code(&address, code).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let FinalizationResult { gas_left, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params, &mut substate, BytesRef::Fixed(&mut []), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1402,9 +1416,10 @@ mod tests { let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let executed = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let opts = TransactOptions::with_no_tracing(); ex.transact(&t, opts).unwrap() }; @@ -1439,9 +1454,10 @@ mod tests { let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let res = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let opts = TransactOptions::with_no_tracing(); ex.transact(&t, opts) }; @@ -1472,9 +1488,10 @@ mod tests { info.gas_used = U256::from(20_000); info.gas_limit = U256::from(100_000); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let res = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let opts = TransactOptions::with_no_tracing(); ex.transact(&t, opts) }; @@ -1505,9 +1522,10 @@ mod tests { let mut info = EnvInfo::default(); info.gas_limit = U256::from(100_000); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let res = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); let opts = TransactOptions::with_no_tracing(); ex.transact(&t, opts) }; @@ -1538,10 +1556,11 @@ mod tests { state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); let machine = make_frontier_machine(0); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let result = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) }; @@ -1571,11 +1590,12 @@ mod tests { params.value = ActionValue::Transfer(U256::zero()); let info = EnvInfo::default(); let machine = ::ethereum::new_byzantium_test_machine(); + let schedule = machine.schedule(info.number); let mut substate = Substate::new(); let mut output = [0u8; 14]; let FinalizationResult { gas_left: result, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1618,7 +1638,8 @@ mod tests { let mut output = [0u8; 20]; let FinalizationResult { gas_left: result, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let schedule = machine.schedule(info.number); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params.clone(), &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; @@ -1631,7 +1652,8 @@ mod tests { let mut output = [0u8; 20]; let FinalizationResult { gas_left: result, .. } = { - let mut ex = Executive::new(&mut state, &info, &machine); + let schedule = machine.schedule(info.number); + let mut ex = Executive::new(&mut state, &info, &machine, &schedule); ex.call(params, &mut Substate::new(), BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer).unwrap() }; diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index d315122d5..9aa308a23 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -66,11 +66,11 @@ impl OriginInfo { pub struct Externalities<'a, T: 'a, V: 'a, B: 'a> { state: &'a mut State, env_info: &'a EnvInfo, - machine: &'a Machine, depth: usize, origin_info: OriginInfo, substate: &'a mut Substate, - schedule: Schedule, + machine: &'a Machine, + schedule: &'a Schedule, output: OutputPolicy<'a, 'a>, tracer: &'a mut T, vm_tracer: &'a mut V, @@ -81,9 +81,11 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B> where T: Tracer, V: VMTracer, B: StateBackend { /// Basic `Externalities` constructor. - pub fn new(state: &'a mut State, + pub fn new( + state: &'a mut State, env_info: &'a EnvInfo, machine: &'a Machine, + schedule: &'a Schedule, depth: usize, origin_info: OriginInfo, substate: &'a mut Substate, @@ -95,11 +97,11 @@ impl<'a, T: 'a, V: 'a, B: 'a> Externalities<'a, T, V, B> Externalities { state: state, env_info: env_info, - machine: machine, depth: depth, origin_info: origin_info, substate: substate, - schedule: machine.schedule(env_info.number), + machine: machine, + schedule: schedule, output: output, tracer: tracer, vm_tracer: vm_tracer, @@ -170,7 +172,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> }; let mut output = H256::new(); - let mut ex = Executive::new(self.state, self.env_info, self.machine); + let mut ex = Executive::new(self.state, self.env_info, self.machine, self.schedule); 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 @@ -226,7 +228,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> } } } - let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.depth, self.static_flag); + let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.schedule, self.depth, self.static_flag); // TODO: handle internal error separately match ex.create(params, self.substate, &mut None, self.tracer, self.vm_tracer) { @@ -280,7 +282,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.machine, self.depth, self.static_flag); + let mut ex = Executive::from_parent(self.state, self.env_info, self.machine, self.schedule, self.depth, self.static_flag); match ex.call(params, self.substate, BytesRef::Fixed(output), self.tracer, self.vm_tracer) { Ok(FinalizationResult{ gas_left, return_data, apply_state: true }) => MessageCallResult::Success(gas_left, return_data), @@ -440,6 +442,7 @@ mod tests { struct TestSetup { state: State<::state_db::StateDB>, machine: ::machine::EthereumMachine, + schedule: Schedule, sub_state: Substate, env_info: EnvInfo } @@ -452,11 +455,15 @@ mod tests { impl TestSetup { fn new() -> Self { + let machine = ::spec::Spec::new_test_machine(); + let env_info = get_test_env_info(); + let schedule = machine.schedule(env_info.number); TestSetup { state: get_temp_state(), - machine: ::spec::Spec::new_test_machine(), + schedule: schedule, + machine: machine, sub_state: Substate::new(), - env_info: get_test_env_info() + env_info: env_info, } } } @@ -468,7 +475,7 @@ mod tests { let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; - let ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); assert_eq!(ext.env_info().number, 100); } @@ -480,7 +487,7 @@ mod tests { let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::().unwrap()); @@ -504,7 +511,7 @@ mod tests { let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::().unwrap()); @@ -519,7 +526,7 @@ mod tests { let mut tracer = NoopTracer; let mut vm_tracer = NoopVMTracer; - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); let mut output = vec![]; @@ -547,7 +554,7 @@ mod tests { let mut vm_tracer = NoopVMTracer; { - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); ext.log(log_topics, &log_data).unwrap(); } @@ -564,7 +571,7 @@ mod tests { let mut vm_tracer = NoopVMTracer; { - let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); + let mut ext = Externalities::new(state, &setup.env_info, &setup.machine, &setup.schedule, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false); ext.suicide(refund_account).unwrap(); } diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index 2eff7d760..c6b9b0f6d 100644 --- a/ethcore/src/factory.rs +++ b/ethcore/src/factory.rs @@ -18,7 +18,7 @@ use trie::TrieFactory; use ethtrie::RlpCodec; use account_db::Factory as AccountFactory; use evm::{Factory as EvmFactory, VMType}; -use vm::{Vm, ActionParams, Schedule}; +use vm::{Vm, ActionParams}; use wasm::WasmInterpreter; use keccak_hasher::KeccakHasher; @@ -31,8 +31,8 @@ pub struct VmFactory { } impl VmFactory { - pub fn create(&self, params: &ActionParams, schedule: &Schedule) -> Box { - if schedule.wasm.is_some() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { + pub fn create(&self, params: &ActionParams, wasm: bool) -> Box { + if wasm && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { Box::new(WasmInterpreter) } else { self.evm.create(¶ms.gas) diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index daeed18eb..3fc14be2a 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -86,6 +86,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B> state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, + schedule: &'a Schedule, depth: usize, origin_info: OriginInfo, substate: &'a mut Substate, @@ -97,7 +98,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B> let static_call = false; Ok(TestExt { nonce: state.nonce(&address)?, - ext: Externalities::new(state, info, machine, depth, origin_info, substate, output, tracer, vm_tracer, static_call), + ext: Externalities::new(state, info, machine, schedule, depth, origin_info, substate, output, tracer, vm_tracer, static_call), callcreates: vec![], sender: address, }) @@ -245,7 +246,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8] let out_of_gas = vm.out_of_gas(); let mut state = get_temp_state(); state.populate_from(From::from(vm.pre_state.clone())); - let info = From::from(vm.env); + let info: EnvInfo = From::from(vm.env); let machine = { let mut machine = ::ethereum::new_frontier_test_machine(); machine.set_schedule_creation_rules(Box::new(move |s, _| s.max_depth = 1)); @@ -262,10 +263,12 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8] // execute let (res, callcreates) = { + let schedule = machine.schedule(info.number); let mut ex = try_fail!(TestExt::new( &mut state, &info, &machine, + &schedule, 0, OriginInfo::from(¶ms), &mut substate, @@ -274,7 +277,7 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8] &mut tracer, &mut vm_tracer, )); - let mut evm = vm_factory.create(¶ms, &machine.schedule(0u64.into())); + let mut evm = vm_factory.create(¶ms, schedule.wasm.is_some()); let res = evm.exec(params, &mut ex); // a return in finalize will not alter callcreates let callcreates = ex.callcreates.clone(); diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index dbf66aa12..633f837dc 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -145,7 +145,8 @@ impl EthereumMachine { call_type: CallType::Call, params_type: ParamsType::Separate, }; - let mut ex = Executive::new(&mut state, &env_info, self); + let schedule = self.schedule(env_info.number); + let mut ex = Executive::new(&mut state, &env_info, self, &schedule); let mut substate = Substate::new(); let mut output = Vec::new(); if let Err(e) = ex.call(params, &mut substate, BytesRef::Flexible(&mut output), &mut NoopTracer, &mut NoopVMTracer) { diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 2b3e1e265..015755f83 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -631,7 +631,9 @@ impl Spec { let mut substate = Substate::new(); { - let mut exec = Executive::new(&mut state, &env_info, self.engine.machine()); + let machine = self.engine.machine(); + let schedule = machine.schedule(env_info.number); + let mut exec = Executive::new(&mut state, &env_info, &machine, &schedule); if let Err(e) = exec.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) { warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e); } diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 0da614254..796ec0c1d 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -745,7 +745,8 @@ impl State { fn execute(&mut self, env_info: &EnvInfo, machine: &Machine, t: &SignedTransaction, options: TransactOptions, virt: bool) -> Result, ExecutionError> where T: trace::Tracer, V: trace::VMTracer, { - let mut e = Executive::new(self, env_info, machine); + let schedule = machine.schedule(env_info.number); + let mut e = Executive::new(self, env_info, machine, &schedule); match virt { true => e.transact_virtual(t, options), diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index 0b8f2c4fa..a7629313d 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -373,8 +373,11 @@ fn transaction_proof() { factories.accountdb = ::account_db::Factory::Plain; // raw state values, no mangled keys. let root = *client.best_block_header().state_root(); + let machine = test_spec.engine.machine(); + let env_info = client.latest_env_info(); + let schedule = machine.schedule(env_info.number); let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap(); - Executive::new(&mut state, &client.latest_env_info(), test_spec.engine.machine()) + Executive::new(&mut state, &env_info, &machine, &schedule) .transact(&transaction, TransactOptions::with_no_tracing().dont_check_nonce()).unwrap(); assert_eq!(state.balance(&Address::default()).unwrap(), 5.into()); diff --git a/ethcore/src/tests/evm.rs b/ethcore/src/tests/evm.rs index 4f4ad4241..239905fac 100644 --- a/ethcore/src/tests/evm.rs +++ b/ethcore/src/tests/evm.rs @@ -62,7 +62,8 @@ fn test_blockhash_eip210(factory: Factory) { call_type: CallType::Call, params_type: ParamsType::Separate, }; - let mut ex = Executive::new(&mut state, &env_info, &machine); + let schedule = machine.schedule(env_info.number); + let mut ex = Executive::new(&mut state, &env_info, &machine, &schedule); 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) { @@ -85,7 +86,8 @@ fn test_blockhash_eip210(factory: Factory) { call_type: CallType::Call, params_type: ParamsType::Separate, }; - let mut ex = Executive::new(&mut state, &env_info, &machine); + let schedule = machine.schedule(env_info.number); + let mut ex = Executive::new(&mut state, &env_info, &machine, &schedule); 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) {