From 0004ed8960e0d237b558838cd92a880777f60667 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 11 Jan 2016 17:37:22 +0100 Subject: [PATCH] Integrate Executive into State. --- src/action_params.rs | 4 +++- src/block.rs | 6 +++--- src/error.rs | 24 ++++++++++++++++++++++++ src/executive.rs | 36 +++++++++++++++--------------------- src/receipt.rs | 11 +++++++++++ src/state.rs | 13 +++++-------- 6 files changed, 61 insertions(+), 33 deletions(-) diff --git a/src/action_params.rs b/src/action_params.rs index 9913b838f..c92fe4c80 100644 --- a/src/action_params.rs +++ b/src/action_params.rs @@ -3,7 +3,9 @@ use util::hash::*; use util::uint::*; use util::bytes::*; -/// Evm input params. Everything else should be specified in Externalities. +// TODO: should be a trait, possible to avoid cloning everything from a Transaction(/View). + +/// Action (call/create) input params. Everything else should be specified in Externalities. #[derive(Clone, Debug)] pub struct ActionParams { /// Address of currently executed code. diff --git a/src/block.rs b/src/block.rs index 5837ce2c9..b683ab159 100644 --- a/src/block.rs +++ b/src/block.rs @@ -170,12 +170,12 @@ impl<'x, 'y> OpenBlock<'x, 'y> { pub fn push_transaction(&mut self, t: Transaction, h: Option) -> Result<&Receipt, Error> { let env_info = self.env_info(); match self.block.state.apply(&env_info, self.engine, &t) { - Ok(x) => { + Ok(receipt) => { self.block.archive_set.insert(h.unwrap_or_else(||t.hash())); - self.block.archive.push(Entry { transaction: t, receipt: x.receipt }); + self.block.archive.push(Entry { transaction: t, receipt: receipt }); Ok(&self.block.archive.last().unwrap().receipt) } - Err(x) => Err(x) + Err(x) => Err(From::from(x)) } } diff --git a/src/error.rs b/src/error.rs index c18782502..4b5b1b6f1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -16,6 +16,23 @@ pub struct OutOfBounds { pub found: T, } +/// Result of executing the transaction. +#[derive(PartialEq, Debug)] +pub enum ExecutionError { + /// 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 }, + /// Returned when transaction nonce does not match state nonce. + InvalidNonce { expected: U256, is: U256 }, + /// Returned when cost of transaction (value + gas_price * gas) exceeds + /// current sender balance. + NotEnoughCash { required: U256, is: U256 }, + /// Returned when internal evm error occurs. + Internal +} + #[derive(Debug)] pub enum BlockError { TooManyUncles(OutOfBounds), @@ -65,6 +82,7 @@ pub enum Error { Util(UtilError), Block(BlockError), UnknownEngineName(String), + Execution(ExecutionError), } impl From for Error { @@ -73,6 +91,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: ExecutionError) -> Error { + Error::Execution(err) + } +} + // TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted. /*#![feature(concat_idents)] macro_rules! assimilate { diff --git a/src/executive.rs b/src/executive.rs index b3ff92483..59c0b0c8a 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -55,26 +55,10 @@ pub struct Executed { /// where `tn` is current transaction. pub cumulative_gas_used: U256, /// Vector of logs generated by transaction. - pub logs: Vec -} + pub logs: Vec, -/// Result of executing the transaction. -#[derive(PartialEq, Debug)] -pub enum ExecutionError { - /// 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 }, - /// Returned when transaction nonce does not match state nonce. - InvalidNonce { expected: U256, is: U256 }, - /// Returned when cost of transaction (value + gas_price * gas) exceeds - /// current sender balance. - NotEnoughCash { required: U256, is: U256 }, - /// Returned when transaction execution runs out of gas. - OutOfGas, - /// Returned when internal evm error occurs. - Internal + /// Execution ended running out of gas. + pub out_of_gas: bool, } pub type ExecutionResult = Result; @@ -228,7 +212,14 @@ impl<'a> Executive<'a> { Err(evm::Error::Internal) => Err(ExecutionError::Internal), Err(evm::Error::OutOfGas) => { *self.state = backup; - Err(ExecutionError::OutOfGas) + Ok(Executed { + gas: t.gas, + gas_used: t.gas, + refunded: U256::zero(), + cumulative_gas_used: self.info.gas_used + t.gas, + logs: vec![], + out_of_gas: true, + }) }, Ok(gas_left) => { let schedule = self.engine.schedule(self.info); @@ -259,7 +250,8 @@ impl<'a> Executive<'a> { gas_used: gas_used, refunded: refund, cumulative_gas_used: self.info.gas_used + gas_used, - logs: substate.logs + logs: substate.logs, + out_of_gas: false, }) } } @@ -499,6 +491,8 @@ mod tests { assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0xf9u64))); assert_eq!(state.balance(&sender), U256::from(0xf9)); assert_eq!(state.balance(&address), U256::from(0x7)); + + // TODO: just test state root. } #[test] diff --git a/src/receipt.rs b/src/receipt.rs index ef46e0f48..ef7e03cc8 100644 --- a/src/receipt.rs +++ b/src/receipt.rs @@ -10,6 +10,17 @@ pub struct Receipt { pub logs: Vec, } +impl Receipt { + pub fn new(state_root: H256, gas_used: U256, logs: Vec) -> Receipt { + Receipt { + state_root: state_root, + gas_used: gas_used, + log_bloom: logs.iter().fold(LogBloom::new(), |mut b, l| { b |= &l.bloom(); b }), + logs: logs, + } + } +} + impl RlpStandard for Receipt { fn rlp_append(&self, s: &mut RlpStream) { s.append_list(4); diff --git a/src/state.rs b/src/state.rs index 35da33d5a..cdd861b33 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,13 +1,8 @@ use common::*; use engine::Engine; -//use executive::Executive; +use executive::Executive; -/// Information concerning the result of the `State::apply` operation. -pub struct ApplyInfo { - pub receipt: Receipt, -} - -pub type ApplyResult = Result; +pub type ApplyResult = Result; /// Representation of the entire state of all accounts in the system. pub struct State { @@ -136,7 +131,9 @@ impl State { /// Execute a given transaction. /// This will change the state accordingly. pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult { - unimplemented!(); + let e = try!(Executive::new(self, env_info, engine).transact(t)); + self.commit(); + Ok(Receipt::new(self.root().clone(), e.gas_used, e.logs)) } /// Convert into a JSON representation.