propagate evmjit errors upstream
This commit is contained in:
parent
dea9ec203b
commit
bbb25fb6ce
@ -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
|
||||||
|
@ -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(¶ms, self.substate).map(|gas_left| (gas_left.low_u64(), Some(address)))
|
||||||
ex.state.inc_nonce(&address);
|
|
||||||
let res = ex.create(¶ms, &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(¶ms, 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(¶ms, &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(¶ms, &mut substate);
|
let _res = ex.create(¶ms, &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(¶ms, &mut substate, &mut []);
|
let _res = ex.call(¶ms, &mut substate, &mut []);
|
||||||
|
println!("res: {:?}", _res);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(false);
|
assert!(false);
|
||||||
|
@ -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>;
|
||||||
|
@ -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)),
|
||||||
|
Loading…
Reference in New Issue
Block a user