Integrate Executive into State.

This commit is contained in:
Gav Wood 2016-01-11 17:37:22 +01:00
parent 7650dead6d
commit 0004ed8960
6 changed files with 61 additions and 33 deletions

View File

@ -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.

View File

@ -170,12 +170,12 @@ impl<'x, 'y> OpenBlock<'x, 'y> {
pub fn push_transaction(&mut self, t: Transaction, h: Option<H256>) -> 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))
}
}

View File

@ -16,6 +16,23 @@ pub struct OutOfBounds<T: fmt::Debug> {
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<usize>),
@ -65,6 +82,7 @@ pub enum Error {
Util(UtilError),
Block(BlockError),
UnknownEngineName(String),
Execution(ExecutionError),
}
impl From<BlockError> for Error {
@ -73,6 +91,12 @@ impl From<BlockError> for Error {
}
}
impl From<ExecutionError> 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 {

View File

@ -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<LogEntry>
}
pub logs: Vec<LogEntry>,
/// 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<Executed, ExecutionError>;
@ -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]

View File

@ -10,6 +10,17 @@ pub struct Receipt {
pub logs: Vec<LogEntry>,
}
impl Receipt {
pub fn new(state_root: H256, gas_used: U256, logs: Vec<LogEntry>) -> 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);

View File

@ -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<ApplyInfo, Error>;
pub type ApplyResult = Result<Receipt, ExecutionError>;
/// 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.