openethereum/crates/ethcore/src/json_tests/state.rs

154 lines
5.8 KiB
Rust

// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{test_common::*, HookType};
use client::{EvmTestClient, EvmTestError, TransactErr, TransactSuccess};
use ethjson::{self, spec::ForkSpec};
use pod_state::PodState;
use std::path::Path;
use trace;
use vm::EnvInfo;
fn skip_test(
test: &ethjson::test::StateTests,
subname: &str,
chain: &String,
number: usize,
) -> bool {
trace!(target: "json-tests", "[state, skip_test] subname: '{}', chain: '{}', number: {}", subname, chain, number);
test.skip.iter().any(|state_test| {
if let Some(subtest) = state_test.names.get(subname) {
trace!(target: "json-tests", "[state, skip_test] Maybe skipping {:?}", subtest);
chain == &subtest.chain
&& (subtest.subnumbers[0] == "*"
|| subtest.subnumbers.contains(&number.to_string()))
} else {
false
}
})
}
pub fn json_state_test<H: FnMut(&str, HookType)>(
state_test: &ethjson::test::StateTests,
path: &Path,
json_data: &[u8],
start_stop_hook: &mut H,
) -> Vec<String> {
let _ = ::env_logger::try_init();
let tests = ethjson::state::test::Test::load(json_data).expect(&format!(
"Could not parse JSON state test data from {}",
path.display()
));
let mut failed = Vec::new();
for (name, test) in tests.into_iter() {
if !super::debug_include_test(&name) {
continue;
}
start_stop_hook(&name, HookType::OnStart);
{
let multitransaction = test.transaction;
let env: EnvInfo = test.env.into();
let pre: PodState = test.pre_state.into();
for (spec_name, states) in test.post_states {
let spec = match EvmTestClient::spec_from_json(&spec_name) {
Some(spec) => spec,
None => {
panic!(
"Unimplemented chainspec '{:?}' in test '{}'",
spec_name, name
);
}
};
//hardcode base fee for part of the london tests, that miss base fee field in env
let mut test_env = env.clone();
if spec_name >= ForkSpec::London {
if test_env.base_fee.is_none() {
test_env.base_fee = Some(0x0a.into());
}
}
for (i, state) in states.into_iter().enumerate() {
let info = format!(
"TestState/{}/{:?}/{}/trie",
path.to_string_lossy(),
spec_name,
i
);
if skip_test(&state_test, &name, &spec.name, i + 1) {
println!("{}: SKIPPED", info);
continue;
}
let post_root: H256 = state.hash.into();
let transaction = multitransaction.select(&state.indexes);
let result = || -> Result<_, EvmTestError> {
Ok(EvmTestClient::from_pod_state(&spec, pre.clone())?.transact(
&test_env,
transaction,
trace::NoopTracer,
trace::NoopVMTracer,
))
};
match result() {
Err(err) => {
println!("{} !!! Unexpected internal error: {:?}", info, err);
flushln!("{} fail", info);
failed.push(name.clone());
}
Ok(Ok(TransactSuccess { state_root, .. })) if state_root != post_root => {
println!(
"{}: post state root mismatch: got {:?}, want {:?}",
info, state_root, post_root
);
flushln!("{} fail", info);
failed.push(name.clone());
}
Ok(Err(TransactErr {
state_root,
ref error,
..
})) if state_root != post_root => {
println!(
"{}: post state root mismatch: got {:?}, want {:?}",
info, state_root, post_root
);
println!("{} !!! Execution error: {:?}", info, error);
flushln!("{} fail", info);
failed.push(name.clone());
}
Ok(Err(TransactErr { error, .. })) => {
flushln!("{} ok ({:?})", info, error);
}
Ok(_) => {
flushln!("{} ok", info);
}
}
}
}
}
start_stop_hook(&name, HookType::OnStop);
}
failed
}