From 9c595aff9547073391260ee048aca16516e63b2c Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Tue, 14 Aug 2018 04:06:15 +0800 Subject: [PATCH] Allow single opcode stepping for EVM (#9051) * Feed in ActionParams on VM creation * Fix ethcore after Vm interface change * Move informant inside Interpreter struct * Move do_trace to Interpreter struct * Move all remaining exec variables to Interpreter struct * Refactor VM to allow single opcode step * Fix all EVM tests * Fix all wasm tests * Fix wasm runner tests * Fix a check case where code length is zero * Fix jsontests compile * Fix cargo lock * Use match instead of expect * Use cheaper check reader.len() == 0 for the initial special case * Get rid of try_and_done! macro by using Result<(), ReturnType> * Use Never instead of () * Fix parity-bytes path * Bypass gasometer lifetime problem by borrow only for a instance * typo: missing { * Fix ethcore test compile * Fix evm tests --- Cargo.lock | 1 + ethcore/evm/Cargo.toml | 1 + ethcore/evm/src/evm.rs | 6 + ethcore/evm/src/factory.rs | 20 +- ethcore/evm/src/interpreter/mod.rs | 690 ++++++++++++++++------------ ethcore/evm/src/lib.rs | 1 + ethcore/evm/src/tests.rs | 146 +++--- ethcore/src/executive.rs | 19 +- ethcore/src/factory.rs | 10 +- ethcore/src/json_tests/executive.rs | 4 +- ethcore/vm/src/lib.rs | 2 +- ethcore/wasm/run/src/runner.rs | 10 +- ethcore/wasm/src/lib.rs | 26 +- ethcore/wasm/src/tests.rs | 84 ++-- 14 files changed, 574 insertions(+), 446 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3e229c40..d69838383 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1007,6 +1007,7 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (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 ce9f644cc..3ccabffb3 100644 --- a/ethcore/evm/Cargo.toml +++ b/ethcore/evm/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Parity Technologies "] [dependencies] bit-set = "0.4" +parity-bytes = { git = "https://github.com/paritytech/parity-common" } ethereum-types = "0.3" heapsize = "0.4" lazy_static = "1.0" diff --git a/ethcore/evm/src/evm.rs b/ethcore/evm/src/evm.rs index 4c85b3702..9d2ff0cb1 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 65a683cd4..84e01460d 100644 --- a/ethcore/evm/src/factory.rs +++ b/ethcore/evm/src/factory.rs @@ -17,8 +17,9 @@ //! Evm factory. //! use std::sync::Arc; -use vm::Vm; +use vm::{Vm, Schedule}; 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, schedule: &Schedule, depth: usize) -> 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(), schedule, depth)) } else { - Box::new(super::interpreter::Interpreter::::new(self.evm_cache.clone())) + Box::new(super::interpreter::Interpreter::::new(params, self.evm_cache.clone(), schedule, depth)) } } } @@ -68,7 +69,14 @@ impl Default for Factory { #[test] fn test_create_vm() { - let _vm = Factory::default().create(&U256::zero()); + use vm::Ext; + use vm::tests::FakeExt; + use bytes::Bytes; + + let mut params = ActionParams::default(); + params.code = Some(Arc::new(Bytes::default())); + 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 3af1e34dd..fefa3a60b 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -27,11 +27,12 @@ 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, - ContractCreateResult, CreateContractAddress, ReturnData, GasLeft + self, ActionParams, ParamsType, ActionValue, CallType, MessageCallResult, + ContractCreateResult, CreateContractAddress, ReturnData, GasLeft, Schedule }; use evm::CostType; @@ -44,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]); @@ -58,17 +61,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,127 +105,236 @@ enum InstructionResult { StopExecution, } +enum Never {} + +/// 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, + } + } +} + +/// 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, +} + +impl From for InterpreterResult { + fn from(error: vm::Error) -> InterpreterResult { + InterpreterResult::Done(Err(error)) + } +} + /// Intepreter EVM implementation pub struct Interpreter { mem: Vec, cache: Arc, + params: InterpreterParams, + reader: CodeReader, return_data: ReturnData, + informant: informant::EvmInformant, + do_trace: bool, + done: bool, + valid_jump_destinations: Option>, + gasometer: Option>, + stack: VecStack, _type: PhantomData, } impl vm::Vm for Interpreter { - fn exec(&mut self, params: ActionParams, 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 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]; - let instruction = Instruction::from_u8(opcode); - 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(), - ); - - 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, &stack)?; - - // 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()); - } - - 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; - - evm_debug!({ informant.before_instruction(reader.position, instruction, info, &gasometer.current_gas, &stack) }); - - let (mem_written, store_written) = match do_trace { - true => (Self::mem_written(instruction, &stack), Self::store_written(instruction, &stack)), - false => (None, None), - }; - - // Execute instruction - let result = self.exec_instruction( - gasometer.current_gas, ¶ms, ext, instruction, &mut reader, &mut stack, requirements.provide_gas - )?; - - evm_debug!({ informant.after_instruction(instruction) }); - - if let InstructionResult::UnusedGas(ref gas) = result { - gasometer.current_gas = gasometer.current_gas + *gas; - } - - if do_trace { - ext.trace_executed( - gasometer.current_gas.as_u256(), - stack.peek_top(info.ret), - mem_written.map(|(o, s)| (o, &(self.mem[o..o+s]))), - store_written, - ); - } - - // Advance + fn exec(&mut self, ext: &mut vm::Ext) -> vm::Result { + loop { + let result = self.step(ext); 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 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; - }, - InstructionResult::StopExecutionNeedsReturn {gas, init_off, init_size, apply} => { - 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.") } } - informant.done(); - Ok(GasLeft::Known(gasometer.current_gas.as_u256())) } } impl Interpreter { /// Create a new `Interpreter` instance with shared cache. - pub fn new(cache: Arc) -> 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(depth); + let valid_jump_destinations = None; + let gasometer = Cost::from_u256(params.gas).ok().map(|gas| Gasometer::::new(gas)); + let stack = VecStack::with_capacity(schedule.stack_limit, U256::zero()); + Interpreter { + cache, params, reader, informant, + valid_jump_destinations, gasometer, stack, + done: false, + do_trace: true, mem: Vec::new(), - cache: cache, return_data: ReturnData::empty(), - _type: PhantomData::default(), + _type: PhantomData, } } - fn verify_instruction(&self, ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack) -> vm::Result<()> { + /// Execute a single step on the VM. + #[inline(always)] + pub fn step(&mut self, ext: &mut vm::Ext) -> InterpreterResult { + if self.done { + return InterpreterResult::Stopped; + } + + let result = if self.gasometer.is_none() { + 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 { + self.step_inner(ext).err().expect("step_inner never returns Ok(()); qed") + }; + + if let &InterpreterResult::Done(_) = &result { + self.done = true; + self.informant.done(); + } + return result; + } + + /// Inner helper function for step. + #[inline(always)] + 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; + + // 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.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256(), + ); + + let instruction = match instruction { + Some(i) => i, + None => return Err(InterpreterResult::Done(Err(vm::Error::BadInstruction { + instruction: opcode + }))), + }; + + let info = instruction.info(); + self.verify_instruction(ext, instruction, info)?; + + // Calculate gas cost + 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()); + } + + self.gasometer.as_mut().expect(GASOMETER_PROOF).verify_gas(&requirements.gas_cost)?; + self.mem.expand(requirements.memory_required_size); + 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, &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)), + false => (None, None), + }; + + // Execute instruction + let current_gas = self.gasometer.as_mut().expect(GASOMETER_PROOF).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.as_mut().expect(GASOMETER_PROOF).current_gas = self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas + *gas; + } + + if self.do_trace { + ext.trace_executed( + 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, + ); + } + + // 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.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256())))); + }, + _ => {}, + } + + if self.reader.position >= self.reader.len() { + return Err(InterpreterResult::Done(Ok(GasLeft::Known(self.gasometer.as_mut().expect(GASOMETER_PROOF).current_gas.as_u256())))); + } + + Err(InterpreterResult::Continue) + } + + 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) || @@ -238,13 +350,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, @@ -289,24 +401,21 @@ 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> { 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 )); @@ -316,14 +425,14 @@ impl Interpreter { // ignore }, instructions::CREATE | instructions::CREATE2 => { - let endowment = stack.pop_back(); + let endowment = self.stack.pop_back(); let address_scheme = match instruction { instructions::CREATE => CreateContractAddress::FromSenderAndNonce, - instructions::CREATE2 => CreateContractAddress::FromSenderSaltAndCodeHash(stack.pop_back().into()), + instructions::CREATE2 => CreateContractAddress::FromSenderSaltAndCodeHash(self.stack.pop_back().into()), _ => unreachable!("instruction can only be CREATE/CREATE2 checked above; qed"), }; - 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(); 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"); @@ -334,9 +443,9 @@ 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()); + self.stack.push(U256::zero()); return Ok(InstructionResult::UnusedGas(create_gas)); } @@ -345,16 +454,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) }, }; @@ -362,9 +471,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 { @@ -372,13 +481,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() { @@ -392,15 +501,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)) }; @@ -409,7 +518,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)); } @@ -423,30 +532,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}) }, @@ -454,16 +563,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(); @@ -478,157 +587,157 @@ 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); - stack.push(val); + let val = self.reader.read(bytes); + 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(code.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(params.address.clone())); + self.stack.push(address_to_u256(self.params.address.clone())); }, instructions::ORIGIN => { - stack.push(address_to_u256(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(params.sender.clone())); + self.stack.push(address_to_u256(self.params.sender.clone())); }, instructions::CALLVALUE => { - stack.push(match 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) = 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]; 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(params.data.clone().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(code.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)?.unwrap_or(0); - stack.push(U256::from(len)); + self.stack.push(U256::from(len)); }, instructions::EXTCODEHASH => { - let address = u256_to_address(&stack.pop_back()); + let address = u256_to_address(&self.stack.pop_back()); let hash = ext.extcodehash(&address)?.unwrap_or_else(H256::zero); - stack.push(U256::from(hash)); + self.stack.push(U256::from(hash)); }, 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, &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, params.code.as_ref().map_or_else(|| &[] as &[u8], |c| &**c as &[u8])); + 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, + &mut self.stack, code.as_ref().map(|c| &(*c)[..]).unwrap_or(&[]) ); }, instructions::GASPRICE => { - stack.push(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 @@ -638,38 +747,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, @@ -688,21 +797,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 @@ -712,12 +821,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 { @@ -725,84 +834,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; @@ -813,11 +922,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; @@ -827,14 +936,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 @@ -844,28 +953,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. @@ -873,8 +982,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 { @@ -891,7 +1000,7 @@ impl Interpreter { } shifted }; - stack.push(result); + self.stack.push(result); }, }; Ok(InstructionResult::Ok) @@ -936,11 +1045,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 { @@ -979,12 +1084,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.schedule(), ext.depth()) } #[test] @@ -1002,8 +1106,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); @@ -1024,8 +1128,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/lib.rs b/ethcore/evm/src/lib.rs index cd326a317..0a067e88f 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 parity_bytes as bytes; #[macro_use] extern crate lazy_static; diff --git a/ethcore/evm/src/tests.rs b/ethcore/evm/src/tests.rs index b8f0df363..b1f6268bf 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,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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + 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.schedule(), ext.depth()); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_set_contains(&ext.calls, &FakeCall { @@ -781,8 +781,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.schedule(), ext.depth()); + test_finalize(vm.exec(&mut ext)).unwrap_err() }; assert_eq!(err, vm::Error::MutableCallInStaticContext); @@ -1049,8 +1049,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.schedule(), ext.depth()); + test_finalize(vm.exec(&mut ext)).unwrap() }; assert_store(&ext, 0, result); diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index b77cb050e..1d1a733ad 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -354,23 +354,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, wasm); - 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, wasm); - 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 c6b9b0f6d..dbfdcffc7 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; @@ -31,11 +31,11 @@ pub struct VmFactory { } impl VmFactory { - pub fn create(&self, params: &ActionParams, wasm: bool) -> Box { - if wasm && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) { - Box::new(WasmInterpreter) + 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::new(params)) } else { - self.evm.create(¶ms.gas) + self.evm.create(params, schedule, depth) } } diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index a8fd4b453..3a04bbe5e 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -281,8 +281,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.wasm.is_some()); - 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) diff --git a/ethcore/vm/src/lib.rs b/ethcore/vm/src/lib.rs index 2c98cfcd2..314db030e 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/run/src/runner.rs b/ethcore/wasm/run/src/runner.rs index 3e24ced5d..a6b7b83a8 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); } }; diff --git a/ethcore/wasm/src/lib.rs b/ethcore/wasm/src/lib.rs index 1fcfe9371..97758c192 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(), }, ); diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index e72cc15c8..fdbb54590 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 { .. } => { @@ -284,8 +284,8 @@ fn create() { ext.schedule.wasm.as_mut().unwrap().have_create2 = true; 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(_) => { panic!("Create contract always return 40 bytes of the creation address, or in the case where it fails, return 40 bytes of zero."); @@ -346,8 +346,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"); }, @@ -389,8 +389,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()), @@ -437,8 +437,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()), @@ -478,8 +478,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()), @@ -500,8 +500,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()), @@ -527,8 +527,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()), @@ -553,8 +553,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()), @@ -700,8 +700,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 @@ -719,8 +719,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 @@ -829,8 +829,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()), @@ -857,8 +857,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()), @@ -897,8 +897,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