From 011a42fd6dafcae6526f916705ffb5bb7a9ac9ed Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 12 Jan 2016 13:39:12 +0100 Subject: [PATCH 1/6] added max_depth to executive, fixed bugs in externalities call, added "bomb" tests --- src/executive.rs | 157 ++++++++++++++++++++++++++++++++++------------- src/log_entry.rs | 3 +- 2 files changed, 117 insertions(+), 43 deletions(-) diff --git a/src/executive.rs b/src/executive.rs index c98191050..789ba3e33 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -35,6 +35,7 @@ impl Substate { } /// Transaction execution receipt. +#[derive(Debug)] pub struct Executed { /// Gas paid up front for execution of transaction. pub gas: U256, @@ -65,27 +66,29 @@ pub struct Executive<'a> { info: &'a EnvInfo, engine: &'a Engine, depth: usize, + max_depth: usize } impl<'a> Executive<'a> { /// Basic constructor. pub fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine) -> Self { - Executive::new_with_depth(state, info, engine, 0) + Executive::new_with_depth(state, info, engine, 0, 1024) } /// Populates executive from parent properties. Increments executive depth. - 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) + fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize, max_depth: usize) -> Self { + Executive::new_with_depth(state, info, engine, depth + 1, max_depth) } /// Helper constructor. Should be used to create `Executive` with desired depth. /// Private. - fn new_with_depth(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self { + fn new_with_depth(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize, max_depth: usize) -> Self { Executive { state: state, info: info, engine: engine, depth: depth, + max_depth: max_depth } } @@ -122,8 +125,9 @@ impl<'a> Executive<'a> { // NOTE: there can be no invalid transactions from this point. self.state.inc_nonce(&sender); - let mut substate = Substate::new(); + self.state.sub_balance(&sender, &gas_cost); + let mut substate = Substate::new(); let backup = self.state.clone(); let res = match t.action() { @@ -269,6 +273,7 @@ struct Externalities<'a> { info: &'a EnvInfo, engine: &'a Engine, depth: usize, + max_depth: usize, params: &'a ActionParams, substate: &'a mut Substate, schedule: Schedule, @@ -281,6 +286,7 @@ impl<'a> Externalities<'a> { info: &'a EnvInfo, engine: &'a Engine, depth: usize, + max_depth: usize, params: &'a ActionParams, substate: &'a mut Substate, output: OutputPolicy<'a>) -> Self { @@ -289,6 +295,7 @@ impl<'a> Externalities<'a> { info: info, engine: engine, depth: depth, + max_depth: max_depth, params: params, substate: substate, schedule: engine.schedule(info), @@ -298,7 +305,7 @@ impl<'a> Externalities<'a> { /// 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) + Self::new(e.state, e.info, e.engine, e.depth, e.max_depth, params, substate, output) } } @@ -331,7 +338,7 @@ impl<'a> Ext for Externalities<'a> { fn create(&mut self, gas: u64, value: &U256, code: &[u8]) -> Result<(u64, Option
), evm::Error> { // if balance is insufficient or we are to deep, return - if self.state.balance(&self.params.address) < *value && self.depth >= 1024 { + if self.state.balance(&self.params.address) < *value || self.depth >= self.max_depth { return Ok((gas, None)); } @@ -350,7 +357,7 @@ impl<'a> Ext for Externalities<'a> { data: vec![], }; - let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); + let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth, self.max_depth); ex.state.inc_nonce(&self.params.address); ex.create(¶ms, self.substate).map(|gas_left| (gas_left.low_u64(), Some(address))) } @@ -376,9 +383,8 @@ impl<'a> Ext for Externalities<'a> { let gas = gas - gas_cost; - //println!("depth: {:?}", self.depth); // if balance is insufficient or we are to deep, return - if self.state.balance(&self.params.address) < *value && self.depth >= 1024 { + if self.state.balance(&self.params.address) < *value || self.depth >= self.max_depth { return Ok(gas + call_gas) } @@ -393,8 +399,10 @@ impl<'a> Ext for Externalities<'a> { data: data.to_vec(), }; - let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); - ex.call(¶ms, self.substate, output).map(|gas_left| gas + gas_left.low_u64()) + let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth, self.max_depth); + ex.call(¶ms, self.substate, output).map(|gas_left| { + gas + gas_left.low_u64() + }) } fn extcode(&self, address: &Address) -> Vec { @@ -463,13 +471,13 @@ mod tests { #[test] // TODO: replace params with transactions! - fn test_executive() { + fn test_sender_balance() { let sender = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let address = contract_address(&sender, &U256::zero()); let mut params = ActionParams::new(); params.address = address.clone(); params.sender = sender.clone(); - params.gas = U256::from(0x174876e800u64); + params.gas = U256::from(100_000); params.code = "3331600055".from_hex().unwrap(); params.value = U256::from(0x7); let mut state = State::new_temp(); @@ -478,11 +486,12 @@ mod tests { let engine = NullEngine::new_boxed(ethereum::new_frontier()); let mut substate = Substate::new(); - { + let gas_left = { let mut ex = Executive::new(&mut state, &info, engine.deref()); - let _res = ex.create(¶ms, &mut substate); - } + ex.create(¶ms, &mut substate).unwrap() + }; + assert_eq!(gas_left, U256::from(79_975)); 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)); @@ -492,30 +501,98 @@ mod tests { #[test] fn test_create_contract() { + // 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes? + // 60 00 - push 0 + // 52 + // 60 1d - push 29 + // 60 03 - push 3 + // 60 17 - push 17 + // f0 - create + // 60 00 - push 0 + // 55 sstore + + let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055".from_hex().unwrap(); + let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let address = contract_address(&sender, &U256::zero()); - let next_address = contract_address(&address, &U256::zero()); + // TODO: add tests for 'callcreate' + //let next_address = contract_address(&address, &U256::zero()); let mut params = ActionParams::new(); params.address = address.clone(); params.sender = sender.clone(); params.origin = sender.clone(); - params.gas = U256::from(0x174876e800u64); - params.code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036000f0600055".from_hex().unwrap(); + params.gas = U256::from(100_000); + params.code = code.clone(); let mut state = State::new_temp(); - state.add_balance(&sender, &U256::from(0x100u64)); + state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::new(); let engine = NullEngine::new_boxed(ethereum::new_frontier()); let mut substate = Substate::new(); - { - let mut ex = Executive::new(&mut state, &info, engine.deref()); - let _res = ex.create(¶ms, &mut substate); - println!("res: {:?}", _res); - } + let gas_left = { + let mut ex = Executive::new_with_depth(&mut state, &info, engine.deref(), 0, 0); + ex.create(¶ms, &mut substate).unwrap() + }; - 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); + assert_eq!(gas_left, U256::from(47_976)); + } + + #[test] + fn test_aba_calls() { + // 60 00 - push 0 + // 60 00 - push 0 + // 60 00 - push 0 + // 60 00 - push 0 + // 60 18 - push 18 + // 73 945304eb96065b2a98b57a48a06ae28d285a71b5 - push this address + // 61 03e8 - push 1000 + // f1 - message call + // 58 - get PC + // 55 - sstore + + let code_a = "6000600060006000601873945304eb96065b2a98b57a48a06ae28d285a71b56103e8f15855".from_hex().unwrap(); + + // 60 00 - push 0 + // 60 00 - push 0 + // 60 00 - push 0 + // 60 00 - push 0 + // 60 17 - push 17 + // 73 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 - push this address + // 61 0x01f4 - push 500 + // f1 - message call + // 60 01 - push 1 + // 01 - add + // 58 - get PC + // 55 - sstore + let code_b = "60006000600060006017730f572e5295c57f15886f9b263e2f6d2d6c7b5ec66101f4f16001015855".from_hex().unwrap(); + + let address_a = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); + let address_b = Address::from_str("945304eb96065b2a98b57a48a06ae28d285a71b5" ).unwrap(); + let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); + + let mut params = ActionParams::new(); + params.address = address_a.clone(); + params.sender = sender.clone(); + params.gas = U256::from(100_000); + params.code = code_a.clone(); + params.value = U256::from(100_000); + + let mut state = State::new_temp(); + state.init_code(&address_a, code_a.clone()); + state.init_code(&address_b, code_b.clone()); + state.add_balance(&sender, &U256::from(100_000)); + + let info = EnvInfo::new(); + let engine = NullEngine::new_boxed(ethereum::new_frontier()); + let mut substate = Substate::new(); + + let gas_left = { + let mut ex = Executive::new_with_depth(&mut state, &info, engine.deref(), 0, 0); + ex.call(¶ms, &mut substate, &mut []).unwrap() + }; + + assert_eq!(gas_left, U256::from(73_237)); + assert_eq!(state.storage_at(&address_a, &H256::from(&U256::from(0x23))), H256::from(&U256::from(1))); } #[test] @@ -537,31 +614,27 @@ mod tests { // 03 - sub // f1 - message call (self in this case) // 60 01 - push 1 - // 55 - store + // 55 - sstore let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); let code = "600160005401600055600060006000600060003060e05a03f1600155".from_hex().unwrap(); let address = contract_address(&sender, &U256::zero()); let mut params = ActionParams::new(); params.address = address.clone(); - params.sender = sender.clone(); - params.origin = sender.clone(); - params.gas = U256::from(0x590b3); - params.gas_price = U256::one(); + params.gas = U256::from(100_000); 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 = NullEngine::new_boxed(ethereum::new_frontier()); let mut substate = Substate::new(); - { - let mut ex = Executive::new(&mut state, &info, engine.deref()); - let _res = ex.call(¶ms, &mut substate, &mut []); - println!("res: {:?}", _res); - } - - assert!(false); + let gas_left = { + let mut ex = Executive::new_with_depth(&mut state, &info, engine.deref(), 0, 0); + ex.call(¶ms, &mut substate, &mut []).unwrap() + }; + assert_eq!(gas_left, U256::from(59_870)); + assert_eq!(state.storage_at(&address, &H256::from(&U256::zero())), H256::from(&U256::from(1))); + assert_eq!(state.storage_at(&address, &H256::from(&U256::one())), H256::from(&U256::from(1))); } } diff --git a/src/log_entry.rs b/src/log_entry.rs index 939d60276..8602eeb66 100644 --- a/src/log_entry.rs +++ b/src/log_entry.rs @@ -2,6 +2,7 @@ use util::*; use basic_types::LogBloom; /// A single log's entry. +#[derive(Debug)] pub struct LogEntry { pub address: Address, pub topics: Vec, @@ -59,4 +60,4 @@ mod tests { let log = LogEntry::new(address, vec![], vec![]); assert_eq!(log.bloom(), bloom); } -} \ No newline at end of file +} From f7af71e272a566686151ba547b1c31651947109b Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 12 Jan 2016 13:54:54 +0100 Subject: [PATCH 2/6] fixed checking address existance in externalities call callback --- src/executive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/executive.rs b/src/executive.rs index 8133911e7..62928b5b6 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -367,7 +367,7 @@ impl<'a> Ext for Externalities<'a> { let mut call_gas = call_gas; let is_call = receive_address == code_address; - if is_call && self.state.code(&code_address).is_none() { + if is_call && !self.state.exists(&code_address) { gas_cost = gas_cost + self.schedule.call_new_account_gas as u64; } From 1aa62691c67bd17613d6c7a54130d6773a1cb917 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 12 Jan 2016 14:56:19 +0100 Subject: [PATCH 3/6] executive checks schedule exceptional code deposit before returning OutOfGas --- src/executive.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/executive.rs b/src/executive.rs index 62928b5b6..402b7927c 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -419,7 +419,10 @@ impl<'a> Ext for Externalities<'a> { &mut OutputPolicy::InitContract => { let return_cost = data.len() as u64 * self.schedule.create_data_gas as u64; if return_cost > gas { - return Err(evm::Error::OutOfGas); + match self.schedule.exceptional_failed_code_deposit { + true => return Err(evm::Error::OutOfGas), + false => return Ok(gas) + } } let mut code = vec![]; code.reserve(data.len()); From 51610480b062c7e09e03038da77b9f29c486a44b Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 12 Jan 2016 15:12:03 +0100 Subject: [PATCH 4/6] executive uses stack_limit from schedule --- src/executive.rs | 69 ++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/src/executive.rs b/src/executive.rs index 402b7927c..d5ecdb296 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -65,30 +65,28 @@ pub struct Executive<'a> { state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, - depth: usize, - max_depth: usize + depth: usize } impl<'a> Executive<'a> { /// Basic constructor. pub fn new(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine) -> Self { - Executive::new_with_depth(state, info, engine, 0, 1024) + Executive::new_with_depth(state, info, engine, 0) } /// Populates executive from parent properties. Increments executive depth. - fn from_parent(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize, max_depth: usize) -> Self { - Executive::new_with_depth(state, info, engine, depth + 1, max_depth) + 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) } /// Helper constructor. Should be used to create `Executive` with desired depth. /// Private. - fn new_with_depth(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize, max_depth: usize) -> Self { + fn new_with_depth(state: &'a mut State, info: &'a EnvInfo, engine: &'a Engine, depth: usize) -> Self { Executive { state: state, info: info, engine: engine, - depth: depth, - max_depth: max_depth + depth: depth } } @@ -273,7 +271,6 @@ struct Externalities<'a> { info: &'a EnvInfo, engine: &'a Engine, depth: usize, - max_depth: usize, params: &'a ActionParams, substate: &'a mut Substate, schedule: Schedule, @@ -286,7 +283,6 @@ impl<'a> Externalities<'a> { info: &'a EnvInfo, engine: &'a Engine, depth: usize, - max_depth: usize, params: &'a ActionParams, substate: &'a mut Substate, output: OutputPolicy<'a>) -> Self { @@ -295,7 +291,6 @@ impl<'a> Externalities<'a> { info: info, engine: engine, depth: depth, - max_depth: max_depth, params: params, substate: substate, schedule: engine.schedule(info), @@ -305,7 +300,7 @@ impl<'a> Externalities<'a> { /// 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, e.max_depth, params, substate, output) + Self::new(e.state, e.info, e.engine, e.depth, params, substate, output) } } @@ -338,7 +333,7 @@ impl<'a> Ext for Externalities<'a> { fn create(&mut self, gas: u64, value: &U256, code: &[u8]) -> Result<(u64, Option
), evm::Error> { // if balance is insufficient or we are to deep, return - if self.state.balance(&self.params.address) < *value || self.depth >= self.max_depth { + if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.stack_limit { return Ok((gas, None)); } @@ -357,7 +352,7 @@ impl<'a> Ext for Externalities<'a> { data: vec![], }; - let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth, self.max_depth); + let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); ex.state.inc_nonce(&self.params.address); ex.create(¶ms, self.substate).map(|gas_left| (gas_left.low_u64(), Some(address))) } @@ -384,7 +379,7 @@ impl<'a> Ext for Externalities<'a> { let gas = gas - gas_cost; // if balance is insufficient or we are to deep, return - if self.state.balance(&self.params.address) < *value || self.depth >= self.max_depth { + if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.stack_limit { return Ok(gas + call_gas) } @@ -399,7 +394,7 @@ impl<'a> Ext for Externalities<'a> { data: data.to_vec(), }; - let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth, self.max_depth); + let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); ex.call(¶ms, self.substate, output).map(|gas_left| { gas + gas_left.low_u64() }) @@ -462,9 +457,33 @@ mod tests { use common::*; use state::*; use ethereum; - use null_engine::*; + use engine::*; + use spec::*; + use evm::Schedule; use super::Substate; + struct TestEngine { + spec: Spec + } + + impl TestEngine { + fn new() -> TestEngine { + TestEngine { + spec: ethereum::new_frontier() + } + } + } + + impl Engine for TestEngine { + fn name(&self) -> &str { "TestEngine" } + fn spec(&self) -> &Spec { &self.spec } + fn schedule(&self, _env_info: &EnvInfo) -> Schedule { + let mut schedule = Schedule::new_frontier(); + schedule.stack_limit = 0; + schedule + } + } + #[test] fn test_contract_address() { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); @@ -486,11 +505,11 @@ mod tests { let mut state = State::new_temp(); state.add_balance(&sender, &U256::from(0x100u64)); let info = EnvInfo::new(); - let engine = NullEngine::new_boxed(ethereum::new_frontier()); + let engine = TestEngine::new(); let mut substate = Substate::new(); let gas_left = { - let mut ex = Executive::new(&mut state, &info, engine.deref()); + let mut ex = Executive::new(&mut state, &info, &engine); ex.create(¶ms, &mut substate).unwrap() }; @@ -529,11 +548,11 @@ mod tests { let mut state = State::new_temp(); state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::new(); - let engine = NullEngine::new_boxed(ethereum::new_frontier()); + let engine = TestEngine::new(); let mut substate = Substate::new(); let gas_left = { - let mut ex = Executive::new_with_depth(&mut state, &info, engine.deref(), 0, 0); + let mut ex = Executive::new(&mut state, &info, &engine); ex.create(¶ms, &mut substate).unwrap() }; @@ -586,11 +605,11 @@ mod tests { state.add_balance(&sender, &U256::from(100_000)); let info = EnvInfo::new(); - let engine = NullEngine::new_boxed(ethereum::new_frontier()); + let engine = TestEngine::new(); let mut substate = Substate::new(); let gas_left = { - let mut ex = Executive::new_with_depth(&mut state, &info, engine.deref(), 0, 0); + let mut ex = Executive::new(&mut state, &info, &engine); ex.call(¶ms, &mut substate, &mut []).unwrap() }; @@ -628,11 +647,11 @@ mod tests { let mut state = State::new_temp(); state.init_code(&address, code.clone()); let info = EnvInfo::new(); - let engine = NullEngine::new_boxed(ethereum::new_frontier()); + let engine = TestEngine::new(); let mut substate = Substate::new(); let gas_left = { - let mut ex = Executive::new_with_depth(&mut state, &info, engine.deref(), 0, 0); + let mut ex = Executive::new(&mut state, &info, &engine); ex.call(¶ms, &mut substate, &mut []).unwrap() }; From 36e250bcc9f43f0cb79315a9345016460ad08f1c Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 12 Jan 2016 16:05:54 +0100 Subject: [PATCH 5/6] executive returns addresses of contracts created during execution --- src/executive.rs | 99 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 8 deletions(-) diff --git a/src/executive.rs b/src/executive.rs index d5ecdb296..cca1997f3 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -21,6 +21,8 @@ struct Substate { logs: Vec, /// Refund counter of SSTORE nonzero->zero. refunds_count: U256, + /// Created contracts. + contracts_created: Vec
} impl Substate { @@ -30,6 +32,7 @@ impl Substate { suicides: HashSet::new(), logs: vec![], refunds_count: U256::zero(), + contracts_created: vec![] } } } @@ -55,6 +58,13 @@ pub struct Executed { /// Execution ended running out of gas. pub out_of_gas: bool, + /// Addresses of contracts created during execution of transaction. + /// Ordered from earliest creation. + /// + /// eg. sender creates contract A and A in constructor creates contract B + /// + /// B creation ends first, and it will be the first element of the vector. + pub contracts_created: Vec
} /// Transaction execution result. @@ -217,6 +227,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + t.gas, logs: vec![], out_of_gas: true, + contracts_created: vec![] }) }, Ok(gas_left) => { @@ -250,6 +261,7 @@ impl<'a> Executive<'a> { cumulative_gas_used: self.info.gas_used + gas_used, logs: substate.logs, out_of_gas: false, + contracts_created: substate.contracts_created }) } } @@ -405,6 +417,7 @@ impl<'a> Ext for Externalities<'a> { } fn ret(&mut self, gas: u64, data: &[u8]) -> Result { + println!("ret"); match &mut self.output { &mut OutputPolicy::Return(ref mut slice) => unsafe { let len = cmp::min(slice.len(), data.len()); @@ -427,6 +440,7 @@ impl<'a> Ext for Externalities<'a> { } let address = &self.params.address; self.state.init_code(address, code); + self.substate.contracts_created.push(address.clone()); Ok(gas - return_cost) } } @@ -463,13 +477,15 @@ mod tests { use super::Substate; struct TestEngine { - spec: Spec + spec: Spec, + stack_limit: usize } impl TestEngine { - fn new() -> TestEngine { + fn new(stack_limit: usize) -> TestEngine { TestEngine { - spec: ethereum::new_frontier() + spec: ethereum::new_frontier(), + stack_limit: stack_limit } } } @@ -479,7 +495,7 @@ mod tests { fn spec(&self) -> &Spec { &self.spec } fn schedule(&self, _env_info: &EnvInfo) -> Schedule { let mut schedule = Schedule::new_frontier(); - schedule.stack_limit = 0; + schedule.stack_limit = self.stack_limit; schedule } } @@ -505,7 +521,7 @@ mod tests { let mut state = State::new_temp(); state.add_balance(&sender, &U256::from(0x100u64)); let info = EnvInfo::new(); - let engine = TestEngine::new(); + let engine = TestEngine::new(0); let mut substate = Substate::new(); let gas_left = { @@ -517,12 +533,16 @@ 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)); + // 0 cause contract hasn't returned + assert_eq!(substate.contracts_created.len(), 0); // TODO: just test state root. } #[test] fn test_create_contract() { + // code: + // // 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes? // 60 00 - push 0 // 52 @@ -532,6 +552,16 @@ mod tests { // f0 - create // 60 00 - push 0 // 55 sstore + // + // other code: + // + // 60 10 - push 16 + // 80 - duplicate first stack item + // 60 0c - push 12 + // 60 00 - push 0 + // 39 - copy current code to memory + // 60 00 - push 0 + // f3 - return let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055".from_hex().unwrap(); @@ -545,10 +575,11 @@ mod tests { params.origin = sender.clone(); params.gas = U256::from(100_000); params.code = code.clone(); + params.value = U256::from(100); let mut state = State::new_temp(); state.add_balance(&sender, &U256::from(100)); let info = EnvInfo::new(); - let engine = TestEngine::new(); + let engine = TestEngine::new(0); let mut substate = Substate::new(); let gas_left = { @@ -557,6 +588,58 @@ mod tests { }; assert_eq!(gas_left, U256::from(47_976)); + assert_eq!(substate.contracts_created.len(), 0); + } + + #[test] + fn test_create_contract_without_stack_limit() { + // code: + // + // 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes? + // 60 00 - push 0 + // 52 + // 60 1d - push 29 + // 60 03 - push 3 + // 60 17 - push 17 + // f0 - create + // 60 00 - push 0 + // 55 sstore + // + // other code: + // + // 60 10 - push 16 + // 80 - duplicate first stack item + // 60 0c - push 12 + // 60 00 - push 0 + // 39 - copy current code to memory + // 60 00 - push 0 + // f3 - return + + let code = "7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055".from_hex().unwrap(); + + let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap(); + let address = contract_address(&sender, &U256::zero()); + let next_address = contract_address(&address, &U256::zero()); + let mut params = ActionParams::new(); + params.address = address.clone(); + params.sender = sender.clone(); + params.origin = sender.clone(); + params.gas = U256::from(100_000); + params.code = code.clone(); + params.value = U256::from(100); + let mut state = State::new_temp(); + state.add_balance(&sender, &U256::from(100)); + let info = EnvInfo::new(); + let engine = TestEngine::new(1024); + let mut substate = Substate::new(); + + { + let mut ex = Executive::new(&mut state, &info, &engine); + ex.create(¶ms, &mut substate).unwrap(); + } + + assert_eq!(substate.contracts_created.len(), 1); + assert_eq!(substate.contracts_created[0], next_address); } #[test] @@ -605,7 +688,7 @@ mod tests { state.add_balance(&sender, &U256::from(100_000)); let info = EnvInfo::new(); - let engine = TestEngine::new(); + let engine = TestEngine::new(0); let mut substate = Substate::new(); let gas_left = { @@ -647,7 +730,7 @@ mod tests { let mut state = State::new_temp(); state.init_code(&address, code.clone()); let info = EnvInfo::new(); - let engine = TestEngine::new(); + let engine = TestEngine::new(0); let mut substate = Substate::new(); let gas_left = { From a5e1db11ca07d038695e14a66309f7e62f61d8c2 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 12 Jan 2016 16:32:51 +0100 Subject: [PATCH 6/6] match return => return match --- src/executive.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/executive.rs b/src/executive.rs index cca1997f3..4e829cdd5 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -427,9 +427,9 @@ impl<'a> Ext for Externalities<'a> { &mut OutputPolicy::InitContract => { let return_cost = data.len() as u64 * self.schedule.create_data_gas as u64; if return_cost > gas { - match self.schedule.exceptional_failed_code_deposit { - true => return Err(evm::Error::OutOfGas), - false => return Ok(gas) + return match self.schedule.exceptional_failed_code_deposit { + true => Err(evm::Error::OutOfGas), + false => Ok(gas) } } let mut code = vec![];