From d96858d38c1d6a78ffef8799ddb59eeb6926e847 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 15 Mar 2016 18:17:48 +0100 Subject: [PATCH 1/3] proper blockchain json parsing --- Cargo.lock | 13 +++++ Cargo.toml | 1 + json/Cargo.toml | 21 ++++++++ json/build.rs | 45 ++++++++++++++++ json/src/blockchain/account.rs | 30 +++++++++++ json/src/blockchain/block.rs | 35 +++++++++++++ json/src/blockchain/blockchain.rs | 35 +++++++++++++ json/src/blockchain/header.rs | 51 ++++++++++++++++++ json/src/blockchain/mod.rs | 25 +++++++++ json/src/blockchain/state.rs | 34 ++++++++++++ json/src/blockchain/test.rs | 32 ++++++++++++ json/src/blockchain/transaction.rs | 35 +++++++++++++ json/src/bytes.rs | 81 ++++++++++++++++++++++++++++ json/src/hash.rs | 81 ++++++++++++++++++++++++++++ json/src/lib.rs | 28 ++++++++++ json/src/lib.rs.in | 25 +++++++++ json/src/uint.rs | 84 ++++++++++++++++++++++++++++++ 17 files changed, 656 insertions(+) create mode 100644 json/Cargo.toml create mode 100644 json/build.rs create mode 100644 json/src/blockchain/account.rs create mode 100644 json/src/blockchain/block.rs create mode 100644 json/src/blockchain/blockchain.rs create mode 100644 json/src/blockchain/header.rs create mode 100644 json/src/blockchain/mod.rs create mode 100644 json/src/blockchain/state.rs create mode 100644 json/src/blockchain/test.rs create mode 100644 json/src/blockchain/transaction.rs create mode 100644 json/src/bytes.rs create mode 100644 json/src/hash.rs create mode 100644 json/src/lib.rs create mode 100644 json/src/lib.rs.in create mode 100644 json/src/uint.rs diff --git a/Cargo.lock b/Cargo.lock index dfe37dbb4..f099dc670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,7 @@ dependencies = [ "ethcore-devtools 1.1.0", "ethcore-rpc 1.1.0", "ethcore-util 1.1.0", + "ethjson 0.1.0", "ethminer 1.1.0", "ethsync 1.1.0", "fdlimit 0.1.0", @@ -286,6 +287,18 @@ dependencies = [ "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethjson" +version = "0.1.0" +dependencies = [ + "ethcore-util 1.1.0", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethminer" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 782dd1c79..fd1d16cff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ ethsync = { path = "sync" } ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } +ethjson = { path = "json" } [features] default = ["rpc"] diff --git a/json/Cargo.toml b/json/Cargo.toml new file mode 100644 index 000000000..61599c331 --- /dev/null +++ b/json/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ethjson" +version = "0.1.0" +authors = ["debris "] +build = "build.rs" + +[dependencies] +ethcore-util = { path = "../util" } +rustc-serialize = "0.3" +serde = "0.7.0" +serde_json = "0.7.0" +serde_macros = { version = "0.7.0", optional = true } +clippy = { version = "0.0.50", optional = true } + +[build-dependencies] +serde_codegen = { version = "0.7.0", optional = true } +syntex = "0.29.0" + +[features] +default = ["serde_codegen"] +nightly = ["serde_macros"] diff --git a/json/build.rs b/json/build.rs new file mode 100644 index 000000000..a23790d86 --- /dev/null +++ b/json/build.rs @@ -0,0 +1,45 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +#[cfg(not(feature = "serde_macros"))] +mod inner { + extern crate syntex; + extern crate serde_codegen; + + use std::env; + use std::path::Path; + + pub fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + + let src = Path::new("src/lib.rs.in"); + let dst = Path::new(&out_dir).join("lib.rs"); + + let mut registry = syntex::Registry::new(); + + serde_codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } +} + +#[cfg(feature = "serde_macros")] +mod inner { + pub fn main() {} +} + +fn main() { + inner::main(); +} diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs new file mode 100644 index 000000000..0d72d7fd7 --- /dev/null +++ b/json/src/blockchain/account.rs @@ -0,0 +1,30 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test account deserializer. + +use std::collections::BTreeMap; +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test account deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Account { + balance: Uint, + code: Bytes, + nonce: Uint, + storage: BTreeMap, +} diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs new file mode 100644 index 000000000..5dd423e7c --- /dev/null +++ b/json/src/blockchain/block.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test block deserializer. + +use uint::Uint; +use bytes::Bytes; +use blockchain::header::Header; +use blockchain::transaction::Transaction; + +/// Blockchain test block deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Block { + #[serde(rename="blockHeader")] + header: Header, + #[serde(rename="blocknumber")] + number: Uint, + rlp: Bytes, + transactions: Vec, + #[serde(rename="uncleHeaders")] + uncles: Vec
, +} diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs new file mode 100644 index 000000000..675e10718 --- /dev/null +++ b/json/src/blockchain/blockchain.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain deserialization. + +use bytes::Bytes; +use blockchain::state::State; +use blockchain::header::Header; + +/// Blockchain deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct BlockChain { + #[serde(rename="genesisBlockHeader")] + genesis_block: Header, + #[serde(rename="genesisRLP")] + genesis_rlp: Bytes, + blocks: Vec
, + #[serde(rename="postState")] + post_state: State, + #[serde(rename="preState")] + pre_state: State, +} diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs new file mode 100644 index 000000000..ea58c76a1 --- /dev/null +++ b/json/src/blockchain/header.rs @@ -0,0 +1,51 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test header deserializer. + +use hash::Hash; +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test header deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Header { + bloom: Hash, // TODO Bloom + coinbase: Hash, + difficulty: Uint, + #[serde(rename="extraData")] + extra_data: Bytes, + #[serde(rename="gasLimit")] + gas_limit: Uint, + #[serde(rename="gasUsed")] + gas_used: Uint, + hash: Hash, + #[serde(rename="mixHash")] + mix_hash: Hash, + nonce: Uint, // TODO fix parsing + number: Uint, + #[serde(rename="parentHash")] + parent_hash: Hash, + #[serde(rename="receiptTrie")] + receipt_trie: Hash, + #[serde(rename="stateRoot")] + state_root: Hash, + timestamp: Uint, + #[serde(rename="transactionsTrie")] + transactions_trie: Hash, + #[serde(rename="uncleHash")] + uncle_hash: Hash, +} diff --git a/json/src/blockchain/mod.rs b/json/src/blockchain/mod.rs new file mode 100644 index 000000000..046b2e534 --- /dev/null +++ b/json/src/blockchain/mod.rs @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test deserialization. + +pub mod account; +pub mod block; +pub mod blockchain; +pub mod header; +pub mod state; +pub mod transaction; +pub mod test; diff --git a/json/src/blockchain/state.rs b/json/src/blockchain/state.rs new file mode 100644 index 000000000..c934d7c0a --- /dev/null +++ b/json/src/blockchain/state.rs @@ -0,0 +1,34 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test state deserializer. + +use std::collections::BTreeMap; +use std::ops::Deref; +use hash::Hash; +use blockchain::account::Account; + +/// Blockchain test state deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct State(BTreeMap); + +impl Deref for State { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/json/src/blockchain/test.rs b/json/src/blockchain/test.rs new file mode 100644 index 000000000..6097a60e6 --- /dev/null +++ b/json/src/blockchain/test.rs @@ -0,0 +1,32 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test deserializer. + +use std::collections::BTreeMap; +use std::ops::Deref; +use blockchain::blockchain::BlockChain; + +/// Blockchain test deserializer. +pub struct Test(BTreeMap); + +impl Deref for Test { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/json/src/blockchain/transaction.rs b/json/src/blockchain/transaction.rs new file mode 100644 index 000000000..5d04748f5 --- /dev/null +++ b/json/src/blockchain/transaction.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test transaction deserialization. + +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test transaction deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Transaction { + data: Bytes, + #[serde(rename="gasLimit")] + gas_limit: Uint, + #[serde(rename="gasPrice")] + gas_price: Uint, + nonce: Uint, + r: Uint, + s: Uint, + v: Uint, + value: Uint +} diff --git a/json/src/bytes.rs b/json/src/bytes.rs new file mode 100644 index 000000000..034c90d62 --- /dev/null +++ b/json/src/bytes.rs @@ -0,0 +1,81 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Lenient bytes json deserialization for test json files. + +use rustc_serialize::hex::FromHex; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; + +/// Lenient bytes json deserialization for test json files. +#[derive(Default, Debug, PartialEq)] +pub struct Bytes(Vec); + +impl Into> for Bytes { + fn into(self) -> Vec { + self.0 + } +} + +impl Deserialize for Bytes { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(BytesVisitor) + } +} + +struct BytesVisitor; + +impl Visitor for BytesVisitor { + type Value = Bytes; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let v = match value.len() { + 0 => vec![], + 2 if value.starts_with("0x") => vec![], + _ if value.starts_with("0x") => try!(FromHex::from_hex(&value[2..]).map_err(|_| Error::custom("Invalid hex value."))), + _ => try!(FromHex::from_hex(value).map_err(|_| Error::custom("Invalid hex value"))) + }; + Ok(Bytes(v)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +//mod test { + //use std::str::FromStr; + //use serde_json; + //use util::hash::H256; + //use hash::Hash; + + //#[test] + //fn uint_deserialization() { + //let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; + //let deserialized: Vec = serde_json::from_str(s).unwrap(); + //assert_eq!(deserialized, vec![ + //Hash(H256::from(0)), + //Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) + //]); + //} + + //#[test] + //fn uint_into() { + //assert_eq!(H256::from(0), Hash(H256::from(0)).into()); + //} +//} diff --git a/json/src/hash.rs b/json/src/hash.rs new file mode 100644 index 000000000..e5bbedbfa --- /dev/null +++ b/json/src/hash.rs @@ -0,0 +1,81 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Lenient hash json deserialization for test json files. + +use std::str::FromStr; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::hash::H256; + +/// Lenient hash json deserialization for test json files. +#[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Hash(H256); + +impl Into for Hash { + fn into(self) -> H256 { + self.0 + } +} + +impl Deserialize for Hash { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(HashVisitor) + } +} + +struct HashVisitor; + +impl Visitor for HashVisitor { + type Value = Hash; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => H256::from(0), + _ => try!(H256::from_str(value).map_err(|_| Error::custom("invalid hex value."))) + }; + + Ok(Hash(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod test { + use std::str::FromStr; + use serde_json; + use util::hash::H256; + use hash::Hash; + + #[test] + fn uint_deserialization() { + let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Hash(H256::from(0)), + Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) + ]); + } + + #[test] + fn uint_into() { + assert_eq!(H256::from(0), Hash(H256::from(0)).into()); + } +} diff --git a/json/src/lib.rs b/json/src/lib.rs new file mode 100644 index 000000000..b94e1fa55 --- /dev/null +++ b/json/src/lib.rs @@ -0,0 +1,28 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Json deserialization module. + +#![warn(missing_docs)] +#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))] +#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))] + +#[cfg(feature = "serde_macros")] +include!("lib.rs.in"); + +#[cfg(not(feature = "serde_macros"))] +include!(concat!(env!("OUT_DIR"), "/lib.rs")); + diff --git a/json/src/lib.rs.in b/json/src/lib.rs.in new file mode 100644 index 000000000..6d3437811 --- /dev/null +++ b/json/src/lib.rs.in @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +extern crate rustc_serialize; +extern crate serde; +extern crate serde_json; +extern crate ethcore_util as util; + +pub mod hash; +pub mod uint; +pub mod bytes; +pub mod blockchain; diff --git a/json/src/uint.rs b/json/src/uint.rs new file mode 100644 index 000000000..f7f34f1dd --- /dev/null +++ b/json/src/uint.rs @@ -0,0 +1,84 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Lenient uint json deserialization for test json files. + +use std::str::FromStr; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::numbers::{U256, Uint as U}; + +/// Lenient uint json deserialization for test json files. +#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Uint(U256); + +impl Into for Uint { + fn into(self) -> U256 { + self.0 + } +} + +impl Deserialize for Uint { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(UintVisitor) + } +} + +struct UintVisitor; + +impl Visitor for UintVisitor { + type Value = Uint; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => U256::from(0), + 2 if value.starts_with("0x") => U256::from(0), + _ if value.starts_with("0x") => try!(U256::from_str(&value[2..]).map_err(|_| Error::custom("invalid hex value."))), + _ => try!(U256::from_dec_str(value).map_err(|_| Error::custom("invalid decimal value."))) + }; + + Ok(Uint(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod test { + use serde_json; + use util::numbers::U256; + use uint::Uint; + + #[test] + fn uint_deserialization() { + let s = r#"["0xa", "10", "", "0x"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Uint(U256::from(10)), + Uint(U256::from(10)), + Uint(U256::from(0)), + Uint(U256::from(0)) + ]); + } + + #[test] + fn uint_into() { + assert_eq!(U256::from(10), Uint(U256::from(10)).into()); + } +} From b4849d1c5870db13020f356bdffe4cee7c6a7161 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 15 Mar 2016 18:23:59 +0100 Subject: [PATCH 2/3] finished blockchain test deserialization --- json/src/blockchain/header.rs | 22 ++++----- json/src/blockchain/state.rs | 6 +-- json/src/bytes.rs | 40 +++++++-------- json/src/hash.rs | 91 ++++++++++++++++++++--------------- 4 files changed, 86 insertions(+), 73 deletions(-) diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs index ea58c76a1..fc27fc1f5 100644 --- a/json/src/blockchain/header.rs +++ b/json/src/blockchain/header.rs @@ -16,15 +16,15 @@ //! Blockchain test header deserializer. -use hash::Hash; +use hash::{H64, H256, Bloom}; use uint::Uint; use bytes::Bytes; /// Blockchain test header deserializer. #[derive(Debug, PartialEq, Deserialize)] pub struct Header { - bloom: Hash, // TODO Bloom - coinbase: Hash, + bloom: Bloom, + coinbase: H256, difficulty: Uint, #[serde(rename="extraData")] extra_data: Bytes, @@ -32,20 +32,20 @@ pub struct Header { gas_limit: Uint, #[serde(rename="gasUsed")] gas_used: Uint, - hash: Hash, + hash: H256, #[serde(rename="mixHash")] - mix_hash: Hash, - nonce: Uint, // TODO fix parsing + mix_hash: H256, + nonce: H64, number: Uint, #[serde(rename="parentHash")] - parent_hash: Hash, + parent_hash: H256, #[serde(rename="receiptTrie")] - receipt_trie: Hash, + receipt_trie: H256, #[serde(rename="stateRoot")] - state_root: Hash, + state_root: H256, timestamp: Uint, #[serde(rename="transactionsTrie")] - transactions_trie: Hash, + transactions_trie: H256, #[serde(rename="uncleHash")] - uncle_hash: Hash, + uncle_hash: H256, } diff --git a/json/src/blockchain/state.rs b/json/src/blockchain/state.rs index c934d7c0a..2af0dbf21 100644 --- a/json/src/blockchain/state.rs +++ b/json/src/blockchain/state.rs @@ -18,15 +18,15 @@ use std::collections::BTreeMap; use std::ops::Deref; -use hash::Hash; +use hash::Address; use blockchain::account::Account; /// Blockchain test state deserializer. #[derive(Debug, PartialEq, Deserialize)] -pub struct State(BTreeMap); +pub struct State(BTreeMap); impl Deref for State { - type Target = BTreeMap; + type Target = BTreeMap; fn deref(&self) -> &Self::Target { &self.0 diff --git a/json/src/bytes.rs b/json/src/bytes.rs index 034c90d62..c9e31e888 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -58,24 +58,26 @@ impl Visitor for BytesVisitor { } #[cfg(test)] -//mod test { - //use std::str::FromStr; - //use serde_json; - //use util::hash::H256; - //use hash::Hash; +mod test { + use serde_json; + use bytes::Bytes; - //#[test] - //fn uint_deserialization() { - //let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; - //let deserialized: Vec = serde_json::from_str(s).unwrap(); - //assert_eq!(deserialized, vec![ - //Hash(H256::from(0)), - //Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) - //]); - //} + #[test] + fn bytes_deserialization() { + let s = r#"["", "0x", "0x12", "1234"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Bytes(vec![]), + Bytes(vec![]), + Bytes(vec![0x12]), + Bytes(vec![0x12, 0x34]) + ]); + } - //#[test] - //fn uint_into() { - //assert_eq!(H256::from(0), Hash(H256::from(0)).into()); - //} -//} + #[test] + fn bytes_into() { + let bytes = Bytes(vec![0xff, 0x11]); + let v: Vec = bytes.into(); + assert_eq!(vec![0xff, 0x11], v); + } +} diff --git a/json/src/hash.rs b/json/src/hash.rs index e5bbedbfa..8ed28c33c 100644 --- a/json/src/hash.rs +++ b/json/src/hash.rs @@ -19,63 +19,74 @@ use std::str::FromStr; use serde::{Deserialize, Deserializer, Error}; use serde::de::Visitor; -use util::hash::H256; +use util::hash::{H64 as Hash64, Address as Hash160, H256 as Hash256, H2048 as Hash2048}; -/// Lenient hash json deserialization for test json files. -#[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Hash(H256); -impl Into for Hash { - fn into(self) -> H256 { - self.0 +macro_rules! impl_hash { + ($name: ident, $inner: ident) => { + /// Lenient hash json deserialization for test json files. + #[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub struct $name($inner); + + impl Into<$inner> for $name { + fn into(self) -> $inner { + self.0 + } + } + + impl Deserialize for $name { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + + struct HashVisitor; + + impl Visitor for HashVisitor { + type Value = $name; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => $inner::from(0), + _ => try!($inner::from_str(value).map_err(|_| Error::custom("invalid hex value."))) + }; + + Ok($name(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } + } + + deserializer.deserialize(HashVisitor) + } + } } } -impl Deserialize for Hash { - fn deserialize(deserializer: &mut D) -> Result - where D: Deserializer { - deserializer.deserialize(HashVisitor) - } -} - -struct HashVisitor; - -impl Visitor for HashVisitor { - type Value = Hash; - - fn visit_str(&mut self, value: &str) -> Result where E: Error { - let value = match value.len() { - 0 => H256::from(0), - _ => try!(H256::from_str(value).map_err(|_| Error::custom("invalid hex value."))) - }; - - Ok(Hash(value)) - } - - fn visit_string(&mut self, value: String) -> Result where E: Error { - self.visit_str(value.as_ref()) - } -} +impl_hash!(H64, Hash64); +impl_hash!(Address, Hash160); +impl_hash!(H256, Hash256); +impl_hash!(Bloom, Hash2048); #[cfg(test)] mod test { use std::str::FromStr; use serde_json; - use util::hash::H256; - use hash::Hash; + use util::hash; + use hash::H256; #[test] - fn uint_deserialization() { + fn hash_deserialization() { let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; - let deserialized: Vec = serde_json::from_str(s).unwrap(); + let deserialized: Vec = serde_json::from_str(s).unwrap(); assert_eq!(deserialized, vec![ - Hash(H256::from(0)), - Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) + H256(hash::H256::from(0)), + H256(hash::H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) ]); } #[test] - fn uint_into() { - assert_eq!(H256::from(0), Hash(H256::from(0)).into()); + fn hash_into() { + assert_eq!(hash::H256::from(0), H256(hash::H256::from(0)).into()); } } From 196c6e8eccb73b885596e5225ce714abff35c80e Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 15 Mar 2016 19:32:07 +0100 Subject: [PATCH 3/3] tests for loading test json files --- json/src/blockchain/account.rs | 20 ++++++ json/src/blockchain/block.rs | 39 +++++++++- json/src/blockchain/blockchain.rs | 114 +++++++++++++++++++++++++++++- json/src/blockchain/header.rs | 34 ++++++++- json/src/bytes.rs | 8 ++- json/src/hash.rs | 4 +- json/src/uint.rs | 8 ++- 7 files changed, 215 insertions(+), 12 deletions(-) diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs index 0d72d7fd7..eb6f0a1dd 100644 --- a/json/src/blockchain/account.rs +++ b/json/src/blockchain/account.rs @@ -28,3 +28,23 @@ pub struct Account { nonce: Uint, storage: BTreeMap, } + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::account::Account; + + #[test] + fn header_deserialization() { + let s = r#"{ + "balance" : "0x09184e72a078", + "code" : "0x600140600155", + "nonce" : "0x00", + "storage" : { + "0x01" : "0x9a10c2b5bb8f3c602e674006d9b21f09167df57c87a78a5ce96d4159ecb76520" + } + }"#; + let _deserialized: Account= serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs index 5dd423e7c..ed297077c 100644 --- a/json/src/blockchain/block.rs +++ b/json/src/blockchain/block.rs @@ -16,7 +16,6 @@ //! Blockchain test block deserializer. -use uint::Uint; use bytes::Bytes; use blockchain::header::Header; use blockchain::transaction::Transaction; @@ -26,10 +25,44 @@ use blockchain::transaction::Transaction; pub struct Block { #[serde(rename="blockHeader")] header: Header, - #[serde(rename="blocknumber")] - number: Uint, rlp: Bytes, transactions: Vec, #[serde(rename="uncleHeaders")] uncles: Vec
, } + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::block::Block; + + #[test] + fn block_deserialization() { + let s = r#"{ + "blockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x", + "gasLimit" : "0x2fefba", + "gasUsed" : "0x00", + "hash" : "65ebf1b97fb89b14680267e0723d69267ec4bf9a96d4a60ffcb356ae0e81c18f", + "mixHash" : "13735ab4156c9b36327224d92e1692fab8fc362f8e0f868c94d421848ef7cd06", + "nonce" : "931dcc53e5edc514", + "number" : "0x01", + "parentHash" : "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "c5c83ff43741f573a0c9b31d0e56fdd745f4e37d193c4e78544f302777aafcf3", + "timestamp" : "0x56850b7b", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "blocknumber" : "1", + "rlp" : "0xf901fcf901f7a05a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c5c83ff43741f573a0c9b31d0e56fdd745f4e37d193c4e78544f302777aafcf3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefba808456850b7b80a013735ab4156c9b36327224d92e1692fab8fc362f8e0f868c94d421848ef7cd0688931dcc53e5edc514c0c0", + "transactions" : [], + "uncleHeaders" : [] + }"#; + let _deserialized: Block = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs index 675e10718..f6b1259ca 100644 --- a/json/src/blockchain/blockchain.rs +++ b/json/src/blockchain/blockchain.rs @@ -19,6 +19,7 @@ use bytes::Bytes; use blockchain::state::State; use blockchain::header::Header; +use blockchain::block::Block; /// Blockchain deserialization. #[derive(Debug, PartialEq, Deserialize)] @@ -27,9 +28,118 @@ pub struct BlockChain { genesis_block: Header, #[serde(rename="genesisRLP")] genesis_rlp: Bytes, - blocks: Vec
, + blocks: Vec, #[serde(rename="postState")] post_state: State, - #[serde(rename="preState")] + #[serde(rename="pre")] pre_state: State, } + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::blockchain::BlockChain; + + #[test] + fn blockchain_deserialization() { + let s = r#"{ + "blocks" : [{ + "blockHeader" : { + "bloom" : "00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000040000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x0102030405060708091011121314151617181920212223242526272829303132", + "gasLimit" : "0x2fefba", + "gasUsed" : "0x560b", + "hash" : "06b5b1742bde29468510c92641f36b719c61b3fc3e9a21c92a23978f4f7faa2a", + "mixHash" : "5266ca43e81d25925a9ba573c3e4f9180bc076d316d90e63c6f8708b272f5ce2", + "nonce" : "59ba4daed1898e21", + "number" : "0x01", + "parentHash" : "f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524d", + "receiptTrie" : "c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296", + "stateRoot" : "bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bf", + "timestamp" : "0x56850c2c", + "transactionsTrie" : "498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "rlp" : "0xf90285f90219a0f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0498785da562aa0c5dd5937cf15f22139b0b1bcf3b4fc48986e1bb1dae9292796a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefba82560b8456850c2ca00102030405060708091011121314151617181920212223242526272829303132a05266ca43e81d25925a9ba573c3e4f9180bc076d316d90e63c6f8708b272f5ce28859ba4daed1898e21f866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ca0ee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3a04e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21c0", + "transactions" : [ + { + "data" : "0x", + "gasLimit" : "0xc350", + "gasPrice" : "0x0a", + "nonce" : "0x00", + "r" : "0xee0b9ec878fbd4258a9473199d8ecc32996a20c323c004e79e0cda20e0418ce3", + "s" : "0x4e6bc63927d1510bab54f37e46fa036faf4b2c465d271920d9afea1fadf7bd21", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "v" : "0x1c", + "value" : "0x012a05f200" + } + ], + "uncleHeaders" : [ + ] + }], + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x42", + "gasLimit" : "0x2fefd8", + "gasUsed" : "0x00", + "hash" : "f052d217bd5275a5177a3c3b7debdfe2670f1c8394b2965ccd5c1883cc1a524d", + "mixHash" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0102030405060708", + "number" : "0x00", + "parentHash" : "0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7", + "timestamp" : "0x54c98c81", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "genesisRLP" : "0xf901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421880102030405060708c0c0", + "lastblockhash" : "06b5b1742bde29468510c92641f36b719c61b3fc3e9a21c92a23978f4f7faa2a", + "postState" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0x012a05f264", + "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1", + "nonce" : "0x00", + "storage" : { + } + }, + "8888f1f195afa192cfee860698584c030f4c9db1" : { + "balance" : "0x4563918244f75c6e", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x012a029592", + "code" : "0x", + "nonce" : "0x01", + "storage" : { + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0x64", + "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600052600060206000a1", + "nonce" : "0x00", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "0x02540be400", + "code" : "0x", + "nonce" : "0x00", + "storage" : { + } + } + } + }"#; + let _deserialized: BlockChain = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + //} +} diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs index fc27fc1f5..e97039213 100644 --- a/json/src/blockchain/header.rs +++ b/json/src/blockchain/header.rs @@ -16,7 +16,7 @@ //! Blockchain test header deserializer. -use hash::{H64, H256, Bloom}; +use hash::{H64, Address, H256, Bloom}; use uint::Uint; use bytes::Bytes; @@ -24,7 +24,7 @@ use bytes::Bytes; #[derive(Debug, PartialEq, Deserialize)] pub struct Header { bloom: Bloom, - coinbase: H256, + coinbase: Address, difficulty: Uint, #[serde(rename="extraData")] extra_data: Bytes, @@ -49,3 +49,33 @@ pub struct Header { #[serde(rename="uncleHash")] uncle_hash: H256, } + +#[cfg(test)] +mod tests { + use serde_json; + use blockchain::header::Header; + + #[test] + fn header_deserialization() { + let s = r#"{ + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "0x020000", + "extraData" : "0x", + "gasLimit" : "0x2fefba", + "gasUsed" : "0x00", + "hash" : "65ebf1b97fb89b14680267e0723d69267ec4bf9a96d4a60ffcb356ae0e81c18f", + "mixHash" : "13735ab4156c9b36327224d92e1692fab8fc362f8e0f868c94d421848ef7cd06", + "nonce" : "931dcc53e5edc514", + "number" : "0x01", + "parentHash" : "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "c5c83ff43741f573a0c9b31d0e56fdd745f4e37d193c4e78544f302777aafcf3", + "timestamp" : "0x56850b7b", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }"#; + let _deserialized: Header = serde_json::from_str(s).unwrap(); + // TODO: validate all fields + } +} diff --git a/json/src/bytes.rs b/json/src/bytes.rs index c9e31e888..28b7636d4 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -46,8 +46,12 @@ impl Visitor for BytesVisitor { let v = match value.len() { 0 => vec![], 2 if value.starts_with("0x") => vec![], - _ if value.starts_with("0x") => try!(FromHex::from_hex(&value[2..]).map_err(|_| Error::custom("Invalid hex value."))), - _ => try!(FromHex::from_hex(value).map_err(|_| Error::custom("Invalid hex value"))) + _ if value.starts_with("0x") => try!(FromHex::from_hex(&value[2..]).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })), + _ => try!(FromHex::from_hex(value).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })) }; Ok(Bytes(v)) } diff --git a/json/src/hash.rs b/json/src/hash.rs index 8ed28c33c..098f2e7a8 100644 --- a/json/src/hash.rs +++ b/json/src/hash.rs @@ -46,7 +46,9 @@ macro_rules! impl_hash { fn visit_str(&mut self, value: &str) -> Result where E: Error { let value = match value.len() { 0 => $inner::from(0), - _ => try!($inner::from_str(value).map_err(|_| Error::custom("invalid hex value."))) + _ => try!($inner::from_str(value).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })) }; Ok($name(value)) diff --git a/json/src/uint.rs b/json/src/uint.rs index f7f34f1dd..41e717277 100644 --- a/json/src/uint.rs +++ b/json/src/uint.rs @@ -47,8 +47,12 @@ impl Visitor for UintVisitor { let value = match value.len() { 0 => U256::from(0), 2 if value.starts_with("0x") => U256::from(0), - _ if value.starts_with("0x") => try!(U256::from_str(&value[2..]).map_err(|_| Error::custom("invalid hex value."))), - _ => try!(U256::from_dec_str(value).map_err(|_| Error::custom("invalid decimal value."))) + _ if value.starts_with("0x") => try!(U256::from_str(&value[2..]).map_err(|_| { + Error::custom(format!("Invalid hex value {}.", value).as_ref()) + })), + _ => try!(U256::from_dec_str(value).map_err(|_| { + Error::custom(format!("Invalid decimal value {}.", value).as_ref()) + })) }; Ok(Uint(value))