Merge pull request #317 from ethcore/evm-tests
Additional evm tests (extops, call, jumps) and some docs
This commit is contained in:
commit
4a88adfde7
@ -1,25 +1,45 @@
|
||||
use common::*;
|
||||
use evm;
|
||||
use evm::{Ext, Schedule, Factory, VMType, ContractCreateResult, MessageCallResult};
|
||||
use std::fmt::Debug;
|
||||
|
||||
struct FakeLogEntry {
|
||||
topics: Vec<H256>,
|
||||
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<Address>,
|
||||
receive_address: Option<Address>,
|
||||
value: Option<U256>,
|
||||
data: Bytes,
|
||||
code_address: Option<Address>
|
||||
}
|
||||
|
||||
/// Fake externalities test structure.
|
||||
///
|
||||
/// Can't do recursive calls.
|
||||
#[derive(Default)]
|
||||
struct FakeExt {
|
||||
sstore_clears: usize,
|
||||
depth: usize,
|
||||
store: HashMap<H256, H256>,
|
||||
_balances: HashMap<Address, U256>,
|
||||
blockhashes: HashMap<U256, H256>,
|
||||
codes: HashMap<Address, Bytes>,
|
||||
logs: Vec<FakeLogEntry>,
|
||||
_suicides: HashSet<Address>,
|
||||
info: EnvInfo,
|
||||
schedule: Schedule
|
||||
schedule: Schedule,
|
||||
balances: HashMap<Address, U256>,
|
||||
calls: HashSet<FakeCall>
|
||||
}
|
||||
|
||||
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<U256>,
|
||||
_data: &[u8],
|
||||
_code_address: &Address,
|
||||
_output: &mut [u8]) -> MessageCallResult {
|
||||
unimplemented!();
|
||||
gas: &U256,
|
||||
sender_address: &Address,
|
||||
receive_address: &Address,
|
||||
value: Option<U256>,
|
||||
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<T : Debug + Eq + PartialEq + Hash>(set: &HashSet<T>, 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());
|
||||
}
|
||||
|
@ -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<u64> + 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<Self, Self::FromDecStrErr>;
|
||||
|
||||
/// Conversion to u32
|
||||
@ -105,25 +105,25 @@ pub trait Uint: Sized + Default + FromStr + From<u64> + 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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user