diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 292a0d869..bcd0819de 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -1,25 +1,45 @@ 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. #[derive(Default)] 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 { @@ -43,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 { @@ -98,11 +137,11 @@ impl Ext for FakeExt { } fn depth(&self) -> usize { - unimplemented!(); + self.depth } fn inc_sstore_clears(&mut self) { - unimplemented!(); + self.sstore_clears += 1; } } @@ -766,6 +805,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 +824,105 @@ 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)); +} + +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)); +} + + +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()); } diff --git a/util/src/uint.rs b/util/src/uint.rs index 4deee5837..568885c82 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -104,26 +104,25 @@ pub trait Uint: Sized + Default + FromStr + From + FromJson + fmt::Debug + /// Return wrapped eponentation `self**other` and flag if there was an overflow fn overflowing_pow(self, other: Self) -> (Self, bool); - - /// Overflowing addition operation. + /// Add this `Uint` to other returning result and possible overflow fn overflowing_add(self, other: Self) -> (Self, bool); - /// Overflowing subtract operation. + /// Subtract another `Uint` from this returning result and possible overflow fn overflowing_sub(self, other: Self) -> (Self, bool); - /// Overflowing multiply operation. + /// Multiple this `Uint` with other returning result and possible overflow fn overflowing_mul(self, other: Self) -> (Self, bool); - /// Overflowing divide operation. + /// Divide this `Uint` by other returning result and possible overflow fn overflowing_div(self, other: Self) -> (Self, bool); - /// Overflowing remainder operation. + /// Returns reminder of division of this `Uint` by other and possible overflow fn overflowing_rem(self, other: Self) -> (Self, bool); - /// Overflowing negative operation. + /// Returns negation of this `Uint` and overflow (always true) fn overflowing_neg(self) -> (Self, bool); - /// Overflowing left bit shift. + /// Shifts this `Uint` and returns overflow fn overflowing_shl(self, shift: u32) -> (Self, bool); }