diff --git a/src/executive.rs b/src/executive.rs
index 3251763f4..512f2bb11 100644
--- a/src/executive.rs
+++ b/src/executive.rs
@@ -2,7 +2,9 @@
use common::*;
use state::*;
use engine::*;
-use evm::{self, Schedule, Factory, Ext};
+use evm::{self, Factory, Ext};
+use externalities::*;
+use substate::*;
/// Returns new address created from address and given nonce.
pub fn contract_address(address: &Address, nonce: &U256) -> Address {
@@ -12,38 +14,6 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
From::from(stream.out().sha3())
}
-/// State changes which should be applied in finalize,
-/// after transaction is fully executed.
-pub struct Substate {
- /// Any accounts that have suicided.
- suicides: HashSet
,
- /// Any logs.
- logs: Vec,
- /// Refund counter of SSTORE nonzero->zero.
- refunds_count: U256,
- /// Created contracts.
- contracts_created: Vec
-}
-
-impl Substate {
- /// Creates new substate.
- pub fn new() -> Self {
- Substate {
- suicides: HashSet::new(),
- logs: vec![],
- refunds_count: U256::zero(),
- contracts_created: vec![]
- }
- }
-
- pub fn accrue(&mut self, s: Substate) {
- self.suicides.extend(s.suicides.into_iter());
- self.logs.extend(s.logs.into_iter());
- self.refunds_count = self.refunds_count + s.refunds_count;
- self.contracts_created.extend(s.contracts_created.into_iter());
- }
-}
-
/// Transaction execution receipt.
#[derive(Debug)]
pub struct Executed {
@@ -89,7 +59,7 @@ impl<'a> Executive<'a> {
}
/// Populates executive from parent properties. Increments executive depth.
- fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self {
+ pub fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self {
Executive::new_with_depth(state, info, engine, depth + 1)
}
@@ -104,8 +74,13 @@ impl<'a> Executive<'a> {
}
}
+ /// Creates `Externalities` from `Executive`.
+ pub fn to_externalities<'_>(&'_ mut self, params: &'_ ActionParams, substate: &'_ mut Substate, output: OutputPolicy<'_>) -> Externalities {
+ Externalities::new(self.state, self.info, self.engine, self.depth, params, substate, output)
+ }
+
/// This funtion should be used to execute transaction.
- pub fn transact(&mut self, t: &Transaction) -> Result {
+ pub fn transact(&'a mut self, t: &Transaction) -> Result {
let sender = try!(t.sender());
let nonce = self.state.nonce(&sender);
@@ -215,7 +190,7 @@ impl<'a> Executive<'a> {
let mut unconfirmed_substate = Substate::new();
let res = {
- let mut ext = Externalities::from_executive(self, params, &mut unconfirmed_substate, OutputPolicy::Return(output));
+ let mut ext = self.to_externalities(params, &mut unconfirmed_substate, OutputPolicy::Return(output));
let evm = Factory::create();
evm.exec(¶ms, &mut ext)
};
@@ -230,7 +205,7 @@ impl<'a> Executive<'a> {
/// Creates contract with given contract params.
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
/// Modifies the substate.
- fn create(&mut self, params: &ActionParams, substate: &mut Substate) -> evm::Result {
+ pub fn create(&mut self, params: &ActionParams, substate: &mut Substate) -> evm::Result {
// backup used in case of running out of gas
let backup = self.state.clone();
@@ -244,7 +219,7 @@ impl<'a> Executive<'a> {
self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value);
let res = {
- let mut ext = Externalities::from_executive(self, params, &mut unconfirmed_substate, OutputPolicy::InitContract);
+ let mut ext = self.to_externalities(params, &mut unconfirmed_substate, OutputPolicy::InitContract);
let evm = Factory::create();
evm.exec(¶ms, &mut ext)
};
@@ -319,228 +294,6 @@ impl<'a> Executive<'a> {
}
}
-/// Policy for handling output data on `RETURN` opcode.
-pub enum OutputPolicy<'a> {
- /// Return reference to fixed sized output.
- /// Used for message calls.
- Return(BytesRef<'a>),
- /// Init new contract as soon as `RETURN` is called.
- InitContract
-}
-
-/// Implementation of evm Externalities.
-pub struct Externalities<'a> {
- #[cfg(test)]
- pub state: &'a mut State,
- #[cfg(not(test))]
- state: &'a mut State,
- info: &'a EnvInfo,
- engine: &'a Engine,
- depth: usize,
- #[cfg(test)]
- pub params: &'a ActionParams,
- #[cfg(not(test))]
- params: &'a ActionParams,
- substate: &'a mut Substate,
- schedule: Schedule,
- output: OutputPolicy<'a>
-}
-
-impl<'a> Externalities<'a> {
- /// Basic `Externalities` constructor.
- pub fn new(state: &'a mut State,
- info: &'a EnvInfo,
- engine: &'a Engine,
- depth: usize,
- params: &'a ActionParams,
- substate: &'a mut Substate,
- output: OutputPolicy<'a>) -> Self {
- Externalities {
- state: state,
- info: info,
- engine: engine,
- depth: depth,
- params: params,
- substate: substate,
- schedule: engine.schedule(info),
- output: output
- }
- }
-
- /// Creates `Externalities` from `Executive`.
- fn from_executive(e: &'a mut Executive, params: &'a ActionParams, substate: &'a mut Substate, output: OutputPolicy<'a>) -> Self {
- Self::new(e.state, e.info, e.engine, e.depth, params, substate, output)
- }
-}
-
-impl<'a> Ext for Externalities<'a> {
- fn sload(&self, key: &H256) -> H256 {
- self.state.storage_at(&self.params.address, key)
- }
-
- fn sstore(&mut self, key: H256, value: H256) {
- // if SSTORE nonzero -> zero, increment refund count
- if value == H256::new() && self.state.storage_at(&self.params.address, &key) != H256::new() {
- self.substate.refunds_count = self.substate.refunds_count + U256::one();
- }
- self.state.set_storage(&self.params.address, key, value)
- }
-
- fn balance(&self, address: &Address) -> U256 {
- self.state.balance(address)
- }
-
- fn blockhash(&self, number: &U256) -> H256 {
- match *number < U256::from(self.info.number) && number.low_u64() >= cmp::max(256, self.info.number) - 256 {
- true => {
- let index = self.info.number - number.low_u64() - 1;
- self.info.last_hashes[index as usize].clone()
- },
- false => H256::from(&U256::zero()),
- }
- }
-
- fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> (U256, Option) {
- // if balance is insufficient or we are to deep, return
- if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth {
- return (*gas, None);
- }
-
- // create new contract address
- let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address));
-
- // prepare the params
- let params = ActionParams {
- address: address.clone(),
- sender: self.params.address.clone(),
- origin: self.params.origin.clone(),
- gas: *gas,
- gas_price: self.params.gas_price.clone(),
- value: value.clone(),
- code: code.to_vec(),
- data: vec![],
- };
-
- let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth);
- ex.state.inc_nonce(&self.params.address);
- match ex.create(¶ms, self.substate) {
- Ok(gas_left) => (gas_left, Some(address)),
- _ => (U256::zero(), None)
- }
- }
-
- fn call(&mut self,
- gas: &U256,
- call_gas: &U256,
- receive_address: &Address,
- value: &U256,
- data: &[u8],
- code_address: &Address,
- output: &mut [u8]) -> Result<(U256, bool), evm::Error> {
- let mut gas_cost = *call_gas;
- let mut call_gas = *call_gas;
-
- let is_call = receive_address == code_address;
- if is_call && !self.state.exists(&code_address) {
- gas_cost = gas_cost + U256::from(self.schedule.call_new_account_gas);
- }
-
- if *value > U256::zero() {
- assert!(self.schedule.call_value_transfer_gas > self.schedule.call_stipend, "overflow possible");
- gas_cost = gas_cost + U256::from(self.schedule.call_value_transfer_gas);
- call_gas = call_gas + U256::from(self.schedule.call_stipend);
- }
-
- if gas_cost > *gas {
- return Err(evm::Error::OutOfGas);
- }
-
- let gas = *gas - gas_cost;
-
- // if balance is insufficient or we are too deep, return
- if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth {
- return Ok((gas + call_gas, true));
- }
-
- let params = ActionParams {
- address: receive_address.clone(),
- sender: self.params.address.clone(),
- origin: self.params.origin.clone(),
- gas: call_gas,
- gas_price: self.params.gas_price.clone(),
- value: value.clone(),
- code: self.state.code(code_address).unwrap_or(vec![]),
- data: data.to_vec(),
- };
-
- let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth);
- match ex.call(¶ms, self.substate, BytesRef::Fixed(output)) {
- Ok(gas_left) => Ok((gas + gas_left, true)),
- _ => Ok((gas, false))
- }
- }
-
- fn extcode(&self, address: &Address) -> Vec {
- self.state.code(address).unwrap_or(vec![])
- }
-
- fn ret(&mut self, gas: &U256, data: &[u8]) -> Result {
- match &mut self.output {
- &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe {
- let len = cmp::min(slice.len(), data.len());
- ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len);
- Ok(*gas)
- },
- &mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe {
- vec.clear();
- vec.reserve(data.len());
- ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len());
- vec.set_len(data.len());
- Ok(*gas)
- },
- &mut OutputPolicy::InitContract => {
- let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas);
- if return_cost > *gas {
- return match self.schedule.exceptional_failed_code_deposit {
- true => Err(evm::Error::OutOfGas),
- false => Ok(*gas)
- }
- }
- 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);
- self.substate.contracts_created.push(address.clone());
- Ok(*gas - return_cost)
- }
- }
- }
-
- fn log(&mut self, topics: Vec, data: Bytes) {
- let address = self.params.address.clone();
- self.substate.logs.push(LogEntry::new(address, topics, data));
- }
-
- fn suicide(&mut self, refund_address: &Address) {
- let address = self.params.address.clone();
- let balance = self.balance(&address);
- self.state.transfer_balance(&address, refund_address, &balance);
- self.substate.suicides.insert(address);
- }
-
- fn schedule(&self) -> &Schedule {
- &self.schedule
- }
-
- fn env_info(&self) -> &EnvInfo {
- &self.info
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
@@ -550,6 +303,7 @@ mod tests {
use engine::*;
use spec::*;
use evm::Schedule;
+ use substate::*;
struct TestEngine {
spec: Spec,
diff --git a/src/externalities.rs b/src/externalities.rs
new file mode 100644
index 000000000..84131c8e8
--- /dev/null
+++ b/src/externalities.rs
@@ -0,0 +1,228 @@
+//! Transaction Execution environment.
+use common::*;
+use state::*;
+use engine::*;
+use executive::*;
+use evm::{self, Schedule, Ext};
+use substate::*;
+
+/// Policy for handling output data on `RETURN` opcode.
+pub enum OutputPolicy<'a> {
+ /// Return reference to fixed sized output.
+ /// Used for message calls.
+ Return(BytesRef<'a>),
+ /// Init new contract as soon as `RETURN` is called.
+ InitContract
+}
+
+/// Implementation of evm Externalities.
+pub struct Externalities<'a> {
+
+ #[cfg(test)]
+ pub state: &'a mut State,
+ #[cfg(not(test))]
+ state: &'a mut State,
+
+ info: &'a EnvInfo,
+ engine: &'a Engine,
+ depth: usize,
+
+ #[cfg(test)]
+ pub params: &'a ActionParams,
+ #[cfg(not(test))]
+ params: &'a ActionParams,
+
+ substate: &'a mut Substate,
+ schedule: Schedule,
+ output: OutputPolicy<'a>
+}
+
+impl<'a> Externalities<'a> {
+ /// Basic `Externalities` constructor.
+ pub fn new(state: &'a mut State,
+ info: &'a EnvInfo,
+ engine: &'a Engine,
+ depth: usize,
+ params: &'a ActionParams,
+ substate: &'a mut Substate,
+ output: OutputPolicy<'a>) -> Self {
+ Externalities {
+ state: state,
+ info: info,
+ engine: engine,
+ depth: depth,
+ params: params,
+ substate: substate,
+ schedule: engine.schedule(info),
+ output: output
+ }
+ }
+}
+
+impl<'a> Ext for Externalities<'a> {
+ fn sload(&self, key: &H256) -> H256 {
+ self.state.storage_at(&self.params.address, key)
+ }
+
+ fn sstore(&mut self, key: H256, value: H256) {
+ // if SSTORE nonzero -> zero, increment refund count
+ if value == H256::new() && self.state.storage_at(&self.params.address, &key) != H256::new() {
+ self.substate.refunds_count = self.substate.refunds_count + U256::one();
+ }
+ self.state.set_storage(&self.params.address, key, value)
+ }
+
+ fn balance(&self, address: &Address) -> U256 {
+ self.state.balance(address)
+ }
+
+ fn blockhash(&self, number: &U256) -> H256 {
+ match *number < U256::from(self.info.number) && number.low_u64() >= cmp::max(256, self.info.number) - 256 {
+ true => {
+ let index = self.info.number - number.low_u64() - 1;
+ self.info.last_hashes[index as usize].clone()
+ },
+ false => H256::from(&U256::zero()),
+ }
+ }
+
+ fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> (U256, Option) {
+ // if balance is insufficient or we are to deep, return
+ if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth {
+ return (*gas, None);
+ }
+
+ // create new contract address
+ let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address));
+
+ // prepare the params
+ let params = ActionParams {
+ address: address.clone(),
+ sender: self.params.address.clone(),
+ origin: self.params.origin.clone(),
+ gas: *gas,
+ gas_price: self.params.gas_price.clone(),
+ value: value.clone(),
+ code: code.to_vec(),
+ data: vec![],
+ };
+
+ self.state.inc_nonce(&self.params.address);
+ let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth);
+ match ex.create(¶ms, self.substate) {
+ Ok(gas_left) => (gas_left, Some(address)),
+ _ => (U256::zero(), None)
+ }
+ }
+
+ fn call(&mut self,
+ gas: &U256,
+ call_gas: &U256,
+ receive_address: &Address,
+ value: &U256,
+ data: &[u8],
+ code_address: &Address,
+ output: &mut [u8]) -> Result<(U256, bool), evm::Error> {
+ let mut gas_cost = *call_gas;
+ let mut call_gas = *call_gas;
+
+ let is_call = receive_address == code_address;
+ if is_call && !self.state.exists(&code_address) {
+ gas_cost = gas_cost + U256::from(self.schedule.call_new_account_gas);
+ }
+
+ if *value > U256::zero() {
+ assert!(self.schedule.call_value_transfer_gas > self.schedule.call_stipend, "overflow possible");
+ gas_cost = gas_cost + U256::from(self.schedule.call_value_transfer_gas);
+ call_gas = call_gas + U256::from(self.schedule.call_stipend);
+ }
+
+ if gas_cost > *gas {
+ return Err(evm::Error::OutOfGas);
+ }
+
+ let gas = *gas - gas_cost;
+
+ // if balance is insufficient or we are too deep, return
+ if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth {
+ return Ok((gas + call_gas, true));
+ }
+
+ let params = ActionParams {
+ address: receive_address.clone(),
+ sender: self.params.address.clone(),
+ origin: self.params.origin.clone(),
+ gas: call_gas,
+ gas_price: self.params.gas_price.clone(),
+ value: value.clone(),
+ code: self.state.code(code_address).unwrap_or(vec![]),
+ data: data.to_vec(),
+ };
+
+ let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth);
+ match ex.call(¶ms, self.substate, BytesRef::Fixed(output)) {
+ Ok(gas_left) => Ok((gas + gas_left, true)),
+ _ => Ok((gas, false))
+ }
+ }
+
+ fn extcode(&self, address: &Address) -> Vec {
+ self.state.code(address).unwrap_or(vec![])
+ }
+
+ fn ret(&mut self, gas: &U256, data: &[u8]) -> Result {
+ match &mut self.output {
+ &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe {
+ let len = cmp::min(slice.len(), data.len());
+ ptr::copy(data.as_ptr(), slice.as_mut_ptr(), len);
+ Ok(*gas)
+ },
+ &mut OutputPolicy::Return(BytesRef::Flexible(ref mut vec)) => unsafe {
+ vec.clear();
+ vec.reserve(data.len());
+ ptr::copy(data.as_ptr(), vec.as_mut_ptr(), data.len());
+ vec.set_len(data.len());
+ Ok(*gas)
+ },
+ &mut OutputPolicy::InitContract => {
+ let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas);
+ if return_cost > *gas {
+ return match self.schedule.exceptional_failed_code_deposit {
+ true => Err(evm::Error::OutOfGas),
+ false => Ok(*gas)
+ }
+ }
+ 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);
+ self.substate.contracts_created.push(address.clone());
+ Ok(*gas - return_cost)
+ }
+ }
+ }
+
+ fn log(&mut self, topics: Vec, data: Bytes) {
+ let address = self.params.address.clone();
+ self.substate.logs.push(LogEntry::new(address, topics, data));
+ }
+
+ fn suicide(&mut self, refund_address: &Address) {
+ let address = self.params.address.clone();
+ let balance = self.balance(&address);
+ self.state.transfer_balance(&address, refund_address, &balance);
+ self.substate.suicides.insert(address);
+ }
+
+ fn schedule(&self) -> &Schedule {
+ &self.schedule
+ }
+
+ fn env_info(&self) -> &EnvInfo {
+ &self.info
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 0b81f4fd3..666edebae 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -89,7 +89,6 @@ extern crate ethcore_util as util;
pub mod common;
pub mod basic_types;
-pub mod executive;
pub mod error;
pub mod log_entry;
pub mod env_info;
@@ -110,7 +109,10 @@ pub mod spec;
pub mod views;
pub mod blockchain;
pub mod extras;
+pub mod substate;
pub mod evm;
+pub mod executive;
+pub mod externalities;
#[cfg(test)]
mod tests;
diff --git a/src/substate.rs b/src/substate.rs
new file mode 100644
index 000000000..f85427745
--- /dev/null
+++ b/src/substate.rs
@@ -0,0 +1,33 @@
+use common::*;
+
+/// State changes which should be applied in finalize,
+/// after transaction is fully executed.
+pub struct Substate {
+ /// Any accounts that have suicided.
+ pub suicides: HashSet,
+ /// Any logs.
+ pub logs: Vec,
+ /// Refund counter of SSTORE nonzero->zero.
+ pub refunds_count: U256,
+ /// Created contracts.
+ pub contracts_created: Vec
+}
+
+impl Substate {
+ /// Creates new substate.
+ pub fn new() -> Self {
+ Substate {
+ suicides: HashSet::new(),
+ logs: vec![],
+ refunds_count: U256::zero(),
+ contracts_created: vec![]
+ }
+ }
+
+ pub fn accrue(&mut self, s: Substate) {
+ self.suicides.extend(s.suicides.into_iter());
+ self.logs.extend(s.logs.into_iter());
+ self.refunds_count = self.refunds_count + s.refunds_count;
+ self.contracts_created.extend(s.contracts_created.into_iter());
+ }
+}
diff --git a/src/tests/executive.rs b/src/tests/executive.rs
index 6b59774a5..3e0eae4b5 100644
--- a/src/tests/executive.rs
+++ b/src/tests/executive.rs
@@ -6,6 +6,8 @@ use engine::*;
use evm;
use evm::{Schedule, Ext, Factory};
use ethereum;
+use externalities::*;
+use substate::*;
struct TestEngine {
spec: Spec,