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

@@ -16,9 +16,23 @@
//! VM errors module
use ::{ResumeCall, ResumeCreate};
use ethereum_types::Address;
use action_params::ActionParams;
use std::fmt;
use ethtrie;
#[derive(Debug)]
pub enum TrapKind {
Call(ActionParams),
Create(ActionParams, Address),
}
pub enum TrapError<Call, Create> {
Call(ActionParams, Call),
Create(ActionParams, Address, Create),
}
/// VM errors.
#[derive(Debug, Clone, PartialEq)]
pub enum Error {
@@ -76,18 +90,13 @@ impl From<Box<ethtrie::TrieError>> for Error {
Error::Internal(format!("Internal error: {}", err))
}
}
impl From<ethtrie::TrieError> for Error {
fn from(err: ethtrie::TrieError) -> Self {
Error::Internal(format!("Internal error: {}", err))
}
}
// impl From<wasm::RuntimeError> for Error {
// fn from(err: wasm::RuntimeError) -> Self {
// Error::Wasm(format!("Runtime error: {:?}", err))
// }
// }
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
@@ -108,3 +117,7 @@ impl fmt::Display for Error {
}
pub type Result<T> = ::std::result::Result<T, Error>;
pub type TrapResult<T, Call, Create> = ::std::result::Result<Result<T>, TrapError<Call, Create>>;
pub type ExecTrapResult<T> = TrapResult<T, Box<ResumeCall>, Box<ResumeCreate>>;
pub type ExecTrapError = TrapError<Box<ResumeCall>, Box<ResumeCreate>>;

View File

@@ -23,8 +23,9 @@ use call_type::CallType;
use env_info::EnvInfo;
use schedule::Schedule;
use return_data::ReturnData;
use error::Result;
use error::{Result, TrapKind};
#[derive(Debug)]
/// Result of externalities create function.
pub enum ContractCreateResult {
/// Returned when creation was successfull.
@@ -37,6 +38,7 @@ pub enum ContractCreateResult {
Reverted(U256, ReturnData),
}
#[derive(Debug)]
/// Result of externalities call function.
pub enum MessageCallResult {
/// Returned when message call was successfull.
@@ -90,22 +92,31 @@ pub trait Ext {
/// Creates new contract.
///
/// Returns gas_left and contract address if contract creation was succesfull.
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], address: CreateContractAddress) -> ContractCreateResult;
fn create(
&mut self,
gas: &U256,
value: &U256,
code: &[u8],
address: CreateContractAddress,
trap: bool,
) -> ::std::result::Result<ContractCreateResult, TrapKind>;
/// Message call.
///
/// Returns Err, if we run out of gas.
/// Otherwise returns call_result which contains gas left
/// and true if subcall was successfull.
fn call(&mut self,
fn call(
&mut self,
gas: &U256,
sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
code_address: &Address,
call_type: CallType
) -> MessageCallResult;
call_type: CallType,
trap: bool
) -> ::std::result::Result<MessageCallResult, TrapKind>;
/// Returns code at given address
fn extcode(&self, address: &Address) -> Result<Option<Arc<Bytes>>>;
@@ -149,10 +160,10 @@ pub trait Ext {
fn trace_next_instruction(&mut self, _pc: usize, _instruction: u8, _current_gas: U256) -> bool { false }
/// Prepare to trace an operation. Passthrough for the VM trace.
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: U256) {}
fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8, _gas_cost: U256, _mem_written: Option<(usize, usize)>, _store_written: Option<(U256, U256)>) {}
/// Trace the finalised execution of a single instruction.
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem_diff: Option<(usize, &[u8])>, _store_diff: Option<(U256, U256)>) {}
fn trace_executed(&mut self, _gas_used: U256, _stack_push: &[U256], _mem: &[u8]) {}
/// Check if running in static context.
fn is_static(&self) -> bool;

View File

@@ -41,12 +41,24 @@ pub use env_info::{EnvInfo, LastHashes};
pub use schedule::{Schedule, CleanDustMode, WasmCosts};
pub use ext::{Ext, MessageCallResult, ContractCreateResult, CreateContractAddress};
pub use return_data::{ReturnData, GasLeft};
pub use error::{Error, Result};
pub use error::{Error, Result, TrapResult, TrapError, TrapKind, ExecTrapResult, ExecTrapError};
/// Virtual Machine interface
pub trait Vm {
pub trait Exec: Send {
/// 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, ext: &mut Ext) -> Result<GasLeft>;
fn exec(self: Box<Self>, ext: &mut Ext) -> ExecTrapResult<GasLeft>;
}
/// Resume call interface
pub trait ResumeCall: Send {
/// Resume an execution for call, returns back the Vm interface.
fn resume_call(self: Box<Self>, result: MessageCallResult) -> Box<Exec>;
}
/// Resume create interface
pub trait ResumeCreate: Send {
/// Resume an execution from create, returns back the Vm interface.
fn resume_create(self: Box<Self>, result: ContractCreateResult) -> Box<Exec>;
}

View File

@@ -25,6 +25,7 @@ use {
CreateContractAddress, Result, GasLeft,
};
use hash::keccak;
use error::TrapKind;
pub struct FakeLogEntry {
pub topics: Vec<H256>,
@@ -138,7 +139,14 @@ impl Ext for FakeExt {
self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
}
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], address: CreateContractAddress) -> ContractCreateResult {
fn create(
&mut self,
gas: &U256,
value: &U256,
code: &[u8],
address: CreateContractAddress,
_trap: bool,
) -> ::std::result::Result<ContractCreateResult, TrapKind> {
self.calls.insert(FakeCall {
call_type: FakeCallType::Create,
create_scheme: Some(address),
@@ -149,19 +157,21 @@ impl Ext for FakeExt {
data: code.to_vec(),
code_address: None
});
ContractCreateResult::Failed
// TODO: support traps in testing.
Ok(ContractCreateResult::Failed)
}
fn call(&mut self,
gas: &U256,
sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
code_address: &Address,
_call_type: CallType
) -> MessageCallResult {
fn call(
&mut self,
gas: &U256,
sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
code_address: &Address,
_call_type: CallType,
_trap: bool,
) -> ::std::result::Result<MessageCallResult, TrapKind> {
self.calls.insert(FakeCall {
call_type: FakeCallType::Call,
create_scheme: None,
@@ -172,7 +182,8 @@ impl Ext for FakeExt {
data: data.to_vec(),
code_address: Some(code_address.clone())
});
MessageCallResult::Success(*gas, ReturnData::empty())
// TODO: support traps in testing.
Ok(MessageCallResult::Success(*gas, ReturnData::empty()))
}
fn extcode(&self, address: &Address) -> Result<Option<Arc<Bytes>>> {