diff --git a/src/executive.rs b/src/executive.rs index ea95c69e4..8252b9221 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); @@ -198,13 +173,15 @@ impl<'a> Executive<'a> { self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); if self.engine.is_builtin(¶ms.code_address) { + // if destination is builtin, try to execute it + let default = []; let data = if let &Some(ref d) = ¶ms.data { d as &[u8] } else { &default as &[u8] }; - // if destination is builtin, try to execute it - let cost = self.engine.cost_of_builtin(¶ms.code_address, &data); + + let cost = self.engine.cost_of_builtin(¶ms.code_address, data); match cost <= params.gas { true => { - self.engine.execute_builtin(¶ms.code_address, &data, &mut output); + self.engine.execute_builtin(¶ms.code_address, data, &mut output); Ok(params.gas - cost) }, // just drain the whole gas @@ -220,7 +197,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) }; @@ -235,7 +212,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(); @@ -249,7 +226,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) }; @@ -324,231 +301,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 { - code_address: address.clone(), - 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: Some(code.to_vec()), - data: None - }; - - 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; - - // TODO: move gas calculation out! - 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 { - code_address: code_address.clone(), - 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), - data: Some(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::*; @@ -558,6 +310,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..f5a72288a --- /dev/null +++ b/src/externalities.rs @@ -0,0 +1,230 @@ +//! 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 { + code_address: address.clone(), + 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: Some(code.to_vec()), + data: None, + }; + + 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 { + code_address: code_address.clone(), + 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), + data: Some(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,