propagate evmjit errors upstream

This commit is contained in:
debris 2016-01-11 14:08:03 +01:00
parent dea9ec203b
commit bbb25fb6ce
4 changed files with 83 additions and 59 deletions

View File

@ -4,6 +4,7 @@ use util::uint::U256;
use evm::{EvmParams, Ext};
/// Evm errors.
#[derive(Debug)]
pub enum EvmError {
/// `OutOfGas` is returned when transaction execution runs out of gas.
/// The state should be reverted to the state from before the

View File

@ -123,9 +123,9 @@ impl<'a> Executive<'a> {
Executive::new_with_depth(state, info, engine, 0)
}
/// Populates executive from parent externalities. Increments executive depth.
fn from_parent(e: &'a mut Externalities) -> Self {
Executive::new_with_depth(e.state, e.info, e.engine, e.depth + 1)
/// Populates executive from parent properties. Increments executive depth.
fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self {
Executive::new_with_depth(state, info, engine, depth + 1)
}
/// Helper constructor. Should be used to create `Executive` with desired depth.
@ -353,10 +353,10 @@ impl<'a> Ext for Externalities<'a> {
}
}
fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(u64, Address)> {
fn create(&mut self, gas: u64, value: &U256, code: &[u8]) -> Result<(u64, Option<Address>), EvmError> {
// if balance is insufficient or we are to deep, return
if self.state.balance(&self.params.address) < *endowment && self.depth >= 1024 {
return None
if self.state.balance(&self.params.address) < *value && self.depth >= 1024 {
return Ok((gas, None));
}
// create new contract address
@ -369,28 +369,17 @@ impl<'a> Ext for Externalities<'a> {
origin: self.params.origin.clone(),
gas: U256::from(gas),
gas_price: self.params.gas_price.clone(),
value: endowment.clone(),
value: value.clone(),
code: code.to_vec(),
data: vec![],
};
let mut substate = Substate::new();
{
let mut ex = Executive::from_parent(self);
ex.state.inc_nonce(&address);
let res = ex.create(&params, &mut substate);
}
self.substate.accrue(substate);
Some((gas, address))
let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth);
ex.state.inc_nonce(&self.params.address);
ex.create(&params, self.substate).map(|gas_left| (gas_left.low_u64(), Some(address)))
}
fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> Option<u64> {
// TODO: validation of the call
println!("gas: {:?}", gas);
println!("call_gas: {:?}", call_gas);
fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> Result<u64, EvmError> {
let mut gas_cost = call_gas;
let mut call_gas = call_gas;
@ -406,13 +395,15 @@ impl<'a> Ext for Externalities<'a> {
}
if gas_cost > gas {
return None;
return Err(EvmError::OutOfGas)
}
// if we are too deep, return
// TODO: replace with >= 1024
if self.depth == 1 {
return None;
let mut gas = gas - gas_cost;
//println!("depth: {:?}", self.depth);
// if balance is insufficient or we are to deep, return
if self.state.balance(&self.params.address) < *value && self.depth >= 1024 {
return Ok(gas + call_gas)
}
let params = EvmParams {
@ -426,18 +417,8 @@ impl<'a> Ext for Externalities<'a> {
data: data.to_vec(),
};
println!("params: {:?}", params);
let mut substate = Substate::new();
{
let mut ex = Executive::from_parent(self);
// TODO: take output into account
ex.call(&params, &mut substate, output);
}
self.substate.accrue(substate);
// TODO: replace call_gas with what's actually left
Some(gas - gas_cost + call_gas)
let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth);
ex.call(&params, self.substate, output).map(|gas_left| gas + gas_left.low_u64())
}
fn extcode(&self, address: &Address) -> Vec<u8> {
@ -556,6 +537,7 @@ mod tests {
{
let mut ex = Executive::new(&mut state, &info, engine.deref());
let _res = ex.create(&params, &mut substate);
println!("res: {:?}", _res);
}
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(next_address.clone()));
@ -584,7 +566,7 @@ mod tests {
// 60 01 - push 1
// 55 - store
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let code = "600160005401600055600060006000600060003360e05a03f1600155".from_hex().unwrap();
let code = "600160005401600055600060006000600060003060e05a03f1600155".from_hex().unwrap();
let address = contract_address(&sender, &U256::zero());
let mut params = EvmParams::new();
params.address = address.clone();
@ -603,6 +585,7 @@ mod tests {
{
let mut ex = Executive::new(&mut state, &info, engine.deref());
let _res = ex.call(&params, &mut substate, &mut []);
println!("res: {:?}", _res);
}
assert!(false);

View File

@ -4,6 +4,7 @@ use util::hash::*;
use util::uint::*;
use util::bytes::*;
use evm_schedule::*;
use evm::EvmError;
pub trait Ext {
/// Returns a value for given key.
@ -19,15 +20,24 @@ pub trait Ext {
fn blockhash(&self, number: &U256) -> H256;
/// Creates new contract.
/// If contract creation is successfull,
/// return gas_left and contract address,
/// otherwise `None`.
fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(u64, Address)>;
///
/// If contract creation is successfull, return gas_left and contract address,
/// If depth is too big or transfer value exceeds balance, return None
/// Otherwise return appropriate `EvmError`.
fn create(&mut self, gas: u64, value: &U256, code: &[u8]) -> Result<(u64, Option<Address>), EvmError>;
/// Message call.
///
/// If call is successfull, returns gas left.
/// otherwise `None`.
fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> Option<u64>;
/// otherwise `EvmError`.
fn call(&mut self,
gas: u64,
call_gas: u64,
receive_address: &Address,
value: &U256,
data: &[u8],
code_address: &Address,
output: &mut [u8]) -> Result<u64, EvmError>;
/// Returns code at given address
fn extcode(&self, address: &Address) -> Vec<u8>;

View File

@ -160,13 +160,15 @@ impl IntoJit<evmjit::RuntimeDataHandle> for RuntimeData {
}
struct ExtAdapter<'a> {
ext: &'a mut evm::Ext
ext: &'a mut evm::Ext,
err: &'a mut Option<evm::EvmError>
}
impl<'a> ExtAdapter<'a> {
fn new(ext: &'a mut evm::Ext) -> Self {
fn new(ext: &'a mut evm::Ext, err: &'a mut Option<evm::EvmError>) -> Self {
ExtAdapter {
ext: ext
ext: ext,
err: err
}
}
}
@ -210,12 +212,21 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
address: *mut evmjit::H256) {
unsafe {
match self.ext.create(*io_gas, &U256::from_jit(&*endowment), slice::from_raw_parts(init_beg, init_size as usize)) {
Some((gas_left, addr)) => {
Ok((gas_left, opt)) => {
*io_gas = gas_left;
*address = addr.into_jit();
if let Some(addr) = opt {
*address = addr.into_jit();
}
},
None => ()
};
Err(err @ evm::EvmError::OutOfGas) => {
*self.err = Some(err);
// hack to propagate `OutOfGas` to evmjit and stop
// the execution immediately.
// Works, cause evmjit uses i64, not u64
*io_gas = -1i64 as u64
},
Err(err) => *self.err = Some(err)
}
}
}
@ -230,7 +241,7 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
out_size: u64,
code_address: *const evmjit::H256) -> bool {
unsafe {
let opt = self.ext.call(*io_gas,
let res = self.ext.call(*io_gas,
call_gas,
&Address::from_jit(&*receive_address),
&U256::from_jit(&*value),
@ -238,11 +249,22 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
&Address::from_jit(&*code_address),
slice::from_raw_parts_mut(out_beg, out_size as usize));
match opt {
None => false,
Some(gas_left) => {
match res {
Ok(gas_left) => {
*io_gas = gas_left;
true
},
Err(err @ evm::EvmError::OutOfGas) => {
*self.err = Some(err);
// hack to propagate `OutOfGas` to evmjit and stop
// the execution immediately.
// Works, cause evmjit uses i64, not u64
*io_gas = -1i64 as u64;
false
},
Err(err) => {
*self.err = Some(err);
false
}
}
}
@ -294,8 +316,9 @@ pub struct JitEvm;
impl evm::Evm for JitEvm {
fn exec(&self, params: &evm::EvmParams, ext: &mut evm::Ext) -> evm::EvmResult {
let mut optional_err = None;
// Dirty hack. This is unsafe, but we interact with ffi, so it's justified.
let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext)) };
let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, &mut optional_err)) };
let mut ext_handle = evmjit::ExtHandle::new(ext_adapter);
let mut data = RuntimeData::new();
data.gas = params.gas;
@ -315,7 +338,14 @@ impl evm::Evm for JitEvm {
data.timestamp = 0;
let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) };
match context.exec() {
let res = context.exec();
// check in adapter if execution of children contracts failed.
if let Some(err) = optional_err {
return Err(err);
}
match res {
evmjit::ReturnCode::Stop => Ok(U256::from(context.gas_left())),
evmjit::ReturnCode::Return => match ext.ret(context.gas_left(), context.output_data()) {
Some(gas_left) => Ok(U256::from(gas_left)),