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:
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 -
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user