From 3f725ce89d6e83859aba1a4f374906d0ee85e265 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 11 Jan 2016 15:55:54 +0100 Subject: [PATCH] reverting the execution state when out of gas --- src/evm/executive.rs | 61 ++++++++++++++++++++++++++------------------ src/evm/ext.rs | 1 + src/evm/jit.rs | 4 +++ 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/evm/executive.rs b/src/evm/executive.rs index 5645f4daa..7b4b7da59 100644 --- a/src/evm/executive.rs +++ b/src/evm/executive.rs @@ -65,8 +65,6 @@ pub struct Executed { /// /// where `tn` is current transaction. pub cumulative_gas_used: U256, - /// Transaction output. - pub output: Bytes, /// Vector of logs generated by transaction. pub logs: Vec } @@ -78,7 +76,6 @@ impl Executed { gas_used: U256::zero(), refunded: U256::zero(), cumulative_gas_used: U256::zero(), - output: vec![], logs: vec![] } } @@ -168,6 +165,8 @@ impl<'a> Executive<'a> { self.state.inc_nonce(&sender); let mut substate = Substate::new(); + let backup = self.state.clone(); + let res = match t.action() { &Action::Create => { let params = EvmParams { @@ -198,9 +197,7 @@ impl<'a> Executive<'a> { }; // finalize here! - self.finalize(substate, &sender, U256::zero(), U256::zero(), t.gas_price); - //res - Ok(Executed::new()) + self.finalize(t, substate, backup, res) } /// Calls contract function with given contract params. @@ -247,27 +244,41 @@ impl<'a> Executive<'a> { } /// Finalizes the transaction (does refunds and suicides). - fn finalize(&mut self, substate: Substate, sender: &Address, gas: U256, gas_left: U256, gas_price: U256) { - let schedule = self.engine.evm_schedule(self.info); + fn finalize(&mut self, t: &Transaction, substate: Substate, backup: State, result: EvmResult) -> ExecutionResult { + match result { + Err(EvmError::Internal) => Err(ExecutionError::Internal), + Err(EvmError::OutOfGas) => { + let executed = Executed::new(); + *self.state = backup; + Ok(executed) + }, + Ok(gas_left) => { + let executed = Executed::new(); - // refunds from SSTORE nonzero -> zero - let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.refunds_count; - // refunds from contract suicides - let suicide_refunds = U256::from(schedule.suicide_refund_gas) * U256::from(substate.suicides.len()); + let schedule = self.engine.evm_schedule(self.info); - // real ammount to refund - let refund = cmp::min(sstore_refunds + suicide_refunds, (gas - gas_left) / U256::from(2)) + gas_left; - let refund_value = refund * gas_price; - self.state.add_balance(sender, &refund_value); - - // fees earned by author - let fees = (gas - refund) * gas_price; - let author = &self.info.author; - self.state.add_balance(author, &fees); + // refunds from SSTORE nonzero -> zero + let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.refunds_count; + // refunds from contract suicides + let suicide_refunds = U256::from(schedule.suicide_refund_gas) * U256::from(substate.suicides.len()); - // perform suicides - for address in substate.suicides.iter() { - self.state.kill_account(address); + // real ammount to refund + let refund = cmp::min(sstore_refunds + suicide_refunds, (t.gas - gas_left) / U256::from(2)) + gas_left; + let refund_value = refund * t.gas_price; + self.state.add_balance(&t.sender(), &refund_value); + + // fees earned by author + let fees = (t.gas - refund) * t.gas_price; + let author = &self.info.author; + self.state.add_balance(author, &fees); + + // perform suicides + for address in substate.suicides.iter() { + self.state.kill_account(address); + } + + Ok(executed) + } } } } @@ -392,7 +403,7 @@ impl<'a> Ext for Externalities<'a> { return Err(EvmError::OutOfGas) } - let mut gas = gas - gas_cost; + let gas = gas - gas_cost; //println!("depth: {:?}", self.depth); // if balance is insufficient or we are to deep, return diff --git a/src/evm/ext.rs b/src/evm/ext.rs index 33f89e32f..e2680ea71 100644 --- a/src/evm/ext.rs +++ b/src/evm/ext.rs @@ -6,6 +6,7 @@ use util::bytes::*; use evm_schedule::*; use evm::EvmError; +// TODO: replace all u64 with u256 pub trait Ext { /// Returns a value for given key. fn sload(&self, key: &H256) -> H256; diff --git a/src/evm/jit.rs b/src/evm/jit.rs index 467d871a4..d397ee77d 100644 --- a/src/evm/jit.rs +++ b/src/evm/jit.rs @@ -159,6 +159,10 @@ impl IntoJit for RuntimeData { } } +/// Externalities adapter. Maps callbacks from evmjit to externalities trait. +/// +/// Evmjit doesn't have to know about children execution failures. +/// This adapter 'catches' them and moves upstream. struct ExtAdapter<'a> { ext: &'a mut evm::Ext, err: &'a mut Option