big refactor of executive in progress
This commit is contained in:
parent
b72da41ea7
commit
b273792ef0
@ -4,15 +4,26 @@ use util::uint::U256;
|
|||||||
use util::bytes::Bytes;
|
use util::bytes::Bytes;
|
||||||
use evm::{EvmParams, Ext};
|
use evm::{EvmParams, Ext};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
/// Evm errors.
|
||||||
pub enum EvmResult {
|
pub enum EvmError {
|
||||||
Stop { gas_left: U256 },
|
/// Returned when transaction execution run out of gas.
|
||||||
Return(Bytes),
|
/// The state should be reverted to the state from before the
|
||||||
Suicide,
|
/// transaction execution. But it does not mean that transaction
|
||||||
|
/// was invalid. Balance still should be transfered and nonce
|
||||||
|
/// should be increased.
|
||||||
OutOfGas,
|
OutOfGas,
|
||||||
InternalError
|
/// Returned on evm internal error. Should never be ignored during development.
|
||||||
|
/// Likely to cause consensus issues.
|
||||||
|
Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evm result.
|
||||||
|
///
|
||||||
|
/// Returns gas_left if execution is successfull, otherwise error.
|
||||||
|
pub type EvmResult = Result<U256, EvmError>;
|
||||||
|
|
||||||
|
/// Evm interface.
|
||||||
pub trait Evm {
|
pub trait Evm {
|
||||||
|
/// This function should be used to execute transaction.
|
||||||
fn exec(&self, params: &EvmParams, ext: &mut Ext) -> EvmResult;
|
fn exec(&self, params: &EvmParams, ext: &mut Ext) -> EvmResult;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::ptr;
|
||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
use util::uint::*;
|
use util::uint::*;
|
||||||
use util::rlp::*;
|
use util::rlp::*;
|
||||||
@ -7,9 +8,10 @@ use util::sha3::*;
|
|||||||
use util::bytes::*;
|
use util::bytes::*;
|
||||||
use state::*;
|
use state::*;
|
||||||
use env_info::*;
|
use env_info::*;
|
||||||
|
use evm_schedule::*;
|
||||||
use engine::*;
|
use engine::*;
|
||||||
use transaction::*;
|
use transaction::*;
|
||||||
use evm::{VmFactory, Ext, LogEntry, EvmParams, EvmResult};
|
use evm::{VmFactory, Ext, LogEntry, EvmParams, EvmResult, EvmError};
|
||||||
|
|
||||||
/// 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 {
|
||||||
@ -40,6 +42,7 @@ impl Substate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
pub fn logs(&self) -> &[LogEntry] {
|
pub fn logs(&self) -> &[LogEntry] {
|
||||||
&self.logs
|
&self.logs
|
||||||
}
|
}
|
||||||
@ -52,17 +55,59 @@ impl Substate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transaction execution result.
|
||||||
|
pub struct Executed {
|
||||||
|
/// Gas paid up front for execution of transaction.
|
||||||
|
pub gas: U256,
|
||||||
|
/// Gas used during execution of transaction.
|
||||||
|
pub gas_used: U256,
|
||||||
|
/// Gas refunded after the execution of transaction.
|
||||||
|
/// To get gas that was required up front, add `refunded` and `gas_used`.
|
||||||
|
pub refunded: U256,
|
||||||
|
/// Cumulative gas used in current block so far.
|
||||||
|
///
|
||||||
|
/// cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)
|
||||||
|
///
|
||||||
|
/// where `tn` is current transaction.
|
||||||
|
pub cumulative_gas_used: U256,
|
||||||
|
/// Transaction output.
|
||||||
|
pub output: Bytes,
|
||||||
|
/// Vector of logs generated by transaction.
|
||||||
|
pub logs: Vec<LogEntry>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Executed {
|
||||||
|
fn new() -> Executed {
|
||||||
|
Executed {
|
||||||
|
gas: U256::zero(),
|
||||||
|
gas_used: U256::zero(),
|
||||||
|
refunded: U256::zero(),
|
||||||
|
cumulative_gas_used: U256::zero(),
|
||||||
|
output: vec![],
|
||||||
|
logs: vec![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Result of executing the transaction.
|
/// Result of executing the transaction.
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum ExecutiveResult {
|
pub enum ExecutionError {
|
||||||
Ok,
|
/// Returned when block (gas_used + gas) > gas_limit.
|
||||||
|
///
|
||||||
|
/// If gas =< gas_limit, upstream may try to execute the transaction
|
||||||
|
/// in next block.
|
||||||
BlockGasLimitReached { gas_limit: U256, gas_used: U256, gas: U256 },
|
BlockGasLimitReached { gas_limit: U256, gas_used: U256, gas: U256 },
|
||||||
|
/// Returned when transaction nonce does not match state nonce.
|
||||||
InvalidNonce { expected: U256, is: U256 },
|
InvalidNonce { expected: U256, is: U256 },
|
||||||
|
/// Returned when cost of transaction (value + gas_price * gas) exceeds
|
||||||
|
/// current sender balance.
|
||||||
NotEnoughCash { required: U256, is: U256 },
|
NotEnoughCash { required: U256, is: U256 },
|
||||||
OutOfGas,
|
/// Returned when internal evm error occurs.
|
||||||
InternalError
|
Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type ExecutionResult = Result<Executed, ExecutionError>;
|
||||||
|
|
||||||
/// Message-call/contract-creation executor; useful for executing transactions.
|
/// Message-call/contract-creation executor; useful for executing transactions.
|
||||||
pub struct Executive<'a> {
|
pub struct Executive<'a> {
|
||||||
state: &'a mut State,
|
state: &'a mut State,
|
||||||
@ -94,22 +139,24 @@ impl<'a> Executive<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This funtion should be used to execute transaction.
|
/// This funtion should be used to execute transaction.
|
||||||
pub fn transact(e: &mut Executive<'a>, t: &Transaction) -> ExecutiveResult {
|
pub fn transact(e: &mut Executive<'a>, t: &Transaction) -> ExecutionResult {
|
||||||
// validate if transaction fits into given block
|
// TODO: validate transaction signature ?/ sender
|
||||||
if e.info.gas_used + t.gas > e.info.gas_limit {
|
|
||||||
return ExecutiveResult::BlockGasLimitReached {
|
|
||||||
gas_limit: e.info.gas_limit,
|
|
||||||
gas_used: e.info.gas_used,
|
|
||||||
gas: t.gas
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
let nonce = e.state.nonce(&sender);
|
let nonce = e.state.nonce(&sender);
|
||||||
|
|
||||||
// validate transaction nonce
|
// validate transaction nonce
|
||||||
if t.nonce != nonce {
|
if t.nonce != nonce {
|
||||||
return ExecutiveResult::InvalidNonce { expected: nonce, is: t.nonce };
|
return Err(ExecutionError::InvalidNonce { expected: nonce, is: t.nonce });
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate if transaction fits into given block
|
||||||
|
if e.info.gas_used + t.gas > e.info.gas_limit {
|
||||||
|
return Err(ExecutionError::BlockGasLimitReached {
|
||||||
|
gas_limit: e.info.gas_limit,
|
||||||
|
gas_used: e.info.gas_used,
|
||||||
|
gas: t.gas
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we might need bigints here, or at least check overflows.
|
// TODO: we might need bigints here, or at least check overflows.
|
||||||
@ -119,9 +166,10 @@ impl<'a> Executive<'a> {
|
|||||||
|
|
||||||
// avoid unaffordable transactions
|
// avoid unaffordable transactions
|
||||||
if balance < total_cost {
|
if balance < total_cost {
|
||||||
return ExecutiveResult::NotEnoughCash { required: total_cost, is: balance };
|
return Err(ExecutionError::NotEnoughCash { required: total_cost, is: balance });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: there can be no invalid transactions from this point.
|
||||||
e.state.inc_nonce(&sender);
|
e.state.inc_nonce(&sender);
|
||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
|
|
||||||
@ -137,7 +185,7 @@ impl<'a> Executive<'a> {
|
|||||||
code: t.data.clone(),
|
code: t.data.clone(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
};
|
||||||
Executive::call(e, ¶ms, &mut substate)
|
Executive::call(e, ¶ms, &mut substate, &mut [])
|
||||||
},
|
},
|
||||||
TransactionKind::MessageCall => {
|
TransactionKind::MessageCall => {
|
||||||
let params = EvmParams {
|
let params = EvmParams {
|
||||||
@ -156,78 +204,51 @@ impl<'a> Executive<'a> {
|
|||||||
|
|
||||||
// finalize here!
|
// finalize here!
|
||||||
e.finalize(substate, &sender, U256::zero(), U256::zero(), t.gas_price);
|
e.finalize(substate, &sender, U256::zero(), U256::zero(), t.gas_price);
|
||||||
res
|
//res
|
||||||
|
Ok(Executed::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls contract function with given contract params.
|
/// Calls contract function with given contract params.
|
||||||
/// *Note. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
||||||
fn call(e: &mut Executive<'a>, params: &EvmParams, substate: &mut Substate) -> ExecutiveResult {
|
/// Modifies the substate and the output.
|
||||||
|
/// Returns either gas_left or `EvmError`.
|
||||||
|
fn call(e: &mut Executive<'a>, params: &EvmParams, substate: &mut Substate, output: &mut [u8]) -> EvmResult {
|
||||||
// at first, transfer value to destination
|
// at first, transfer value to destination
|
||||||
e.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value);
|
e.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value);
|
||||||
|
|
||||||
// if destination is builtin, try to execute it, or quickly return
|
|
||||||
if e.engine.is_builtin(¶ms.address) {
|
if e.engine.is_builtin(¶ms.address) {
|
||||||
return match e.engine.cost_of_builtin(¶ms.address, ¶ms.data) > params.gas {
|
// if destination is builtin, try to execute it
|
||||||
true => ExecutiveResult::OutOfGas,
|
let cost = e.engine.cost_of_builtin(¶ms.address, ¶ms.data);
|
||||||
false => {
|
match cost <= params.gas {
|
||||||
// TODO: substract gas for execution
|
true => {
|
||||||
let mut out = vec![];
|
e.engine.execute_builtin(¶ms.address, ¶ms.data, output);
|
||||||
e.engine.execute_builtin(¶ms.address, ¶ms.data, &mut out);
|
Ok(params.gas - cost)
|
||||||
ExecutiveResult::Ok
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise do `normal` execution if destination is a contract
|
|
||||||
// TODO: is executing contract with no code different from not executing contract at all?
|
|
||||||
// if yes, there is a logic issue here. mk
|
|
||||||
if params.code.len() > 0 {
|
|
||||||
return match {
|
|
||||||
let mut ext = Externalities::new(e.state, e.info, e.engine, e.depth, params, substate);
|
|
||||||
let evm = VmFactory::create();
|
|
||||||
evm.exec(¶ms, &mut ext)
|
|
||||||
} {
|
|
||||||
EvmResult::Stop { gas_left } => ExecutiveResult::Ok,
|
|
||||||
EvmResult::Return(_) => ExecutiveResult::Ok,
|
|
||||||
EvmResult::Suicide => {
|
|
||||||
substate.suicides.insert(params.address.clone());
|
|
||||||
ExecutiveResult::Ok
|
|
||||||
},
|
},
|
||||||
EvmResult::OutOfGas => ExecutiveResult::OutOfGas,
|
false => Err(EvmError::OutOfGas)
|
||||||
_err => ExecutiveResult::InternalError
|
|
||||||
}
|
}
|
||||||
|
} else if params.code.len() > 0 {
|
||||||
|
// if destination is a contract, do normal message call
|
||||||
|
let mut ext = Externalities::new(e.state, e.info, e.engine, e.depth, params, substate, OutputPolicy::Return(output));
|
||||||
|
let evm = VmFactory::create();
|
||||||
|
evm.exec(¶ms, &mut ext)
|
||||||
|
} else {
|
||||||
|
// otherwise, nothing
|
||||||
|
Ok(params.gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutiveResult::Ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates contract with given contract params.
|
/// Creates contract with given contract params.
|
||||||
/// *Note. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
||||||
fn create(e: &mut Executive<'a>, params: &EvmParams, substate: &mut Substate) -> ExecutiveResult {
|
/// Modifies the substate.
|
||||||
|
fn create(e: &mut Executive<'a>, params: &EvmParams, substate: &mut Substate) -> EvmResult {
|
||||||
// at first create new contract
|
// at first create new contract
|
||||||
e.state.new_contract(¶ms.address);
|
e.state.new_contract(¶ms.address);
|
||||||
// then transfer value to it
|
// then transfer value to it
|
||||||
e.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value);
|
e.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value);
|
||||||
|
|
||||||
match {
|
let mut ext = Externalities::new(e.state, e.info, e.engine, e.depth, params, substate, OutputPolicy::InitContract);
|
||||||
let mut ext = Externalities::new(e.state, e.info, e.engine, e.depth, params, substate);
|
let evm = VmFactory::create();
|
||||||
let evm = VmFactory::create();
|
evm.exec(¶ms, &mut ext)
|
||||||
evm.exec(¶ms, &mut ext)
|
|
||||||
} {
|
|
||||||
EvmResult::Stop { gas_left } => {
|
|
||||||
ExecutiveResult::Ok
|
|
||||||
},
|
|
||||||
EvmResult::Return(output) => {
|
|
||||||
e.state.init_code(¶ms.address, output);
|
|
||||||
ExecutiveResult::Ok
|
|
||||||
},
|
|
||||||
EvmResult::Suicide => {
|
|
||||||
substate.suicides.insert(params.address.clone());
|
|
||||||
ExecutiveResult::Ok
|
|
||||||
},
|
|
||||||
EvmResult::OutOfGas => ExecutiveResult::OutOfGas,
|
|
||||||
_err => ExecutiveResult::InternalError
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalizes the transaction (does refunds and suicides).
|
/// Finalizes the transaction (does refunds and suicides).
|
||||||
@ -256,6 +277,19 @@ impl<'a> Executive<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ExtMode {
|
||||||
|
Call,
|
||||||
|
Create
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper structure for evm return data to avoid unnecessary copying.
|
||||||
|
pub enum OutputPolicy<'a> {
|
||||||
|
/// Reference to fixed sized output of a message call.
|
||||||
|
Return(&'a mut [u8]),
|
||||||
|
/// Use it, if you want return code to initialize contract.
|
||||||
|
InitContract
|
||||||
|
}
|
||||||
|
|
||||||
/// Implementation of evm Externalities.
|
/// Implementation of evm Externalities.
|
||||||
pub struct Externalities<'a> {
|
pub struct Externalities<'a> {
|
||||||
state: &'a mut State,
|
state: &'a mut State,
|
||||||
@ -263,19 +297,29 @@ pub struct Externalities<'a> {
|
|||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
params: &'a EvmParams,
|
params: &'a EvmParams,
|
||||||
substate: &'a mut Substate
|
substate: &'a mut Substate,
|
||||||
|
schedule: EvmSchedule,
|
||||||
|
output: OutputPolicy<'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Externalities<'a> {
|
impl<'a> Externalities<'a> {
|
||||||
/// Basic `Externalities` constructor.
|
/// Basic `Externalities` constructor.
|
||||||
pub fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize, params: &'a EvmParams, substate: &'a mut Substate) -> Self {
|
pub fn new(state: &'a mut State,
|
||||||
|
info: &'a EnvInfo,
|
||||||
|
engine: &'a Engine,
|
||||||
|
depth: usize,
|
||||||
|
params: &'a EvmParams,
|
||||||
|
substate: &'a mut Substate,
|
||||||
|
output: OutputPolicy<'a>) -> Self {
|
||||||
Externalities {
|
Externalities {
|
||||||
state: state,
|
state: state,
|
||||||
info: info,
|
info: info,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
depth: depth,
|
depth: depth,
|
||||||
params: params,
|
params: params,
|
||||||
substate: substate
|
substate: substate,
|
||||||
|
schedule: engine.evm_schedule(info),
|
||||||
|
output: output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,19 +389,18 @@ impl<'a> Ext for Externalities<'a> {
|
|||||||
println!("gas: {:?}", gas);
|
println!("gas: {:?}", gas);
|
||||||
println!("call_gas: {:?}", call_gas);
|
println!("call_gas: {:?}", call_gas);
|
||||||
|
|
||||||
let schedule = self.engine.evm_schedule(self.info);
|
|
||||||
let mut gas_cost = call_gas;
|
let mut gas_cost = call_gas;
|
||||||
let mut call_gas = call_gas;
|
let mut call_gas = call_gas;
|
||||||
|
|
||||||
let is_call = receive_address == code_address;
|
let is_call = receive_address == code_address;
|
||||||
if is_call && self.state.code(&code_address).is_none() {
|
if is_call && self.state.code(&code_address).is_none() {
|
||||||
gas_cost = gas_cost + schedule.call_new_account_gas as u64;
|
gas_cost = gas_cost + self.schedule.call_new_account_gas as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
if *value > U256::zero() {
|
if *value > U256::zero() {
|
||||||
assert!(schedule.call_value_transfer_gas > schedule.call_stipend, "overflow possible");
|
assert!(self.schedule.call_value_transfer_gas > self.schedule.call_stipend, "overflow possible");
|
||||||
gas_cost = gas_cost + schedule.call_value_transfer_gas as u64;
|
gas_cost = gas_cost + self.schedule.call_value_transfer_gas as u64;
|
||||||
call_gas = call_gas + schedule.call_stipend as u64;
|
call_gas = call_gas + self.schedule.call_stipend as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
if gas_cost > gas {
|
if gas_cost > gas {
|
||||||
@ -387,9 +430,11 @@ impl<'a> Ext for Externalities<'a> {
|
|||||||
let mut substate = Substate::new();
|
let mut substate = Substate::new();
|
||||||
{
|
{
|
||||||
let mut ex = Executive::from_parent(self);
|
let mut ex = Executive::from_parent(self);
|
||||||
Executive::call(&mut ex, ¶ms, &mut substate);
|
// TODO: take output into account
|
||||||
|
Executive::call(&mut ex, ¶ms, &mut substate, &mut []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.substate.accrue(substate);
|
||||||
// TODO: replace call_gas with what's actually left
|
// TODO: replace call_gas with what's actually left
|
||||||
Some((vec![], gas - gas_cost + call_gas))
|
Some((vec![], gas - gas_cost + call_gas))
|
||||||
}
|
}
|
||||||
@ -398,10 +443,44 @@ impl<'a> Ext for Externalities<'a> {
|
|||||||
self.state.code(address).unwrap_or(vec![])
|
self.state.code(address).unwrap_or(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ret(&mut self, gas: u64, data: &[u8]) -> Option<u64> {
|
||||||
|
match &mut self.output {
|
||||||
|
&mut OutputPolicy::Return(ref mut slice) => unsafe {
|
||||||
|
let len = cmp::min(slice.len(), data.len());
|
||||||
|
ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len);
|
||||||
|
Some(gas)
|
||||||
|
},
|
||||||
|
&mut OutputPolicy::InitContract => {
|
||||||
|
let return_cost = data.len() as u64 * self.schedule.create_data_gas as u64;
|
||||||
|
if return_cost > gas {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut code = vec![];
|
||||||
|
code.reserve(data.len());
|
||||||
|
unsafe {
|
||||||
|
ptr::copy(data.as_ptr(), code.as_mut_ptr(), data.len());
|
||||||
|
code.set_len(data.len());
|
||||||
|
}
|
||||||
|
let address = &self.params.address;
|
||||||
|
self.state.init_code(address, code);
|
||||||
|
Some(gas - return_cost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn log(&mut self, topics: Vec<H256>, data: Bytes) {
|
fn log(&mut self, topics: Vec<H256>, data: Bytes) {
|
||||||
let address = self.params.address.clone();
|
let address = self.params.address.clone();
|
||||||
self.substate.logs.push(LogEntry::new(address, topics, data));
|
self.substate.logs.push(LogEntry::new(address, topics, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn suicide(&mut self) {
|
||||||
|
let address = self.params.address.clone();
|
||||||
|
self.substate.suicides.insert(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule(&self) -> &EvmSchedule {
|
||||||
|
&self.schedule
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -462,7 +541,7 @@ mod tests {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
assert_eq!(Executive::create(&mut ex, ¶ms, &mut substate), ExecutiveResult::Ok);
|
assert_eq!(Executive::create(&mut ex, ¶ms, &mut substate), ExecutionResult::Ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0xf9u64)));
|
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0xf9u64)));
|
||||||
@ -489,7 +568,7 @@ mod tests {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
assert_eq!(Executive::create(&mut ex, ¶ms, &mut substate), ExecutiveResult::Ok);
|
assert_eq!(Executive::create(&mut ex, ¶ms, &mut substate), ExecutionResult::Ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
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()));
|
||||||
@ -537,7 +616,7 @@ mod tests {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let mut ex = Executive::new(&mut state, &info, engine.deref());
|
let mut ex = Executive::new(&mut state, &info, engine.deref());
|
||||||
assert_eq!(Executive::call(&mut ex, ¶ms, &mut substate), ExecutiveResult::Ok);
|
assert_eq!(Executive::call(&mut ex, ¶ms, &mut substate), ExecutionResult::Ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(false);
|
assert!(false);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
use util::uint::*;
|
use util::uint::*;
|
||||||
use util::bytes::*;
|
use util::bytes::*;
|
||||||
|
use evm_schedule::*;
|
||||||
|
|
||||||
pub trait Ext {
|
pub trait Ext {
|
||||||
/// Returns a value for given key.
|
/// Returns a value for given key.
|
||||||
@ -33,4 +34,14 @@ pub trait Ext {
|
|||||||
|
|
||||||
/// Creates log entry with given topics and data
|
/// Creates log entry with given topics and data
|
||||||
fn log(&mut self, topics: Vec<H256>, data: Bytes);
|
fn log(&mut self, topics: Vec<H256>, data: Bytes);
|
||||||
|
|
||||||
|
/// Should be called when transaction calls `RETURN` opcode.
|
||||||
|
/// Returns gas_left if cost of returning the data is not too high.
|
||||||
|
fn ret(&mut self, gas: u64, data: &[u8]) -> Option<u64>;
|
||||||
|
|
||||||
|
/// Should be called when contract commits suicide.
|
||||||
|
fn suicide(&mut self);
|
||||||
|
|
||||||
|
/// Returns schedule.
|
||||||
|
fn schedule(&self) -> &EvmSchedule;
|
||||||
}
|
}
|
||||||
|
@ -316,11 +316,21 @@ impl evm::Evm for JitEvm {
|
|||||||
|
|
||||||
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() {
|
match context.exec() {
|
||||||
evmjit::ReturnCode::Stop => evm::EvmResult::Stop { gas_left: U256::from(context.gas_left()) },
|
evmjit::ReturnCode::Stop => Ok(evm::EvmOutput::new(U256::from(context.gas_left()), None)),
|
||||||
evmjit::ReturnCode::Return => evm::EvmResult::Return(context.output_data().to_vec()),
|
evmjit::ReturnCode::Return => {
|
||||||
evmjit::ReturnCode::Suicide => evm::EvmResult::Suicide,
|
if context.output_data().len() as u64 * ext.schedule().create_data_gas as u64 > context.gas_left() {
|
||||||
evmjit::ReturnCode::OutOfGas => evm::EvmResult::OutOfGas,
|
return Err(evm::EvmError::OutOfGas);
|
||||||
_ => evm::EvmResult::InternalError
|
}
|
||||||
|
|
||||||
|
Ok(evm::EvmOutput::new(U256::from(context.gas_left()), Some(context.output_data().to_vec())))
|
||||||
|
},
|
||||||
|
evmjit::ReturnCode::Suicide => {
|
||||||
|
// what if there is a suicide and we run out of gas just after?
|
||||||
|
ext.suicide();
|
||||||
|
Ok(evm::EvmOutput::new(U256::from(context.gas_left()), None))
|
||||||
|
},
|
||||||
|
evmjit::ReturnCode::OutOfGas => Err(evm::EvmError::OutOfGas),
|
||||||
|
_err => Err(evm::EvmError::Internal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@ pub mod params;
|
|||||||
#[cfg(feature = "jit" )]
|
#[cfg(feature = "jit" )]
|
||||||
mod jit;
|
mod jit;
|
||||||
|
|
||||||
pub use self::evm::{Evm, EvmResult};
|
pub use self::evm::{Evm, EvmError, EvmResult};
|
||||||
pub use self::ext::{Ext};
|
pub use self::ext::{Ext};
|
||||||
pub use self::logentry::LogEntry;
|
pub use self::logentry::LogEntry;
|
||||||
pub use self::vmfactory::VmFactory;
|
pub use self::vmfactory::VmFactory;
|
||||||
pub use self::executive::{Executive, ExecutiveResult, Externalities, Substate};
|
pub use self::executive::{Executive, ExecutionResult, Externalities, Substate};
|
||||||
pub use self::params::EvmParams;
|
pub use self::params::EvmParams;
|
||||||
|
Loading…
Reference in New Issue
Block a user