From 3850eaeaee6659360fea77e50b6027259939d09a Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 18:18:25 +0800 Subject: [PATCH 01/21] Feed in ActionParams on VM creation --- ethcore/evm/Cargo.toml | 1 + ethcore/evm/src/factory.rs | 9 +- ethcore/evm/src/interpreter/mod.rs | 134 ++++++++++++++++++++--------- ethcore/evm/src/lib.rs | 1 + ethcore/vm/src/lib.rs | 2 +- ethcore/wasm/src/lib.rs | 26 ++++-- 6 files changed, 116 insertions(+), 57 deletions(-) diff --git a/ethcore/evm/Cargo.toml b/ethcore/evm/Cargo.toml index 654f7879a1c..2f41e06f817 100644 --- a/ethcore/evm/Cargo.toml +++ b/ethcore/evm/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Parity Technologies "] [dependencies] bit-set = "0.4" +ethcore-bytes = { path = "../../util/bytes" } ethereum-types = "0.3" heapsize = "0.4" lazy_static = "1.0" diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index 65a683cd4a8..3a66dfa085a 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -19,6 +19,7 @@ use std::sync::Arc; use vm::Vm; use ethereum_types::U256; +use super::vm::ActionParams; use super::interpreter::SharedCache; use super::vmtype::VMType; @@ -32,12 +33,12 @@ pub struct Factory { impl Factory { /// Create fresh instance of VM /// Might choose implementation depending on supplied gas. - pub fn create(&self, gas: &U256) -> Box { + pub fn create(&self, params: ActionParams) -> Box { match self.evm { - VMType::Interpreter => if Self::can_fit_in_usize(gas) { - Box::new(super::interpreter::Interpreter::::new(self.evm_cache.clone())) + VMType::Interpreter => if Self::can_fit_in_usize(¶ms.gas) { + Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone())) } else { - Box::new(super::interpreter::Interpreter::::new(self.evm_cache.clone())) + Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone())) } } } diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 1119869138c..2fe5285cf0a 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -27,10 +27,11 @@ use std::marker::PhantomData; use std::{cmp, mem}; use std::sync::Arc; use hash::keccak; +use bytes::Bytes; use ethereum_types::{U256, U512, H256, Address}; use vm::{ - self, ActionParams, ActionValue, CallType, MessageCallResult, + self, ActionParams, ParamsType, ActionValue, CallType, MessageCallResult, ContractCreateResult, CreateContractAddress, ReturnData, GasLeft }; @@ -58,17 +59,17 @@ const TWO_POW_224: U256 = U256([0, 0, 0, 0x100000000]); //0x1 00000000 00000000 const TWO_POW_248: U256 = U256([0, 0, 0, 0x100000000000000]); //0x1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000 /// Abstraction over raw vector of Bytes. Easier state management of PC. -struct CodeReader<'a> { +struct CodeReader { position: ProgramCounter, - code: &'a [u8] + code: Arc, } -impl<'a> CodeReader<'a> { +impl CodeReader { /// Create new code reader - starting at position 0. - fn new(code: &'a [u8]) -> Self { + fn new(code: Arc) -> Self { CodeReader { + code, position: 0, - code: code, } } @@ -102,36 +103,82 @@ enum InstructionResult { StopExecution, } +/// ActionParams without code, so that it can be feed into CodeReader. +#[derive(Debug)] +struct InterpreterParams { + /// Address of currently executed code. + pub code_address: Address, + /// Hash of currently executed code. + pub code_hash: Option, + /// Receive address. Usually equal to code_address, + /// except when called using CALLCODE. + pub address: Address, + /// Sender of current part of the transaction. + pub sender: Address, + /// Transaction initiator. + pub origin: Address, + /// Gas paid up front for transaction execution + pub gas: U256, + /// Gas price. + pub gas_price: U256, + /// Transaction value. + pub value: ActionValue, + /// Input data. + pub data: Option, + /// Type of call + pub call_type: CallType, + /// Param types encoding + pub params_type: ParamsType, +} + +impl From for InterpreterParams { + fn from(params: ActionParams) -> Self { + InterpreterParams { + code_address: params.code_address, + code_hash: params.code_hash, + address: params.address, + sender: params.sender, + origin: params.origin, + gas: params.gas, + gas_price: params.gas_price, + value: params.value, + data: params.data, + call_type: params.call_type, + params_type: params.params_type, + } + } +} + /// Intepreter EVM implementation pub struct Interpreter { mem: Vec, cache: Arc, + params: InterpreterParams, + reader: CodeReader, return_data: ReturnData, _type: PhantomData, } impl vm::Vm for Interpreter { - fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result { + fn exec(&mut self, ext: &mut vm::Ext) -> vm::Result { self.mem.clear(); let mut informant = informant::EvmInformant::new(ext.depth()); let mut do_trace = true; - let code = ¶ms.code.as_ref().expect("exec always called with code; qed"); let mut valid_jump_destinations = None; - let mut gasometer = Gasometer::::new(Cost::from_u256(params.gas)?); + let mut gasometer = Gasometer::::new(Cost::from_u256(self.params.gas)?); let mut stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero()); - let mut reader = CodeReader::new(code); - while reader.position < code.len() { - let opcode = code[reader.position]; + while self.reader.position < self.reader.len() { + let opcode = self.reader.code[self.reader.position]; let instruction = Instruction::from_u8(opcode); - reader.position += 1; + self.reader.position += 1; // TODO: make compile-time removable if too much of a performance hit. do_trace = do_trace && ext.trace_next_instruction( - reader.position - 1, opcode, gasometer.current_gas.as_u256(), + self.reader.position - 1, opcode, gasometer.current_gas.as_u256(), ); if instruction.is_none() { @@ -147,7 +194,7 @@ impl vm::Vm for Interpreter { // Calculate gas cost let requirements = gasometer.requirements(ext, instruction, info, &stack, self.mem.size())?; if do_trace { - ext.trace_prepare_execute(reader.position - 1, opcode, requirements.gas_cost.as_u256()); + ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256()); } gasometer.verify_gas(&requirements.gas_cost)?; @@ -164,7 +211,7 @@ impl vm::Vm for Interpreter { // Execute instruction let result = self.exec_instruction( - gasometer.current_gas, ¶ms, ext, instruction, &mut reader, &mut stack, requirements.provide_gas + gasometer.current_gas, ext, instruction, &mut stack, requirements.provide_gas )?; evm_debug!({ informant.after_instruction(instruction) }); @@ -186,12 +233,12 @@ impl vm::Vm for Interpreter { match result { InstructionResult::JumpToPosition(position) => { if valid_jump_destinations.is_none() { - let code_hash = params.code_hash.clone().unwrap_or_else(|| keccak(code.as_ref())); - valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, code)); + let code_hash = self.params.code_hash.clone().unwrap_or_else(|| keccak(self.reader.code.as_ref())); + valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, &self.reader.code)); } let jump_destinations = valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed"); let pos = self.verify_jump(position, jump_destinations)?; - reader.position = pos; + self.reader.position = pos; }, InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { informant.done(); @@ -213,12 +260,15 @@ impl vm::Vm for Interpreter { impl Interpreter { /// Create a new `Interpreter` instance with shared cache. - pub fn new(cache: Arc) -> Interpreter { + pub fn new(mut params: ActionParams, cache: Arc) -> Interpreter { + let reader = CodeReader::new(params.code.take().expect("VM always called with code; qed")); + let params = params.into(); + Interpreter { + cache, params, reader, mem: Vec::new(), - cache: cache, return_data: ReturnData::empty(), - _type: PhantomData::default(), + _type: PhantomData, } } @@ -288,10 +338,8 @@ impl Interpreter { fn exec_instruction( &mut self, gas: Cost, - params: &ActionParams, ext: &mut vm::Ext, instruction: Instruction, - code: &mut CodeReader, stack: &mut Stack, provided: Option ) -> vm::Result> { @@ -328,7 +376,7 @@ impl Interpreter { // clear return data buffer before creating new call frame. self.return_data = ReturnData::empty(); - let can_create = ext.balance(¶ms.address)? >= endowment && ext.depth() < ext.schedule().max_depth; + let can_create = ext.balance(&self.params.address)? >= endowment && ext.depth() < ext.schedule().max_depth; if !can_create { stack.push(U256::zero()); return Ok(InstructionResult::UnusedGas(create_gas)); @@ -387,15 +435,15 @@ impl Interpreter { if ext.is_static() && value.map_or(false, |v| !v.is_zero()) { return Err(vm::Error::MutableCallInStaticContext); } - let has_balance = ext.balance(¶ms.address)? >= value.expect("value set for all but delegate call; qed"); - (¶ms.address, &code_address, has_balance, CallType::Call) + let has_balance = ext.balance(&self.params.address)? >= value.expect("value set for all but delegate call; qed"); + (&self.params.address, &code_address, has_balance, CallType::Call) }, instructions::CALLCODE => { - let has_balance = ext.balance(¶ms.address)? >= value.expect("value set for all but delegate call; qed"); - (¶ms.address, ¶ms.address, has_balance, CallType::CallCode) + let has_balance = ext.balance(&self.params.address)? >= value.expect("value set for all but delegate call; qed"); + (&self.params.address, &self.params.address, has_balance, CallType::CallCode) }, - instructions::DELEGATECALL => (¶ms.sender, ¶ms.address, true, CallType::DelegateCall), - instructions::STATICCALL => (¶ms.address, &code_address, true, CallType::StaticCall), + instructions::DELEGATECALL => (&self.params.sender, &self.params.address, true, CallType::DelegateCall), + instructions::STATICCALL => (&self.params.address, &code_address, true, CallType::StaticCall), _ => panic!(format!("Unexpected instruction {:?} in CALL branch.", instruction)) }; @@ -473,7 +521,7 @@ impl Interpreter { instructions::PUSH25 | instructions::PUSH26 | instructions::PUSH27 | instructions::PUSH28 | instructions::PUSH29 | instructions::PUSH30 | instructions::PUSH31 | instructions::PUSH32 => { let bytes = instruction.push_bytes().expect("push_bytes always return some for PUSH* instructions"); - let val = code.read(bytes); + let val = self.reader.read(bytes); stack.push(val); }, instructions::MLOAD => { @@ -516,16 +564,16 @@ impl Interpreter { ext.set_storage(address, H256::from(&val))?; }, instructions::PC => { - stack.push(U256::from(code.position - 1)); + stack.push(U256::from(self.reader.position - 1)); }, instructions::GAS => { stack.push(gas.as_u256()); }, instructions::ADDRESS => { - stack.push(address_to_u256(params.address.clone())); + stack.push(address_to_u256(self.params.address.clone())); }, instructions::ORIGIN => { - stack.push(address_to_u256(params.origin.clone())); + stack.push(address_to_u256(self.params.origin.clone())); }, instructions::BALANCE => { let address = u256_to_address(&stack.pop_back()); @@ -533,10 +581,10 @@ impl Interpreter { stack.push(balance); }, instructions::CALLER => { - stack.push(address_to_u256(params.sender.clone())); + stack.push(address_to_u256(self.params.sender.clone())); }, instructions::CALLVALUE => { - stack.push(match params.value { + stack.push(match self.params.value { ActionValue::Transfer(val) | ActionValue::Apparent(val) => val }); }, @@ -544,7 +592,7 @@ impl Interpreter { let big_id = stack.pop_back(); let id = big_id.low_u64() as usize; let max = id.wrapping_add(32); - if let Some(data) = params.data.as_ref() { + if let Some(data) = self.params.data.as_ref() { let bound = cmp::min(data.len(), max); if id < bound && big_id < U256::from(data.len()) { let mut v = [0u8; 32]; @@ -558,10 +606,10 @@ impl Interpreter { } }, instructions::CALLDATASIZE => { - stack.push(U256::from(params.data.clone().map_or(0, |l| l.len()))); + stack.push(U256::from(self.params.data.as_ref().map_or(0, |l| l.len()))); }, instructions::CODESIZE => { - stack.push(U256::from(code.len())); + stack.push(U256::from(self.reader.len())); }, instructions::RETURNDATASIZE => { stack.push(U256::from(self.return_data.len())) @@ -572,7 +620,7 @@ impl Interpreter { stack.push(U256::from(len)); }, instructions::CALLDATACOPY => { - Self::copy_data_to_memory(&mut self.mem, stack, params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); + Self::copy_data_to_memory(&mut self.mem, stack, &self.params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); }, instructions::RETURNDATACOPY => { { @@ -586,7 +634,7 @@ impl Interpreter { Self::copy_data_to_memory(&mut self.mem, stack, &*self.return_data); }, instructions::CODECOPY => { - Self::copy_data_to_memory(&mut self.mem, stack, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8])); + Self::copy_data_to_memory(&mut self.mem, stack, &self.reader.code); }, instructions::EXTCODECOPY => { let address = u256_to_address(&stack.pop_back()); @@ -594,7 +642,7 @@ impl Interpreter { Self::copy_data_to_memory(&mut self.mem, stack, &code); }, instructions::GASPRICE => { - stack.push(params.gas_price.clone()); + stack.push(self.params.gas_price.clone()); }, instructions::BLOCKHASH => { let block_number = stack.pop_back(); diff --git a/ethcore/evm/src/lib.rs b/ethcore/evm/src/lib.rs index cd326a317ec..b79155f00f9 100644 --- a/ethcore/evm/src/lib.rs +++ b/ethcore/evm/src/lib.rs @@ -23,6 +23,7 @@ extern crate heapsize; extern crate vm; extern crate keccak_hash as hash; extern crate memory_cache; +extern crate ethcore_bytes as bytes; #[macro_use] extern crate lazy_static; diff --git a/ethcore/vm/src/lib.rs b/ethcore/vm/src/lib.rs index 658420f74e3..1723f9e0ae1 100644 --- a/ethcore/vm/src/lib.rs +++ b/ethcore/vm/src/lib.rs @@ -48,5 +48,5 @@ pub trait Vm { /// This function should be used to execute transaction. /// It returns either an error, a known amount of gas left, or parameters to be used /// to compute the final gas left. - fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result; + fn exec(&mut self, ext: &mut Ext) -> Result; } diff --git a/ethcore/wasm/src/lib.rs b/ethcore/wasm/src/lib.rs index f1290318e0f..4c8e4af2cce 100644 --- a/ethcore/wasm/src/lib.rs +++ b/ethcore/wasm/src/lib.rs @@ -69,7 +69,15 @@ impl From for vm::Error { } /// Wasm interpreter instance -pub struct WasmInterpreter; +pub struct WasmInterpreter { + params: ActionParams, +} + +impl WasmInterpreter { + pub fn new(params: ActionParams) -> Self { + WasmInterpreter { params } + } +} impl From for vm::Error { fn from(e: runtime::Error) -> Self { @@ -85,8 +93,8 @@ enum ExecutionOutcome { impl vm::Vm for WasmInterpreter { - fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result { - let (module, data) = parser::payload(¶ms, ext.schedule().wasm())?; + fn exec(&mut self, ext: &mut vm::Ext) -> vm::Result { + let (module, data) = parser::payload(&self.params, ext.schedule().wasm())?; let loaded_module = wasmi::Module::from_parity_wasm_module(module).map_err(Error::Interpreter)?; @@ -97,7 +105,7 @@ impl vm::Vm for WasmInterpreter { &wasmi::ImportsBuilder::new().with_resolver("env", &instantiation_resolver) ).map_err(Error::Interpreter)?; - let adjusted_gas = params.gas * U256::from(ext.schedule().wasm().opcodes_div) / + let adjusted_gas = self.params.gas * U256::from(ext.schedule().wasm().opcodes_div) / U256::from(ext.schedule().wasm().opcodes_mul); if adjusted_gas > ::std::u64::MAX.into() @@ -116,11 +124,11 @@ impl vm::Vm for WasmInterpreter { adjusted_gas.low_u64(), data.to_vec(), RuntimeContext { - address: params.address, - sender: params.sender, - origin: params.origin, - code_address: params.code_address, - value: params.value.value(), + address: self.params.address, + sender: self.params.sender, + origin: self.params.origin, + code_address: self.params.code_address, + value: self.params.value.value(), }, ); From 73f58ea1cf0b70e1fd30266df7387c5c7280f866 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 18:22:31 +0800 Subject: [PATCH 02/21] Fix ethcore after Vm interface change --- ethcore/src/executive.rs | 8 ++++---- ethcore/src/factory.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index f375f3c2e88..83eeb5d256c 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -352,8 +352,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let vm_factory = self.state.vm_factory(); 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); - return vm.exec(params, &mut ext).finalize(ext); + let mut vm = vm_factory.create(params, &schedule); + return vm.exec(&mut ext).finalize(ext); } // Start in new thread with stack size needed up to max depth @@ -362,8 +362,8 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { 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); - vm.exec(params, &mut ext).finalize(ext) + let mut vm = vm_factory.create(params, &schedule); + vm.exec(&mut ext).finalize(ext) }).expect("Sub-thread creation cannot fail; the host might run out of resources; qed") }).join() } diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index 2eff7d7605a..2304c171732 100644 --- a/ethcore/src/factory.rs +++ b/ethcore/src/factory.rs @@ -31,11 +31,11 @@ pub struct VmFactory { } impl VmFactory { - pub fn create(&self, params: &ActionParams, schedule: &Schedule) -> Box { + 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) { - Box::new(WasmInterpreter) + Box::new(WasmInterpreter::new(params)) } else { - self.evm.create(¶ms.gas) + self.evm.create(params) } } From db4f030ff3e9a398188bd6b0ddfa2281292e4f1e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 18:31:20 +0800 Subject: [PATCH 03/21] Move informant inside Interpreter struct --- ethcore/evm/src/factory.rs | 8 ++++---- ethcore/evm/src/interpreter/mod.rs | 11 ++++++----- ethcore/src/executive.rs | 4 ++-- ethcore/src/factory.rs | 8 ++++---- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index 3a66dfa085a..5aaa7fc6e14 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -17,7 +17,7 @@ //! Evm factory. //! use std::sync::Arc; -use vm::Vm; +use vm::{self, Vm}; use ethereum_types::U256; use super::vm::ActionParams; use super::interpreter::SharedCache; @@ -33,12 +33,12 @@ pub struct Factory { impl Factory { /// Create fresh instance of VM /// Might choose implementation depending on supplied gas. - pub fn create(&self, params: ActionParams) -> Box { + pub fn create(&self, params: ActionParams, ext: &vm::Ext) -> Box { match self.evm { VMType::Interpreter => if Self::can_fit_in_usize(¶ms.gas) { - Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone())) + Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), ext)) } else { - Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone())) + Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), ext)) } } } diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 2fe5285cf0a..44d20acd4b6 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -156,6 +156,7 @@ pub struct Interpreter { params: InterpreterParams, reader: CodeReader, return_data: ReturnData, + informant: informant::EvmInformant, _type: PhantomData, } @@ -163,7 +164,6 @@ impl vm::Vm for Interpreter { fn exec(&mut self, ext: &mut vm::Ext) -> vm::Result { self.mem.clear(); - let mut informant = informant::EvmInformant::new(ext.depth()); let mut do_trace = true; let mut valid_jump_destinations = None; @@ -241,7 +241,7 @@ impl vm::Vm for Interpreter { self.reader.position = pos; }, InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { - informant.done(); + self.informant.done(); let mem = mem::replace(&mut self.mem, Vec::new()); return Ok(GasLeft::NeedsReturn { gas_left: gas.as_u256(), @@ -253,19 +253,20 @@ impl vm::Vm for Interpreter { _ => {}, } } - informant.done(); + self.informant.done(); Ok(GasLeft::Known(gasometer.current_gas.as_u256())) } } impl Interpreter { /// Create a new `Interpreter` instance with shared cache. - pub fn new(mut params: ActionParams, cache: Arc) -> Interpreter { + pub fn new(mut params: ActionParams, cache: Arc, ext: &vm::Ext) -> Interpreter { let reader = CodeReader::new(params.code.take().expect("VM always called with code; qed")); let params = params.into(); + let informant = informant::EvmInformant::new(ext.depth()); Interpreter { - cache, params, reader, + cache, params, reader, informant, mem: Vec::new(), return_data: ReturnData::empty(), _type: PhantomData, diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 83eeb5d256c..2927d142002 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -352,7 +352,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let vm_factory = self.state.vm_factory(); 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(params, &schedule); + let mut vm = vm_factory.create(params, &ext); return vm.exec(&mut ext).finalize(ext); } @@ -362,7 +362,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { 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(params, &schedule); + let mut vm = vm_factory.create(params, &ext); vm.exec(&mut ext).finalize(ext) }).expect("Sub-thread creation cannot fail; the host might run out of resources; qed") }).join() diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index 2304c171732..b3401bbf93d 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::{self, Vm, ActionParams}; use wasm::WasmInterpreter; use keccak_hasher::KeccakHasher; @@ -31,11 +31,11 @@ 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, ext: &vm::Ext) -> Box { + if ext.schedule().wasm.is_some() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { Box::new(WasmInterpreter::new(params)) } else { - self.evm.create(params) + self.evm.create(params, ext) } } From b3cbf24169275df0026c2f42aab29eced467b7ec Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 18:34:39 +0800 Subject: [PATCH 04/21] Move do_trace to Interpreter struct --- ethcore/evm/src/interpreter/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 44d20acd4b6..9f26f3009e6 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -157,6 +157,7 @@ pub struct Interpreter { reader: CodeReader, return_data: ReturnData, informant: informant::EvmInformant, + do_trace: bool, _type: PhantomData, } @@ -164,8 +165,6 @@ impl vm::Vm for Interpreter { fn exec(&mut self, ext: &mut vm::Ext) -> vm::Result { self.mem.clear(); - let mut do_trace = true; - let mut valid_jump_destinations = None; let mut gasometer = Gasometer::::new(Cost::from_u256(self.params.gas)?); @@ -177,7 +176,7 @@ impl vm::Vm for Interpreter { self.reader.position += 1; // TODO: make compile-time removable if too much of a performance hit. - do_trace = do_trace && ext.trace_next_instruction( + self.do_trace = self.do_trace && ext.trace_next_instruction( self.reader.position - 1, opcode, gasometer.current_gas.as_u256(), ); @@ -193,7 +192,7 @@ impl vm::Vm for Interpreter { // Calculate gas cost let requirements = gasometer.requirements(ext, instruction, info, &stack, self.mem.size())?; - if do_trace { + if self.do_trace { ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256()); } @@ -204,7 +203,7 @@ impl vm::Vm for Interpreter { evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) }); - let (mem_written, store_written) = match do_trace { + let (mem_written, store_written) = match self.do_trace { true => (Self::mem_written(instruction, &stack), Self::store_written(instruction, &stack)), false => (None, None), }; @@ -220,7 +219,7 @@ impl vm::Vm for Interpreter { gasometer.current_gas = gasometer.current_gas + *gas; } - if do_trace { + if self.do_trace { ext.trace_executed( gasometer.current_gas.as_u256(), stack.peek_top(info.ret), @@ -267,6 +266,7 @@ impl Interpreter { Interpreter { cache, params, reader, informant, + do_trace: true, mem: Vec::new(), return_data: ReturnData::empty(), _type: PhantomData, From 3145fc5366f07a8b6cee9cfe337cd4cfaa87d85e Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 19:07:16 +0800 Subject: [PATCH 05/21] Move all remaining exec variables to Interpreter struct --- ethcore/evm/src/evm.rs | 6 + ethcore/evm/src/factory.rs | 6 +- ethcore/evm/src/interpreter/mod.rs | 380 ++++++++++++++--------------- ethcore/src/executive.rs | 14 +- ethcore/src/factory.rs | 4 +- 5 files changed, 210 insertions(+), 200 deletions(-) diff --git a/ethcore/evm/src/evm.rs b/ethcore/evm/src/evm.rs index 4c85b370281..9d2ff0cb13c 100644 --- a/ethcore/evm/src/evm.rs +++ b/ethcore/evm/src/evm.rs @@ -55,6 +55,12 @@ impl Finalize for Result { } } +impl Finalize for Error { + fn finalize(self, _ext: E) -> Result { + Err(self) + } +} + /// Cost calculation type. For low-gas usage we calculate costs using usize instead of U256 pub trait CostType: Sized + From + Copy + ops::Mul + ops::Div + ops::Add +ops::Sub diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index 5aaa7fc6e14..2b7286866d7 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -33,12 +33,12 @@ pub struct Factory { impl Factory { /// Create fresh instance of VM /// Might choose implementation depending on supplied gas. - pub fn create(&self, params: ActionParams, ext: &vm::Ext) -> Box { + pub fn create(&self, params: ActionParams, ext: &vm::Ext) -> vm::Result> { match self.evm { VMType::Interpreter => if Self::can_fit_in_usize(¶ms.gas) { - Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), ext)) + Ok(Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), ext)?)) } else { - Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), ext)) + Ok(Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), ext)?)) } } } diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 9f26f3009e6..df19edacf3d 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -158,6 +158,9 @@ pub struct Interpreter { return_data: ReturnData, informant: informant::EvmInformant, do_trace: bool, + valid_jump_destinations: Option>, + gasometer: Gasometer, + stack: VecStack, _type: PhantomData, } @@ -165,11 +168,6 @@ impl vm::Vm for Interpreter { fn exec(&mut self, ext: &mut vm::Ext) -> vm::Result { self.mem.clear(); - let mut valid_jump_destinations = None; - - let mut gasometer = Gasometer::::new(Cost::from_u256(self.params.gas)?); - let mut stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero()); - while self.reader.position < self.reader.len() { let opcode = self.reader.code[self.reader.position]; let instruction = Instruction::from_u8(opcode); @@ -177,7 +175,7 @@ impl vm::Vm for Interpreter { // TODO: make compile-time removable if too much of a performance hit. self.do_trace = self.do_trace && ext.trace_next_instruction( - self.reader.position - 1, opcode, gasometer.current_gas.as_u256(), + self.reader.position - 1, opcode, self.gasometer.current_gas.as_u256(), ); if instruction.is_none() { @@ -188,41 +186,42 @@ impl vm::Vm for Interpreter { let instruction = instruction.expect("None case is checked above; qed"); let info = instruction.info(); - self.verify_instruction(ext, instruction, info, &stack)?; + self.verify_instruction(ext, instruction, info)?; // Calculate gas cost - let requirements = gasometer.requirements(ext, instruction, info, &stack, self.mem.size())?; + let requirements = self.gasometer.requirements(ext, instruction, info, &self.stack, self.mem.size())?; if self.do_trace { ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256()); } - gasometer.verify_gas(&requirements.gas_cost)?; + self.gasometer.verify_gas(&requirements.gas_cost)?; self.mem.expand(requirements.memory_required_size); - gasometer.current_mem_gas = requirements.memory_total_gas; - gasometer.current_gas = gasometer.current_gas - requirements.gas_cost; + self.gasometer.current_mem_gas = requirements.memory_total_gas; + self.gasometer.current_gas = self.gasometer.current_gas - requirements.gas_cost; evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) }); let (mem_written, store_written) = match self.do_trace { - true => (Self::mem_written(instruction, &stack), Self::store_written(instruction, &stack)), + true => (Self::mem_written(instruction, &self.stack), Self::store_written(instruction, &self.stack)), false => (None, None), }; // Execute instruction + let current_gas = self.gasometer.current_gas; let result = self.exec_instruction( - gasometer.current_gas, ext, instruction, &mut stack, requirements.provide_gas + current_gas, ext, instruction, requirements.provide_gas )?; evm_debug!({ informant.after_instruction(instruction) }); if let InstructionResult::UnusedGas(ref gas) = result { - gasometer.current_gas = gasometer.current_gas + *gas; + self.gasometer.current_gas = self.gasometer.current_gas + *gas; } if self.do_trace { ext.trace_executed( - gasometer.current_gas.as_u256(), - stack.peek_top(info.ret), + self.gasometer.current_gas.as_u256(), + self.stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..o+s]))), store_written, ); @@ -231,11 +230,11 @@ impl vm::Vm for Interpreter { // Advance match result { InstructionResult::JumpToPosition(position) => { - if valid_jump_destinations.is_none() { + if self.valid_jump_destinations.is_none() { let code_hash = self.params.code_hash.clone().unwrap_or_else(|| keccak(self.reader.code.as_ref())); - valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, &self.reader.code)); + self.valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, &self.reader.code)); } - let jump_destinations = valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed"); + let jump_destinations = self.valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed"); let pos = self.verify_jump(position, jump_destinations)?; self.reader.position = pos; }, @@ -253,27 +252,31 @@ impl vm::Vm for Interpreter { } } self.informant.done(); - Ok(GasLeft::Known(gasometer.current_gas.as_u256())) + Ok(GasLeft::Known(self.gasometer.current_gas.as_u256())) } } impl Interpreter { /// Create a new `Interpreter` instance with shared cache. - pub fn new(mut params: ActionParams, cache: Arc, ext: &vm::Ext) -> Interpreter { + pub fn new(mut params: ActionParams, cache: Arc, ext: &vm::Ext) -> vm::Result> { let reader = CodeReader::new(params.code.take().expect("VM always called with code; qed")); - let params = params.into(); + let params = InterpreterParams::from(params); let informant = informant::EvmInformant::new(ext.depth()); + let valid_jump_destinations = None; + let gasometer = Gasometer::::new(Cost::from_u256(params.gas)?); + let stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero()); - Interpreter { + Ok(Interpreter { cache, params, reader, informant, + valid_jump_destinations, gasometer, stack, do_trace: true, mem: Vec::new(), return_data: ReturnData::empty(), _type: PhantomData, - } + }) } - fn verify_instruction(&self, ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack) -> vm::Result<()> { + fn verify_instruction(&self, ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo) -> vm::Result<()> { let schedule = ext.schedule(); if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) || @@ -288,13 +291,13 @@ impl Interpreter { }); } - if !stack.has(info.args) { + if !self.stack.has(info.args) { Err(vm::Error::StackUnderflow { instruction: info.name, wanted: info.args, - on_stack: stack.size() + on_stack: self.stack.size() }) - } else if stack.size() - info.args + info.ret > schedule.stack_limit { + } else if self.stack.size() - info.args + info.ret > schedule.stack_limit { Err(vm::Error::OutOfStack { instruction: info.name, wanted: info.ret - info.args, @@ -341,20 +344,19 @@ impl Interpreter { gas: Cost, ext: &mut vm::Ext, instruction: Instruction, - stack: &mut Stack, provided: Option ) -> vm::Result> { match instruction { instructions::JUMP => { - let jump = stack.pop_back(); + let jump = self.stack.pop_back(); return Ok(InstructionResult::JumpToPosition( jump )); }, instructions::JUMPI => { - let jump = stack.pop_back(); - let condition = stack.pop_back(); - if !self.is_zero(&condition) { + let jump = self.stack.pop_back(); + let condition = self.stack.pop_back(); + if !condition.is_zero() { return Ok(InstructionResult::JumpToPosition( jump )); @@ -364,9 +366,9 @@ impl Interpreter { // ignore }, instructions::CREATE | instructions::CREATE2 => { - let endowment = stack.pop_back(); - let init_off = stack.pop_back(); - let init_size = stack.pop_back(); + let endowment = self.stack.pop_back(); + let init_off = self.stack.pop_back(); + let init_size = self.stack.pop_back(); 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"); @@ -379,7 +381,7 @@ impl Interpreter { let can_create = ext.balance(&self.params.address)? >= endowment && ext.depth() < ext.schedule().max_depth; if !can_create { - stack.push(U256::zero()); + self.stack.push(U256::zero()); return Ok(InstructionResult::UnusedGas(create_gas)); } @@ -389,16 +391,16 @@ impl Interpreter { let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, address_scheme); return match create_result { ContractCreateResult::Created(address, gas_left) => { - stack.push(address_to_u256(address)); + self.stack.push(address_to_u256(address)); Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater."))) }, ContractCreateResult::Reverted(gas_left, return_data) => { - stack.push(U256::zero()); + self.stack.push(U256::zero()); self.return_data = return_data; Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater."))) }, ContractCreateResult::Failed => { - stack.push(U256::zero()); + self.stack.push(U256::zero()); Ok(InstructionResult::Ok) }, }; @@ -406,9 +408,9 @@ impl Interpreter { instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL | instructions::STATICCALL => { assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible"); - stack.pop_back(); + self.stack.pop_back(); let call_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 one of `CALL`/`CALLCODE`/`DELEGATECALL`; qed"); - let code_address = stack.pop_back(); + let code_address = self.stack.pop_back(); let code_address = u256_to_address(&code_address); let value = if instruction == instructions::DELEGATECALL { @@ -416,13 +418,13 @@ impl Interpreter { } else if instruction == instructions::STATICCALL { Some(U256::zero()) } else { - Some(stack.pop_back()) + Some(self.stack.pop_back()) }; - let in_off = stack.pop_back(); - let in_size = stack.pop_back(); - let out_off = stack.pop_back(); - let out_size = stack.pop_back(); + let in_off = self.stack.pop_back(); + let in_size = self.stack.pop_back(); + let out_off = self.stack.pop_back(); + let out_size = self.stack.pop_back(); // Add stipend (only CALL|CALLCODE when value > 0) let call_gas = call_gas + value.map_or_else(|| Cost::from(0), |val| match val.is_zero() { @@ -453,7 +455,7 @@ impl Interpreter { let can_call = has_balance && ext.depth() < ext.schedule().max_depth; if !can_call { - stack.push(U256::zero()); + self.stack.push(U256::zero()); return Ok(InstructionResult::UnusedGas(call_gas)); } @@ -467,30 +469,30 @@ impl Interpreter { return match call_result { MessageCallResult::Success(gas_left, data) => { - stack.push(U256::one()); + self.stack.push(U256::one()); self.return_data = data; Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one"))) }, MessageCallResult::Reverted(gas_left, data) => { - stack.push(U256::zero()); + self.stack.push(U256::zero()); self.return_data = data; Ok(InstructionResult::UnusedGas(Cost::from_u256(gas_left).expect("Gas left cannot be greater than current one"))) }, MessageCallResult::Failed => { - stack.push(U256::zero()); + self.stack.push(U256::zero()); Ok(InstructionResult::Ok) }, }; }, instructions::RETURN => { - let init_off = stack.pop_back(); - let init_size = stack.pop_back(); + let init_off = self.stack.pop_back(); + let init_size = self.stack.pop_back(); return Ok(InstructionResult::StopExecutionNeedsReturn {gas: gas, init_off: init_off, init_size: init_size, apply: true}) }, instructions::REVERT => { - let init_off = stack.pop_back(); - let init_size = stack.pop_back(); + let init_off = self.stack.pop_back(); + let init_size = self.stack.pop_back(); return Ok(InstructionResult::StopExecutionNeedsReturn {gas: gas, init_off: init_off, init_size: init_size, apply: false}) }, @@ -498,16 +500,16 @@ impl Interpreter { return Ok(InstructionResult::StopExecution); }, instructions::SUICIDE => { - let address = stack.pop_back(); + let address = self.stack.pop_back(); ext.suicide(&u256_to_address(&address))?; return Ok(InstructionResult::StopExecution); }, instructions::LOG0 | instructions::LOG1 | instructions::LOG2 | instructions::LOG3 | instructions::LOG4 => { let no_of_topics = instruction.log_topics().expect("log_topics always return some for LOG* instructions; qed"); - let offset = stack.pop_back(); - let size = stack.pop_back(); - let topics = stack.pop_n(no_of_topics) + let offset = self.stack.pop_back(); + let size = self.stack.pop_back(); + let topics = self.stack.pop_n(no_of_topics) .iter() .map(H256::from) .collect(); @@ -523,74 +525,74 @@ impl Interpreter { instructions::PUSH29 | instructions::PUSH30 | instructions::PUSH31 | instructions::PUSH32 => { let bytes = instruction.push_bytes().expect("push_bytes always return some for PUSH* instructions"); let val = self.reader.read(bytes); - stack.push(val); + self.stack.push(val); }, instructions::MLOAD => { - let word = self.mem.read(stack.pop_back()); - stack.push(U256::from(word)); + let word = self.mem.read(self.stack.pop_back()); + self.stack.push(U256::from(word)); }, instructions::MSTORE => { - let offset = stack.pop_back(); - let word = stack.pop_back(); + let offset = self.stack.pop_back(); + let word = self.stack.pop_back(); Memory::write(&mut self.mem, offset, word); }, instructions::MSTORE8 => { - let offset = stack.pop_back(); - let byte = stack.pop_back(); + let offset = self.stack.pop_back(); + let byte = self.stack.pop_back(); self.mem.write_byte(offset, byte); }, instructions::MSIZE => { - stack.push(U256::from(self.mem.size())); + self.stack.push(U256::from(self.mem.size())); }, instructions::SHA3 => { - let offset = stack.pop_back(); - let size = stack.pop_back(); + let offset = self.stack.pop_back(); + let size = self.stack.pop_back(); let k = keccak(self.mem.read_slice(offset, size)); - stack.push(U256::from(&*k)); + self.stack.push(U256::from(&*k)); }, instructions::SLOAD => { - let key = H256::from(&stack.pop_back()); + let key = H256::from(&self.stack.pop_back()); let word = U256::from(&*ext.storage_at(&key)?); - stack.push(word); + self.stack.push(word); }, instructions::SSTORE => { - let address = H256::from(&stack.pop_back()); - let val = stack.pop_back(); + let address = H256::from(&self.stack.pop_back()); + let val = self.stack.pop_back(); let current_val = U256::from(&*ext.storage_at(&address)?); // Increase refund for clear - if !self.is_zero(¤t_val) && self.is_zero(&val) { + if !current_val.is_zero() && val.is_zero() { ext.inc_sstore_clears(); } ext.set_storage(address, H256::from(&val))?; }, instructions::PC => { - stack.push(U256::from(self.reader.position - 1)); + self.stack.push(U256::from(self.reader.position - 1)); }, instructions::GAS => { - stack.push(gas.as_u256()); + self.stack.push(gas.as_u256()); }, instructions::ADDRESS => { - stack.push(address_to_u256(self.params.address.clone())); + self.stack.push(address_to_u256(self.params.address.clone())); }, instructions::ORIGIN => { - stack.push(address_to_u256(self.params.origin.clone())); + self.stack.push(address_to_u256(self.params.origin.clone())); }, instructions::BALANCE => { - let address = u256_to_address(&stack.pop_back()); + let address = u256_to_address(&self.stack.pop_back()); let balance = ext.balance(&address)?; - stack.push(balance); + self.stack.push(balance); }, instructions::CALLER => { - stack.push(address_to_u256(self.params.sender.clone())); + self.stack.push(address_to_u256(self.params.sender.clone())); }, instructions::CALLVALUE => { - stack.push(match self.params.value { + self.stack.push(match self.params.value { ActionValue::Transfer(val) | ActionValue::Apparent(val) => val }); }, instructions::CALLDATALOAD => { - let big_id = stack.pop_back(); + let big_id = self.stack.pop_back(); let id = big_id.low_u64() as usize; let max = id.wrapping_add(32); if let Some(data) = self.params.data.as_ref() { @@ -598,72 +600,72 @@ impl Interpreter { if id < bound && big_id < U256::from(data.len()) { let mut v = [0u8; 32]; v[0..bound-id].clone_from_slice(&data[id..bound]); - stack.push(U256::from(&v[..])) + self.stack.push(U256::from(&v[..])) } else { - stack.push(U256::zero()) + self.stack.push(U256::zero()) } } else { - stack.push(U256::zero()) + self.stack.push(U256::zero()) } }, instructions::CALLDATASIZE => { - stack.push(U256::from(self.params.data.as_ref().map_or(0, |l| l.len()))); + self.stack.push(U256::from(self.params.data.as_ref().map_or(0, |l| l.len()))); }, instructions::CODESIZE => { - stack.push(U256::from(self.reader.len())); + self.stack.push(U256::from(self.reader.len())); }, instructions::RETURNDATASIZE => { - stack.push(U256::from(self.return_data.len())) + self.stack.push(U256::from(self.return_data.len())) }, instructions::EXTCODESIZE => { - let address = u256_to_address(&stack.pop_back()); + let address = u256_to_address(&self.stack.pop_back()); let len = ext.extcodesize(&address)?; - stack.push(U256::from(len)); + self.stack.push(U256::from(len)); }, instructions::CALLDATACOPY => { - Self::copy_data_to_memory(&mut self.mem, stack, &self.params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); + Self::copy_data_to_memory(&mut self.mem, &mut self.stack, &self.params.data.as_ref().map_or_else(|| &[] as &[u8], |d| &*d as &[u8])); }, instructions::RETURNDATACOPY => { { - let source_offset = stack.peek(1); - let size = stack.peek(2); + let source_offset = self.stack.peek(1); + let size = self.stack.peek(2); let return_data_len = U256::from(self.return_data.len()); if source_offset.saturating_add(*size) > return_data_len { return Err(vm::Error::OutOfBounds); } } - Self::copy_data_to_memory(&mut self.mem, stack, &*self.return_data); + Self::copy_data_to_memory(&mut self.mem, &mut self.stack, &*self.return_data); }, instructions::CODECOPY => { - Self::copy_data_to_memory(&mut self.mem, stack, &self.reader.code); + Self::copy_data_to_memory(&mut self.mem, &mut self.stack, &self.reader.code); }, instructions::EXTCODECOPY => { - let address = u256_to_address(&stack.pop_back()); + let address = u256_to_address(&self.stack.pop_back()); let code = ext.extcode(&address)?; - Self::copy_data_to_memory(&mut self.mem, stack, &code); + Self::copy_data_to_memory(&mut self.mem, &mut self.stack, &code); }, instructions::GASPRICE => { - stack.push(self.params.gas_price.clone()); + self.stack.push(self.params.gas_price.clone()); }, instructions::BLOCKHASH => { - let block_number = stack.pop_back(); + let block_number = self.stack.pop_back(); let block_hash = ext.blockhash(&block_number); - stack.push(U256::from(&*block_hash)); + self.stack.push(U256::from(&*block_hash)); }, instructions::COINBASE => { - stack.push(address_to_u256(ext.env_info().author.clone())); + self.stack.push(address_to_u256(ext.env_info().author.clone())); }, instructions::TIMESTAMP => { - stack.push(U256::from(ext.env_info().timestamp)); + self.stack.push(U256::from(ext.env_info().timestamp)); }, instructions::NUMBER => { - stack.push(U256::from(ext.env_info().number)); + self.stack.push(U256::from(ext.env_info().number)); }, instructions::DIFFICULTY => { - stack.push(ext.env_info().difficulty.clone()); + self.stack.push(ext.env_info().difficulty.clone()); }, instructions::GASLIMIT => { - stack.push(ext.env_info().gas_limit.clone()); + self.stack.push(ext.env_info().gas_limit.clone()); }, // Stack instructions @@ -673,38 +675,38 @@ impl Interpreter { instructions::DUP9 | instructions::DUP10 | instructions::DUP11 | instructions::DUP12 | instructions::DUP13 | instructions::DUP14 | instructions::DUP15 | instructions::DUP16 => { let position = instruction.dup_position().expect("dup_position always return some for DUP* instructions"); - let val = stack.peek(position).clone(); - stack.push(val); + let val = self.stack.peek(position).clone(); + self.stack.push(val); }, instructions::SWAP1 | instructions::SWAP2 | instructions::SWAP3 | instructions::SWAP4 | instructions::SWAP5 | instructions::SWAP6 | instructions::SWAP7 | instructions::SWAP8 | instructions::SWAP9 | instructions::SWAP10 | instructions::SWAP11 | instructions::SWAP12 | instructions::SWAP13 | instructions::SWAP14 | instructions::SWAP15 | instructions::SWAP16 => { let position = instruction.swap_position().expect("swap_position always return some for SWAP* instructions"); - stack.swap_with_top(position) + self.stack.swap_with_top(position) }, instructions::POP => { - stack.pop_back(); + self.stack.pop_back(); }, instructions::ADD => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a.overflowing_add(b).0); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(a.overflowing_add(b).0); }, instructions::MUL => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a.overflowing_mul(b).0); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(a.overflowing_mul(b).0); }, instructions::SUB => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a.overflowing_sub(b).0); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(a.overflowing_sub(b).0); }, instructions::DIV => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(if !self.is_zero(&b) { + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(if !b.is_zero() { match b { ONE => a, TWO => a >> 1, @@ -723,21 +725,21 @@ impl Interpreter { }); }, instructions::MOD => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(if !self.is_zero(&b) { + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(if !b.is_zero() { a.overflowing_rem(b).0 } else { U256::zero() }); }, instructions::SDIV => { - let (a, sign_a) = get_and_reset_sign(stack.pop_back()); - let (b, sign_b) = get_and_reset_sign(stack.pop_back()); + let (a, sign_a) = get_and_reset_sign(self.stack.pop_back()); + let (b, sign_b) = get_and_reset_sign(self.stack.pop_back()); // -2^255 let min = (U256::one() << 255) - U256::one(); - stack.push(if self.is_zero(&b) { + self.stack.push(if b.is_zero() { U256::zero() } else if a == min && b == !U256::zero() { min @@ -747,12 +749,12 @@ impl Interpreter { }); }, instructions::SMOD => { - let ua = stack.pop_back(); - let ub = stack.pop_back(); + let ua = self.stack.pop_back(); + let ub = self.stack.pop_back(); let (a, sign_a) = get_and_reset_sign(ua); let b = get_and_reset_sign(ub).0; - stack.push(if !self.is_zero(&b) { + self.stack.push(if !b.is_zero() { let c = a.overflowing_rem(b).0; set_sign(c, sign_a) } else { @@ -760,84 +762,84 @@ impl Interpreter { }); }, instructions::EXP => { - let base = stack.pop_back(); - let expon = stack.pop_back(); + let base = self.stack.pop_back(); + let expon = self.stack.pop_back(); let res = base.overflowing_pow(expon).0; - stack.push(res); + self.stack.push(res); }, instructions::NOT => { - let a = stack.pop_back(); - stack.push(!a); + let a = self.stack.pop_back(); + self.stack.push(!a); }, instructions::LT => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(self.bool_to_u256(a < b)); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(Self::bool_to_u256(a < b)); }, instructions::SLT => { - let (a, neg_a) = get_and_reset_sign(stack.pop_back()); - let (b, neg_b) = get_and_reset_sign(stack.pop_back()); + let (a, neg_a) = get_and_reset_sign(self.stack.pop_back()); + let (b, neg_b) = get_and_reset_sign(self.stack.pop_back()); let is_positive_lt = a < b && !(neg_a | neg_b); let is_negative_lt = a > b && (neg_a & neg_b); let has_different_signs = neg_a && !neg_b; - stack.push(self.bool_to_u256(is_positive_lt | is_negative_lt | has_different_signs)); + self.stack.push(Self::bool_to_u256(is_positive_lt | is_negative_lt | has_different_signs)); }, instructions::GT => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(self.bool_to_u256(a > b)); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(Self::bool_to_u256(a > b)); }, instructions::SGT => { - let (a, neg_a) = get_and_reset_sign(stack.pop_back()); - let (b, neg_b) = get_and_reset_sign(stack.pop_back()); + let (a, neg_a) = get_and_reset_sign(self.stack.pop_back()); + let (b, neg_b) = get_and_reset_sign(self.stack.pop_back()); let is_positive_gt = a > b && !(neg_a | neg_b); let is_negative_gt = a < b && (neg_a & neg_b); let has_different_signs = !neg_a && neg_b; - stack.push(self.bool_to_u256(is_positive_gt | is_negative_gt | has_different_signs)); + self.stack.push(Self::bool_to_u256(is_positive_gt | is_negative_gt | has_different_signs)); }, instructions::EQ => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(self.bool_to_u256(a == b)); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(Self::bool_to_u256(a == b)); }, instructions::ISZERO => { - let a = stack.pop_back(); - stack.push(self.bool_to_u256(self.is_zero(&a))); + let a = self.stack.pop_back(); + self.stack.push(Self::bool_to_u256(a.is_zero())); }, instructions::AND => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a & b); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(a & b); }, instructions::OR => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a | b); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(a | b); }, instructions::XOR => { - let a = stack.pop_back(); - let b = stack.pop_back(); - stack.push(a ^ b); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + self.stack.push(a ^ b); }, instructions::BYTE => { - let word = stack.pop_back(); - let val = stack.pop_back(); + let word = self.stack.pop_back(); + let val = self.stack.pop_back(); let byte = match word < U256::from(32) { true => (val >> (8 * (31 - word.low_u64() as usize))) & U256::from(0xff), false => U256::zero() }; - stack.push(byte); + self.stack.push(byte); }, instructions::ADDMOD => { - let a = stack.pop_back(); - let b = stack.pop_back(); - let c = stack.pop_back(); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + let c = self.stack.pop_back(); - stack.push(if !self.is_zero(&c) { + self.stack.push(if !c.is_zero() { // upcast to 512 let a5 = U512::from(a); let res = a5.overflowing_add(U512::from(b)).0; @@ -848,11 +850,11 @@ impl Interpreter { }); }, instructions::MULMOD => { - let a = stack.pop_back(); - let b = stack.pop_back(); - let c = stack.pop_back(); + let a = self.stack.pop_back(); + let b = self.stack.pop_back(); + let c = self.stack.pop_back(); - stack.push(if !self.is_zero(&c) { + self.stack.push(if !c.is_zero() { let a5 = U512::from(a); let res = a5.overflowing_mul(U512::from(b)).0; let x = res.overflowing_rem(U512::from(c)).0; @@ -862,14 +864,14 @@ impl Interpreter { }); }, instructions::SIGNEXTEND => { - let bit = stack.pop_back(); + let bit = self.stack.pop_back(); if bit < U256::from(32) { - let number = stack.pop_back(); + let number = self.stack.pop_back(); let bit_position = (bit.low_u64() * 8 + 7) as usize; let bit = number.bit(bit_position); let mask = (U256::one() << bit_position) - U256::one(); - stack.push(if bit { + self.stack.push(if bit { number | !mask } else { number & mask @@ -879,28 +881,28 @@ impl Interpreter { instructions::SHL => { const CONST_256: U256 = U256([256, 0, 0, 0]); - let shift = stack.pop_back(); - let value = stack.pop_back(); + let shift = self.stack.pop_back(); + let value = self.stack.pop_back(); let result = if shift >= CONST_256 { U256::zero() } else { value << (shift.as_u32() as usize) }; - stack.push(result); + self.stack.push(result); }, instructions::SHR => { const CONST_256: U256 = U256([256, 0, 0, 0]); - let shift = stack.pop_back(); - let value = stack.pop_back(); + let shift = self.stack.pop_back(); + let value = self.stack.pop_back(); let result = if shift >= CONST_256 { U256::zero() } else { value >> (shift.as_u32() as usize) }; - stack.push(result); + self.stack.push(result); }, instructions::SAR => { // We cannot use get_and_reset_sign/set_sign here, because the rounding looks different. @@ -908,8 +910,8 @@ impl Interpreter { const CONST_256: U256 = U256([256, 0, 0, 0]); const CONST_HIBIT: U256 = U256([0, 0, 0, 0x8000000000000000]); - let shift = stack.pop_back(); - let value = stack.pop_back(); + let shift = self.stack.pop_back(); + let value = self.stack.pop_back(); let sign = value & CONST_HIBIT != U256::zero(); let result = if shift >= CONST_256 { @@ -926,7 +928,7 @@ impl Interpreter { } shifted }; - stack.push(result); + self.stack.push(result); }, }; Ok(InstructionResult::Ok) @@ -971,11 +973,7 @@ impl Interpreter { } } - fn is_zero(&self, val: &U256) -> bool { - val.is_zero() - } - - fn bool_to_u256(&self, val: bool) -> U256 { + fn bool_to_u256(val: bool) -> U256 { if val { U256::one() } else { diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 2927d142002..dca231a6ebe 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -352,8 +352,11 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { let vm_factory = self.state.vm_factory(); 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(params, &ext); - return vm.exec(&mut ext).finalize(ext); + let vm = vm_factory.create(params, &ext); + return match vm { + Ok(mut vm) => vm.exec(&mut ext).finalize(ext), + Err(e) => e.finalize(ext), + } } // Start in new thread with stack size needed up to max depth @@ -362,8 +365,11 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { 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(params, &ext); - vm.exec(&mut ext).finalize(ext) + let vm = vm_factory.create(params, &ext); + match vm { + Ok(mut vm) => vm.exec(&mut ext).finalize(ext), + Err(e) => e.finalize(ext), + } }).expect("Sub-thread creation cannot fail; the host might run out of resources; qed") }).join() } diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index b3401bbf93d..84adcf89813 100644 --- a/ethcore/src/factory.rs +++ b/ethcore/src/factory.rs @@ -31,9 +31,9 @@ pub struct VmFactory { } impl VmFactory { - pub fn create(&self, params: ActionParams, ext: &vm::Ext) -> Box { + pub fn create(&self, params: ActionParams, ext: &vm::Ext) -> vm::Result> { if ext.schedule().wasm.is_some() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { - Box::new(WasmInterpreter::new(params)) + Ok(Box::new(WasmInterpreter::new(params))) } else { self.evm.create(params, ext) } From b98129e6329209d0f9e84236c56cc769bc9eb4bf Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 19:55:16 +0800 Subject: [PATCH 06/21] Refactor VM to allow single opcode step --- ethcore/evm/src/interpreter/mod.rs | 217 ++++++++++++++++++----------- 1 file changed, 133 insertions(+), 84 deletions(-) diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index df19edacf3d..994a3aa5b4a 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -149,6 +149,16 @@ impl From for InterpreterParams { } } +/// Stepping result returned by interpreter. +pub enum InterpreterResult { + /// The VM has already stopped. + Stopped, + /// The VM has just finished execution in the current step. + Done(vm::Result), + /// The VM can continue to run. + Continue, +} + /// Intepreter EVM implementation pub struct Interpreter { mem: Vec, @@ -158,6 +168,7 @@ pub struct Interpreter { return_data: ReturnData, informant: informant::EvmInformant, do_trace: bool, + done: bool, valid_jump_destinations: Option>, gasometer: Gasometer, stack: VecStack, @@ -166,93 +177,14 @@ pub struct Interpreter { impl vm::Vm for Interpreter { fn exec(&mut self, ext: &mut vm::Ext) -> vm::Result { - self.mem.clear(); - - while self.reader.position < self.reader.len() { - let opcode = self.reader.code[self.reader.position]; - let instruction = Instruction::from_u8(opcode); - self.reader.position += 1; - - // TODO: make compile-time removable if too much of a performance hit. - self.do_trace = self.do_trace && ext.trace_next_instruction( - self.reader.position - 1, opcode, self.gasometer.current_gas.as_u256(), - ); - - if instruction.is_none() { - return Err(vm::Error::BadInstruction { - instruction: opcode - }); - } - let instruction = instruction.expect("None case is checked above; qed"); - - let info = instruction.info(); - self.verify_instruction(ext, instruction, info)?; - - // Calculate gas cost - let requirements = self.gasometer.requirements(ext, instruction, info, &self.stack, self.mem.size())?; - if self.do_trace { - ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256()); - } - - self.gasometer.verify_gas(&requirements.gas_cost)?; - self.mem.expand(requirements.memory_required_size); - self.gasometer.current_mem_gas = requirements.memory_total_gas; - self.gasometer.current_gas = self.gasometer.current_gas - requirements.gas_cost; - - evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) }); - - let (mem_written, store_written) = match self.do_trace { - true => (Self::mem_written(instruction, &self.stack), Self::store_written(instruction, &self.stack)), - false => (None, None), - }; - - // Execute instruction - let current_gas = self.gasometer.current_gas; - let result = self.exec_instruction( - current_gas, ext, instruction, requirements.provide_gas - )?; - - evm_debug!({ informant.after_instruction(instruction) }); - - if let InstructionResult::UnusedGas(ref gas) = result { - self.gasometer.current_gas = self.gasometer.current_gas + *gas; - } - - if self.do_trace { - ext.trace_executed( - self.gasometer.current_gas.as_u256(), - self.stack.peek_top(info.ret), - mem_written.map(|(o, s)| (o, &(self.mem[o..o+s]))), - store_written, - ); - } - - // Advance + loop { + let result = self.step(ext); match result { - InstructionResult::JumpToPosition(position) => { - if self.valid_jump_destinations.is_none() { - let code_hash = self.params.code_hash.clone().unwrap_or_else(|| keccak(self.reader.code.as_ref())); - self.valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, &self.reader.code)); - } - let jump_destinations = self.valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed"); - let pos = self.verify_jump(position, jump_destinations)?; - self.reader.position = pos; - }, - InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { - self.informant.done(); - let mem = mem::replace(&mut self.mem, Vec::new()); - return Ok(GasLeft::NeedsReturn { - gas_left: gas.as_u256(), - data: mem.into_return_data(init_off, init_size), - apply_state: apply - }); - }, - InstructionResult::StopExecution => break, - _ => {}, + InterpreterResult::Continue => {}, + InterpreterResult::Done(value) => return value, + InterpreterResult::Stopped => panic!("Attempted to execute an already stopped VM.") } } - self.informant.done(); - Ok(GasLeft::Known(self.gasometer.current_gas.as_u256())) } } @@ -269,6 +201,7 @@ impl Interpreter { Ok(Interpreter { cache, params, reader, informant, valid_jump_destinations, gasometer, stack, + done: false, do_trace: true, mem: Vec::new(), return_data: ReturnData::empty(), @@ -276,6 +209,122 @@ impl Interpreter { }) } + /// Execute a single step on the VM. + #[inline(always)] + pub fn step(&mut self, ext: &mut vm::Ext) -> InterpreterResult { + macro_rules! try_or_done { + ( $expr: expr ) => { + match $expr { + Ok(value) => value, + Err(err) => return InterpreterResult::Done(Err(err)), + } + } + } + + if self.done { + return InterpreterResult::Stopped; + } + + let result = { + let mut inner = || { + let opcode = self.reader.code[self.reader.position]; + let instruction = Instruction::from_u8(opcode); + self.reader.position += 1; + + // TODO: make compile-time removable if too much of a performance hit. + self.do_trace = self.do_trace && ext.trace_next_instruction( + self.reader.position - 1, opcode, self.gasometer.current_gas.as_u256(), + ); + + if instruction.is_none() { + try_or_done!(Err(vm::Error::BadInstruction { + instruction: opcode + })); + } + let instruction = instruction.expect("None case is checked above; qed"); + + let info = instruction.info(); + try_or_done!(self.verify_instruction(ext, instruction, info)); + + // Calculate gas cost + let requirements = try_or_done!(self.gasometer.requirements(ext, instruction, info, &self.stack, self.mem.size())); + if self.do_trace { + ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256()); + } + + try_or_done!(self.gasometer.verify_gas(&requirements.gas_cost)); + self.mem.expand(requirements.memory_required_size); + self.gasometer.current_mem_gas = requirements.memory_total_gas; + self.gasometer.current_gas = self.gasometer.current_gas - requirements.gas_cost; + + evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) }); + + let (mem_written, store_written) = match self.do_trace { + true => (Self::mem_written(instruction, &self.stack), Self::store_written(instruction, &self.stack)), + false => (None, None), + }; + + // Execute instruction + let current_gas = self.gasometer.current_gas; + let result = try_or_done!(self.exec_instruction( + current_gas, ext, instruction, requirements.provide_gas + )); + + evm_debug!({ informant.after_instruction(instruction) }); + + if let InstructionResult::UnusedGas(ref gas) = result { + self.gasometer.current_gas = self.gasometer.current_gas + *gas; + } + + if self.do_trace { + ext.trace_executed( + self.gasometer.current_gas.as_u256(), + self.stack.peek_top(info.ret), + mem_written.map(|(o, s)| (o, &(self.mem[o..o+s]))), + store_written, + ); + } + + // Advance + match result { + InstructionResult::JumpToPosition(position) => { + if self.valid_jump_destinations.is_none() { + let code_hash = self.params.code_hash.clone().unwrap_or_else(|| keccak(self.reader.code.as_ref())); + self.valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, &self.reader.code)); + } + let jump_destinations = self.valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed"); + let pos = try_or_done!(self.verify_jump(position, jump_destinations)); + self.reader.position = pos; + }, + InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { + let mem = mem::replace(&mut self.mem, Vec::new()); + try_or_done!(Ok(GasLeft::NeedsReturn { + gas_left: gas.as_u256(), + data: mem.into_return_data(init_off, init_size), + apply_state: apply + })); + }, + InstructionResult::StopExecution => { + try_or_done!(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); + }, + _ => {}, + } + + if self.reader.position >= self.reader.len() { + try_or_done!(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); + } + + InterpreterResult::Continue + }; + inner() + }; + if let &InterpreterResult::Done(_) = &result { + self.done = true; + self.informant.done(); + } + return result; + } + fn verify_instruction(&self, ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo) -> vm::Result<()> { let schedule = ext.schedule(); From bb944c80e8926466db6faa03e8aa6a8dd36918ae Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 20:06:03 +0800 Subject: [PATCH 07/21] Fix all EVM tests --- ethcore/evm/src/factory.rs | 7 +- ethcore/evm/src/interpreter/mod.rs | 23 +++-- ethcore/evm/src/tests.rs | 144 ++++++++++++++--------------- 3 files changed, 89 insertions(+), 85 deletions(-) diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index 2b7286866d7..73271148301 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -69,7 +69,12 @@ impl Default for Factory { #[test] fn test_create_vm() { - let _vm = Factory::default().create(&U256::zero()); + use vm::tests::FakeExt; + use bytes::Bytes; + + let mut params = ActionParams::default(); + params.code = Some(Arc::new(Bytes::default())); + let _vm = Factory::default().create(params, &FakeExt::new()); } /// Create tests by injecting different VM factories diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 994a3aa5b4a..69811e61de7 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -237,7 +237,7 @@ impl Interpreter { ); if instruction.is_none() { - try_or_done!(Err(vm::Error::BadInstruction { + return InterpreterResult::Done(Err(vm::Error::BadInstruction { instruction: opcode })); } @@ -298,20 +298,20 @@ impl Interpreter { }, InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { let mem = mem::replace(&mut self.mem, Vec::new()); - try_or_done!(Ok(GasLeft::NeedsReturn { + return InterpreterResult::Done(Ok(GasLeft::NeedsReturn { gas_left: gas.as_u256(), data: mem.into_return_data(init_off, init_size), apply_state: apply })); }, InstructionResult::StopExecution => { - try_or_done!(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); + return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); }, _ => {}, } if self.reader.position >= self.reader.len() { - try_or_done!(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); + return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); } InterpreterResult::Continue @@ -1061,12 +1061,11 @@ mod tests { use rustc_hex::FromHex; use vmtype::VMType; use factory::Factory; - use vm::{Vm, ActionParams, ActionValue}; + use vm::{self, Vm, ActionParams, ActionValue}; use vm::tests::{FakeExt, test_finalize}; - use ethereum_types::U256; - fn interpreter(gas: &U256) -> Box { - Factory::new(VMType::Interpreter, 1).create(gas) + fn interpreter(params: ActionParams, ext: &vm::Ext) -> Box { + Factory::new(VMType::Interpreter, 1).create(params, ext).unwrap() } #[test] @@ -1084,8 +1083,8 @@ mod tests { ext.tracing = true; let gas_left = { - let mut vm = interpreter(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = interpreter(params, &ext); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(ext.calls.len(), 1); @@ -1106,8 +1105,8 @@ mod tests { ext.tracing = true; let err = { - let mut vm = interpreter(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).err().unwrap() + let mut vm = interpreter(params, &ext); + test_finalize(vm.exec(&mut ext)).err().unwrap() }; assert_eq!(err, ::vm::Error::OutOfBounds); diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index b62faf87d77..8cda6774578 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -38,8 +38,8 @@ fn test_add(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_988)); @@ -58,8 +58,8 @@ fn test_sha3(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_961)); @@ -78,8 +78,8 @@ fn test_address(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -100,8 +100,8 @@ fn test_origin(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -122,8 +122,8 @@ fn test_sender(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -157,8 +157,8 @@ fn test_extcodecopy(factory: super::Factory) { ext.codes.insert(sender, Arc::new(sender_code)); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_935)); @@ -177,8 +177,8 @@ fn test_log_empty(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(99_619)); @@ -209,8 +209,8 @@ fn test_log_sender(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(98_974)); @@ -234,8 +234,8 @@ fn test_blockhash(factory: super::Factory) { ext.blockhashes.insert(U256::zero(), blockhash.clone()); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_974)); @@ -256,8 +256,8 @@ fn test_calldataload(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_991)); @@ -277,8 +277,8 @@ fn test_author(factory: super::Factory) { ext.info.author = author; let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -297,8 +297,8 @@ fn test_timestamp(factory: super::Factory) { ext.info.timestamp = timestamp; let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -317,8 +317,8 @@ fn test_number(factory: super::Factory) { ext.info.number = number; let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -337,8 +337,8 @@ fn test_difficulty(factory: super::Factory) { ext.info.difficulty = difficulty; let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -357,8 +357,8 @@ fn test_gas_limit(factory: super::Factory) { ext.info.gas_limit = gas_limit; let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -375,8 +375,8 @@ fn test_mul(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "000000000000000000000000000000000000000000000000734349397b853383"); @@ -393,8 +393,8 @@ fn test_sub(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000012364ad0302"); @@ -411,8 +411,8 @@ fn test_div(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "000000000000000000000000000000000000000000000000000000000002e0ac"); @@ -429,8 +429,8 @@ fn test_div_zero(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); @@ -447,8 +447,8 @@ fn test_mod(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000076b4b"); @@ -466,8 +466,8 @@ fn test_smod(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000076b4b"); @@ -485,8 +485,8 @@ fn test_sdiv(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "000000000000000000000000000000000000000000000000000000000002e0ac"); @@ -504,8 +504,8 @@ fn test_exp(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "90fd23767b60204c3d6fc8aec9e70a42a3f127140879c133a20129a597ed0c59"); @@ -524,8 +524,8 @@ fn test_comparison(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); @@ -545,8 +545,8 @@ fn test_signed_comparison(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); @@ -566,8 +566,8 @@ fn test_bitops(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "00000000000000000000000000000000000000000000000000000000000000f0"); @@ -589,8 +589,8 @@ fn test_addmod_mulmod(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000001"); @@ -610,8 +610,8 @@ fn test_byte(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); @@ -629,8 +629,8 @@ fn test_signextend(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000fff"); @@ -649,8 +649,8 @@ fn test_badinstruction_int() { let mut ext = FakeExt::new(); let err = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap_err() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap_err() }; match err { @@ -669,8 +669,8 @@ fn test_pop(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "00000000000000000000000000000000000000000000000000000000000000f0"); @@ -689,8 +689,8 @@ fn test_extops(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000004"); // PC / CALLDATASIZE @@ -712,8 +712,8 @@ fn test_jumps(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_eq!(ext.sstore_clears, 1); @@ -740,8 +740,8 @@ fn test_calls(factory: super::Factory) { }; let gas_left = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_set_contains(&ext.calls, &FakeCall { @@ -779,8 +779,8 @@ fn test_create_in_staticcall(factory: super::Factory) { ext.is_static = true; let err = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap_err() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap_err() }; assert_eq!(err, vm::Error::MutableCallInStaticContext); @@ -1047,8 +1047,8 @@ fn push_two_pop_one_constantinople_test(factory: &super::Factory, opcode: u8, pu let mut ext = FakeExt::new_constantinople(); let _ = { - let mut vm = factory.create(¶ms.gas); - test_finalize(vm.exec(params, &mut ext)).unwrap() + let mut vm = factory.create(params, &ext).unwrap(); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, result); From 9ea14090c5cfedc833dec9b08974e8a3c9f4c563 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 20:09:14 +0800 Subject: [PATCH 08/21] Fix all wasm tests --- ethcore/wasm/src/tests.rs | 84 +++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index 726b9ebabbb..9fcc771c4f9 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -47,8 +47,8 @@ macro_rules! reqrep_test { fake_ext.info = $info; fake_ext.blockhashes = $block_hashes; - let mut interpreter = wasm_interpreter(); - interpreter.exec(params, &mut fake_ext) + let mut interpreter = wasm_interpreter(params); + interpreter.exec(&mut fake_ext) .map(|result| match result { GasLeft::Known(_) => { panic!("Test is expected to return payload to check"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -65,8 +65,8 @@ fn test_finalize(res: Result) -> Result { } } -fn wasm_interpreter() -> WasmInterpreter { - WasmInterpreter +fn wasm_interpreter(params: ActionParams) -> WasmInterpreter { + WasmInterpreter::new(params) } /// Empty contract does almost nothing except producing 1 (one) local node debug log message @@ -82,8 +82,8 @@ fn empty() { let mut ext = FakeExt::new().with_wasm(); let gas_left = { - let mut interpreter = wasm_interpreter(); - test_finalize(interpreter.exec(params, &mut ext)).unwrap() + let mut interpreter = wasm_interpreter(params); + test_finalize(interpreter.exec(&mut ext)).unwrap() }; assert_eq!(gas_left, U256::from(96_926)); @@ -111,8 +111,8 @@ fn logger() { let mut ext = FakeExt::new().with_wasm(); let gas_left = { - let mut interpreter = wasm_interpreter(); - test_finalize(interpreter.exec(params, &mut ext)).unwrap() + let mut interpreter = wasm_interpreter(params); + test_finalize(interpreter.exec(&mut ext)).unwrap() }; let address_val: H256 = address.into(); @@ -160,8 +160,8 @@ fn identity() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("Identity contract should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -195,8 +195,8 @@ fn dispersion() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("Dispersion routine should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -223,8 +223,8 @@ fn suicide_not() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("Suicidal contract should return payload when had not actualy killed himself"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -256,8 +256,8 @@ fn suicide() { let mut ext = FakeExt::new().with_wasm(); let gas_left = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(gas) => gas, GasLeft::NeedsReturn { .. } => { @@ -283,8 +283,8 @@ fn create() { let mut ext = FakeExt::new().with_wasm(); let gas_left = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(gas) => gas, GasLeft::NeedsReturn { .. } => { @@ -328,8 +328,8 @@ fn call_msg() { ext.balances.insert(receiver.clone(), U256::from(10000000000u64)); let gas_left = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(gas_left) => gas_left, GasLeft::NeedsReturn { .. } => { panic!("Call test should not return payload"); }, @@ -370,8 +370,8 @@ fn call_code() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("Call test should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -417,8 +417,8 @@ fn call_static() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("Static call test should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -457,8 +457,8 @@ fn realloc() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("Realloc should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -479,8 +479,8 @@ fn alloc() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("alloc test should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -506,8 +506,8 @@ fn storage_read() { ext.store.insert("0100000000000000000000000000000000000000000000000000000000000000".into(), address.into()); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("storage_read should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -532,8 +532,8 @@ fn keccak() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("keccak should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -679,8 +679,8 @@ fn storage_metering() { ]); let gas_left = { - let mut interpreter = wasm_interpreter(); - test_finalize(interpreter.exec(params, &mut ext)).unwrap() + let mut interpreter = wasm_interpreter(params); + test_finalize(interpreter.exec(&mut ext)).unwrap() }; // 0 -> not 0 @@ -698,8 +698,8 @@ fn storage_metering() { ]); let gas_left = { - let mut interpreter = wasm_interpreter(); - test_finalize(interpreter.exec(params, &mut ext)).unwrap() + let mut interpreter = wasm_interpreter(params); + test_finalize(interpreter.exec(&mut ext)).unwrap() }; // not 0 -> not 0 @@ -808,8 +808,8 @@ fn embedded_keccak() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("keccak should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -836,8 +836,8 @@ fn events() { let mut ext = FakeExt::new().with_wasm(); let (gas_left, result) = { - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors"); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors"); match result { GasLeft::Known(_) => { panic!("events should return payload"); }, GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), @@ -876,8 +876,8 @@ fn recursive() { let mut ext = FakeExt::new().with_wasm(); - let mut interpreter = wasm_interpreter(); - let result = interpreter.exec(params, &mut ext); + let mut interpreter = wasm_interpreter(params); + let result = interpreter.exec(&mut ext); // We expect that stack overflow will occur and it should be generated by // deterministic stack metering. Exceeding deterministic stack height limit From c8a3a542c7ebfdf682e50cc748a8d19deea53a0c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 20:12:34 +0800 Subject: [PATCH 09/21] Fix wasm runner tests --- ethcore/wasm/run/src/runner.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ethcore/wasm/run/src/runner.rs b/ethcore/wasm/run/src/runner.rs index 3e24ced5db2..a6b7b83a8c4 100644 --- a/ethcore/wasm/run/src/runner.rs +++ b/ethcore/wasm/run/src/runner.rs @@ -31,8 +31,8 @@ fn load_code>(p: P) -> io::Result> { Ok(result) } -fn wasm_interpreter() -> WasmInterpreter { - WasmInterpreter +fn wasm_interpreter(params: ActionParams) -> WasmInterpreter { + WasmInterpreter::new(params) } #[derive(Debug)] @@ -131,7 +131,7 @@ pub fn construct( params.params_type = ParamsType::Separate; Ok( - match wasm_interpreter().exec(params, ext)? { + match wasm_interpreter(params).exec(ext)? { GasLeft::Known(_) => Vec::new(), GasLeft::NeedsReturn { data, .. } => data.to_vec(), } @@ -192,9 +192,9 @@ pub fn run_fixture(fixture: &Fixture) -> Vec { } } - let mut interpreter = wasm_interpreter(); + let mut interpreter = wasm_interpreter(params); - let interpreter_return = match interpreter.exec(params, &mut ext) { + let interpreter_return = match interpreter.exec(&mut ext) { Ok(ret) => ret, Err(e) => { return Fail::runtime(e); } }; From 5f0a41991a060f7f23cab6de83483b8e52e8d721 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 20:21:40 +0800 Subject: [PATCH 10/21] Fix a check case where code length is zero --- ethcore/evm/src/interpreter/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 69811e61de7..85eee98fb01 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -227,6 +227,11 @@ impl Interpreter { let result = { let mut inner = || { + // This case is needed because code length can be zero. + if self.reader.position >= self.reader.len() { + return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); + } + let opcode = self.reader.code[self.reader.position]; let instruction = Instruction::from_u8(opcode); self.reader.position += 1; From e2bb5468c9752d0d1a90a863710b06c213eca15f Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 20:30:10 +0800 Subject: [PATCH 11/21] Fix jsontests compile --- ethcore/src/json_tests/executive.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index daeed18ebfb..f4bd2bfcb7d 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -274,11 +274,20 @@ 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 res = evm.exec(params, &mut ex); - // a return in finalize will not alter callcreates - let callcreates = ex.callcreates.clone(); - (res.finalize(ex), callcreates) + let evm = vm_factory.create(params, &ex); + match evm { + Ok(mut evm) => { + let res = evm.exec(&mut ex); + // a return in finalize will not alter callcreates + let callcreates = ex.callcreates.clone(); + (res.finalize(ex), callcreates) + }, + Err(e) => { + // a return in finalize will not alter callcreates + let callcreates = ex.callcreates.clone(); + (e.finalize(ex), callcreates) + } + } }; let log_hash = { From bb303d7384d7860bdc90bd1f536f88043accbd62 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 5 Jul 2018 20:31:37 +0800 Subject: [PATCH 12/21] Fix cargo lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 855cc5e628d..ca6b1ddf6fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -558,7 +558,6 @@ dependencies = [ "ethstore 0.2.0", "evm 0.1.0", "fake-hardware-wallet 0.0.1", - "fetch 0.1.0", "hardware-wallet 1.12.0", "hashdb 0.2.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1052,6 +1051,7 @@ name = "evm" version = "0.1.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-bytes 0.1.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", From 8578b2062e71ef8b247447d57cf2ed933a47e1c1 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Jul 2018 16:13:44 +0800 Subject: [PATCH 13/21] Use match instead of expect --- ethcore/evm/src/interpreter/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 85eee98fb01..551457e696e 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -241,12 +241,12 @@ impl Interpreter { self.reader.position - 1, opcode, self.gasometer.current_gas.as_u256(), ); - if instruction.is_none() { - return InterpreterResult::Done(Err(vm::Error::BadInstruction { + let instruction = match instruction { + Some(i) => i, + None => return InterpreterResult::Done(Err(vm::Error::BadInstruction { instruction: opcode - })); - } - let instruction = instruction.expect("None case is checked above; qed"); + })), + }; let info = instruction.info(); try_or_done!(self.verify_instruction(ext, instruction, info)); From 9e8b23cb326534b2aac58e9e86458548d29c7707 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Jul 2018 16:19:23 +0800 Subject: [PATCH 14/21] Use cheaper check reader.len() == 0 for the initial special case --- ethcore/evm/src/interpreter/mod.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 551457e696e..6523f88ada8 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -225,13 +225,10 @@ impl Interpreter { return InterpreterResult::Stopped; } - let result = { + let result = if self.reader.len() == 0 { + InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))) + } else { let mut inner = || { - // This case is needed because code length can be zero. - if self.reader.position >= self.reader.len() { - return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); - } - let opcode = self.reader.code[self.reader.position]; let instruction = Instruction::from_u8(opcode); self.reader.position += 1; From e6fb25b6eb79738f9c59c43ac49dd424f8b062f7 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Jul 2018 16:48:23 +0800 Subject: [PATCH 15/21] Get rid of try_and_done! macro by using Result<(), ReturnType> --- ethcore/evm/src/interpreter/mod.rs | 185 +++++++++++++++-------------- 1 file changed, 93 insertions(+), 92 deletions(-) diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 6523f88ada8..bf1ff2c0ccd 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -159,6 +159,12 @@ pub enum InterpreterResult { Continue, } +impl From for InterpreterResult { + fn from(error: vm::Error) -> InterpreterResult { + InterpreterResult::Done(Err(error)) + } +} + /// Intepreter EVM implementation pub struct Interpreter { mem: Vec, @@ -212,15 +218,6 @@ impl Interpreter { /// Execute a single step on the VM. #[inline(always)] pub fn step(&mut self, ext: &mut vm::Ext) -> InterpreterResult { - macro_rules! try_or_done { - ( $expr: expr ) => { - match $expr { - Ok(value) => value, - Err(err) => return InterpreterResult::Done(Err(err)), - } - } - } - if self.done { return InterpreterResult::Stopped; } @@ -228,103 +225,107 @@ impl Interpreter { let result = if self.reader.len() == 0 { InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))) } else { - let mut inner = || { - let opcode = self.reader.code[self.reader.position]; - let instruction = Instruction::from_u8(opcode); - self.reader.position += 1; - - // TODO: make compile-time removable if too much of a performance hit. - self.do_trace = self.do_trace && ext.trace_next_instruction( - self.reader.position - 1, opcode, self.gasometer.current_gas.as_u256(), - ); - - let instruction = match instruction { - Some(i) => i, - None => return InterpreterResult::Done(Err(vm::Error::BadInstruction { - instruction: opcode - })), - }; + self.step_inner(ext).err().expect("step_inner never returns Ok(()); qed") + }; - let info = instruction.info(); - try_or_done!(self.verify_instruction(ext, instruction, info)); + if let &InterpreterResult::Done(_) = &result { + self.done = true; + self.informant.done(); + } + return result; + } - // Calculate gas cost - let requirements = try_or_done!(self.gasometer.requirements(ext, instruction, info, &self.stack, self.mem.size())); - if self.do_trace { - ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256()); - } + /// Inner helper function for step. + #[inline(always)] + fn step_inner(&mut self, ext: &mut vm::Ext) -> Result<(), InterpreterResult> { + let opcode = self.reader.code[self.reader.position]; + let instruction = Instruction::from_u8(opcode); + self.reader.position += 1; + + // TODO: make compile-time removable if too much of a performance hit. + self.do_trace = self.do_trace && ext.trace_next_instruction( + self.reader.position - 1, opcode, self.gasometer.current_gas.as_u256(), + ); + + let instruction = match instruction { + Some(i) => i, + None => return Err(InterpreterResult::Done(Err(vm::Error::BadInstruction { + instruction: opcode + }))), + }; - try_or_done!(self.gasometer.verify_gas(&requirements.gas_cost)); - self.mem.expand(requirements.memory_required_size); - self.gasometer.current_mem_gas = requirements.memory_total_gas; - self.gasometer.current_gas = self.gasometer.current_gas - requirements.gas_cost; + let info = instruction.info(); + self.verify_instruction(ext, instruction, info)?; - evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) }); + // Calculate gas cost + let requirements = self.gasometer.requirements(ext, instruction, info, &self.stack, self.mem.size())?; + if self.do_trace { + ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256()); + } - let (mem_written, store_written) = match self.do_trace { - true => (Self::mem_written(instruction, &self.stack), Self::store_written(instruction, &self.stack)), - false => (None, None), - }; + self.gasometer.verify_gas(&requirements.gas_cost)?; + self.mem.expand(requirements.memory_required_size); + self.gasometer.current_mem_gas = requirements.memory_total_gas; + self.gasometer.current_gas = self.gasometer.current_gas - requirements.gas_cost; - // Execute instruction - let current_gas = self.gasometer.current_gas; - let result = try_or_done!(self.exec_instruction( - current_gas, ext, instruction, requirements.provide_gas - )); + evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) }); - evm_debug!({ informant.after_instruction(instruction) }); + let (mem_written, store_written) = match self.do_trace { + true => (Self::mem_written(instruction, &self.stack), Self::store_written(instruction, &self.stack)), + false => (None, None), + }; - if let InstructionResult::UnusedGas(ref gas) = result { - self.gasometer.current_gas = self.gasometer.current_gas + *gas; - } + // Execute instruction + let current_gas = self.gasometer.current_gas; + let result = self.exec_instruction( + current_gas, ext, instruction, requirements.provide_gas + )?; - if self.do_trace { - ext.trace_executed( - self.gasometer.current_gas.as_u256(), - self.stack.peek_top(info.ret), - mem_written.map(|(o, s)| (o, &(self.mem[o..o+s]))), - store_written, - ); - } + evm_debug!({ informant.after_instruction(instruction) }); - // Advance - match result { - InstructionResult::JumpToPosition(position) => { - if self.valid_jump_destinations.is_none() { - let code_hash = self.params.code_hash.clone().unwrap_or_else(|| keccak(self.reader.code.as_ref())); - self.valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, &self.reader.code)); - } - let jump_destinations = self.valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed"); - let pos = try_or_done!(self.verify_jump(position, jump_destinations)); - self.reader.position = pos; - }, - InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { - let mem = mem::replace(&mut self.mem, Vec::new()); - return InterpreterResult::Done(Ok(GasLeft::NeedsReturn { - gas_left: gas.as_u256(), - data: mem.into_return_data(init_off, init_size), - apply_state: apply - })); - }, - InstructionResult::StopExecution => { - return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); - }, - _ => {}, - } + if let InstructionResult::UnusedGas(ref gas) = result { + self.gasometer.current_gas = self.gasometer.current_gas + *gas; + } - if self.reader.position >= self.reader.len() { - return InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256()))); + if self.do_trace { + ext.trace_executed( + self.gasometer.current_gas.as_u256(), + self.stack.peek_top(info.ret), + mem_written.map(|(o, s)| (o, &(self.mem[o..o+s]))), + store_written, + ); + } + + // Advance + match result { + InstructionResult::JumpToPosition(position) => { + if self.valid_jump_destinations.is_none() { + let code_hash = self.params.code_hash.clone().unwrap_or_else(|| keccak(self.reader.code.as_ref())); + self.valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, &self.reader.code)); } + let jump_destinations = self.valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed"); + let pos = self.verify_jump(position, jump_destinations)?; + self.reader.position = pos; + }, + InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { + let mem = mem::replace(&mut self.mem, Vec::new()); + return Err(InterpreterResult::Done(Ok(GasLeft::NeedsReturn { + gas_left: gas.as_u256(), + data: mem.into_return_data(init_off, init_size), + apply_state: apply + }))); + }, + InstructionResult::StopExecution => { + return Err(InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256())))); + }, + _ => {}, + } - InterpreterResult::Continue - }; - inner() - }; - if let &InterpreterResult::Done(_) = &result { - self.done = true; - self.informant.done(); + if self.reader.position >= self.reader.len() { + return Err(InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.current_gas.as_u256())))); } - return result; + + Err(InterpreterResult::Continue) } fn verify_instruction(&self, ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo) -> vm::Result<()> { From 151101ad3035395cb6ac0a74b092a2df486f0ba2 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 17 Jul 2018 16:56:49 +0800 Subject: [PATCH 16/21] Use Never instead of () --- ethcore/evm/src/interpreter/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index bf1ff2c0ccd..ff8b9c5b240 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -103,6 +103,8 @@ enum InstructionResult { StopExecution, } +enum Never {} + /// ActionParams without code, so that it can be feed into CodeReader. #[derive(Debug)] struct InterpreterParams { @@ -237,7 +239,7 @@ impl Interpreter { /// Inner helper function for step. #[inline(always)] - fn step_inner(&mut self, ext: &mut vm::Ext) -> Result<(), InterpreterResult> { + fn step_inner(&mut self, ext: &mut vm::Ext) -> Result { let opcode = self.reader.code[self.reader.position]; let instruction = Instruction::from_u8(opcode); self.reader.position += 1; From 1d1a319d017e11315415ad02ebff3658b50c0386 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 24 Jul 2018 15:25:17 +0800 Subject: [PATCH 17/21] Fix parity-bytes path --- Cargo.lock | 2 +- ethcore/evm/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34d53c2d41a..369394a7529 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -982,13 +982,13 @@ name = "evm" version = "0.1.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-bytes 0.1.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2 (git+https://github.com/paritytech/parity-common)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memory-cache 0.1.0", + "parity-bytes 0.1.0 (git+https://github.com/paritytech/parity-common)", "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", diff --git a/ethcore/evm/Cargo.toml b/ethcore/evm/Cargo.toml index f4253383a1a..f5f2e814676 100644 --- a/ethcore/evm/Cargo.toml +++ b/ethcore/evm/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] [dependencies] bit-set = "0.4" -ethcore-bytes = { path = "../../util/bytes" } +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethereum-types = "0.3" heapsize = "0.4" lazy_static = "1.0" From 45f715b4a244bf43ca153d4b74ef84e1f0659b6a Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 24 Jul 2018 15:34:11 +0800 Subject: [PATCH 18/21] Bypass gasometer lifetime problem by borrow only for a instance --- ethcore/evm/src/interpreter/mod.rs | 33 +++++++++++++++--------------- ethcore/evm/src/lib.rs | 2 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 6a21c95105e..1f33f9d5bd8 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -45,6 +45,8 @@ pub use self::shared_cache::SharedCache; use bit_set::BitSet; +const GASOMETER_PROOF: &str = "If gasometer is None, Err is immediately returned in step; this function is only called by step; qed"; + type ProgramCounter = usize; const ONE: U256 = U256([1, 0, 0, 0]); @@ -198,7 +200,7 @@ impl vm::Vm for Interpreter { impl Interpreter { /// Create a new `Interpreter` instance with shared cache. - pub fn new(mut params: ActionParams, cache: Arc, ext: &vm::Ext) -> vm::Result> { + pub fn new(mut params: ActionParams, cache: Arc, ext: &vm::Ext) -> Interpreter { let reader = CodeReader::new(params.code.take().expect("VM always called with code; qed")); let params = InterpreterParams::from(params); let informant = informant::EvmInformant::new(ext.depth()); @@ -206,7 +208,7 @@ impl Interpreter { let gasometer = Cost::from_u256(params.gas).ok().map(|gas| Gasometer::::new(gas)); let stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero()); - Ok(Interpreter { + Interpreter { cache, params, reader, informant, valid_jump_destinations, gasometer, stack, done: false, @@ -214,7 +216,7 @@ impl Interpreter { mem: Vec::new(), return_data: ReturnData::empty(), _type: PhantomData, - }) + } } /// Execute a single step on the VM. @@ -225,7 +227,7 @@ impl Interpreter { } let result = if self.gasometer.is_none() { - InterpreterResult::Done(Err(Error::OutOfGas)) + InterpreterResult::Done(Err(vm::Error::OutOfGas)) } else if self.reader.len() == 0 { InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_ref().expect("Gasometer None case is checked above; qed").current_gas.as_u256()))) } else { @@ -243,13 +245,12 @@ impl Interpreter { #[inline(always)] fn step_inner(&mut self, ext: &mut vm::Ext) -> Result { let opcode = self.reader.code[self.reader.position]; - let gasometer = self.gasometer.as_mut().expect("If gasometer is None, Err is immediately returned in step; this function is only called by step; qed"); let instruction = Instruction::from_u8(opcode); self.reader.position += 1; // TODO: make compile-time removable if too much of a performance hit. self.do_trace = self.do_trace && ext.trace_next_instruction( - self.reader.position - 1, opcode, gasometer.current_gas.as_u256(), + self.reader.position - 1, opcode, self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256(), ); let instruction = match instruction { @@ -263,17 +264,17 @@ impl Interpreter { self.verify_instruction(ext, instruction, info)?; // Calculate gas cost - let requirements = gasometer.requirements(ext, instruction, info, &self.stack, self.mem.size())?; + let requirements = self.gasometer.as_mut().expect(GASOMETER_PROOF).requirements(ext, instruction, info, &self.stack, self.mem.size())?; if self.do_trace { ext.trace_prepare_execute(self.reader.position - 1, opcode, requirements.gas_cost.as_u256()); } - gasometer.verify_gas(&requirements.gas_cost)?; + self.gasometer.as_mut().expect(GASOMETER_PROOF).verify_gas(&requirements.gas_cost)?; self.mem.expand(requirements.memory_required_size); - gasometer.current_mem_gas = requirements.memory_total_gas; - gasometer.current_gas = gasometer.current_gas - requirements.gas_cost; + self.gasometer.as_mut().expect(GASOMETER_PROOF).current_mem_gas = requirements.memory_total_gas; + self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas = self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas - requirements.gas_cost; - evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) }); + evm_debug!({ informant.before_instruction(reader.position, instruction, info, &self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas, &stack) }); let (mem_written, store_written) = match self.do_trace { true => (Self::mem_written(instruction, &self.stack), Self::store_written(instruction, &self.stack)), @@ -281,7 +282,7 @@ impl Interpreter { }; // Execute instruction - let current_gas = gasometer.current_gas; + let current_gas = self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas; let result = self.exec_instruction( current_gas, ext, instruction, requirements.provide_gas )?; @@ -289,12 +290,12 @@ impl Interpreter { evm_debug!({ informant.after_instruction(instruction) }); if let InstructionResult::UnusedGas(ref gas) = result { - gasometer.current_gas = gasometer.current_gas + *gas; + self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas = self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas + *gas; } if self.do_trace { ext.trace_executed( - gasometer.current_gas.as_u256(), + self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256(), self.stack.peek_top(info.ret), mem_written.map(|(o, s)| (o, &(self.mem[o..o+s]))), store_written, @@ -321,13 +322,13 @@ impl Interpreter { }))); }, InstructionResult::StopExecution => { - return Err(InterpreterResult::Done(Ok(GasLeft::Known(gasometer.current_gas.as_u256())))); + return Err(InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256())))); }, _ => {}, } if self.reader.position >= self.reader.len() { - return Err(InterpreterResult::Done(Ok(GasLeft::Known(gasometer.current_gas.as_u256())))); + return Err(InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256())))); } Err(InterpreterResult::Continue) diff --git a/ethcore/evm/src/lib.rs b/ethcore/evm/src/lib.rs index b79155f00f9..0a067e88f1c 100644 --- a/ethcore/evm/src/lib.rs +++ b/ethcore/evm/src/lib.rs @@ -23,7 +23,7 @@ extern crate heapsize; extern crate vm; extern crate keccak_hash as hash; extern crate memory_cache; -extern crate ethcore_bytes as bytes; +extern crate parity_bytes as bytes; #[macro_use] extern crate lazy_static; From 21b8729a5479b8f61cde4311171ad359fbcefdad Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 24 Jul 2018 15:35:06 +0800 Subject: [PATCH 19/21] typo: missing { --- ethcore/src/factory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index 2fc002625c0..c168e6deb6f 100644 --- a/ethcore/src/factory.rs +++ b/ethcore/src/factory.rs @@ -31,7 +31,7 @@ pub struct VmFactory { } impl VmFactory { - pub fn create(&self, params: ActionParams, schedule: &Schedule, depth: usize) -> Box + pub fn create(&self, params: ActionParams, schedule: &Schedule, depth: usize) -> Box { if schedule.wasm.is_some() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { Box::new(WasmInterpreter) } else { From 104f844fe86647ff8b983cea396d8686e469c955 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 24 Jul 2018 15:43:28 +0800 Subject: [PATCH 20/21] Fix ethcore test compile --- ethcore/evm/src/factory.rs | 8 ++++---- ethcore/evm/src/interpreter/mod.rs | 8 ++++---- ethcore/src/executive.rs | 19 +++++++++---------- ethcore/src/factory.rs | 4 ++-- ethcore/src/json_tests/executive.rs | 4 ++-- 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index 1b4d843bbc8..e3150a95fb5 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -17,7 +17,7 @@ //! Evm factory. //! use std::sync::Arc; -use vm::{self, Vm}; +use vm::{Vm, Schedule}; use ethereum_types::U256; use super::vm::ActionParams; use super::interpreter::SharedCache; @@ -33,12 +33,12 @@ pub struct Factory { impl Factory { /// Create fresh instance of VM /// Might choose implementation depending on supplied gas. - pub fn create(&self, params: ActionParams, ext: &vm::Ext) -> Box { + pub fn create(&self, params: ActionParams, schedule: &Schedule, depth: usize) -> Box { match self.evm { VMType::Interpreter => if Self::can_fit_in_usize(¶ms.gas) { - Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), ext)) + Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), schedule, depth)) } else { - Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), ext)) + Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), schedule, depth)) } } } diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 1f33f9d5bd8..fe01da953b8 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -32,7 +32,7 @@ use ethereum_types::{U256, U512, H256, Address}; use vm::{ self, ActionParams, ParamsType, ActionValue, CallType, MessageCallResult, - ContractCreateResult, CreateContractAddress, ReturnData, GasLeft + ContractCreateResult, CreateContractAddress, ReturnData, GasLeft, Schedule }; use evm::CostType; @@ -200,13 +200,13 @@ impl vm::Vm for Interpreter { impl Interpreter { /// Create a new `Interpreter` instance with shared cache. - pub fn new(mut params: ActionParams, cache: Arc, ext: &vm::Ext) -> Interpreter { + pub fn new(mut params: ActionParams, cache: Arc, schedule: &Schedule, depth: usize) -> Interpreter { let reader = CodeReader::new(params.code.take().expect("VM always called with code; qed")); let params = InterpreterParams::from(params); - let informant = informant::EvmInformant::new(ext.depth()); + let informant = informant::EvmInformant::new(depth); let valid_jump_destinations = None; let gasometer = Cost::from_u256(params.gas).ok().map(|gas| Gasometer::::new(gas)); - let stack = VecStack::with_capacity(ext.schedule().stack_limit, U256::zero()); + let stack = VecStack::with_capacity(schedule.stack_limit, U256::zero()); Interpreter { cache, params, reader, informant, diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index b7646815429..d2fb3f100a8 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -352,23 +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(); + let origin_info = OriginInfo::from(¶ms); 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); - let mut vm = vm_factory.create(¶ms, self.schedule, self.depth); - return vm.exec(params, &mut ext).finalize(ext); + let mut vm = vm_factory.create(params, self.schedule, self.depth); + let mut ext = self.as_externalities(origin_info, unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); + return vm.exec(&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); + let origin_info = OriginInfo::from(¶ms); - 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, self.schedule, self.depth); - vm.exec(params, &mut ext).finalize(ext) + scope.builder().stack_size(::std::cmp::max(self.schedule.max_depth.saturating_sub(depth_threshold) * STACK_SIZE_PER_DEPTH, local_stack_size)).spawn(move || { + let mut vm = vm_factory.create(params, self.schedule, self.depth); + let mut ext = self.as_externalities(origin_info, unconfirmed_substate, output_policy, tracer, vm_tracer, static_call); + vm.exec(&mut ext).finalize(ext) }).expect("Sub-thread creation cannot fail; the host might run out of resources; qed") }).join() } diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index c168e6deb6f..dbfdcffc7ad 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}; +use vm::{Vm, ActionParams, Schedule}; use wasm::WasmInterpreter; use keccak_hasher::KeccakHasher; @@ -33,7 +33,7 @@ pub struct VmFactory { impl VmFactory { pub fn create(&self, params: ActionParams, schedule: &Schedule, depth: usize) -> Box { if schedule.wasm.is_some() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { - Box::new(WasmInterpreter) + Box::new(WasmInterpreter::new(params)) } else { self.evm.create(params, schedule, depth) } diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index e26228e7d4d..5dddeee485b 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -277,8 +277,8 @@ fn do_json_test_for(vm_type: &VMType, json_data: &[u8] &mut tracer, &mut vm_tracer, )); - let mut evm = vm_factory.create(¶ms, schedule, 0); - let res = evm.exec(params, &mut ex); + let mut evm = vm_factory.create(params, &schedule, 0); + let res = evm.exec(&mut ex); // a return in finalize will not alter callcreates let callcreates = ex.callcreates.clone(); (res.finalize(ex), callcreates) From f936a56f3d5149db12c56420d07b12e9c9e69ab4 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 24 Jul 2018 16:39:08 +0800 Subject: [PATCH 21/21] Fix evm tests --- ethcore/evm/src/factory.rs | 4 +- ethcore/evm/src/interpreter/mod.rs | 2 +- ethcore/evm/src/tests.rs | 74 +++++++++++++++--------------- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/ethcore/evm/src/factory.rs b/ethcore/evm/src/factory.rs index e3150a95fb5..84e01460daf 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -69,12 +69,14 @@ impl Default for Factory { #[test] fn test_create_vm() { + use vm::Ext; use vm::tests::FakeExt; use bytes::Bytes; let mut params = ActionParams::default(); params.code = Some(Arc::new(Bytes::default())); - let _vm = Factory::default().create(params, &FakeExt::new()); + let ext = FakeExt::new(); + let _vm = Factory::default().create(params, ext.schedule(), ext.depth()); } /// Create tests by injecting different VM factories diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index fe01da953b8..5294b402653 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -1074,7 +1074,7 @@ mod tests { use vm::tests::{FakeExt, test_finalize}; fn interpreter(params: ActionParams, ext: &vm::Ext) -> Box { - Factory::new(VMType::Interpreter, 1).create(params, ext).unwrap() + Factory::new(VMType::Interpreter, 1).create(params, ext.schedule(), ext.depth()) } #[test] diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index 8cda6774578..d18f1d08841 100644 --- a/ethcore/evm/src/tests.rs +++ b/ethcore/evm/src/tests.rs @@ -21,7 +21,7 @@ use std::sync::Arc; use std::collections::{HashMap, HashSet}; use rustc_hex::FromHex; use ethereum_types::{U256, H256, Address}; -use vm::{self, ActionParams, ActionValue}; +use vm::{self, ActionParams, ActionValue, Ext}; use vm::tests::{FakeExt, FakeCall, FakeCallType, test_finalize}; use factory::Factory; use vmtype::VMType; @@ -38,7 +38,7 @@ fn test_add(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -58,7 +58,7 @@ fn test_sha3(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -78,7 +78,7 @@ fn test_address(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -100,7 +100,7 @@ fn test_origin(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -122,7 +122,7 @@ fn test_sender(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -157,7 +157,7 @@ fn test_extcodecopy(factory: super::Factory) { ext.codes.insert(sender, Arc::new(sender_code)); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -177,7 +177,7 @@ fn test_log_empty(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -209,7 +209,7 @@ fn test_log_sender(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -234,7 +234,7 @@ fn test_blockhash(factory: super::Factory) { ext.blockhashes.insert(U256::zero(), blockhash.clone()); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -256,7 +256,7 @@ fn test_calldataload(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -277,7 +277,7 @@ fn test_author(factory: super::Factory) { ext.info.author = author; let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -297,7 +297,7 @@ fn test_timestamp(factory: super::Factory) { ext.info.timestamp = timestamp; let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -317,7 +317,7 @@ fn test_number(factory: super::Factory) { ext.info.number = number; let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -337,7 +337,7 @@ fn test_difficulty(factory: super::Factory) { ext.info.difficulty = difficulty; let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -357,7 +357,7 @@ fn test_gas_limit(factory: super::Factory) { ext.info.gas_limit = gas_limit; let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -375,7 +375,7 @@ fn test_mul(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -393,7 +393,7 @@ fn test_sub(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -411,7 +411,7 @@ fn test_div(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -429,7 +429,7 @@ fn test_div_zero(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -447,7 +447,7 @@ fn test_mod(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -466,7 +466,7 @@ fn test_smod(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -485,7 +485,7 @@ fn test_sdiv(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -504,7 +504,7 @@ fn test_exp(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -524,7 +524,7 @@ fn test_comparison(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -545,7 +545,7 @@ fn test_signed_comparison(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -566,7 +566,7 @@ fn test_bitops(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -589,7 +589,7 @@ fn test_addmod_mulmod(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -610,7 +610,7 @@ fn test_byte(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -629,7 +629,7 @@ fn test_signextend(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -649,7 +649,7 @@ fn test_badinstruction_int() { let mut ext = FakeExt::new(); let err = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap_err() }; @@ -669,7 +669,7 @@ fn test_pop(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -689,7 +689,7 @@ fn test_extops(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -712,7 +712,7 @@ fn test_jumps(factory: super::Factory) { let mut ext = FakeExt::new(); let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -740,7 +740,7 @@ fn test_calls(factory: super::Factory) { }; let gas_left = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() }; @@ -779,7 +779,7 @@ fn test_create_in_staticcall(factory: super::Factory) { ext.is_static = true; let err = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap_err() }; @@ -1047,7 +1047,7 @@ fn push_two_pop_one_constantinople_test(factory: &super::Factory, opcode: u8, pu let mut ext = FakeExt::new_constantinople(); let _ = { - let mut vm = factory.create(params, &ext).unwrap(); + let mut vm = factory.create(params, ext.schedule(), ext.depth()); test_finalize(vm.exec(&mut ext)).unwrap() };