openethereum/ethcore/src/tests/executive.rs

286 lines
8.4 KiB
Rust
Raw Normal View History

2016-01-13 01:23:01 +01:00
use super::test_common::*;
use state::*;
use executive::*;
use spec::*;
use engine::*;
2016-01-13 13:16:53 +01:00
use evm;
2016-01-16 20:11:12 +01:00
use evm::{Schedule, Ext, Factory, VMType, ContractCreateResult, MessageCallResult};
2016-01-13 01:23:01 +01:00
use ethereum;
2016-01-15 14:22:46 +01:00
use externalities::*;
use substate::*;
use tests::helpers::*;
2016-01-13 01:23:01 +01:00
struct TestEngine {
2016-01-14 17:24:57 +01:00
vm_factory: Factory,
2016-01-13 01:23:01 +01:00
spec: Spec,
2016-01-14 12:33:49 +01:00
max_depth: usize
2016-01-13 01:23:01 +01:00
}
impl TestEngine {
2016-01-14 17:24:57 +01:00
fn new(max_depth: usize, vm_type: VMType) -> TestEngine {
2016-01-13 01:23:01 +01:00
TestEngine {
2016-01-14 17:24:57 +01:00
vm_factory: Factory::new(vm_type),
2016-01-13 01:23:01 +01:00
spec: ethereum::new_frontier_test(),
2016-01-14 12:33:49 +01:00
max_depth: max_depth
2016-01-13 01:23:01 +01:00
}
}
}
impl Engine for TestEngine {
fn name(&self) -> &str { "TestEngine" }
fn spec(&self) -> &Spec { &self.spec }
2016-01-14 17:24:57 +01:00
fn vm_factory(&self) -> &Factory { &self.vm_factory }
2016-01-13 01:23:01 +01:00
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
let mut schedule = Schedule::new_frontier();
2016-01-14 12:33:49 +01:00
schedule.max_depth = self.max_depth;
2016-01-13 01:23:01 +01:00
schedule
}
}
2016-01-13 13:16:53 +01:00
struct CallCreate {
data: Bytes,
2016-01-14 23:36:35 +01:00
destination: Option<Address>,
2016-01-16 20:11:12 +01:00
gas_limit: U256,
2016-01-13 13:16:53 +01:00
value: U256
}
/// Tiny wrapper around executive externalities.
/// Stores callcreates.
struct TestExt<'a> {
ext: Externalities<'a>,
2016-01-16 20:11:12 +01:00
callcreates: Vec<CallCreate>,
contract_address: Address
2016-01-13 13:16:53 +01:00
}
impl<'a> TestExt<'a> {
2016-01-16 20:11:12 +01:00
fn new(state: &'a mut State,
info: &'a EnvInfo,
engine: &'a Engine,
depth: usize,
origin_info: OriginInfo,
substate: &'a mut Substate,
output: OutputPolicy<'a>,
address: Address) -> Self {
2016-01-13 13:16:53 +01:00
TestExt {
2016-01-16 20:11:12 +01:00
contract_address: contract_address(&address, &state.nonce(&address)),
ext: Externalities::new(state, info, engine, depth, origin_info, substate, output),
2016-01-13 13:16:53 +01:00
callcreates: vec![]
}
}
}
impl<'a> Ext for TestExt<'a> {
2016-01-15 18:56:28 +01:00
fn storage_at(&self, key: &H256) -> H256 {
self.ext.storage_at(key)
2016-01-13 13:16:53 +01:00
}
2016-01-16 20:11:12 +01:00
fn set_storage(&mut self, key: H256, value: H256) {
self.ext.set_storage(key, value)
}
fn exists(&self, address: &Address) -> bool {
self.ext.exists(address)
2016-01-13 13:16:53 +01:00
}
fn balance(&self, address: &Address) -> U256 {
self.ext.balance(address)
}
fn blockhash(&self, number: &U256) -> H256 {
self.ext.blockhash(number)
}
2016-01-16 20:11:12 +01:00
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult {
self.callcreates.push(CallCreate {
data: code.to_vec(),
destination: None,
gas_limit: *gas,
value: *value
});
ContractCreateResult::Created(self.contract_address.clone(), *gas)
2016-01-13 13:16:53 +01:00
}
fn call(&mut self,
gas: &U256,
2016-01-23 10:41:13 +01:00
_sender_address: &Address,
2016-01-13 13:16:53 +01:00
receive_address: &Address,
2016-01-25 23:59:50 +01:00
value: Option<U256>,
2016-01-13 13:16:53 +01:00
data: &[u8],
2016-01-16 20:11:12 +01:00
_code_address: &Address,
_output: &mut [u8]) -> MessageCallResult {
self.callcreates.push(CallCreate {
data: data.to_vec(),
destination: Some(receive_address.clone()),
gas_limit: *gas,
2016-01-25 23:59:50 +01:00
value: value.unwrap()
2016-01-20 16:52:22 +01:00
});
MessageCallResult::Success(*gas)
}
2016-01-16 17:17:43 +01:00
fn extcode(&self, address: &Address) -> Bytes {
2016-01-13 13:16:53 +01:00
self.ext.extcode(address)
}
2016-01-16 17:17:43 +01:00
fn log(&mut self, topics: Vec<H256>, data: &[u8]) {
2016-01-13 13:16:53 +01:00
self.ext.log(topics, data)
}
fn ret(&mut self, gas: &U256, data: &[u8]) -> Result<U256, evm::Error> {
2016-01-13 13:16:53 +01:00
self.ext.ret(gas, data)
}
2016-01-13 16:16:21 +01:00
fn suicide(&mut self, refund_address: &Address) {
self.ext.suicide(refund_address)
2016-01-13 13:16:53 +01:00
}
fn schedule(&self) -> &Schedule {
self.ext.schedule()
}
fn env_info(&self) -> &EnvInfo {
self.ext.env_info()
}
2016-01-16 20:11:12 +01:00
fn depth(&self) -> usize {
0
}
fn inc_sstore_clears(&mut self) {
self.ext.inc_sstore_clears()
}
2016-01-13 13:16:53 +01:00
}
2016-01-13 01:23:01 +01:00
fn do_json_test(json_data: &[u8]) -> Vec<String> {
2016-01-14 18:29:18 +01:00
let vms = VMType::all();
vms
.iter()
.flat_map(|vm| do_json_test_for(vm, json_data))
.collect()
}
fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
2016-01-13 01:23:01 +01:00
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
let mut failed = Vec::new();
for (name, test) in json.as_object().unwrap() {
2016-01-14 17:40:38 +01:00
println!("name: {:?}", name);
2016-01-13 17:26:04 +01:00
// sync io is usefull when something crashes in jit
2016-01-14 18:29:18 +01:00
// ::std::io::stdout().write(&name.as_bytes());
// ::std::io::stdout().write(b"\n");
// ::std::io::stdout().flush();
2016-01-13 01:23:01 +01:00
let mut fail = false;
//let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.to_string()); fail = true };
2016-01-14 18:29:18 +01:00
let mut fail_unless = |cond: bool, s: &str | if !cond && !fail {
2016-01-19 13:47:30 +01:00
failed.push(format!("[{}] {}: {}", vm, name, s));
2016-01-14 18:29:18 +01:00
fail = true
};
2016-01-13 01:23:01 +01:00
// test env
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();
2016-01-13 01:23:01 +01:00
test.find("pre").map(|pre| for (addr, s) in pre.as_object().unwrap() {
2016-01-13 22:06:05 +01:00
let address = Address::from(addr.as_ref());
let balance = xjson!(&s["balance"]);
2016-01-14 21:58:37 +01:00
let code = xjson!(&s["code"]);
let _nonce: U256 = xjson!(&s["nonce"]);
2016-01-13 01:23:01 +01:00
state.new_contract(&address, balance);
2016-01-13 01:23:01 +01:00
state.init_code(&address, code);
2016-01-14 21:58:37 +01:00
BTreeMap::from_json(&s["storage"]).into_iter().foreach(|(k, v)| state.set_storage(&address, k, v));
2016-01-13 01:23:01 +01:00
});
2016-01-20 17:57:53 +01:00
let info = test.find("env").map(|env| {
EnvInfo::from_json(env)
}).unwrap_or_default();
2016-01-13 01:23:01 +01:00
2016-01-16 20:11:12 +01:00
let engine = TestEngine::new(1, vm.clone());
2016-01-13 01:23:01 +01:00
// params
2016-01-20 16:52:22 +01:00
let mut params = ActionParams::default();
2016-01-13 01:23:01 +01:00
test.find("exec").map(|exec| {
2016-01-14 21:58:37 +01:00
params.address = xjson!(&exec["address"]);
params.sender = xjson!(&exec["caller"]);
params.origin = xjson!(&exec["origin"]);
params.code = xjson!(&exec["code"]);
params.data = xjson!(&exec["data"]);
params.gas = xjson!(&exec["gas"]);
params.gas_price = xjson!(&exec["gasPrice"]);
2016-01-20 17:31:37 +01:00
params.value = ActionValue::Transfer(xjson!(&exec["value"]));
2016-01-13 01:23:01 +01:00
});
2016-01-13 17:26:04 +01:00
let out_of_gas = test.find("callcreates").map(|_calls| {
2016-01-13 01:23:01 +01:00
}).is_none();
let mut substate = Substate::new();
2016-01-13 15:26:52 +01:00
let mut output = vec![];
2016-01-13 01:23:01 +01:00
// execute
2016-01-13 17:26:04 +01:00
let (res, callcreates) = {
2016-01-16 20:11:12 +01:00
let mut ex = TestExt::new(&mut state,
&info,
&engine,
0,
OriginInfo::from(&params),
&mut substate,
OutputPolicy::Return(BytesRef::Flexible(&mut output)),
params.address.clone());
2016-01-14 18:29:18 +01:00
let evm = engine.vm_factory().create();
2016-01-16 20:11:12 +01:00
let res = evm.exec(params, &mut ex);
(res, ex.callcreates)
2016-01-13 01:23:01 +01:00
};
// then validate
match res {
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
Ok(gas_left) => {
2016-01-15 22:46:29 +01:00
// println!("name: {}, gas_left : {:?}", name, gas_left);
2016-01-13 01:23:01 +01:00
fail_unless(!out_of_gas, "expected to run out of gas.");
fail_unless(gas_left == xjson!(&test["gas"]), "gas_left is incorrect");
2016-01-14 21:58:37 +01:00
fail_unless(output == Bytes::from_json(&test["out"]), "output is incorrect");
2016-01-13 16:16:21 +01:00
test.find("post").map(|pre| for (addr, s) in pre.as_object().unwrap() {
2016-01-13 22:06:05 +01:00
let address = Address::from(addr.as_ref());
2016-01-19 13:47:30 +01:00
fail_unless(state.code(&address).unwrap_or_else(|| vec![]) == Bytes::from_json(&s["code"]), "code is incorrect");
fail_unless(state.balance(&address) == xjson!(&s["balance"]), "balance is incorrect");
fail_unless(state.nonce(&address) == xjson!(&s["nonce"]), "nonce is incorrect");
2016-01-14 21:58:37 +01:00
BTreeMap::from_json(&s["storage"]).iter().foreach(|(k, v)| fail_unless(&state.storage_at(&address, &k) == v, "storage is incorrect"));
2016-01-13 16:16:21 +01:00
});
2016-01-13 17:26:04 +01:00
let cc = test["callcreates"].as_array().unwrap();
fail_unless(callcreates.len() == cc.len(), "callcreates does not match");
for i in 0..cc.len() {
let callcreate = &callcreates[i];
2016-01-13 17:26:04 +01:00
let expected = &cc[i];
fail_unless(callcreate.data == Bytes::from_json(&expected["data"]), "callcreates data is incorrect");
fail_unless(callcreate.destination == xjson!(&expected["destination"]), "callcreates destination is incorrect");
fail_unless(callcreate.value == xjson!(&expected["value"]), "callcreates value is incorrect");
2016-01-16 20:11:12 +01:00
fail_unless(callcreate.gas_limit == xjson!(&expected["gasLimit"]), "callcreates gas_limit is incorrect");
2016-01-13 17:26:04 +01:00
}
2016-01-13 01:23:01 +01:00
}
}
}
2016-01-19 13:47:30 +01:00
for f in &failed {
2016-01-13 01:23:01 +01:00
println!("FAILED: {:?}", f);
}
//assert!(false);
failed
}
declare_test!{ExecutiveTests_vmArithmeticTest, "VMTests/vmArithmeticTest"}
declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperationTest"}
declare_test!{ExecutiveTests_vmBlockInfoTest, "VMTests/vmBlockInfoTest"}
// TODO [todr] Fails with Signal 11 when using JIT
2016-01-13 01:23:01 +01:00
declare_test!{ExecutiveTests_vmEnvironmentalInfoTest, "VMTests/vmEnvironmentalInfoTest"}
2016-01-13 13:16:53 +01:00
declare_test!{ExecutiveTests_vmIOandFlowOperationsTest, "VMTests/vmIOandFlowOperationsTest"}
2016-01-21 16:08:09 +01:00
declare_test!{heavy => ExecutiveTests_vmInputLimits, "VMTests/vmInputLimits"}
2016-01-13 13:16:53 +01:00
declare_test!{ExecutiveTests_vmLogTest, "VMTests/vmLogTest"}
declare_test!{ExecutiveTests_vmPerformanceTest, "VMTests/vmPerformanceTest"}
declare_test!{ExecutiveTests_vmPushDupSwapTest, "VMTests/vmPushDupSwapTest"}
declare_test!{ExecutiveTests_vmSha3Test, "VMTests/vmSha3Test"}
declare_test!{ExecutiveTests_vmSystemOperationsTest, "VMTests/vmSystemOperationsTest"}
declare_test!{ExecutiveTests_vmtests, "VMTests/vmtests"}