From 6e5a1c00dc5e5141f6438f68754788237f1df816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Mon, 10 Sep 2018 22:38:30 +0200 Subject: [PATCH] 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 --- ethcore/res/ethereum/eip161_test.json | 2 +- ethcore/res/ethereum/tests | 2 +- ethcore/src/client/evm_test_client.rs | 34 ++++++-- ethcore/src/json_tests/difficulty.rs | 59 ++++++++++--- ethcore/src/json_tests/state.rs | 14 +++ ethcore/src/json_tests/test_common.rs | 8 +- ethcore/src/json_tests/transaction.rs | 116 +++++++++++++------------ ethcore/transaction/src/transaction.rs | 17 ---- evmbin/src/info.rs | 2 +- json/src/blockchain/blockchain.rs | 3 +- json/src/spec/mod.rs | 2 +- json/src/spec/spec.rs | 15 ++++ json/src/state/test.rs | 16 +--- json/src/transaction/test.rs | 2 +- json/src/transaction/txtest.rs | 65 +++++++++----- rpc/src/v1/tests/eth.rs | 2 +- 16 files changed, 221 insertions(+), 138 deletions(-) diff --git a/ethcore/res/ethereum/eip161_test.json b/ethcore/res/ethereum/eip161_test.json index 722881158..b64b6b047 100644 --- a/ethcore/res/ethereum/eip161_test.json +++ b/ethcore/res/ethereum/eip161_test.json @@ -23,7 +23,7 @@ "eip161abcTransition": "0x0", "eip161dTransition": "0x0", "eip98Transition": "0x7fffffffffffffff", - "eip155Transition": "0x7fffffffffffffff", + "eip155Transition": "0x0", "maxCodeSize": 24576, "maxCodeSizeTransition": "0x0" }, diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index b6011c3fb..b8a21c193 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit b6011c3fb567d7178915574de0a8d4b5331fe725 +Subproject commit b8a21c193696976ca3b33b6d82107601063a5d26 diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs index 7767c9922..1d827dea6 100644 --- a/ethcore/src/client/evm_test_client.rs +++ b/ethcore/src/client/evm_test_client.rs @@ -60,7 +60,7 @@ impl fmt::Display for EvmTestError { } use ethereum; -use ethjson::state::test::ForkSpec; +use ethjson::spec::ForkSpec; /// Simplified, single-block EVM test client. pub struct EvmTestClient<'a> { @@ -69,12 +69,12 @@ pub struct EvmTestClient<'a> { } impl<'a> fmt::Debug for EvmTestClient<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("EvmTestClient") - .field("state", &self.state) - .field("spec", &self.spec.name) - .finish() - } + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("EvmTestClient") + .field("state", &self.state) + .field("spec", &self.spec.name) + .finish() + } } impl<'a> 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 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 { Ok(result) => { - self.state.commit().ok(); TransactResult::Ok { state_root: *self.state.root(), gas_left: initial_gas - result.receipt.gas_used, diff --git a/ethcore/src/json_tests/difficulty.rs b/ethcore/src/json_tests/difficulty.rs index 2647e1659..0de1f1777 100644 --- a/ethcore/src/json_tests/difficulty.rs +++ b/ethcore/src/json_tests/difficulty.rs @@ -52,26 +52,61 @@ pub fn json_difficulty_test(json_data: &[u8], spec: Sp vec![] } -mod difficulty_test_byzantium { - use super::json_difficulty_test; - use json_tests::HookType; +macro_rules! difficulty_json_test { + ( $spec:ident ) => { - fn do_json_test(json_data: &[u8], h: &mut H) -> Vec { - 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 tempdir::TempDir; use json_tests::HookType; fn do_json_test(json_data: &[u8], h: &mut H) -> Vec { 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(json_data: &[u8], h: &mut H) -> Vec { + 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"} } + +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"} +} + diff --git a/ethcore/src/json_tests/state.rs b/ethcore/src/json_tests/state.rs index da1716972..5837f191c 100644 --- a/ethcore/src/json_tests/state.rs +++ b/ethcore/src/json_tests/state.rs @@ -114,12 +114,16 @@ mod state_tests { json_chain_test(json_data, h) } + declare_test!{GeneralStateTest_stArgsZeroOneBalance, "GeneralStateTests/stArgsZeroOneBalance/"} declare_test!{GeneralStateTest_stAttackTest, "GeneralStateTests/stAttackTest/"} declare_test!{GeneralStateTest_stBadOpcodeTest, "GeneralStateTests/stBadOpcode/"} + declare_test!{GeneralStateTest_stBugs, "GeneralStateTests/stBugs/"} declare_test!{GeneralStateTest_stCallCodes, "GeneralStateTests/stCallCodes/"} + declare_test!{GeneralStateTest_stCallCreateCallCodeTest, "GeneralStateTests/stCallCreateCallCodeTest/"} declare_test!{GeneralStateTest_stCallDelegateCodesCallCodeHomestead, "GeneralStateTests/stCallDelegateCodesCallCodeHomestead/"} declare_test!{GeneralStateTest_stCallDelegateCodesHomestead, "GeneralStateTests/stCallDelegateCodesHomestead/"} declare_test!{GeneralStateTest_stChangedEIP150, "GeneralStateTests/stChangedEIP150/"} + declare_test!{GeneralStateTest_stCodeCopyTest, "GeneralStateTests/stCodeCopyTest/"} declare_test!{GeneralStateTest_stCodeSizeLimit, "GeneralStateTests/stCodeSizeLimit/"} declare_test!{GeneralStateTest_stCreateTest, "GeneralStateTests/stCreateTest/"} declare_test!{GeneralStateTest_stDelegatecallTestHomestead, "GeneralStateTests/stDelegatecallTestHomestead/"} @@ -135,12 +139,15 @@ mod state_tests { declare_test!{GeneralStateTest_stMemoryTest, "GeneralStateTests/stMemoryTest/"} declare_test!{GeneralStateTest_stNonZeroCallsTest, "GeneralStateTests/stNonZeroCallsTest/"} declare_test!{GeneralStateTest_stPreCompiledContracts, "GeneralStateTests/stPreCompiledContracts/"} + declare_test!{GeneralStateTest_stPreCompiledContracts2, "GeneralStateTests/stPreCompiledContracts2/"} declare_test!{heavy => GeneralStateTest_stQuadraticComplexityTest, "GeneralStateTests/stQuadraticComplexityTest/"} declare_test!{GeneralStateTest_stRandom, "GeneralStateTests/stRandom/"} + declare_test!{GeneralStateTest_stRandom2, "GeneralStateTests/stRandom2/"} declare_test!{GeneralStateTest_stRecursiveCreate, "GeneralStateTests/stRecursiveCreate/"} declare_test!{GeneralStateTest_stRefundTest, "GeneralStateTests/stRefundTest/"} declare_test!{GeneralStateTest_stReturnDataTest, "GeneralStateTests/stReturnDataTest/"} declare_test!{GeneralStateTest_stRevertTest, "GeneralStateTests/stRevertTest/"} + declare_test!{GeneralStateTest_stShift, "GeneralStateTests/stShift/"} declare_test!{GeneralStateTest_stSolidityTest, "GeneralStateTests/stSolidityTest/"} declare_test!{GeneralStateTest_stSpecialTest, "GeneralStateTests/stSpecialTest/"} declare_test!{GeneralStateTest_stStackTests, "GeneralStateTests/stStackTests/"} @@ -152,4 +159,11 @@ mod state_tests { declare_test!{GeneralStateTest_stZeroCallsRevert, "GeneralStateTests/stZeroCallsRevert/"} declare_test!{GeneralStateTest_stZeroCallsTest, "GeneralStateTests/stZeroCallsTest/"} 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/"} } diff --git a/ethcore/src/json_tests/test_common.rs b/ethcore/src/json_tests/test_common.rs index 39b7447c7..ce5c68a73 100644 --- a/ethcore/src/json_tests/test_common.rs +++ b/ethcore/src/json_tests/test_common.rs @@ -41,6 +41,7 @@ pub fn run_test_path( os.push(".json"); os }).collect(); + let extension = path.extension().and_then(|s| s.to_str()); if path.is_dir() { for p in read_dir(path).unwrap().filter_map(|e| { let e = e.unwrap(); @@ -51,6 +52,8 @@ pub fn run_test_path( }}) { run_test_path(&p, skip, runner, start_stop_hook) } + } else if extension == Some("swp") || extension == None { + // Ignore junk } else { let mut path = p.to_path_buf(); path.set_extension("json"); @@ -64,7 +67,10 @@ pub fn run_test_file( start_stop_hook: &mut H ) { 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"); let results = runner(&data, start_stop_hook); let empty: [String; 0] = []; diff --git a/ethcore/src/json_tests/transaction.rs b/ethcore/src/json_tests/transaction.rs index af16481f4..70021c9e9 100644 --- a/ethcore/src/json_tests/transaction.rs +++ b/ethcore/src/json_tests/transaction.rs @@ -16,10 +16,11 @@ use std::path::Path; use super::test_common::*; -use evm; +use client::EvmTestClient; +use header::Header; use ethjson; use rlp::Rlp; -use transaction::{Action, UnverifiedTransaction, SignedTransaction}; +use transaction::UnverifiedTransaction; /// Run transaction jsontests on a given folder. pub fn run_test_path(p: &Path, skip: &[&'static str], h: &mut H) { @@ -31,55 +32,61 @@ pub fn run_test_file(p: &Path, h: &mut 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(json_data: &[u8], start_stop_hook: &mut H) -> Vec { let tests = ethjson::transaction::Test::load(json_data).unwrap(); 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() { 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); }; - - let number: Option = test.block_number.map(Into::into); - let schedule = match number { - None => &frontier_schedule, - Some(x) if x < 1_150_000 => &frontier_schedule, - 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 = test.rlp.into(); - let res = Rlp::new(&rlp) - .as_val() - .map_err(::error::Error::from) - .and_then(|t: UnverifiedTransaction| { - t.validate(schedule, schedule.have_delegate_call, allow_chain_id_of_one, allow_unsigned).map_err(Into::into) - }); - - fail_unless(test.transaction.is_none() == res.is_err(), "Validity different"); - if let (Some(tx), Some(sender)) = (test.transaction, test.sender) { - let t = res.unwrap(); - fail_unless(SignedTransaction::new(t.clone()).unwrap().sender() == sender.into(), "sender mismatch"); - let is_acceptable_chain_id = match t.chain_id() { - None => true, - Some(1) if allow_chain_id_of_one => true, - _ => false, + for (spec_name, result) in test.post_state { + let spec = match EvmTestClient::spec_from_json(&spec_name) { + Some(spec) => spec, + None => { + println!(" - {} | {:?} Ignoring tests because of missing spec", name, spec_name); + continue; + } }; - fail_unless(is_acceptable_chain_id, "Network ID unacceptable"); - let data: Vec = 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 = tx.to.into(); - let to: Option
= 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"), + + 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 = test.rlp.clone().into(); + let res = Rlp::new(&rlp) + .as_val() + .map_err(::error::Error::from) + .and_then(|t: UnverifiedTransaction| { + 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)?) + }); + + match (res, result.hash, result.sender) { + (Ok(t), Some(hash), Some(sender)) => { + fail_unless(t.sender() == sender.into(), "sender mismatch"); + fail_unless(t.hash() == hash.into(), "hash mismatch"); + }, + (Err(_), None, None) => {}, + data => { + fail_unless( + false, + &format!("Validity different: {:?}", data) + ); + } } } @@ -92,13 +99,14 @@ fn do_json_test(json_data: &[u8], start_stop_hook: &mu failed } -declare_test!{TransactionTests_ttEip155VitaliksHomesead, "TransactionTests/ttEip155VitaliksHomesead"} -declare_test!{TransactionTests_ttEip155VitaliksEip158, "TransactionTests/ttEip155VitaliksEip158"} -declare_test!{TransactionTests_ttEip158, "TransactionTests/ttEip158"} -declare_test!{TransactionTests_ttFrontier, "TransactionTests/ttFrontier"} -declare_test!{TransactionTests_ttHomestead, "TransactionTests/ttHomestead"} -declare_test!{TransactionTests_ttVRuleEip158, "TransactionTests/ttVRuleEip158"} -declare_test!{TransactionTests_ttWrongRLPFrontier, "TransactionTests/ttWrongRLPFrontier"} -declare_test!{TransactionTests_ttWrongRLPHomestead, "TransactionTests/ttWrongRLPHomestead"} -declare_test!{TransactionTests_ttConstantinople, "TransactionTests/ttConstantinople"} -declare_test!{TransactionTests_ttSpecConstantinople, "TransactionTests/ttSpecConstantinople"} +declare_test!{TransactionTests_ttAddress, "TransactionTests/ttAddress"} +declare_test!{TransactionTests_ttData, "TransactionTests/ttData"} +declare_test!{TransactionTests_ttGasLimit, "TransactionTests/ttGasLimit"} +declare_test!{TransactionTests_ttGasPrice, "TransactionTests/ttGasPrice"} +declare_test!{TransactionTests_ttNonce, "TransactionTests/ttNonce"} +declare_test!{TransactionTests_ttRSValue, "TransactionTests/ttRSValue"} +declare_test!{TransactionTests_ttSignature, "TransactionTests/ttSignature"} +declare_test!{TransactionTests_ttValue, "TransactionTests/ttValue"} +declare_test!{TransactionTests_ttVValue, "TransactionTests/ttVValue"} +declare_test!{TransactionTests_ttWrongRLP, "TransactionTests/ttWrongRLP"} + diff --git a/ethcore/transaction/src/transaction.rs b/ethcore/transaction/src/transaction.rs index 49804f187..f5034c4b2 100644 --- a/ethcore/transaction/src/transaction.rs +++ b/ethcore/transaction/src/transaction.rs @@ -393,23 +393,6 @@ impl UnverifiedTransaction { 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 - { - 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. pub fn verify_basic(&self, check_low_s: bool, chain_id: Option, allow_empty_signature: bool) -> Result<(), error::Error> { if check_low_s && !(allow_empty_signature && self.is_unsigned()) { diff --git a/evmbin/src/info.rs b/evmbin/src/info.rs index f2102f017..6483bb1e0 100644 --- a/evmbin/src/info.rs +++ b/evmbin/src/info.rs @@ -93,7 +93,7 @@ pub fn run_action( pub fn run_transaction( name: &str, idx: usize, - spec: ðjson::state::test::ForkSpec, + spec: ðjson::spec::ForkSpec, pre_state: &pod_state::PodState, post_root: H256, env_info: &client::EnvInfo, diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index 9e4d650b8..ff0bc556f 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -21,8 +21,7 @@ use hash::H256; use blockchain::state::State; use blockchain::header::Header; use blockchain::block::Block; -use state::test::ForkSpec; -use spec::{Genesis, Seal, Ethereum}; +use spec::{ForkSpec, Genesis, Seal, Ethereum}; /// Blockchain deserialization. #[derive(Debug, PartialEq, Deserialize)] diff --git a/json/src/spec/mod.rs b/json/src/spec/mod.rs index 9adbc1fe1..9e4e67241 100644 --- a/json/src/spec/mod.rs +++ b/json/src/spec/mod.rs @@ -37,7 +37,7 @@ pub use self::account::Account; pub use self::builtin::{Builtin, Pricing, Linear}; pub use self::genesis::Genesis; 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::engine::Engine; pub use self::state::State; diff --git a/json/src/spec/spec.rs b/json/src/spec/spec.rs index 2be695689..a15d1faf6 100644 --- a/json/src/spec/spec.rs +++ b/json/src/spec/spec.rs @@ -21,6 +21,21 @@ use serde_json; use serde_json::Error; 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. #[derive(Debug, PartialEq, Deserialize)] pub struct Spec { diff --git a/json/src/state/test.rs b/json/src/state/test.rs index 528a49b5a..85eac0c93 100644 --- a/json/src/state/test.rs +++ b/json/src/state/test.rs @@ -21,6 +21,7 @@ use std::collections::BTreeMap; use uint::Uint; use bytes::Bytes; use hash::{Address, H256}; +use spec::ForkSpec; use state::{Env, AccountState, Transaction}; use maybe::MaybeEmpty; 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. #[derive(Debug, PartialEq, Deserialize)] pub struct PostStateIndexes { diff --git a/json/src/transaction/test.rs b/json/src/transaction/test.rs index e1bd588de..2c5f39f13 100644 --- a/json/src/transaction/test.rs +++ b/json/src/transaction/test.rs @@ -23,7 +23,7 @@ use serde_json::Error; use transaction::TransactionTest; /// TransactionTest test deserializer. -#[derive(Debug, PartialEq, Deserialize)] +#[derive(Debug, Deserialize)] pub struct Test(BTreeMap); impl IntoIterator for Test { diff --git a/json/src/transaction/txtest.rs b/json/src/transaction/txtest.rs index 60d65e70d..2be035b4f 100644 --- a/json/src/transaction/txtest.rs +++ b/json/src/transaction/txtest.rs @@ -16,23 +16,29 @@ //! Transaction test deserialization. -use uint::Uint; +use std::collections::BTreeMap; use bytes::Bytes; use hash::Address; -use transaction::Transaction; +use hash::H256; +use spec::ForkSpec; /// Transaction test deserialization. -#[derive(Debug, PartialEq, Deserialize)] +#[derive(Debug, Deserialize)] pub struct TransactionTest { - /// Block number. - #[serde(rename="blocknumber")] - pub block_number: Option, - /// Transaction rlp. pub rlp: Bytes, + pub _info: ::serde::de::IgnoredAny, + #[serde(flatten)] + pub post_state: BTreeMap, +} + +/// TransactionTest post state. +#[derive(Debug, PartialEq, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct PostState { /// Transaction sender. pub sender: Option
, - /// Transaction - pub transaction: Option, + /// Transaction hash. + pub hash: Option, } #[cfg(test)] @@ -43,21 +49,34 @@ mod tests { #[test] fn transaction_deserialization() { let s = r#"{ - "blocknumber" : "0", - "rlp" : "0xf83f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870b801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a3664935301", - "sender" : "e115cf6bb5656786569dd273705242ca72d84bc0", - "transaction" : { - "data" : "", - "gasLimit" : "0x5208", - "gasPrice" : "0x01", - "nonce" : "0x00", - "r" : "0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353", - "s" : "0x01", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "v" : "0x1b", - "value" : "0x0b" - } + "Byzantium" : { + "hash" : "4782cb5edcaeda1f0aef204b161214f124cefade9e146245183abbb9ca01bca5", + "sender" : "2ea991808ba979ba103147edfd72304ebd95c028" + }, + "Constantinople" : { + "hash" : "4782cb5edcaeda1f0aef204b161214f124cefade9e146245183abbb9ca01bca5", + "sender" : "2ea991808ba979ba103147edfd72304ebd95c028" + }, + "EIP150" : { + }, + "EIP158" : { + "hash" : "4782cb5edcaeda1f0aef204b161214f124cefade9e146245183abbb9ca01bca5", + "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(); // TODO: validate all fields } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 217e03290..231ee450e 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -28,7 +28,7 @@ use ethcore::spec::{Genesis, Spec}; use ethcore::test_helpers; use ethcore::verification::queue::kind::blocks::Unverified; use ethjson::blockchain::BlockChain; -use ethjson::state::test::ForkSpec; +use ethjson::spec::ForkSpec; use io::IoChannel; use miner::external::ExternalMiner; use parking_lot::Mutex;