2016-02-05 13:40:41 +01:00
|
|
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
|
|
|
// This file is part of Parity.
|
|
|
|
|
|
|
|
// Parity is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
|
|
|
// Parity is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
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::*;
|
2016-01-31 10:52:07 +01:00
|
|
|
use tests::helpers::*;
|
2016-03-24 01:25:59 +01:00
|
|
|
use ethjson;
|
2016-01-13 01:23:01 +01:00
|
|
|
|
2016-02-10 00:20:36 +01:00
|
|
|
struct TestEngineFrontier {
|
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
|
|
|
}
|
|
|
|
|
2016-02-10 00:20:36 +01:00
|
|
|
impl TestEngineFrontier {
|
|
|
|
fn new(max_depth: usize, vm_type: VMType) -> TestEngineFrontier {
|
|
|
|
TestEngineFrontier {
|
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-02-10 00:20:36 +01:00
|
|
|
max_depth: max_depth
|
2016-01-13 01:23:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-10 00:20:36 +01:00
|
|
|
impl Engine for TestEngineFrontier {
|
2016-01-13 01:23:01 +01:00
|
|
|
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-02-10 00:20:36 +01:00
|
|
|
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
|
2016-01-13 01:23:01 +01:00
|
|
|
let mut schedule = Schedule::new_frontier();
|
2016-02-10 00:20:36 +01:00
|
|
|
schedule.max_depth = self.max_depth;
|
2016-01-13 01:23:01 +01:00
|
|
|
schedule
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-24 01:25:59 +01:00
|
|
|
#[derive(Debug, PartialEq)]
|
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
|
|
|
|
}
|
|
|
|
|
2016-03-24 01:25:59 +01:00
|
|
|
impl From<ethjson::vm::Call> for CallCreate {
|
|
|
|
fn from(c: ethjson::vm::Call) -> Self {
|
|
|
|
let dst: Option<_> = c.destination.into();
|
|
|
|
CallCreate {
|
|
|
|
data: c.data.into(),
|
|
|
|
destination: dst.map(Into::into),
|
|
|
|
gas_limit: c.gas_limit.into(),
|
|
|
|
value: c.value.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-13 13:16:53 +01:00
|
|
|
/// 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-02-10 00:20:36 +01:00
|
|
|
fn new(state: &'a mut State,
|
|
|
|
info: &'a EnvInfo,
|
|
|
|
engine: &'a Engine,
|
2016-01-16 20:11:12 +01:00
|
|
|
depth: usize,
|
|
|
|
origin_info: OriginInfo,
|
2016-02-10 00:20:36 +01:00
|
|
|
substate: &'a mut Substate,
|
2016-03-19 19:06:13 +01:00
|
|
|
output: OutputPolicy<'a, 'a>,
|
2016-01-16 20:11:12 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-02-10 00:20:36 +01:00
|
|
|
fn call(&mut self,
|
|
|
|
gas: &U256,
|
|
|
|
_sender_address: &Address,
|
|
|
|
receive_address: &Address,
|
2016-01-25 23:59:50 +01:00
|
|
|
value: Option<U256>,
|
2016-02-10 00:20:36 +01:00
|
|
|
data: &[u8],
|
|
|
|
_code_address: &Address,
|
2016-01-16 20:11:12 +01:00
|
|
|
_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-02-10 00:20:36 +01:00
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2016-01-13 22:16:24 +01:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2016-03-24 01:25:59 +01:00
|
|
|
fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
|
|
|
|
let tests = ethjson::vm::Test::load(json_data).unwrap();
|
2016-01-13 01:23:01 +01:00
|
|
|
let mut failed = Vec::new();
|
2016-03-24 01:25:59 +01:00
|
|
|
|
|
|
|
for (name, vm) in tests.into_iter() {
|
2016-01-14 17:40:38 +01:00
|
|
|
println!("name: {:?}", name);
|
2016-01-13 01:23:01 +01:00
|
|
|
let mut fail = false;
|
2016-03-24 01:25:59 +01:00
|
|
|
|
2016-02-10 00:20:36 +01:00
|
|
|
let mut fail_unless = |cond: bool, s: &str | if !cond && !fail {
|
2016-03-24 01:25:59 +01:00
|
|
|
failed.push(format!("[{}] {}: {}", vm_type, name, s));
|
2016-02-10 00:20:36 +01:00
|
|
|
fail = true
|
2016-01-14 18:29:18 +01:00
|
|
|
};
|
2016-02-10 00:20:36 +01:00
|
|
|
|
2016-03-24 01:25:59 +01:00
|
|
|
let out_of_gas = vm.out_of_gas();
|
2016-01-31 10:52:07 +01:00
|
|
|
let mut state_result = get_temp_state();
|
|
|
|
let mut state = state_result.reference_mut();
|
2016-03-24 01:25:59 +01:00
|
|
|
state.populate_from(From::from(vm.pre_state.clone()));
|
|
|
|
let info = From::from(vm.env);
|
|
|
|
let engine = TestEngineFrontier::new(1, vm_type.clone());
|
|
|
|
let params = ActionParams::from(vm.transaction);
|
2016-02-10 00:20:36 +01:00
|
|
|
|
2016-03-19 14:10:32 +01:00
|
|
|
let mut substate = Substate::new(false);
|
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-03-19 14:10:32 +01:00
|
|
|
let mut ex = TestExt::new(
|
|
|
|
&mut state,
|
|
|
|
&info,
|
|
|
|
&engine,
|
|
|
|
0,
|
|
|
|
OriginInfo::from(¶ms),
|
|
|
|
&mut substate,
|
2016-03-19 22:14:16 +01:00
|
|
|
OutputPolicy::Return(BytesRef::Flexible(&mut output), None),
|
2016-03-19 14:10:32 +01:00
|
|
|
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
|
|
|
};
|
|
|
|
|
|
|
|
match res {
|
|
|
|
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
|
|
|
|
Ok(gas_left) => {
|
|
|
|
fail_unless(!out_of_gas, "expected to run out of gas.");
|
2016-03-24 01:25:59 +01:00
|
|
|
fail_unless(Some(gas_left) == vm.gas_left.map(Into::into), "gas_left is incorrect");
|
|
|
|
let vm_output: Option<Vec<u8>> = vm.output.map(Into::into);
|
|
|
|
fail_unless(Some(output) == vm_output, "output is incorrect");
|
|
|
|
|
2016-03-24 16:40:52 +01:00
|
|
|
for (address, account) in vm.post_state.unwrap().into_iter() {
|
|
|
|
let address = address.into();
|
|
|
|
let code: Vec<u8> = account.code.into();
|
|
|
|
fail_unless(state.code(&address).unwrap_or_else(Vec::new) == code, "code is incorrect");
|
|
|
|
fail_unless(state.balance(&address) == account.balance.into(), "balance is incorrect");
|
|
|
|
fail_unless(state.nonce(&address) == account.nonce.into(), "nonce is incorrect");
|
|
|
|
account.storage.into_iter().foreach(|(k, v)| {
|
|
|
|
let key: U256 = k.into();
|
|
|
|
let value: U256 = v.into();
|
|
|
|
fail_unless(state.storage_at(&address, &From::from(key)) == From::from(value), "storage is incorrect");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-03-24 01:25:59 +01:00
|
|
|
let calls: Option<Vec<CallCreate>> = vm.calls.map(|c| c.into_iter().map(From::from).collect());
|
|
|
|
fail_unless(Some(callcreates) == calls, "callcreates does not match");
|
2016-01-13 01:23:01 +01:00
|
|
|
}
|
2016-03-24 01:25:59 +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);
|
|
|
|
}
|
|
|
|
|
|
|
|
failed
|
|
|
|
}
|
|
|
|
|
|
|
|
declare_test!{ExecutiveTests_vmArithmeticTest, "VMTests/vmArithmeticTest"}
|
|
|
|
declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperationTest"}
|
2016-01-26 10:15:55 +01:00
|
|
|
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"}
|