Local EIP2930 and EN/DE block tests (#237)
This commit is contained in:
@@ -68,7 +68,7 @@ impl fmt::Display for EvmTestError {
|
||||
}
|
||||
}
|
||||
|
||||
use ethereum;
|
||||
use ethereum::{self};
|
||||
use ethjson::spec::ForkSpec;
|
||||
|
||||
/// Simplified, single-block EVM test client.
|
||||
@@ -99,6 +99,7 @@ impl<'a> EvmTestClient<'a> {
|
||||
ForkSpec::Homestead => Some(ethereum::new_homestead_test()),
|
||||
ForkSpec::EIP150 => Some(ethereum::new_eip150_test()),
|
||||
ForkSpec::EIP158 => Some(ethereum::new_eip161_test()),
|
||||
ForkSpec::EIP2930 => Some(ethereum::new_eip2930_test()),
|
||||
ForkSpec::Byzantium => Some(ethereum::new_byzantium_test()),
|
||||
ForkSpec::Constantinople => Some(ethereum::new_constantinople_test()),
|
||||
ForkSpec::ConstantinopleFix => Some(ethereum::new_constantinople_fix_test()),
|
||||
|
||||
@@ -267,6 +267,14 @@ pub fn new_berlin_test() -> Spec {
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new Foundation Berlin era spec.
|
||||
pub fn new_eip2930_test() -> Spec {
|
||||
load(
|
||||
None,
|
||||
include_bytes!("../../res/chainspec/test/eip2930_test.json"),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new YOLO spec
|
||||
pub fn new_yolo3_test() -> Spec {
|
||||
load(
|
||||
|
||||
@@ -208,7 +208,7 @@ pub fn json_chain_test<H: FnMut(&str, HookType)>(
|
||||
match block {
|
||||
Ok(block) => {
|
||||
let num = block.header.number();
|
||||
trace!(target: "json-tests", "{} – Importing {} bytes. Block #{}", name, bytes_len, num);
|
||||
debug!(target: "json-tests", "{} – Importing {} bytes. Block #{}", name, bytes_len, num);
|
||||
let res = client.import_block(block);
|
||||
if let Err(e) = res {
|
||||
warn!(target: "json-tests", "{} – Error importing block #{}: {:?}", name, num, e);
|
||||
|
||||
202
crates/ethcore/src/json_tests/local.rs
Normal file
202
crates/ethcore/src/json_tests/local.rs
Normal file
@@ -0,0 +1,202 @@
|
||||
use super::HookType;
|
||||
use ethereum_types::U256;
|
||||
use ethjson::{self, blockchain::Block};
|
||||
use log::warn;
|
||||
use rlp::RlpStream;
|
||||
use std::path::Path;
|
||||
use types::transaction::{TypedTransaction, TypedTxId, UnverifiedTransaction};
|
||||
use verification::queue::kind::blocks::Unverified;
|
||||
|
||||
pub fn json_local_block_en_de_test<H: FnMut(&str, HookType)>(
|
||||
_test: ðjson::test::LocalTests,
|
||||
path: &Path,
|
||||
json_data: &[u8],
|
||||
start_stop_hook: &mut H,
|
||||
) -> Vec<String> {
|
||||
let tests = ethjson::local_tests::BlockEnDeTest::load(json_data).expect(&format!(
|
||||
"Could not parse JSON chain test data from {}",
|
||||
path.display()
|
||||
));
|
||||
let mut failed = Vec::new();
|
||||
|
||||
for (name, ref_block) in tests.into_iter() {
|
||||
start_stop_hook(&name, HookType::OnStart);
|
||||
|
||||
let block = Unverified::from_rlp(ref_block.rlp());
|
||||
let block = match block {
|
||||
Ok(block) => block,
|
||||
Err(decoder_err) => {
|
||||
warn!(target: "json-tests", "Error decoding test block: {:?}", decoder_err);
|
||||
failed.push(name.clone());
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if !is_same_block(&ref_block, &block) {
|
||||
println!("block failed {:?}", block);
|
||||
failed.push(name.clone())
|
||||
}
|
||||
|
||||
start_stop_hook(&name, HookType::OnStop);
|
||||
}
|
||||
failed
|
||||
}
|
||||
|
||||
fn rlp_append_block(block: &Unverified) -> Vec<u8> {
|
||||
let mut rlps = RlpStream::new();
|
||||
rlps.begin_list(3);
|
||||
rlps.append(&block.header);
|
||||
UnverifiedTransaction::rlp_append_list(&mut rlps, &block.transactions);
|
||||
rlps.append_list(&block.uncles);
|
||||
rlps.out()
|
||||
}
|
||||
|
||||
pub fn is_same_block(ref_block: &Block, block: &Unverified) -> bool {
|
||||
let test_exp = |exp: bool, err: &str| -> bool {
|
||||
if !exp {
|
||||
println!("Test mismatch on:{}", err);
|
||||
}
|
||||
exp
|
||||
};
|
||||
|
||||
let header_ok = if let Some(ref header) = ref_block.header {
|
||||
test_exp(*block.header.gas_used() == header.gas_used.0, "Gas used")
|
||||
&& test_exp(
|
||||
*block.header.uncles_hash() == header.uncles_hash.0,
|
||||
"Uncles hash",
|
||||
)
|
||||
&& test_exp(
|
||||
*block.header.transactions_root() == header.transactions_root.0,
|
||||
"Transaction Root",
|
||||
)
|
||||
&& test_exp(
|
||||
block.header.timestamp() == header.timestamp.0.as_u64(),
|
||||
"Timestamp",
|
||||
)
|
||||
&& test_exp(
|
||||
*block.header.state_root() == header.state_root.0,
|
||||
"StateRoot",
|
||||
)
|
||||
&& test_exp(
|
||||
*block.header.receipts_root() == header.receipts_root.0,
|
||||
"ReceiptsRoot",
|
||||
)
|
||||
&& test_exp(
|
||||
*block.header.parent_hash() == header.parent_hash.0,
|
||||
"ParentHash",
|
||||
)
|
||||
&& test_exp(
|
||||
block.header.number() == header.number.0.as_u64(),
|
||||
"Blocn Number",
|
||||
)
|
||||
&& test_exp(block.header.hash() == header.hash.0, "Header hash")
|
||||
&& test_exp(*block.header.gas_limit() == header.gas_limit.0, "GasLimit")
|
||||
&& test_exp(*block.header.gas_used() == header.gas_used.0, "GasUsed")
|
||||
&& test_exp(
|
||||
*block.header.extra_data() == header.extra_data.0,
|
||||
"ExtraData",
|
||||
)
|
||||
&& test_exp(
|
||||
*block.header.difficulty() == header.difficulty.0,
|
||||
"Difficulty",
|
||||
)
|
||||
&& test_exp(*block.header.author() == header.author.0, "Author")
|
||||
&& test_exp(*block.header.log_bloom() == header.bloom.0, "Bloom")
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
// check transactions
|
||||
let transaction_ok = if let Some(ref txs) = ref_block.transactions {
|
||||
let mut is_all_ok = true;
|
||||
for (ref_tx, tx) in txs.iter().zip(block.transactions.iter()) {
|
||||
// check signatures
|
||||
let mut is_ok = test_exp(U256::from(tx.signature().r()) == ref_tx.r.0, "Sig R")
|
||||
&& test_exp(U256::from(tx.signature().s()) == ref_tx.s.0, "Sig S");
|
||||
is_ok = is_ok
|
||||
&& if let Some(chain_id) = ref_tx.chain_id {
|
||||
test_exp(tx.chain_id() == Some(chain_id.0.as_u64()), "Chain Id")
|
||||
} else {
|
||||
true
|
||||
};
|
||||
// check type
|
||||
let ttype = if let Some(ttype) = ref_tx.transaction_type {
|
||||
let ttype = ttype.0.byte(0);
|
||||
if let Some(id) = TypedTxId::from_u8_id(ttype) {
|
||||
id
|
||||
} else {
|
||||
println!("Unknown transaction {}", ttype);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
TypedTxId::Legacy
|
||||
};
|
||||
is_ok = is_ok
|
||||
&& test_exp(tx.tx().nonce == ref_tx.nonce.0, "Tx nonce")
|
||||
&& test_exp(tx.tx().gas_price == ref_tx.gas_price.0, "Tx gas price")
|
||||
&& test_exp(tx.tx().gas == ref_tx.gas_limit.0, "Tx gas")
|
||||
&& test_exp(tx.tx().value == ref_tx.value.0, "Tx value")
|
||||
&& test_exp(tx.tx().data == ref_tx.data.0, "Tx data")
|
||||
&& test_exp(ref_tx.hash.is_some(), "tx hash is none");
|
||||
|
||||
if let Some(hash) = ref_tx.hash {
|
||||
is_ok = is_ok && test_exp(tx.hash() == hash, "Hash mismatch");
|
||||
}
|
||||
|
||||
// check specific tx data
|
||||
is_ok = is_ok
|
||||
&& match ttype {
|
||||
TypedTxId::Legacy => {
|
||||
test_exp(tx.original_v() == ref_tx.v.0.as_u64(), "Original Sig V")
|
||||
}
|
||||
TypedTxId::AccessList => {
|
||||
test_exp(tx.standard_v() as u64 == ref_tx.v.0.as_u64(), "Sig V");
|
||||
let al = match tx.as_unsigned() {
|
||||
TypedTransaction::AccessList(tx) => &tx.access_list,
|
||||
_ => {
|
||||
println!("Wrong data in tx type");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Some(ref ref_al) = ref_tx.access_list {
|
||||
if ref_al.len() != al.len() {
|
||||
println!("Access list mismatch");
|
||||
continue;
|
||||
}
|
||||
let mut is_ok = true;
|
||||
for (al, ref_al) in al.iter().zip(ref_al.iter()) {
|
||||
is_ok = is_ok && test_exp(al.0 == ref_al.address, "AL address");
|
||||
if al.1.len() != ref_al.storage_keys.len() {
|
||||
println!("Access list mismatch");
|
||||
continue;
|
||||
}
|
||||
for (key, ref_key) in al.1.iter().zip(ref_al.storage_keys.iter()) {
|
||||
is_ok = is_ok && test_exp(key == ref_key, "Key mismatch");
|
||||
}
|
||||
}
|
||||
is_ok
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if !is_ok {
|
||||
println!(
|
||||
"Transaction not valid got: {:?} \n expected:{:?}\n",
|
||||
tx, ref_tx
|
||||
);
|
||||
}
|
||||
is_all_ok = is_ok && is_all_ok;
|
||||
}
|
||||
is_all_ok
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
let encript_ok = {
|
||||
let rlp = rlp_append_block(&block);
|
||||
rlp == ref_block.rlp()
|
||||
};
|
||||
|
||||
header_ok && transaction_ok && encript_ok
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
mod chain;
|
||||
mod difficulty;
|
||||
mod executive;
|
||||
mod local;
|
||||
mod state;
|
||||
mod test_common;
|
||||
mod transaction;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use ethjson::test::{
|
||||
ChainTests, DifficultyTests, EthereumTestSuite, ExecutiveTests, StateTests, TestChainSpec,
|
||||
TestTrieSpec, TransactionTests, TrieTests,
|
||||
ChainTests, DifficultyTests, EthereumTestSuite, ExecutiveTests, LocalTests, StateTests,
|
||||
TestChainSpec, TestTrieSpec, TransactionTests, TrieTests,
|
||||
};
|
||||
use globset::Glob;
|
||||
use log::info;
|
||||
@@ -83,6 +83,9 @@ impl TestRunner {
|
||||
/// Run the tests
|
||||
pub fn run(&self) -> TestResult {
|
||||
let mut res = TestResult::zero();
|
||||
for t in &self.0.local {
|
||||
res += Self::run_local_tests(&t);
|
||||
}
|
||||
for t in &self.0.chain {
|
||||
res += Self::run_chain_tests(&t);
|
||||
}
|
||||
@@ -141,6 +144,19 @@ impl TestRunner {
|
||||
false
|
||||
}
|
||||
|
||||
fn run_local_tests(test: &LocalTests) -> TestResult {
|
||||
match test.test_type.as_str() {
|
||||
"block_en_de" => Self::run1(
|
||||
test,
|
||||
&test.path,
|
||||
|test: &LocalTests, path: &Path, json: &[u8]| {
|
||||
super::local::json_local_block_en_de_test(test, &path, &json, &mut |_, _| {})
|
||||
},
|
||||
),
|
||||
_ => TestResult::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
fn run_chain_tests(test: &ChainTests) -> TestResult {
|
||||
Self::run1(
|
||||
test,
|
||||
|
||||
Reference in New Issue
Block a user