From da22bbf21c08090ac0aaa96d24ccccdf7fb1fe92 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Wed, 3 Feb 2016 11:26:24 +0100 Subject: [PATCH 1/3] Tests for some external operations --- ethcore/src/evm/tests.rs | 26 ++++++++++++++++++++++++++ util/src/uint.rs | 24 ++++++++++++------------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 292a0d869..98a6fe696 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -766,6 +766,7 @@ fn test_badinstruction(factory: super::Factory) { _ => assert!(false, "Expected bad instruction") } } + evm_test!{test_pop: test_pop_jit, test_pop_int} fn test_pop(factory: super::Factory) { let code = "60f060aa50600055".from_hex().unwrap(); @@ -784,6 +785,31 @@ fn test_pop(factory: super::Factory) { assert_eq!(gas_left, U256::from(79_989)); } +evm_test!{test_extops: test_extops_jit, test_extops_int} +fn test_extops(factory: super::Factory) { + let code = "5a6001555836553a600255386003553460045560016001526016590454600555".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(150_000); + params.gas_price = U256::from(0x32); + params.value = ActionValue::Transfer(U256::from(0x99)); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000004"); // PC / CALLDATASIZE + assert_store(&ext, 1, "00000000000000000000000000000000000000000000000000000000000249ee"); // GAS + assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000032"); // GASPRICE + assert_store(&ext, 3, "0000000000000000000000000000000000000000000000000000000000000020"); // CODESIZE + assert_store(&ext, 4, "0000000000000000000000000000000000000000000000000000000000000099"); // CALLVALUE + assert_store(&ext, 5, "0000000000000000000000000000000000000000000000000000000000000032"); + assert_eq!(gas_left, U256::from(29_898)); +} + fn assert_store(ext: &FakeExt, pos: u64, val: &str) { assert_eq!(ext.store.get(&H256::from(pos)).unwrap(), &H256::from_str(val).unwrap()); } diff --git a/util/src/uint.rs b/util/src/uint.rs index 7eee6029e..4660506e9 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -60,20 +60,20 @@ macro_rules! panic_on_overflow { } } -/// TODO [Gav Wood] Please document me +/// Generic Uint of unspecified size pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + fmt::Display + PartialOrd + Ord + PartialEq + Eq + Hash { /// Size of this type. const SIZE: usize; - /// TODO [Gav Wood] Please document me + /// Returns `Uint(0)` fn zero() -> Self; - /// TODO [Gav Wood] Please document me + /// Returns `Uint(1)` fn one() -> Self; - /// TODO [Gav Wood] Please document me + /// Error returned when `from_dec_str` method fails type FromDecStrErr; - /// TODO [Gav Wood] Please document me + /// Create `Uint` from specified decimal represented by string fn from_dec_str(value: &str) -> Result; /// Conversion to u32 @@ -105,25 +105,25 @@ pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + fn overflowing_pow(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Add this `Uint` to other returning result and possible overflow fn overflowing_add(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Subtract another `Uint` from this returning result and possible overflow fn overflowing_sub(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Multiple this `Uint` with other returning result and possible overflow fn overflowing_mul(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Divide this `Uint` by other returning result and possible overflow fn overflowing_div(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Returns reminder of division of this `Uint` by other and possible overflow fn overflowing_rem(self, other: Self) -> (Self, bool); - /// TODO [debris] Please document me + /// Returns negation of this `Uint` and overflow (always true) fn overflowing_neg(self) -> (Self, bool); - /// TODO [Gav Wood] Please document me + /// Shifts this `Uint` and returns overflow fn overflowing_shl(self, shift: u32) -> (Self, bool); } From 82496ffb136ce93f99dd28f6bdb8285a67f019f7 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Wed, 3 Feb 2016 11:59:48 +0100 Subject: [PATCH 2/3] Jump tests --- ethcore/src/evm/tests.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 98a6fe696..db01698b1 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -12,6 +12,8 @@ struct FakeLogEntry { /// Can't do recursive calls. #[derive(Default)] struct FakeExt { + sstore_clears: usize, + depth: usize, store: HashMap, _balances: HashMap, blockhashes: HashMap, @@ -98,11 +100,11 @@ impl Ext for FakeExt { } fn depth(&self) -> usize { - unimplemented!(); + self.depth } fn inc_sstore_clears(&mut self) { - unimplemented!(); + self.sstore_clears += 1; } } @@ -810,6 +812,28 @@ fn test_extops(factory: super::Factory) { assert_eq!(gas_left, U256::from(29_898)); } +evm_test!{test_jumps: test_jumps_jit, test_jumps_int} +fn test_jumps(factory: super::Factory) { + let code = "600160015560066000555b60016000540380806000551560245760015402600155600a565b".from_hex().unwrap(); + + let mut params = ActionParams::default(); + params.gas = U256::from(150_000); + params.code = Some(code); + let mut ext = FakeExt::new(); + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_eq!(ext.sstore_clears, 1); + assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000"); // 5! + assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000078"); // 5! + assert_eq!(gas_left, U256::from(54_117)); +} + + + fn assert_store(ext: &FakeExt, pos: u64, val: &str) { assert_eq!(ext.store.get(&H256::from(pos)).unwrap(), &H256::from_str(val).unwrap()); } From 60d7fdf81ff2f111f4f770b3554c7b5631d01694 Mon Sep 17 00:00:00 2001 From: Tomusdrw Date: Wed, 3 Feb 2016 13:04:52 +0100 Subject: [PATCH 3/3] CALL/CALLCODE tests --- ethcore/src/evm/tests.rs | 121 +++++++++++++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 16 deletions(-) diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index db01698b1..bcd0819de 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -1,12 +1,29 @@ use common::*; use evm; use evm::{Ext, Schedule, Factory, VMType, ContractCreateResult, MessageCallResult}; +use std::fmt::Debug; struct FakeLogEntry { topics: Vec, data: Bytes } +#[derive(PartialEq, Eq, Hash, Debug)] +enum FakeCallType { + CALL, CREATE +} + +#[derive(PartialEq, Eq, Hash, Debug)] +struct FakeCall { + call_type: FakeCallType, + gas: U256, + sender_address: Option
, + receive_address: Option
, + value: Option, + data: Bytes, + code_address: Option
+} + /// Fake externalities test structure. /// /// Can't do recursive calls. @@ -15,13 +32,14 @@ struct FakeExt { sstore_clears: usize, depth: usize, store: HashMap, - _balances: HashMap, blockhashes: HashMap, codes: HashMap, logs: Vec, _suicides: HashSet
, info: EnvInfo, - schedule: Schedule + schedule: Schedule, + balances: HashMap, + calls: HashSet } impl FakeExt { @@ -45,31 +63,50 @@ impl Ext for FakeExt { self.store.insert(key, value); } - fn exists(&self, _address: &Address) -> bool { - unimplemented!(); + fn exists(&self, address: &Address) -> bool { + self.balances.contains_key(address) } - fn balance(&self, _address: &Address) -> U256 { - unimplemented!(); + fn balance(&self, address: &Address) -> U256 { + self.balances.get(address).unwrap().clone() } fn blockhash(&self, number: &U256) -> H256 { self.blockhashes.get(number).unwrap_or(&H256::new()).clone() } - fn create(&mut self, _gas: &U256, _value: &U256, _code: &[u8]) -> ContractCreateResult { - unimplemented!(); + fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { + self.calls.insert(FakeCall { + call_type: FakeCallType::CREATE, + gas: gas.clone(), + sender_address: None, + receive_address: None, + value: Some(value.clone()), + data: code.to_vec(), + code_address: None + }); + ContractCreateResult::Failed } fn call(&mut self, - _gas: &U256, - _sender_address: &Address, - _receive_address: &Address, - _value: Option, - _data: &[u8], - _code_address: &Address, - _output: &mut [u8]) -> MessageCallResult { - unimplemented!(); + gas: &U256, + sender_address: &Address, + receive_address: &Address, + value: Option, + data: &[u8], + code_address: &Address, + output: &mut [u8]) -> MessageCallResult { + + self.calls.insert(FakeCall { + call_type: FakeCallType::CALL, + gas: gas.clone(), + sender_address: Some(sender_address.clone()), + receive_address: Some(receive_address.clone()), + value: value, + data: data.to_vec(), + code_address: Some(code_address.clone()) + }); + MessageCallResult::Success(gas.clone()) } fn extcode(&self, address: &Address) -> Bytes { @@ -833,6 +870,58 @@ fn test_jumps(factory: super::Factory) { } +evm_test!{test_calls: test_calls_jit, test_calls_int} +fn test_calls(factory: super::Factory) { + let code = "600054602d57600160005560006000600060006050610998610100f160006000600060006050610998610100f25b".from_hex().unwrap(); + + let address = Address::from(0x155); + let code_address = Address::from(0x998); + let mut params = ActionParams::default(); + params.gas = U256::from(150_000); + params.code = Some(code); + params.address = address.clone(); + let mut ext = FakeExt::new(); + ext.balances = { + let mut s = HashMap::new(); + s.insert(params.address.clone(), params.gas.clone()); + s + }; + + let gas_left = { + let vm = factory.create(); + vm.exec(params, &mut ext).unwrap() + }; + + assert_set_contains(&ext.calls, &FakeCall { + call_type: FakeCallType::CALL, + gas: U256::from(2556), + sender_address: Some(address.clone()), + receive_address: Some(code_address.clone()), + value: Some(U256::from(0x50)), + data: vec!(), + code_address: Some(code_address.clone()) + }); + assert_set_contains(&ext.calls, &FakeCall { + call_type: FakeCallType::CALL, + gas: U256::from(2556), + sender_address: Some(address.clone()), + receive_address: Some(address.clone()), + value: Some(U256::from(0x50)), + data: vec!(), + code_address: Some(code_address.clone()) + }); + assert_eq!(gas_left, U256::from(91_405)); + assert_eq!(ext.calls.len(), 2); +} + +fn assert_set_contains(set: &HashSet, val: &T) { + let contains = set.contains(val); + if !contains { + println!("Set: {:?}", set); + println!("Elem: {:?}", val); + } + assert!(contains, "Element not found in HashSet"); +} fn assert_store(ext: &FakeExt, pos: u64, val: &str) { assert_eq!(ext.store.get(&H256::from(pos)).unwrap(), &H256::from_str(val).unwrap());