ext call refactored
This commit is contained in:
parent
777ac4dc87
commit
6fb580f621
@ -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>;
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(¶ms, &mut ext)
|
evm.exec(¶ms, &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(¶ms, &mut ext)
|
evm.exec(¶ms, &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(¶ms, self.substate).map(|gas_left| (gas_left, Some(address)))
|
//ex.create(¶ms, 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(¶ms, self.substate, BytesRef::Fixed(output)).map(|gas_left| gas + gas_left)
|
match ex.call(¶ms, 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(¶ms, 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> {
|
||||||
|
@ -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> {
|
||||||
|
Loading…
Reference in New Issue
Block a user