openethereum/ethcore/src/json_tests/executive.rs

377 lines
11 KiB
Rust
Raw Normal View History

// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.
2016-02-05 13:40:41 +01:00
// Parity Ethereum is free software: you can redistribute it and/or modify
2016-02-05 13:40:41 +01:00
// 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 Ethereum is distributed in the hope that it will be useful,
2016-02-05 13:40:41 +01:00
// 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
2016-02-05 13:40:41 +01:00
use std::path::Path;
2017-07-29 23:19:33 +02:00
use std::sync::Arc;
2016-01-13 01:23:01 +01:00
use super::test_common::*;
2017-02-22 10:52:58 +01:00
use state::{Backend as StateBackend, State, Substate};
2016-01-13 01:23:01 +01:00
use executive::*;
use evm::{VMType, Finalize};
use vm::{
self, ActionParams, CallType, Schedule, Ext,
ContractCreateResult, EnvInfo, MessageCallResult,
CreateContractAddress, ReturnData,
};
2016-01-15 14:22:46 +01:00
use externalities::*;
Private transactions integration pr (#6422) * Private transaction message added * Empty line removed * Private transactions logic removed from client into the separate module * Fixed compilation after merge with head * Signed private transaction message added as well * Comments after the review fixed * Private tx execution * Test update * Renamed some methods * Fixed some tests * Reverted submodules * Fixed build * Private transaction message added * Empty line removed * Private transactions logic removed from client into the separate module * Fixed compilation after merge with head * Signed private transaction message added as well * Comments after the review fixed * Encrypted private transaction message and signed reply added * Private tx execution * Test update * Main scenario completed * Merged with the latest head * Private transactions API * Comments after review fixed * Parameters for private transactions added to parity arguments * New files added * New API methods added * Do not process packets from unconfirmed peers * Merge with ptm_ss branch * Encryption and permissioning with key server added * Fixed compilation after merge * Version of Parity protocol incremented in order to support private transactions * Doc strings for constants added * Proper format for doc string added * fixed some encryptor.rs grumbles * Private transactions functionality moved to the separate crate * Refactoring in order to remove late initialisation * Tests fixed after moving to the separate crate * Fetch method removed * Sync test helpers refactored * Interaction with encryptor refactored * Contract address retrieving via substate removed * Sensible gas limit for private transactions implemented * New private contract with nonces added * Parsing of the response from key server fixed * Build fixed after the merge, native contracts removed * Crate renamed * Tests moved to the separate directory * Handling of errors reworked in order to use error chain * Encodable macro added, new constructor replaced with default * Native ethabi usage removed * Couple conversions optimized * Interactions with client reworked * Errors omitting removed * Fix after merge * Fix after the merge * private transactions improvements in progress * private_transactions -> ethcore/private-tx * making private transactions more idiomatic * private-tx encryptor uses shared FetchClient and is more idiomatic * removed redundant tests, moved integration tests to tests/ dir * fixed failing service test * reenable add_notify on private tx provider * removed private_tx tests from sync module * removed commented out code * Use plain password instead of unlocking account manager * remove dead code * Link to the contract changed * Transaction signature chain replay protection module created * Redundant type conversion removed * Contract address returned by private provider * Test fixed * Addressing grumbles in PrivateTransactions (#8249) * Tiny fixes part 1. * A bunch of additional comments and todos. * Fix ethsync tests. * resolved merge conflicts * final private tx pr (#8318) * added cli option that enables private transactions * fixed failing test * fixed failing test * fixed failing test * fixed failing test
2018-04-09 16:14:33 +02:00
use test_helpers::get_temp_state;
use ethjson;
use trace::{Tracer, NoopTracer};
use trace::{VMTracer, NoopVMTracer};
use bytes::Bytes;
use ethtrie;
use rlp::RlpStream;
use hash::keccak;
use machine::EthereumMachine as Machine;
2016-01-13 01:23:01 +01:00
use super::HookType;
/// Run executive jsontests on a given folder.
pub fn run_test_path<H: FnMut(&str, HookType)>(p: &Path, skip: &[&'static str], h: &mut H) {
::json_tests::test_common::run_test_path(p, skip, do_json_test, h)
}
/// Run executive jsontests on a given file.
pub fn run_test_file<H: FnMut(&str, HookType)>(p: &Path, h: &mut H) {
::json_tests::test_common::run_test_file(p, do_json_test, h)
}
#[derive(Debug, PartialEq, Clone)]
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
}
impl From<ethjson::vm::Call> for CallCreate {
fn from(c: ethjson::vm::Call) -> Self {
let dst: Option<ethjson::hash::Address> = 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, T: 'a, V: 'a, B: 'a>
where T: Tracer, V: VMTracer, B: StateBackend
2017-02-22 10:52:58 +01:00
{
ext: Externalities<'a, T, V, B>,
2016-01-16 20:11:12 +01:00
callcreates: Vec<CallCreate>,
nonce: U256,
sender: Address,
2016-01-13 13:16:53 +01:00
}
impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B>
where T: Tracer, V: VMTracer, B: StateBackend,
2017-02-22 10:52:58 +01:00
{
fn new(
2017-02-22 10:52:58 +01:00
state: &'a mut State<B>,
info: &'a EnvInfo,
machine: &'a Machine,
schedule: &'a Schedule,
depth: usize,
2018-10-02 16:33:19 +02:00
origin_info: &'a OriginInfo,
substate: &'a mut Substate,
output: OutputPolicy,
address: Address,
tracer: &'a mut T,
vm_tracer: &'a mut V,
) -> ethtrie::Result<Self> {
2017-06-19 11:41:46 +02:00
let static_call = false;
Ok(TestExt {
nonce: state.nonce(&address)?,
2018-10-02 16:33:19 +02:00
ext: Externalities::new(state, info, machine, schedule, depth, 0, origin_info, substate, output, tracer, vm_tracer, static_call),
callcreates: vec![],
sender: address,
})
2016-01-13 13:16:53 +01:00
}
}
impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B>
where T: Tracer, V: VMTracer, B: StateBackend
2017-02-22 10:52:58 +01:00
{
fn storage_at(&self, key: &H256) -> vm::Result<H256> {
2016-01-15 18:56:28 +01:00
self.ext.storage_at(key)
2016-01-13 13:16:53 +01:00
}
fn initial_storage_at(&self, key: &H256) -> vm::Result<H256> {
self.ext.initial_storage_at(key)
}
fn set_storage(&mut self, key: H256, value: H256) -> vm::Result<()> {
2016-01-16 20:11:12 +01:00
self.ext.set_storage(key, value)
}
fn exists(&self, address: &Address) -> vm::Result<bool> {
2016-01-16 20:11:12 +01:00
self.ext.exists(address)
2016-01-13 13:16:53 +01:00
}
fn exists_and_not_null(&self, address: &Address) -> vm::Result<bool> {
self.ext.exists_and_not_null(address)
}
fn balance(&self, address: &Address) -> vm::Result<U256> {
2016-01-13 13:16:53 +01:00
self.ext.balance(address)
}
fn origin_balance(&self) -> vm::Result<U256> {
self.ext.origin_balance()
}
fn blockhash(&mut self, number: &U256) -> H256 {
2016-01-13 13:16:53 +01:00
self.ext.blockhash(number)
}
2018-10-02 16:33:19 +02:00
fn create(
&mut self,
gas: &U256,
value: &U256,
code: &[u8],
address: CreateContractAddress,
_trap: bool
) -> Result<ContractCreateResult, vm::TrapKind> {
2016-01-16 20:11:12 +01:00
self.callcreates.push(CallCreate {
data: code.to_vec(),
destination: None,
gas_limit: *gas,
value: *value
});
2017-06-30 11:30:32 +02:00
let contract_address = contract_address(address, &self.sender, &self.nonce, &code).0;
2018-10-02 16:33:19 +02:00
Ok(ContractCreateResult::Created(contract_address, *gas))
2016-01-13 13:16:53 +01:00
}
2018-10-02 16:33:19 +02:00
fn call(
&mut self,
gas: &U256,
_sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
_code_address: &Address,
2018-10-02 16:33:19 +02:00
_call_type: CallType,
_trap: bool
) -> Result<MessageCallResult, vm::TrapKind> {
2016-01-16 20:11:12 +01:00
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
});
2018-10-02 16:33:19 +02:00
Ok(MessageCallResult::Success(*gas, ReturnData::empty()))
2016-01-20 16:52:22 +01:00
}
fn extcode(&self, address: &Address) -> vm::Result<Option<Arc<Bytes>>> {
2016-01-13 13:16:53 +01:00
self.ext.extcode(address)
}
2016-02-10 00:20:36 +01:00
fn extcodesize(&self, address: &Address) -> vm::Result<Option<usize>> {
self.ext.extcodesize(address)
}
fn extcodehash(&self, address: &Address) -> vm::Result<Option<H256>> {
self.ext.extcodehash(address)
}
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> vm::Result<()> {
2016-01-13 13:16:53 +01:00
self.ext.log(topics, data)
}
fn ret(self, gas: &U256, data: &ReturnData, apply_state: bool) -> Result<U256, vm::Error> {
self.ext.ret(gas, data, apply_state)
2016-01-13 13:16:53 +01:00
}
fn suicide(&mut self, refund_address: &Address) -> vm::Result<()> {
2016-01-13 16:16:21 +01:00
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 chain_id(&self) -> u64 { 0 }
2016-01-16 20:11:12 +01:00
fn depth(&self) -> usize {
0
}
fn is_static(&self) -> bool {
false
}
fn add_sstore_refund(&mut self, value: usize) {
self.ext.add_sstore_refund(value)
}
fn sub_sstore_refund(&mut self, value: usize) {
self.ext.sub_sstore_refund(value)
2016-01-16 20:11:12 +01:00
}
2016-01-13 13:16:53 +01:00
}
fn do_json_test<H: FnMut(&str, HookType)>(json_data: &[u8], h: &mut H) -> 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, h))
2016-01-14 18:29:18 +01:00
.collect()
}
fn do_json_test_for<H: FnMut(&str, HookType)>(vm_type: &VMType, json_data: &[u8], start_stop_hook: &mut H) -> Vec<String> {
let tests = ethjson::vm::Test::load(json_data).unwrap();
2016-01-13 01:23:01 +01:00
let mut failed = Vec::new();
for (name, vm) in tests.into_iter() {
start_stop_hook(&format!("{}-{}", name, vm_type), HookType::OnStart);
info!(target: "jsontests", "name: {:?}", name);
2016-01-13 01:23:01 +01:00
let mut fail = false;
2016-02-10 00:20:36 +01:00
let mut fail_unless = |cond: bool, s: &str | if !cond && !fail {
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
macro_rules! try_fail {
($e: expr) => {
match $e {
Ok(x) => x,
Err(e) => {
let msg = format!("Internal error: {}", e);
fail_unless(false, &msg);
continue
}
}
}
}
let out_of_gas = vm.out_of_gas();
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state();
state.populate_from(From::from(vm.pre_state.clone()));
let info: EnvInfo = From::from(vm.env);
let machine = {
let mut machine = ::ethereum::new_frontier_test_machine();
machine.set_schedule_creation_rules(Box::new(move |s, _| s.max_depth = 1));
machine
};
let params = ActionParams::from(vm.transaction);
2016-02-10 00:20:36 +01:00
2016-04-08 11:48:37 +02:00
let mut substate = Substate::new();
let mut tracer = NoopTracer;
let mut vm_tracer = NoopVMTracer;
let vm_factory = state.vm_factory();
2018-10-02 16:33:19 +02:00
let origin_info = OriginInfo::from(&params);
2016-01-13 01:23:01 +01:00
// execute
2016-01-13 17:26:04 +01:00
let (res, callcreates) = {
let schedule = machine.schedule(info.number);
let mut ex = try_fail!(TestExt::new(
2016-03-19 14:10:32 +01:00
&mut state,
&info,
&machine,
&schedule,
2016-03-19 14:10:32 +01:00
0,
2018-10-02 16:33:19 +02:00
&origin_info,
2016-03-19 14:10:32 +01:00
&mut substate,
OutputPolicy::Return,
2016-04-08 11:48:37 +02:00
params.address.clone(),
&mut tracer,
&mut vm_tracer,
));
let mut evm = vm_factory.create(params, &schedule, 0);
2018-10-02 16:33:19 +02:00
let res = evm.exec(&mut ex).ok().expect("TestExt never trap; resume error never happens; qed");
// a return in finalize will not alter callcreates
let callcreates = ex.callcreates.clone();
(res.finalize(ex), callcreates)
2016-01-13 01:23:01 +01:00
};
let output = match &res {
Ok(res) => res.return_data.to_vec(),
Err(_) => Vec::new(),
};
let log_hash = {
let mut rlp = RlpStream::new_list(substate.logs.len());
for l in &substate.logs {
rlp.append(l);
}
keccak(&rlp.drain())
};
2016-01-13 01:23:01 +01:00
match res {
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
2017-05-23 15:49:17 +02:00
Ok(res) => {
2016-01-13 01:23:01 +01:00
fail_unless(!out_of_gas, "expected to run out of gas.");
2017-05-23 15:49:17 +02:00
fail_unless(Some(res.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");
fail_unless(Some(log_hash) == vm.logs.map(|h| h.0), "logs are incorrect");
for (address, account) in vm.post_state.unwrap().into_iter() {
let address = address.into();
let code: Vec<u8> = account.code.into();
let found_code = try_fail!(state.code(&address));
let found_balance = try_fail!(state.balance(&address));
let found_nonce = try_fail!(state.nonce(&address));
fail_unless(found_code.as_ref().map_or_else(|| code.is_empty(), |c| &**c == &code), "code is incorrect");
fail_unless(found_balance == account.balance.into(), "balance is incorrect");
fail_unless(found_nonce == account.nonce.into(), "nonce is incorrect");
for (k, v) in account.storage {
let key: U256 = k.into();
let value: U256 = v.into();
let found_storage = try_fail!(state.storage_at(&address, &From::from(key)));
fail_unless(found_storage == From::from(value), "storage is incorrect");
}
}
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
}
};
start_stop_hook(&format!("{}-{}", name, vm_type), HookType::OnStop);
2016-01-13 01:23:01 +01:00
}
2016-01-19 13:47:30 +01:00
for f in &failed {
error!("FAILED: {:?}", f);
2016-01-13 01:23:01 +01:00
}
failed
}
declare_test!{ExecutiveTests_vmArithmeticTest, "VMTests/vmArithmeticTest"}
declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperation"}
declare_test!{ExecutiveTests_vmBlockInfoTest, "VMTests/vmBlockInfoTest"}
// TODO [todr] Fails with Signal 11 when using JIT
declare_test!{ExecutiveTests_vmEnvironmentalInfoTest, "VMTests/vmEnvironmentalInfo"}
declare_test!{ExecutiveTests_vmIOandFlowOperationsTest, "VMTests/vmIOandFlowOperations"}
2016-01-13 13:16:53 +01:00
declare_test!{ExecutiveTests_vmLogTest, "VMTests/vmLogTest"}
declare_test!{heavy => ExecutiveTests_vmPerformance, "VMTests/vmPerformance"}
2016-01-13 13:16:53 +01:00
declare_test!{ExecutiveTests_vmPushDupSwapTest, "VMTests/vmPushDupSwapTest"}
declare_test!{ExecutiveTests_vmRandomTest, "VMTests/vmRandomTest"}
2016-01-13 13:16:53 +01:00
declare_test!{ExecutiveTests_vmSha3Test, "VMTests/vmSha3Test"}
declare_test!{ExecutiveTests_vmSystemOperationsTest, "VMTests/vmSystemOperations"}
declare_test!{ExecutiveTests_vmTests, "VMTests/vmTests"}