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
This commit is contained in:
Wei Tang 2018-08-14 04:06:15 +08:00 committed by GitHub
parent 98dbd1fdc7
commit 9c595aff95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 574 additions and 446 deletions

1
Cargo.lock generated
View File

@ -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",

View File

@ -5,6 +5,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
[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"

View File

@ -55,6 +55,12 @@ impl Finalize for Result<GasLeft> {
}
}
impl Finalize for Error {
fn finalize<E: Ext>(self, _ext: E) -> Result<FinalizationResult> {
Err(self)
}
}
/// Cost calculation type. For low-gas usage we calculate costs using usize instead of U256
pub trait CostType: Sized + From<usize> + Copy
+ ops::Mul<Output=Self> + ops::Div<Output=Self> + ops::Add<Output=Self> +ops::Sub<Output=Self>

View File

@ -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<Vm> {
pub fn create(&self, params: ActionParams, schedule: &Schedule, depth: usize) -> Box<Vm> {
match self.evm {
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
VMType::Interpreter => if Self::can_fit_in_usize(&params.gas) {
Box::new(super::interpreter::Interpreter::<usize>::new(params, self.evm_cache.clone(), schedule, depth))
} else {
Box::new(super::interpreter::Interpreter::<U256>::new(self.evm_cache.clone()))
Box::new(super::interpreter::Interpreter::<U256>::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

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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(&params.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);

View File

@ -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(&params);
trace!(target: "executive", "ext.schedule.have_delegate_call: {}", self.schedule.have_delegate_call);
let mut ext = self.as_externalities(OriginInfo::from(&params), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
let mut vm = vm_factory.create(&params, 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(&params), unconfirmed_substate, output_policy, tracer, vm_tracer, static_call);
let origin_info = OriginInfo::from(&params);
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(&params, 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()
}

View File

@ -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<Vm> {
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<Vm> {
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(&params.gas)
self.evm.create(params, schedule, depth)
}
}

View File

@ -281,8 +281,8 @@ fn do_json_test_for<H: FnMut(&str, HookType)>(vm_type: &VMType, json_data: &[u8]
&mut tracer,
&mut vm_tracer,
));
let mut evm = vm_factory.create(&params, 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)

View File

@ -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<GasLeft>;
fn exec(&mut self, ext: &mut Ext) -> Result<GasLeft>;
}

View File

@ -31,8 +31,8 @@ fn load_code<P: AsRef<path::Path>>(p: P) -> io::Result<Vec<u8>> {
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<Fail> {
}
}
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); }
};

View File

@ -69,7 +69,15 @@ impl From<Error> 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<runtime::Error> 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<GasLeft> {
let (module, data) = parser::payload(&params, ext.schedule().wasm())?;
fn exec(&mut self, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
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(),
},
);

View File

@ -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<GasLeft, vm::Error>) -> Result<U256, vm::Error> {
}
}
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