Resumable EVM and heap-allocated callstack (#9360)

* Add new Vm trappable interface

* Exec/Resume interface

* Basic implementation of CallCreateExecutive

* Implement resume_call and resume_create for executive

* Move convertion to call/create result to separate function

* Implement consume that converts resumable to non-resumable

* Use consume for Executive::call/create

* Resumable EVM

* Implement tracing mode without needing subtracers

* Implement vmtracer so it doesn't require extra structs for subtracing

* Use the new tracing mode in executive

* Fix most of the linting errors for cargo build

* Add the concept of stack_depth

* Add back crossbeam

* Fix some test compile

* Fix prefix address test

* Fix evm crate tests

* Fix wasm crate test compile

* Fix wasm runner compile

* Fix jsontests compile

* Fix evmbin compile

* Fix an issue with create nonce and better vm tracing interface

* Fix linting

* Fix evmbin compile

* Fix unconfirmed_substate and static_flag

* Fix an issue in create address logic

* Fix top-level tracing

* Handle builtin tracing

* Fix suicide and reward tracing index stack

* Fix an issue where trap conflicts with tracing

* Fix an issue in parent step vm tracing

* Fix revert tracing

* Fix evmbin tests

* Remove params clone

* Fix TODO proofs

* Fix jsontests compile

* Fix evmbin merge issue

* Fix wasm merge issue

* Fix wasm test

* Fix ethcore merge warnings

* Fix evmbin compile

* Better expect messages and add some trace::skip_one asserts
This commit is contained in:
Wei Tang
2018-10-02 22:33:19 +08:00
committed by GitHub
parent 61ec361182
commit 1e9aebbc86
24 changed files with 1465 additions and 804 deletions

View File

@@ -91,9 +91,8 @@ enum ExecutionOutcome {
NotSpecial,
}
impl vm::Vm for WasmInterpreter {
fn exec(&mut self, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
impl WasmInterpreter {
pub fn run(self: Box<WasmInterpreter>, 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)?;
@@ -190,3 +189,9 @@ impl vm::Vm for WasmInterpreter {
}
}
}
impl vm::Exec for WasmInterpreter {
fn exec(self: Box<WasmInterpreter>, ext: &mut vm::Ext) -> vm::ExecTrapResult<GasLeft> {
Ok(self.run(ext))
}
}

View File

@@ -450,7 +450,8 @@ impl<'a> Runtime<'a> {
&payload,
&address,
call_type,
);
false
).ok().expect("Trap is false; trap error will not happen; qed");
match call_result {
vm::MessageCallResult::Success(gas_left, data) => {
@@ -528,7 +529,7 @@ impl<'a> Runtime<'a> {
* U256::from(self.ext.schedule().wasm().opcodes_mul)
/ U256::from(self.ext.schedule().wasm().opcodes_div);
match self.ext.create(&gas_left, &endowment, &code, scheme) {
match self.ext.create(&gas_left, &endowment, &code, scheme, false).ok().expect("Trap is false; trap error will not happen; qed") {
vm::ContractCreateResult::Created(address, gas_left) => {
self.memory.set(result_ptr, &*address)?;
self.gas_counter = self.gas_limit -

View File

@@ -20,7 +20,7 @@ use byteorder::{LittleEndian, ByteOrder};
use ethereum_types::{H256, U256, Address};
use super::WasmInterpreter;
use vm::{self, Vm, GasLeft, ActionParams, ActionValue, CreateContractAddress};
use vm::{self, Exec, GasLeft, ActionParams, ActionValue, CreateContractAddress};
use vm::tests::{FakeCall, FakeExt, FakeCallType};
macro_rules! load_sample {
@@ -48,7 +48,7 @@ macro_rules! reqrep_test {
fake_ext.blockhashes = $block_hashes;
let mut interpreter = wasm_interpreter(params);
interpreter.exec(&mut fake_ext)
interpreter.exec(&mut fake_ext).ok().unwrap()
.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(params: ActionParams) -> WasmInterpreter {
WasmInterpreter::new(params)
fn wasm_interpreter(params: ActionParams) -> Box<WasmInterpreter> {
Box::new(WasmInterpreter::new(params))
}
/// Empty contract does almost nothing except producing 1 (one) local node debug log message
@@ -83,7 +83,7 @@ fn empty() {
let gas_left = {
let mut interpreter = wasm_interpreter(params);
test_finalize(interpreter.exec(&mut ext)).unwrap()
test_finalize(interpreter.exec(&mut ext).ok().unwrap()).unwrap()
};
assert_eq!(gas_left, U256::from(96_926));
@@ -112,7 +112,7 @@ fn logger() {
let gas_left = {
let mut interpreter = wasm_interpreter(params);
test_finalize(interpreter.exec(&mut ext)).unwrap()
test_finalize(interpreter.exec(&mut ext).ok().unwrap()).unwrap()
};
let address_val: H256 = address.into();
@@ -161,7 +161,7 @@ fn identity() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -196,7 +196,7 @@ fn dispersion() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -224,7 +224,7 @@ fn suicide_not() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -257,7 +257,7 @@ fn suicide() {
let gas_left = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(gas) => gas,
GasLeft::NeedsReturn { .. } => {
@@ -285,7 +285,7 @@ fn create() {
let gas_left = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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.");
@@ -347,7 +347,7 @@ fn call_msg() {
let gas_left = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(gas_left) => gas_left,
GasLeft::NeedsReturn { .. } => { panic!("Call test should not return payload"); },
@@ -395,7 +395,7 @@ fn call_msg_gasleft() {
let gas_left = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(gas_left) => gas_left,
GasLeft::NeedsReturn { .. } => { panic!("Call test should not return payload"); },
@@ -438,7 +438,7 @@ fn call_code() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -486,7 +486,7 @@ fn call_static() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -527,7 +527,7 @@ fn realloc() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -549,7 +549,7 @@ fn alloc() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -576,7 +576,7 @@ fn storage_read() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -602,7 +602,7 @@ fn keccak() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -749,7 +749,7 @@ fn storage_metering() {
let gas_left = {
let mut interpreter = wasm_interpreter(params);
test_finalize(interpreter.exec(&mut ext)).unwrap()
test_finalize(interpreter.exec(&mut ext).ok().unwrap()).unwrap()
};
// 0 -> not 0
@@ -768,7 +768,7 @@ fn storage_metering() {
let gas_left = {
let mut interpreter = wasm_interpreter(params);
test_finalize(interpreter.exec(&mut ext)).unwrap()
test_finalize(interpreter.exec(&mut ext).ok().unwrap()).unwrap()
};
// not 0 -> not 0
@@ -875,8 +875,8 @@ fn gasleft() {
let mut ext = FakeExt::new().with_wasm();
ext.schedule.wasm.as_mut().unwrap().have_gasleft = true;
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).ok().unwrap().expect("Interpreter to execute without any errors");
match result {
GasLeft::Known(_) => {},
GasLeft::NeedsReturn { gas_left, data, .. } => {
@@ -897,8 +897,8 @@ fn gasleft_fail() {
params.gas = U256::from(100_000);
params.code = Some(Arc::new(load_sample!("gasleft.wasm")));
let mut ext = FakeExt::new().with_wasm();
let mut interpreter = wasm_interpreter(params);
match interpreter.exec(&mut ext) {
let interpreter = wasm_interpreter(params);
match interpreter.exec(&mut ext).ok().unwrap() {
Err(_) => {},
Ok(_) => panic!("interpreter.exec should return Err if ext.schedule.wasm.have_gasleft = false")
}
@@ -919,7 +919,7 @@ fn embedded_keccak() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -947,7 +947,7 @@ fn events() {
let (gas_left, result) = {
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).expect("Interpreter to execute without any errors");
let result = interpreter.exec(&mut ext).ok().unwrap().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()),
@@ -986,8 +986,8 @@ fn recursive() {
let mut ext = FakeExt::new().with_wasm();
let mut interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext);
let interpreter = wasm_interpreter(params);
let result = interpreter.exec(&mut ext).ok().unwrap();
// We expect that stack overflow will occur and it should be generated by
// deterministic stack metering. Exceeding deterministic stack height limit