ext call refactored

This commit is contained in:
debris 2016-01-14 19:52:40 +01:00
parent 777ac4dc87
commit 6fb580f621
6 changed files with 64 additions and 39 deletions

View File

@ -6,6 +6,20 @@ use util::bytes::*;
use evm::{Schedule, Error}; use evm::{Schedule, Error};
use env_info::*; use env_info::*;
pub struct CallResult {
pub gas_left: U256,
pub success: bool
}
impl CallResult {
pub fn new(gas_left: U256, success: bool) -> Self {
CallResult {
gas_left: gas_left,
success: success
}
}
}
pub trait Ext { pub trait Ext {
/// Returns a value for given key. /// Returns a value for given key.
fn sload(&self, key: &H256) -> H256; fn sload(&self, key: &H256) -> H256;
@ -26,8 +40,9 @@ pub trait Ext {
/// Message call. /// Message call.
/// ///
/// If call is successfull, returns gas left. /// Returns None, if we run out of gas.
/// otherwise `Error`. /// Otherwise returns call_result which contains gas left
/// and true if subcall was successfull.
fn call(&mut self, fn call(&mut self,
gas: &U256, gas: &U256,
call_gas: &U256, call_gas: &U256,
@ -35,7 +50,7 @@ pub trait Ext {
value: &U256, value: &U256,
data: &[u8], data: &[u8],
code_address: &Address, code_address: &Address,
output: &mut [u8]) -> Result<U256, Error>; output: &mut [u8]) -> Option<CallResult>;
/// 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

@ -229,30 +229,21 @@ 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 res = self.ext.call(&U256::from(*io_gas), let opt = self.ext.call(&U256::from(*io_gas),
&U256::from(call_gas), &U256::from(call_gas),
&Address::from_jit(&*receive_address), &Address::from_jit(&*receive_address),
&U256::from_jit(&*value), &U256::from_jit(&*value),
slice::from_raw_parts(in_beg, in_size as usize), slice::from_raw_parts(in_beg, in_size as usize),
&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 => {
Ok(gas_left) => {
*io_gas = gas_left.low_u64();
true
},
Err(err @ evm::Error::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; *io_gas = -1i64 as u64;
false false
}, },
Err(err) => { Some(res) => {
*self.err = Some(err); *io_gas = res.gas_left.low_u64();
false res.success
} }
} }
} }

View File

@ -11,6 +11,6 @@ mod jit;
mod tests; mod tests;
pub use self::evm::{Evm, Error, Result}; pub use self::evm::{Evm, Error, Result};
pub use self::ext::Ext; pub use self::ext::{Ext, CallResult};
pub use self::factory::Factory; pub use self::factory::Factory;
pub use self::schedule::Schedule; pub use self::schedule::Schedule;

View File

@ -1,6 +1,6 @@
use common::*; use common::*;
use evm; use evm;
use evm::{Ext, Schedule, Factory}; use evm::{Ext, Schedule, Factory, CallResult};
struct FakeLogEntry { struct FakeLogEntry {
topics: Vec<H256>, topics: Vec<H256>,
@ -53,7 +53,7 @@ impl Ext for FakeExt {
_value: &U256, _value: &U256,
_data: &[u8], _data: &[u8],
_code_address: &Address, _code_address: &Address,
_output: &mut [u8]) -> result::Result<U256, evm::Error> { _output: &mut [u8]) -> Option<CallResult> {
unimplemented!(); unimplemented!();
} }

View File

@ -2,7 +2,7 @@
use common::*; use common::*;
use state::*; use state::*;
use engine::*; use engine::*;
use evm::{self, Schedule, Factory, Ext}; use evm::{self, Schedule, Factory, Ext, CallResult};
/// Returns new address created from address and given nonce. /// Returns new address created from address and given nonce.
pub fn contract_address(address: &Address, nonce: &U256) -> Address { pub fn contract_address(address: &Address, nonce: &U256) -> Address {
@ -38,6 +38,8 @@ impl Substate {
contracts_created: vec![] contracts_created: vec![]
} }
} }
pub fn out_of_gas(&self) -> bool { self.out_of_gas }
} }
/// Transaction execution receipt. /// Transaction execution receipt.
@ -207,7 +209,8 @@ impl<'a> Executive<'a> {
let evm = Factory::create(); let evm = Factory::create();
evm.exec(&params, &mut ext) evm.exec(&params, &mut ext)
}; };
self.handle_out_of_gas(res, substate, backup) self.revert_if_needed(&res, substate, backup);
res
} else { } else {
// otherwise, nothing // otherwise, nothing
Ok(params.gas) Ok(params.gas)
@ -232,7 +235,8 @@ impl<'a> Executive<'a> {
let evm = Factory::create(); let evm = Factory::create();
evm.exec(&params, &mut ext) evm.exec(&params, &mut ext)
}; };
self.handle_out_of_gas(res, substate, backup) self.revert_if_needed(&res, substate, backup);
res
} }
/// Finalizes the transaction (does refunds and suicides). /// Finalizes the transaction (does refunds and suicides).
@ -278,12 +282,11 @@ impl<'a> Executive<'a> {
} }
} }
pub fn handle_out_of_gas(&mut self, result: evm::Result, substate: &mut Substate, backup: State) -> evm::Result { pub fn revert_if_needed(&mut self, result: &evm::Result, substate: &mut Substate, backup: State) {
if let &Err(evm::Error::OutOfGas) = &result { if let &Err(evm::Error::OutOfGas) = result {
substate.out_of_gas = true; substate.out_of_gas = true;
self.state.revert(backup); self.state.revert(backup);
} }
result
} }
} }
@ -398,7 +401,14 @@ impl<'a> Ext for Externalities<'a> {
//ex.create(&params, self.substate).map(|gas_left| (gas_left, Some(address))) //ex.create(&params, self.substate).map(|gas_left| (gas_left, Some(address)))
} }
fn call(&mut self, gas: &U256, call_gas: &U256, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address, output: &mut [u8]) -> Result<U256, evm::Error> { fn call(&mut self,
gas: &U256,
call_gas: &U256,
receive_address: &Address,
value: &U256,
data: &[u8],
code_address: &Address,
output: &mut [u8]) -> Option<CallResult> {
let mut gas_cost = *call_gas; let mut gas_cost = *call_gas;
let mut call_gas = *call_gas; let mut call_gas = *call_gas;
@ -414,14 +424,17 @@ impl<'a> Ext for Externalities<'a> {
} }
if gas_cost > *gas { if gas_cost > *gas {
return Err(evm::Error::OutOfGas) self.substate.out_of_gas = true;
return None;
//return (U256::from(-1i64 as u64), false);
} }
let gas = *gas - gas_cost; let gas = *gas - gas_cost;
// 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) < *value || self.depth >= self.schedule.max_depth { if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth {
return Ok(gas + call_gas) return Some(CallResult::new(gas + call_gas, true));
//return (gas + call_gas, true);
} }
let params = ActionParams { let params = ActionParams {
@ -436,7 +449,14 @@ impl<'a> Ext for Externalities<'a> {
}; };
let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth);
ex.call(&params, self.substate, BytesRef::Fixed(output)).map(|gas_left| gas + gas_left) match ex.call(&params, self.substate, BytesRef::Fixed(output)) {
Ok(gas_left) => Some(CallResult::new(gas + gas_left, true)),
_ => {
self.substate.out_of_gas = true;
Some(CallResult::new(gas, false))
}
}
//ex.call(&params, self.substate, BytesRef::Fixed(output)).map(|gas_left| gas + gas_left)
} }
fn extcode(&self, address: &Address) -> Vec<u8> { fn extcode(&self, address: &Address) -> Vec<u8> {

View File

@ -4,7 +4,7 @@ use executive::*;
use spec::*; use spec::*;
use engine::*; use engine::*;
use evm; use evm;
use evm::{Schedule, Ext, Factory}; use evm::{Schedule, Ext, Factory, CallResult};
use ethereum; use ethereum;
struct TestEngine { struct TestEngine {
@ -110,21 +110,20 @@ impl<'a> Ext for TestExt<'a> {
value: &U256, value: &U256,
data: &[u8], data: &[u8],
code_address: &Address, code_address: &Address,
output: &mut [u8]) -> Result<U256, evm::Error> { output: &mut [u8]) -> Option<CallResult> {
let res = self.ext.call(gas, call_gas, receive_address, value, data, code_address, output); let opt = self.ext.call(gas, call_gas, receive_address, value, data, code_address, output);
let ext = &self.ext; let ext = &self.ext;
match res { if let &Some(_) = &opt {
Ok(gas_left) if ext.state.balance(&ext.params.address) >= *value => { if ext.state.balance(&ext.params.address) >= *value {
self.callcreates.push(CallCreate { self.callcreates.push(CallCreate {
data: data.to_vec(), data: data.to_vec(),
destination: receive_address.clone(), destination: receive_address.clone(),
_gas_limit: *call_gas, _gas_limit: *call_gas,
value: *value value: *value
}); });
Ok(gas_left) }
},
other => other
} }
opt
} }
fn extcode(&self, address: &Address) -> Vec<u8> { fn extcode(&self, address: &Address) -> Vec<u8> {