From b72da41ea7533e298b028e5a643094d2546156ba Mon Sep 17 00:00:00 2001 From: debris Date: Sun, 10 Jan 2016 16:21:01 +0100 Subject: [PATCH] proper calculatng of executive gas in progress --- rust-evmjit/src/lib.rs | 24 +++++-- src/evm/evm.rs | 3 +- src/evm/executive.rs | 151 ++++++++++++++++++++++++++++++++--------- src/evm/ext.rs | 4 +- src/evm/jit.rs | 35 ++++++---- src/evm/params.rs | 2 +- 6 files changed, 168 insertions(+), 51 deletions(-) diff --git a/rust-evmjit/src/lib.rs b/rust-evmjit/src/lib.rs index 5e081511e..28e13eac9 100644 --- a/rust-evmjit/src/lib.rs +++ b/rust-evmjit/src/lib.rs @@ -10,7 +10,6 @@ //! let mut context = ContextHandle::new(RuntimeDataHandle::new(), ExtHandle::empty()); //! assert_eq!(context.exec(), ReturnCode::Stop); //! } -//! //! ``` //! //! @@ -43,13 +42,17 @@ pub use self::ffi::JitReturnCode as ReturnCode; pub use self::ffi::JitI256 as I256; pub use self::ffi::JitH256 as H256; -/// Component oriented safe handle to `JitRuntimeData`. +/// Takes care of proper initialization and destruction of `RuntimeData`. +/// +/// This handle must be used to create runtime data, +/// cause underneath it's a `C++` structure. Incombatible with rust +/// structs. pub struct RuntimeDataHandle { runtime_data: *mut JitRuntimeData } impl RuntimeDataHandle { - /// Creates new handle. + /// Creates new `RuntimeData` handle. pub fn new() -> Self { RuntimeDataHandle { runtime_data: unsafe { evmjit_create_runtime_data() } @@ -87,7 +90,11 @@ impl DerefMut for RuntimeDataHandle { } } -/// Safe handle for jit context. +/// Takes care of proper initialization and destruction of jit context. +/// +/// This handle must be used to create context, +/// cause underneath it's a `C++` structure. Incombatible with rust +/// structs. pub struct ContextHandle { context: *mut JitContext, data_handle: RuntimeDataHandle, @@ -95,7 +102,11 @@ pub struct ContextHandle { impl ContextHandle { /// Creates new context handle. + /// /// This function is unsafe cause ext lifetime is not considered + /// We also can't make ExtHandle a member of `ContextHandle` structure, + /// cause this would be a move operation or it would require a template + /// lifetime to a reference. Both solutions are not possible. pub unsafe fn new(data_handle: RuntimeDataHandle, ext: &mut ExtHandle) -> Self { let mut handle = ContextHandle { context: std::mem::uninitialized(), @@ -115,6 +126,11 @@ impl ContextHandle { pub fn output_data(&self) -> &[u8] { unsafe { std::slice::from_raw_parts(self.data_handle.call_data, self.data_handle.call_data_size as usize) } } + + /// Returns gas left. + pub fn gas_left(&self) -> u64 { + self.data_handle.gas as u64 + } } impl Drop for ContextHandle { diff --git a/src/evm/evm.rs b/src/evm/evm.rs index 38f310edd..25b3edd38 100644 --- a/src/evm/evm.rs +++ b/src/evm/evm.rs @@ -1,11 +1,12 @@ //! Evm interface. +use util::uint::U256; use util::bytes::Bytes; use evm::{EvmParams, Ext}; #[derive(Debug, Eq, PartialEq)] pub enum EvmResult { - Stop, + Stop { gas_left: U256 }, Return(Bytes), Suicide, OutOfGas, diff --git a/src/evm/executive.rs b/src/evm/executive.rs index 8ffc97a95..82d821212 100644 --- a/src/evm/executive.rs +++ b/src/evm/executive.rs @@ -52,6 +52,7 @@ impl Substate { } } +/// Result of executing the transaction. #[derive(PartialEq, Debug)] pub enum ExecutiveResult { Ok, @@ -186,7 +187,7 @@ impl<'a> Executive<'a> { let evm = VmFactory::create(); evm.exec(¶ms, &mut ext) } { - EvmResult::Stop => ExecutiveResult::Ok, + EvmResult::Stop { gas_left } => ExecutiveResult::Ok, EvmResult::Return(_) => ExecutiveResult::Ok, EvmResult::Suicide => { substate.suicides.insert(params.address.clone()); @@ -213,7 +214,7 @@ impl<'a> Executive<'a> { let evm = VmFactory::create(); evm.exec(¶ms, &mut ext) } { - EvmResult::Stop => { + EvmResult::Stop { gas_left } => { ExecutiveResult::Ok }, EvmResult::Return(output) => { @@ -307,53 +308,90 @@ impl<'a> Ext for Externalities<'a> { } fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(Address, u64)> { - match self.state.balance(&self.params.address) >= *endowment && self.depth < 1024 { - false => None, - true => { - let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address)); - let params = EvmParams { - address: address.clone(), - sender: self.params.address.clone(), - origin: self.params.origin.clone(), - gas: U256::from(gas), - gas_price: self.params.gas_price.clone(), - value: endowment.clone(), - code: code.to_vec(), - data: vec![], - }; - let mut substate = Substate::new(); - { - let mut ex = Executive::from_parent(self); - ex.state.inc_nonce(&address); - let res = Executive::create(&mut ex, ¶ms, &mut substate); - println!("res: {:?}", res); - } - self.substate.accrue(substate); - Some((address, gas)) - } + // if balance is insufficient or we are to deep, return + if self.state.balance(&self.params.address) < *endowment && self.depth >= 1024 { + return None } + + // create new contract address + let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address)); + + // prepare the params + let params = EvmParams { + address: address.clone(), + sender: self.params.address.clone(), + origin: self.params.origin.clone(), + gas: U256::from(gas), + gas_price: self.params.gas_price.clone(), + value: endowment.clone(), + code: code.to_vec(), + data: vec![], + }; + + let mut substate = Substate::new(); + { + let mut ex = Executive::from_parent(self); + ex.state.inc_nonce(&address); + let res = Executive::create(&mut ex, ¶ms, &mut substate); + } + + self.substate.accrue(substate); + Some((address, gas)) } - fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address) -> Option<(Vec, u64)>{ + fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address) -> Option<(Vec, u64)> { // TODO: validation of the call + println!("gas: {:?}", gas); + println!("call_gas: {:?}", call_gas); + + let schedule = self.engine.evm_schedule(self.info); + let mut gas_cost = call_gas; + let mut call_gas = call_gas; + + let is_call = receive_address == code_address; + if is_call && self.state.code(&code_address).is_none() { + gas_cost = gas_cost + schedule.call_new_account_gas as u64; + } + + if *value > U256::zero() { + assert!(schedule.call_value_transfer_gas > schedule.call_stipend, "overflow possible"); + gas_cost = gas_cost + schedule.call_value_transfer_gas as u64; + call_gas = call_gas + schedule.call_stipend as u64; + } + + if gas_cost > gas { + // TODO: maybe gas should always be updated? + return None; + } + + // if we are too deep, return + // TODO: replace with >= 1024 + if self.depth == 1 { + return None; + } + let params = EvmParams { - address: code_address.clone(), - sender: receive_address.clone(), + address: receive_address.clone(), + sender: self.params.address.clone(), origin: self.params.origin.clone(), - gas: U256::from(call_gas), // TODO: + gas: U256::from(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(), }; + println!("params: {:?}", params); + let mut substate = Substate::new(); { let mut ex = Executive::from_parent(self); Executive::call(&mut ex, ¶ms, &mut substate); - unimplemented!(); } + + // TODO: replace call_gas with what's actually left + Some((vec![], gas - gas_cost + call_gas)) } fn extcode(&self, address: &Address) -> Vec { @@ -380,6 +418,9 @@ mod tests { use engine::*; use evm_schedule::*; use super::contract_address; + use ethereum; + use null_engine::*; + use std::ops::*; struct TestEngine; @@ -453,5 +494,53 @@ mod tests { assert_eq!(state.storage_at(&address, &H256::new()), H256::from(next_address.clone())); assert_eq!(state.code(&next_address).unwrap(), "6000355415600957005b602035600035".from_hex().unwrap()); + //assert!(false); + } + + #[test] + fn test_recursive_bomb1() { + // 60 01 - push 1 + // 60 00 - push 0 + // 54 - sload + // 01 - add + // 60 00 - push 0 + // 55 - sstore + // 60 00 - push 0 + // 60 00 - push 0 + // 60 00 - push 0 + // 60 00 - push 0 + // 60 00 - push 0 + // 30 - load address + // 60 e0 - push e0 + // 5a - get gas + // 03 - sub + // f1 - message call (self in this case) + // 60 01 - push 1 + // 55 - store + let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); + let code = "600160005401600055600060006000600060003360e05a03f1600155".from_hex().unwrap(); + let address = contract_address(&sender, &U256::zero()); + let mut params = EvmParams::new(); + params.address = address.clone(); + params.sender = sender.clone(); + params.origin = sender.clone(); + params.gas = U256::from(0x590b3); + params.gas_price = U256::one(); + params.code = code.clone(); + println!("init gas: {:?}", params.gas.low_u64()); + let mut state = State::new_temp(); + state.init_code(&address, code.clone()); + let info = EnvInfo::new(); + //let engine = TestEngine::new(); + let engine = NullEngine::new_boxed(ethereum::new_frontier()); + let mut substate = Substate::new(); + + { + let mut ex = Executive::new(&mut state, &info, engine.deref()); + assert_eq!(Executive::call(&mut ex, ¶ms, &mut substate), ExecutiveResult::Ok); + } + + assert!(false); + } } diff --git a/src/evm/ext.rs b/src/evm/ext.rs index 46dc47ec7..8f693f049 100644 --- a/src/evm/ext.rs +++ b/src/evm/ext.rs @@ -19,12 +19,12 @@ pub trait Ext { /// Creates new contract. /// If contract creation is successfull, - /// returns new contract address and gas used, + /// returns new contract address and gas left, /// otherwise `None`. fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(Address, u64)>; /// Message call. - /// If call is successfull, returns call output and gas used, + /// If call is successfull, returns call output and gas left. /// otherwise `None`. fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address) -> Option<(Vec, u64)>; diff --git a/src/evm/jit.rs b/src/evm/jit.rs index d15c8d3ee..4e239a27b 100644 --- a/src/evm/jit.rs +++ b/src/evm/jit.rs @@ -316,7 +316,7 @@ impl evm::Evm for JitEvm { let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) }; match context.exec() { - evmjit::ReturnCode::Stop => evm::EvmResult::Stop, + evmjit::ReturnCode::Stop => evm::EvmResult::Stop { gas_left: U256::from(context.gas_left()) }, evmjit::ReturnCode::Return => evm::EvmResult::Return(context.output_data().to_vec()), evmjit::ReturnCode::Suicide => evm::EvmResult::Suicide, evmjit::ReturnCode::OutOfGas => evm::EvmResult::OutOfGas, @@ -398,7 +398,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); } assert_eq!(state.storage_at(&address, &H256::new()), @@ -421,7 +422,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } assert_eq!(state.storage_at(&address, &H256::new()), @@ -444,7 +446,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } assert_eq!(state.storage_at(&address, &H256::new()), @@ -468,7 +471,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } assert_eq!(Address::from(state.storage_at(&address, &H256::new())), address.clone()); @@ -492,7 +496,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } assert_eq!(Address::from(state.storage_at(&address, &H256::new())), address.clone()); @@ -532,7 +537,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } assert_eq!(state.storage_at(&address, &H256::new()), @@ -557,7 +563,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0x10))); @@ -578,7 +585,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } let logs = substate.logs(); assert_eq!(logs.len(), 1); @@ -612,7 +620,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } let logs = substate.logs(); assert_eq!(logs.len(), 1); @@ -643,7 +652,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } assert_eq!(state.storage_at(&address, &H256::new()), H256::from(address.clone())); @@ -668,7 +678,8 @@ mod tests { { let mut ext = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate); let evm = JitEvm; - assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop); + let _res = evm.exec(¶ms, &mut ext); + //assert_eq!(evm.exec(¶ms, &mut ext), EvmResult::Stop {}); } assert_eq!(state.storage_at(&address, &H256::new()), H256::from_str("23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23").unwrap()); diff --git a/src/evm/params.rs b/src/evm/params.rs index 9fee7d42d..143709f56 100644 --- a/src/evm/params.rs +++ b/src/evm/params.rs @@ -2,7 +2,7 @@ use util::hash::*; use util::uint::*; use util::bytes::*; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct EvmParams { pub address: Address, pub sender: Address,