Update state tests execution model (#9440)

* Update & fix JSON state tests.

* Update tests to be able to run ethtest at
021fe3d410773024cd5f0387e62db6e6ec800f32.

- Touch user in state
- Adjust transaction tests to new json format

* Switch to same commit for submodule ethereum/test as geth (next includes constantinople changes).
Added test `json_tests::trie::generic::TrieTests_trieanyorder` and a few
difficulty tests.

* Remove trietestnextprev as it would require to parse differently and
implement it.

* Support new (shitty) format of transaction tests.

* Ignore junk in ethereum/tests repo.

* Ignore incorrect test.

* Update to a later commit

* Move block number to a constant.

* Fix ZK2 test - touched account should also be cleared.

* Fix conflict resolution
This commit is contained in:
Tomasz Drwięga 2018-09-10 22:38:30 +02:00 committed by Afri Schoedon
parent ba487eaaca
commit 6e5a1c00dc
16 changed files with 221 additions and 138 deletions

View File

@ -23,7 +23,7 @@
"eip161abcTransition": "0x0", "eip161abcTransition": "0x0",
"eip161dTransition": "0x0", "eip161dTransition": "0x0",
"eip98Transition": "0x7fffffffffffffff", "eip98Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff", "eip155Transition": "0x0",
"maxCodeSize": 24576, "maxCodeSize": 24576,
"maxCodeSizeTransition": "0x0" "maxCodeSizeTransition": "0x0"
}, },

@ -1 +1 @@
Subproject commit b6011c3fb567d7178915574de0a8d4b5331fe725 Subproject commit b8a21c193696976ca3b33b6d82107601063a5d26

View File

@ -60,7 +60,7 @@ impl fmt::Display for EvmTestError {
} }
use ethereum; use ethereum;
use ethjson::state::test::ForkSpec; use ethjson::spec::ForkSpec;
/// Simplified, single-block EVM test client. /// Simplified, single-block EVM test client.
pub struct EvmTestClient<'a> { pub struct EvmTestClient<'a> {
@ -217,9 +217,27 @@ impl<'a> EvmTestClient<'a> {
let result = self.state.apply_with_tracing(&env_info, self.spec.engine.machine(), &transaction, tracer, vm_tracer); let result = self.state.apply_with_tracing(&env_info, self.spec.engine.machine(), &transaction, tracer, vm_tracer);
let scheme = self.spec.engine.machine().create_address_scheme(env_info.number); let scheme = self.spec.engine.machine().create_address_scheme(env_info.number);
// Touch the coinbase at the end of the test to simulate
// miner reward.
// Details: https://github.com/paritytech/parity-ethereum/issues/9431
let schedule = self.spec.engine.machine().schedule(env_info.number);
self.state.add_balance(&env_info.author, &0.into(), if schedule.no_empty {
state::CleanupMode::NoEmpty
} else {
state::CleanupMode::ForceCreate
}).ok();
// Touching also means that we should remove the account if it's within eip161
// conditions.
self.state.kill_garbage(
&vec![env_info.author].into_iter().collect(),
schedule.kill_empty,
&None,
false
).ok();
self.state.commit().ok();
match result { match result {
Ok(result) => { Ok(result) => {
self.state.commit().ok();
TransactResult::Ok { TransactResult::Ok {
state_root: *self.state.root(), state_root: *self.state.root(),
gas_left: initial_gas - result.receipt.gas_used, gas_left: initial_gas - result.receipt.gas_used,

View File

@ -52,26 +52,61 @@ pub fn json_difficulty_test<H: FnMut(&str, HookType)>(json_data: &[u8], spec: Sp
vec![] vec![]
} }
mod difficulty_test_byzantium { macro_rules! difficulty_json_test {
use super::json_difficulty_test; ( $spec:ident ) => {
use json_tests::HookType;
fn do_json_test<H: FnMut(&str, HookType)>(json_data: &[u8], h: &mut H) -> Vec<String> {
json_difficulty_test(json_data, ::ethereum::new_byzantium_test(), h)
}
declare_test!{DifficultyTests_difficultyByzantium, "BasicTests/difficultyByzantium.json"}
}
mod difficulty_test_foundation {
use super::json_difficulty_test; use super::json_difficulty_test;
use tempdir::TempDir; use tempdir::TempDir;
use json_tests::HookType; use json_tests::HookType;
fn do_json_test<H: FnMut(&str, HookType)>(json_data: &[u8], h: &mut H) -> Vec<String> { fn do_json_test<H: FnMut(&str, HookType)>(json_data: &[u8], h: &mut H) -> Vec<String> {
let tempdir = TempDir::new("").unwrap(); let tempdir = TempDir::new("").unwrap();
json_difficulty_test(json_data, ::ethereum::new_foundation(&tempdir.path()), h) json_difficulty_test(json_data, ::ethereum::$spec(&tempdir.path()), h)
} }
}
}
macro_rules! difficulty_json_test_nopath {
( $spec:ident ) => {
use super::json_difficulty_test;
use json_tests::HookType;
fn do_json_test<H: FnMut(&str, HookType)>(json_data: &[u8], h: &mut H) -> Vec<String> {
json_difficulty_test(json_data, ::ethereum::$spec(), h)
}
}
}
mod difficulty_test {
difficulty_json_test!(new_foundation);
declare_test!{DifficultyTests_difficulty, "BasicTests/difficulty.json"}
}
mod difficulty_test_byzantium {
difficulty_json_test_nopath!(new_byzantium_test);
declare_test!{DifficultyTests_difficultyByzantium, "BasicTests/difficultyByzantium.json"}
}
mod difficulty_test_foundation {
difficulty_json_test!(new_foundation);
declare_test!{DifficultyTests_difficultyMainNetwork, "BasicTests/difficultyMainNetwork.json"} declare_test!{DifficultyTests_difficultyMainNetwork, "BasicTests/difficultyMainNetwork.json"}
} }
mod difficulty_test_ropsten {
difficulty_json_test_nopath!(new_ropsten_test);
declare_test!{DifficultyTests_difficultyRopsten, "BasicTests/difficultyRopsten.json"}
}
mod difficulty_test_frontier {
difficulty_json_test_nopath!(new_frontier_test);
declare_test!{DifficultyTests_difficultyFrontier, "BasicTests/difficultyFrontier.json"}
}
mod difficulty_test_homestead {
difficulty_json_test_nopath!(new_homestead_test);
declare_test!{DifficultyTests_difficultyHomestead, "BasicTests/difficultyHomestead.json"}
}

View File

@ -114,12 +114,16 @@ mod state_tests {
json_chain_test(json_data, h) json_chain_test(json_data, h)
} }
declare_test!{GeneralStateTest_stArgsZeroOneBalance, "GeneralStateTests/stArgsZeroOneBalance/"}
declare_test!{GeneralStateTest_stAttackTest, "GeneralStateTests/stAttackTest/"} declare_test!{GeneralStateTest_stAttackTest, "GeneralStateTests/stAttackTest/"}
declare_test!{GeneralStateTest_stBadOpcodeTest, "GeneralStateTests/stBadOpcode/"} declare_test!{GeneralStateTest_stBadOpcodeTest, "GeneralStateTests/stBadOpcode/"}
declare_test!{GeneralStateTest_stBugs, "GeneralStateTests/stBugs/"}
declare_test!{GeneralStateTest_stCallCodes, "GeneralStateTests/stCallCodes/"} declare_test!{GeneralStateTest_stCallCodes, "GeneralStateTests/stCallCodes/"}
declare_test!{GeneralStateTest_stCallCreateCallCodeTest, "GeneralStateTests/stCallCreateCallCodeTest/"}
declare_test!{GeneralStateTest_stCallDelegateCodesCallCodeHomestead, "GeneralStateTests/stCallDelegateCodesCallCodeHomestead/"} declare_test!{GeneralStateTest_stCallDelegateCodesCallCodeHomestead, "GeneralStateTests/stCallDelegateCodesCallCodeHomestead/"}
declare_test!{GeneralStateTest_stCallDelegateCodesHomestead, "GeneralStateTests/stCallDelegateCodesHomestead/"} declare_test!{GeneralStateTest_stCallDelegateCodesHomestead, "GeneralStateTests/stCallDelegateCodesHomestead/"}
declare_test!{GeneralStateTest_stChangedEIP150, "GeneralStateTests/stChangedEIP150/"} declare_test!{GeneralStateTest_stChangedEIP150, "GeneralStateTests/stChangedEIP150/"}
declare_test!{GeneralStateTest_stCodeCopyTest, "GeneralStateTests/stCodeCopyTest/"}
declare_test!{GeneralStateTest_stCodeSizeLimit, "GeneralStateTests/stCodeSizeLimit/"} declare_test!{GeneralStateTest_stCodeSizeLimit, "GeneralStateTests/stCodeSizeLimit/"}
declare_test!{GeneralStateTest_stCreateTest, "GeneralStateTests/stCreateTest/"} declare_test!{GeneralStateTest_stCreateTest, "GeneralStateTests/stCreateTest/"}
declare_test!{GeneralStateTest_stDelegatecallTestHomestead, "GeneralStateTests/stDelegatecallTestHomestead/"} declare_test!{GeneralStateTest_stDelegatecallTestHomestead, "GeneralStateTests/stDelegatecallTestHomestead/"}
@ -135,12 +139,15 @@ mod state_tests {
declare_test!{GeneralStateTest_stMemoryTest, "GeneralStateTests/stMemoryTest/"} declare_test!{GeneralStateTest_stMemoryTest, "GeneralStateTests/stMemoryTest/"}
declare_test!{GeneralStateTest_stNonZeroCallsTest, "GeneralStateTests/stNonZeroCallsTest/"} declare_test!{GeneralStateTest_stNonZeroCallsTest, "GeneralStateTests/stNonZeroCallsTest/"}
declare_test!{GeneralStateTest_stPreCompiledContracts, "GeneralStateTests/stPreCompiledContracts/"} declare_test!{GeneralStateTest_stPreCompiledContracts, "GeneralStateTests/stPreCompiledContracts/"}
declare_test!{GeneralStateTest_stPreCompiledContracts2, "GeneralStateTests/stPreCompiledContracts2/"}
declare_test!{heavy => GeneralStateTest_stQuadraticComplexityTest, "GeneralStateTests/stQuadraticComplexityTest/"} declare_test!{heavy => GeneralStateTest_stQuadraticComplexityTest, "GeneralStateTests/stQuadraticComplexityTest/"}
declare_test!{GeneralStateTest_stRandom, "GeneralStateTests/stRandom/"} declare_test!{GeneralStateTest_stRandom, "GeneralStateTests/stRandom/"}
declare_test!{GeneralStateTest_stRandom2, "GeneralStateTests/stRandom2/"}
declare_test!{GeneralStateTest_stRecursiveCreate, "GeneralStateTests/stRecursiveCreate/"} declare_test!{GeneralStateTest_stRecursiveCreate, "GeneralStateTests/stRecursiveCreate/"}
declare_test!{GeneralStateTest_stRefundTest, "GeneralStateTests/stRefundTest/"} declare_test!{GeneralStateTest_stRefundTest, "GeneralStateTests/stRefundTest/"}
declare_test!{GeneralStateTest_stReturnDataTest, "GeneralStateTests/stReturnDataTest/"} declare_test!{GeneralStateTest_stReturnDataTest, "GeneralStateTests/stReturnDataTest/"}
declare_test!{GeneralStateTest_stRevertTest, "GeneralStateTests/stRevertTest/"} declare_test!{GeneralStateTest_stRevertTest, "GeneralStateTests/stRevertTest/"}
declare_test!{GeneralStateTest_stShift, "GeneralStateTests/stShift/"}
declare_test!{GeneralStateTest_stSolidityTest, "GeneralStateTests/stSolidityTest/"} declare_test!{GeneralStateTest_stSolidityTest, "GeneralStateTests/stSolidityTest/"}
declare_test!{GeneralStateTest_stSpecialTest, "GeneralStateTests/stSpecialTest/"} declare_test!{GeneralStateTest_stSpecialTest, "GeneralStateTests/stSpecialTest/"}
declare_test!{GeneralStateTest_stStackTests, "GeneralStateTests/stStackTests/"} declare_test!{GeneralStateTest_stStackTests, "GeneralStateTests/stStackTests/"}
@ -152,4 +159,11 @@ mod state_tests {
declare_test!{GeneralStateTest_stZeroCallsRevert, "GeneralStateTests/stZeroCallsRevert/"} declare_test!{GeneralStateTest_stZeroCallsRevert, "GeneralStateTests/stZeroCallsRevert/"}
declare_test!{GeneralStateTest_stZeroCallsTest, "GeneralStateTests/stZeroCallsTest/"} declare_test!{GeneralStateTest_stZeroCallsTest, "GeneralStateTests/stZeroCallsTest/"}
declare_test!{GeneralStateTest_stZeroKnowledge, "GeneralStateTests/stZeroKnowledge/"} declare_test!{GeneralStateTest_stZeroKnowledge, "GeneralStateTests/stZeroKnowledge/"}
// Attempts to send a transaction that requires more than current balance:
// Tx:
// https://github.com/ethereum/tests/blob/726b161ba8a739691006cc1ba080672bb50a9d49/GeneralStateTests/stZeroKnowledge2/ecmul_0-3_5616_28000_96.json#L170
// Balance:
// https://github.com/ethereum/tests/blob/726b161ba8a739691006cc1ba080672bb50a9d49/GeneralStateTests/stZeroKnowledge2/ecmul_0-3_5616_28000_96.json#L126
declare_test!{GeneralStateTest_stZeroKnowledge2, "GeneralStateTests/stZeroKnowledge2/"}
} }

View File

@ -41,6 +41,7 @@ pub fn run_test_path<H: FnMut(&str, HookType)>(
os.push(".json"); os.push(".json");
os os
}).collect(); }).collect();
let extension = path.extension().and_then(|s| s.to_str());
if path.is_dir() { if path.is_dir() {
for p in read_dir(path).unwrap().filter_map(|e| { for p in read_dir(path).unwrap().filter_map(|e| {
let e = e.unwrap(); let e = e.unwrap();
@ -51,6 +52,8 @@ pub fn run_test_path<H: FnMut(&str, HookType)>(
}}) { }}) {
run_test_path(&p, skip, runner, start_stop_hook) run_test_path(&p, skip, runner, start_stop_hook)
} }
} else if extension == Some("swp") || extension == None {
// Ignore junk
} else { } else {
let mut path = p.to_path_buf(); let mut path = p.to_path_buf();
path.set_extension("json"); path.set_extension("json");
@ -64,7 +67,10 @@ pub fn run_test_file<H: FnMut(&str, HookType)>(
start_stop_hook: &mut H start_stop_hook: &mut H
) { ) {
let mut data = Vec::new(); let mut data = Vec::new();
let mut file = File::open(&path).expect("Error opening test file"); let mut file = match File::open(&path) {
Ok(file) => file,
Err(_) => panic!("Error opening test file at: {:?}", path),
};
file.read_to_end(&mut data).expect("Error reading test file"); file.read_to_end(&mut data).expect("Error reading test file");
let results = runner(&data, start_stop_hook); let results = runner(&data, start_stop_hook);
let empty: [String; 0] = []; let empty: [String; 0] = [];

View File

@ -16,10 +16,11 @@
use std::path::Path; use std::path::Path;
use super::test_common::*; use super::test_common::*;
use evm; use client::EvmTestClient;
use header::Header;
use ethjson; use ethjson;
use rlp::Rlp; use rlp::Rlp;
use transaction::{Action, UnverifiedTransaction, SignedTransaction}; use transaction::UnverifiedTransaction;
/// Run transaction jsontests on a given folder. /// Run transaction jsontests on a given folder.
pub fn run_test_path<H: FnMut(&str, HookType)>(p: &Path, skip: &[&'static str], h: &mut H) { pub fn run_test_path<H: FnMut(&str, HookType)>(p: &Path, skip: &[&'static str], h: &mut H) {
@ -31,55 +32,61 @@ 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) ::json_tests::test_common::run_test_file(p, do_json_test, h)
} }
// Block number used to run the tests.
// Make sure that all the specified features are activated.
const BLOCK_NUMBER: u64 = 0x6ffffffffffffe;
fn do_json_test<H: FnMut(&str, HookType)>(json_data: &[u8], start_stop_hook: &mut H) -> Vec<String> { fn do_json_test<H: FnMut(&str, HookType)>(json_data: &[u8], start_stop_hook: &mut H) -> Vec<String> {
let tests = ethjson::transaction::Test::load(json_data).unwrap(); let tests = ethjson::transaction::Test::load(json_data).unwrap();
let mut failed = Vec::new(); let mut failed = Vec::new();
let frontier_schedule = evm::Schedule::new_frontier();
let homestead_schedule = evm::Schedule::new_homestead();
let byzantium_schedule = evm::Schedule::new_byzantium();
for (name, test) in tests.into_iter() { for (name, test) in tests.into_iter() {
start_stop_hook(&name, HookType::OnStart); start_stop_hook(&name, HookType::OnStart);
let mut fail_unless = |cond: bool, title: &str| if !cond { failed.push(name.clone()); println!("Transaction failed: {:?}: {:?}", name, title); }; for (spec_name, result) in test.post_state {
let spec = match EvmTestClient::spec_from_json(&spec_name) {
let number: Option<u64> = test.block_number.map(Into::into); Some(spec) => spec,
let schedule = match number { None => {
None => &frontier_schedule, println!(" - {} | {:?} Ignoring tests because of missing spec", name, spec_name);
Some(x) if x < 1_150_000 => &frontier_schedule, continue;
Some(x) if x < 3_000_000 => &homestead_schedule, }
Some(_) => &byzantium_schedule
}; };
let allow_chain_id_of_one = number.map_or(false, |n| n >= 2_675_000);
let allow_unsigned = number.map_or(false, |n| n >= 3_000_000);
let rlp: Vec<u8> = test.rlp.into(); let mut fail_unless = |cond: bool, title: &str| if !cond {
failed.push(format!("{}-{:?}", name, spec_name));
println!("Transaction failed: {:?}-{:?}: {:?}", name, spec_name, title);
};
let rlp: Vec<u8> = test.rlp.clone().into();
let res = Rlp::new(&rlp) let res = Rlp::new(&rlp)
.as_val() .as_val()
.map_err(::error::Error::from) .map_err(::error::Error::from)
.and_then(|t: UnverifiedTransaction| { .and_then(|t: UnverifiedTransaction| {
t.validate(schedule, schedule.have_delegate_call, allow_chain_id_of_one, allow_unsigned).map_err(Into::into) let mut header: Header = Default::default();
// Use high enough number to activate all required features.
header.set_number(BLOCK_NUMBER);
let minimal = t.gas_required(&spec.engine.schedule(header.number())).into();
if t.gas < minimal {
return Err(::transaction::Error::InsufficientGas {
minimal, got: t.gas,
}.into());
}
spec.engine.verify_transaction_basic(&t, &header)?;
Ok(spec.engine.verify_transaction_unordered(t, &header)?)
}); });
fail_unless(test.transaction.is_none() == res.is_err(), "Validity different"); match (res, result.hash, result.sender) {
if let (Some(tx), Some(sender)) = (test.transaction, test.sender) { (Ok(t), Some(hash), Some(sender)) => {
let t = res.unwrap(); fail_unless(t.sender() == sender.into(), "sender mismatch");
fail_unless(SignedTransaction::new(t.clone()).unwrap().sender() == sender.into(), "sender mismatch"); fail_unless(t.hash() == hash.into(), "hash mismatch");
let is_acceptable_chain_id = match t.chain_id() { },
None => true, (Err(_), None, None) => {},
Some(1) if allow_chain_id_of_one => true, data => {
_ => false, fail_unless(
}; false,
fail_unless(is_acceptable_chain_id, "Network ID unacceptable"); &format!("Validity different: {:?}", data)
let data: Vec<u8> = tx.data.into(); );
fail_unless(t.data == data, "data mismatch"); }
fail_unless(t.gas_price == tx.gas_price.into(), "gas_price mismatch");
fail_unless(t.nonce == tx.nonce.into(), "nonce mismatch");
fail_unless(t.value == tx.value.into(), "value mismatch");
let to: Option<ethjson::hash::Address> = tx.to.into();
let to: Option<Address> = to.map(Into::into);
match t.action {
Action::Call(dest) => fail_unless(Some(dest) == to, "call/destination mismatch"),
Action::Create => fail_unless(None == to, "create mismatch"),
} }
} }
@ -92,13 +99,14 @@ fn do_json_test<H: FnMut(&str, HookType)>(json_data: &[u8], start_stop_hook: &mu
failed failed
} }
declare_test!{TransactionTests_ttEip155VitaliksHomesead, "TransactionTests/ttEip155VitaliksHomesead"} declare_test!{TransactionTests_ttAddress, "TransactionTests/ttAddress"}
declare_test!{TransactionTests_ttEip155VitaliksEip158, "TransactionTests/ttEip155VitaliksEip158"} declare_test!{TransactionTests_ttData, "TransactionTests/ttData"}
declare_test!{TransactionTests_ttEip158, "TransactionTests/ttEip158"} declare_test!{TransactionTests_ttGasLimit, "TransactionTests/ttGasLimit"}
declare_test!{TransactionTests_ttFrontier, "TransactionTests/ttFrontier"} declare_test!{TransactionTests_ttGasPrice, "TransactionTests/ttGasPrice"}
declare_test!{TransactionTests_ttHomestead, "TransactionTests/ttHomestead"} declare_test!{TransactionTests_ttNonce, "TransactionTests/ttNonce"}
declare_test!{TransactionTests_ttVRuleEip158, "TransactionTests/ttVRuleEip158"} declare_test!{TransactionTests_ttRSValue, "TransactionTests/ttRSValue"}
declare_test!{TransactionTests_ttWrongRLPFrontier, "TransactionTests/ttWrongRLPFrontier"} declare_test!{TransactionTests_ttSignature, "TransactionTests/ttSignature"}
declare_test!{TransactionTests_ttWrongRLPHomestead, "TransactionTests/ttWrongRLPHomestead"} declare_test!{TransactionTests_ttValue, "TransactionTests/ttValue"}
declare_test!{TransactionTests_ttConstantinople, "TransactionTests/ttConstantinople"} declare_test!{TransactionTests_ttVValue, "TransactionTests/ttVValue"}
declare_test!{TransactionTests_ttSpecConstantinople, "TransactionTests/ttSpecConstantinople"} declare_test!{TransactionTests_ttWrongRLP, "TransactionTests/ttWrongRLP"}

View File

@ -393,23 +393,6 @@ impl UnverifiedTransaction {
Ok(recover(&self.signature(), &self.unsigned.hash(self.chain_id()))?) Ok(recover(&self.signature(), &self.unsigned.hash(self.chain_id()))?)
} }
/// Do basic validation, checking for valid signature and minimum gas,
// TODO: consider use in block validation.
#[cfg(feature = "json-tests")]
pub fn validate(self, schedule: &Schedule, require_low: bool, allow_chain_id_of_one: bool, allow_empty_signature: bool)
-> Result<UnverifiedTransaction, error::Error>
{
let chain_id = if allow_chain_id_of_one { Some(1) } else { None };
self.verify_basic(require_low, chain_id, allow_empty_signature)?;
if !allow_empty_signature || !self.is_unsigned() {
self.recover_public()?;
}
if self.gas < U256::from(self.gas_required(&schedule)) {
return Err(error::Error::InvalidGasLimit(::unexpected::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}).into())
}
Ok(self)
}
/// Verify basic signature params. Does not attempt sender recovery. /// Verify basic signature params. Does not attempt sender recovery.
pub fn verify_basic(&self, check_low_s: bool, chain_id: Option<u64>, allow_empty_signature: bool) -> Result<(), error::Error> { pub fn verify_basic(&self, check_low_s: bool, chain_id: Option<u64>, allow_empty_signature: bool) -> Result<(), error::Error> {
if check_low_s && !(allow_empty_signature && self.is_unsigned()) { if check_low_s && !(allow_empty_signature && self.is_unsigned()) {

View File

@ -93,7 +93,7 @@ pub fn run_action<T: Informant>(
pub fn run_transaction<T: Informant>( pub fn run_transaction<T: Informant>(
name: &str, name: &str,
idx: usize, idx: usize,
spec: &ethjson::state::test::ForkSpec, spec: &ethjson::spec::ForkSpec,
pre_state: &pod_state::PodState, pre_state: &pod_state::PodState,
post_root: H256, post_root: H256,
env_info: &client::EnvInfo, env_info: &client::EnvInfo,

View File

@ -21,8 +21,7 @@ use hash::H256;
use blockchain::state::State; use blockchain::state::State;
use blockchain::header::Header; use blockchain::header::Header;
use blockchain::block::Block; use blockchain::block::Block;
use state::test::ForkSpec; use spec::{ForkSpec, Genesis, Seal, Ethereum};
use spec::{Genesis, Seal, Ethereum};
/// Blockchain deserialization. /// Blockchain deserialization.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]

View File

@ -37,7 +37,7 @@ pub use self::account::Account;
pub use self::builtin::{Builtin, Pricing, Linear}; pub use self::builtin::{Builtin, Pricing, Linear};
pub use self::genesis::Genesis; pub use self::genesis::Genesis;
pub use self::params::Params; pub use self::params::Params;
pub use self::spec::Spec; pub use self::spec::{Spec, ForkSpec};
pub use self::seal::{Seal, Ethereum, AuthorityRoundSeal, TendermintSeal}; pub use self::seal::{Seal, Ethereum, AuthorityRoundSeal, TendermintSeal};
pub use self::engine::Engine; pub use self::engine::Engine;
pub use self::state::State; pub use self::state::State;

View File

@ -21,6 +21,21 @@ use serde_json;
use serde_json::Error; use serde_json::Error;
use spec::{Params, Genesis, Engine, State, HardcodedSync}; use spec::{Params, Genesis, Engine, State, HardcodedSync};
/// Fork spec definition
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize)]
pub enum ForkSpec {
EIP150,
EIP158,
Frontier,
Homestead,
Byzantium,
Constantinople,
EIP158ToByzantiumAt5,
FrontierToHomesteadAt5,
HomesteadToDaoAt5,
HomesteadToEIP150At5,
}
/// Spec deserialization. /// Spec deserialization.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
pub struct Spec { pub struct Spec {

View File

@ -21,6 +21,7 @@ use std::collections::BTreeMap;
use uint::Uint; use uint::Uint;
use bytes::Bytes; use bytes::Bytes;
use hash::{Address, H256}; use hash::{Address, H256};
use spec::ForkSpec;
use state::{Env, AccountState, Transaction}; use state::{Env, AccountState, Transaction};
use maybe::MaybeEmpty; use maybe::MaybeEmpty;
use serde_json::{self, Error}; use serde_json::{self, Error};
@ -97,21 +98,6 @@ impl MultiTransaction {
} }
} }
/// State test transaction deserialization.
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize)]
pub enum ForkSpec {
EIP150,
EIP158,
Frontier,
Homestead,
Byzantium,
Constantinople,
EIP158ToByzantiumAt5,
FrontierToHomesteadAt5,
HomesteadToDaoAt5,
HomesteadToEIP150At5,
}
/// State test indexes deserialization. /// State test indexes deserialization.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
pub struct PostStateIndexes { pub struct PostStateIndexes {

View File

@ -23,7 +23,7 @@ use serde_json::Error;
use transaction::TransactionTest; use transaction::TransactionTest;
/// TransactionTest test deserializer. /// TransactionTest test deserializer.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, Deserialize)]
pub struct Test(BTreeMap<String, TransactionTest>); pub struct Test(BTreeMap<String, TransactionTest>);
impl IntoIterator for Test { impl IntoIterator for Test {

View File

@ -16,23 +16,29 @@
//! Transaction test deserialization. //! Transaction test deserialization.
use uint::Uint; use std::collections::BTreeMap;
use bytes::Bytes; use bytes::Bytes;
use hash::Address; use hash::Address;
use transaction::Transaction; use hash::H256;
use spec::ForkSpec;
/// Transaction test deserialization. /// Transaction test deserialization.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, Deserialize)]
pub struct TransactionTest { pub struct TransactionTest {
/// Block number.
#[serde(rename="blocknumber")]
pub block_number: Option<Uint>,
/// Transaction rlp.
pub rlp: Bytes, pub rlp: Bytes,
pub _info: ::serde::de::IgnoredAny,
#[serde(flatten)]
pub post_state: BTreeMap<ForkSpec, PostState>,
}
/// TransactionTest post state.
#[derive(Debug, PartialEq, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct PostState {
/// Transaction sender. /// Transaction sender.
pub sender: Option<Address>, pub sender: Option<Address>,
/// Transaction /// Transaction hash.
pub transaction: Option<Transaction>, pub hash: Option<H256>,
} }
#[cfg(test)] #[cfg(test)]
@ -43,21 +49,34 @@ mod tests {
#[test] #[test]
fn transaction_deserialization() { fn transaction_deserialization() {
let s = r#"{ let s = r#"{
"blocknumber" : "0", "Byzantium" : {
"rlp" : "0xf83f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870b801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a3664935301", "hash" : "4782cb5edcaeda1f0aef204b161214f124cefade9e146245183abbb9ca01bca5",
"sender" : "e115cf6bb5656786569dd273705242ca72d84bc0", "sender" : "2ea991808ba979ba103147edfd72304ebd95c028"
"transaction" : { },
"data" : "", "Constantinople" : {
"gasLimit" : "0x5208", "hash" : "4782cb5edcaeda1f0aef204b161214f124cefade9e146245183abbb9ca01bca5",
"gasPrice" : "0x01", "sender" : "2ea991808ba979ba103147edfd72304ebd95c028"
"nonce" : "0x00", },
"r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", "EIP150" : {
"s" : "0x01", },
"to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "EIP158" : {
"v" : "0x1b", "hash" : "4782cb5edcaeda1f0aef204b161214f124cefade9e146245183abbb9ca01bca5",
"value" : "0x0b" "sender" : "2ea991808ba979ba103147edfd72304ebd95c028"
} },
"Frontier" : {
},
"Homestead" : {
},
"_info" : {
"comment" : "",
"filledwith" : "cpp-1.3.0+commit.1829957d.Linux.g++",
"lllcversion" : "Version: 0.4.18-develop.2017.10.11+commit.81f9f86c.Linux.g++",
"source" : "src/TransactionTestsFiller/ttVValue/V_equals37Filler.json",
"sourceHash" : "89ef69312d4c0b4e3742da501263d23d2a64f180258ac93940997ac6a17b9b19"
},
"rlp" : "0xf865808698852840a46f82d6d894095e7baea6a6c7c4c2dfeb977efac326af552d87808025a098ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4aa01887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3"
}"#; }"#;
let _deserialized: TransactionTest = serde_json::from_str(s).unwrap(); let _deserialized: TransactionTest = serde_json::from_str(s).unwrap();
// TODO: validate all fields // TODO: validate all fields
} }

View File

@ -28,7 +28,7 @@ use ethcore::spec::{Genesis, Spec};
use ethcore::test_helpers; use ethcore::test_helpers;
use ethcore::verification::queue::kind::blocks::Unverified; use ethcore::verification::queue::kind::blocks::Unverified;
use ethjson::blockchain::BlockChain; use ethjson::blockchain::BlockChain;
use ethjson::state::test::ForkSpec; use ethjson::spec::ForkSpec;
use io::IoChannel; use io::IoChannel;
use miner::external::ExternalMiner; use miner::external::ExternalMiner;
use parking_lot::Mutex; use parking_lot::Mutex;