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}; use evm::{EvmParams, Ext};
/// Evm errors. /// Evm errors.
#[derive(Debug)]
pub enum EvmError { pub enum EvmError {
/// `OutOfGas` is returned when transaction execution runs out of gas. /// `OutOfGas` is returned when transaction execution runs out of gas.
/// The state should be reverted to the state from before the /// 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) Executive::new_with_depth(state, info, engine, 0)
} }
/// Populates executive from parent externalities. Increments executive depth. /// Populates executive from parent properties. Increments executive depth.
fn from_parent(e: &'a mut Externalities) -> Self { fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self {
Executive::new_with_depth(e.state, e.info, e.engine, e.depth + 1) Executive::new_with_depth(state, info, engine, depth + 1)
} }
/// Helper constructor. Should be used to create `Executive` with desired depth. /// 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 balance is insufficient or we are to deep, return
if self.state.balance(&self.params.address) < *endowment && self.depth >= 1024 { if self.state.balance(&self.params.address) < *value && self.depth >= 1024 {
return None return Ok((gas, None));
} }
// create new contract address // create new contract address
@ -369,28 +369,17 @@ impl<'a> Ext for Externalities<'a> {
origin: self.params.origin.clone(), origin: self.params.origin.clone(),
gas: U256::from(gas), gas: U256::from(gas),
gas_price: self.params.gas_price.clone(), gas_price: self.params.gas_price.clone(),
value: endowment.clone(), value: value.clone(),
code: code.to_vec(), code: code.to_vec(),
data: vec![], data: vec![],
}; };
let mut substate = Substate::new(); let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth);
{ ex.state.inc_nonce(&self.params.address);
let mut ex = Executive::from_parent(self); ex.create(&params, self.substate).map(|gas_left| (gas_left.low_u64(), Some(address)))
ex.state.inc_nonce(&address);
let res = ex.create(&params, &mut substate);
}
self.substate.accrue(substate);
Some((gas, 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> { 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> {
// TODO: validation of the call
println!("gas: {:?}", gas);
println!("call_gas: {:?}", call_gas);
let mut gas_cost = call_gas; let mut gas_cost = call_gas;
let mut call_gas = call_gas; let mut call_gas = call_gas;
@ -406,13 +395,15 @@ impl<'a> Ext for Externalities<'a> {
} }
if gas_cost > gas { if gas_cost > gas {
return None; return Err(EvmError::OutOfGas)
} }
// if we are too deep, return let mut gas = gas - gas_cost;
// TODO: replace with >= 1024
if self.depth == 1 { //println!("depth: {:?}", self.depth);
return None; // 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 { let params = EvmParams {
@ -426,18 +417,8 @@ impl<'a> Ext for Externalities<'a> {
data: data.to_vec(), data: data.to_vec(),
}; };
println!("params: {:?}", params); 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())
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)
} }
fn extcode(&self, address: &Address) -> Vec<u8> { fn extcode(&self, address: &Address) -> Vec<u8> {
@ -556,6 +537,7 @@ mod tests {
{ {
let mut ex = Executive::new(&mut state, &info, engine.deref()); let mut ex = Executive::new(&mut state, &info, engine.deref());
let _res = ex.create(&params, &mut substate); let _res = ex.create(&params, &mut substate);
println!("res: {:?}", _res);
} }
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(next_address.clone())); assert_eq!(state.storage_at(&address, &H256::new()), H256::from(next_address.clone()));
@ -584,7 +566,7 @@ mod tests {
// 60 01 - push 1 // 60 01 - push 1
// 55 - store // 55 - store
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); 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 address = contract_address(&sender, &U256::zero());
let mut params = EvmParams::new(); let mut params = EvmParams::new();
params.address = address.clone(); params.address = address.clone();
@ -603,6 +585,7 @@ mod tests {
{ {
let mut ex = Executive::new(&mut state, &info, engine.deref()); let mut ex = Executive::new(&mut state, &info, engine.deref());
let _res = ex.call(&params, &mut substate, &mut []); let _res = ex.call(&params, &mut substate, &mut []);
println!("res: {:?}", _res);
} }
assert!(false); assert!(false);

View File

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

View File

@ -160,13 +160,15 @@ impl IntoJit<evmjit::RuntimeDataHandle> for RuntimeData {
} }
struct ExtAdapter<'a> { struct ExtAdapter<'a> {
ext: &'a mut evm::Ext ext: &'a mut evm::Ext,
err: &'a mut Option<evm::EvmError>
} }
impl<'a> ExtAdapter<'a> { 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 { ExtAdapter {
ext: ext ext: ext,
err: err
} }
} }
} }
@ -210,12 +212,21 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
address: *mut evmjit::H256) { address: *mut evmjit::H256) {
unsafe { unsafe {
match self.ext.create(*io_gas, &U256::from_jit(&*endowment), slice::from_raw_parts(init_beg, init_size as usize)) { 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; *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, out_size: u64,
code_address: *const evmjit::H256) -> bool { code_address: *const evmjit::H256) -> bool {
unsafe { unsafe {
let opt = self.ext.call(*io_gas, let res = self.ext.call(*io_gas,
call_gas, call_gas,
&Address::from_jit(&*receive_address), &Address::from_jit(&*receive_address),
&U256::from_jit(&*value), &U256::from_jit(&*value),
@ -238,11 +249,22 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> {
&Address::from_jit(&*code_address), &Address::from_jit(&*code_address),
slice::from_raw_parts_mut(out_beg, out_size as usize)); slice::from_raw_parts_mut(out_beg, out_size as usize));
match opt { match res {
None => false, Ok(gas_left) => {
Some(gas_left) => {
*io_gas = gas_left; *io_gas = gas_left;
true 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 { impl evm::Evm for JitEvm {
fn exec(&self, params: &evm::EvmParams, ext: &mut evm::Ext) -> evm::EvmResult { 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. // 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 ext_handle = evmjit::ExtHandle::new(ext_adapter);
let mut data = RuntimeData::new(); let mut data = RuntimeData::new();
data.gas = params.gas; data.gas = params.gas;
@ -315,7 +338,14 @@ impl evm::Evm for JitEvm {
data.timestamp = 0; data.timestamp = 0;
let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) }; 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::Stop => Ok(U256::from(context.gas_left())),
evmjit::ReturnCode::Return => match ext.ret(context.gas_left(), context.output_data()) { evmjit::ReturnCode::Return => match ext.ret(context.gas_left(), context.output_data()) {
Some(gas_left) => Ok(U256::from(gas_left)), Some(gas_left) => Ok(U256::from(gas_left)),