// Copyright 2015-2017 Parity Technologies (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 . use std::ops::Deref; use std::collections::BTreeMap; use ethcore::encoded::Header as EthHeader; use serde::{Serialize, Serializer}; use serde::ser::Error; use v1::types::{Bytes, Transaction, H160, H256, H2048, U256}; /// Block Transactions #[derive(Debug)] pub enum BlockTransactions { /// Only hashes Hashes(Vec), /// Full transactions Full(Vec) } impl Serialize for BlockTransactions { fn serialize(&self, serializer: S) -> Result where S: Serializer { match *self { BlockTransactions::Hashes(ref hashes) => hashes.serialize(serializer), BlockTransactions::Full(ref ts) => ts.serialize(serializer) } } } /// Block representation #[derive(Debug, Serialize)] pub struct Block { /// Hash of the block pub hash: Option, /// Hash of the parent #[serde(rename="parentHash")] pub parent_hash: H256, /// Hash of the uncles #[serde(rename="sha3Uncles")] pub uncles_hash: H256, /// Authors address pub author: H160, // TODO: get rid of this one /// ? pub miner: H160, /// State root hash #[serde(rename="stateRoot")] pub state_root: H256, /// Transactions root hash #[serde(rename="transactionsRoot")] pub transactions_root: H256, /// Transactions receipts root hash #[serde(rename="receiptsRoot")] pub receipts_root: H256, /// Block number pub number: Option, /// Gas Used #[serde(rename="gasUsed")] pub gas_used: U256, /// Gas Limit #[serde(rename="gasLimit")] pub gas_limit: U256, /// Extra data #[serde(rename="extraData")] pub extra_data: Bytes, /// Logs bloom #[serde(rename="logsBloom")] pub logs_bloom: H2048, /// Timestamp pub timestamp: U256, /// Difficulty pub difficulty: U256, /// Total difficulty #[serde(rename="totalDifficulty")] pub total_difficulty: Option, /// Seal fields #[serde(rename="sealFields")] pub seal_fields: Vec, /// Uncles' hashes pub uncles: Vec, /// Transactions pub transactions: BlockTransactions, /// Size in bytes pub size: Option, } /// Block header representation. #[derive(Debug, Serialize, PartialEq, Eq)] pub struct Header { /// Hash of the block pub hash: Option, /// Hash of the parent #[serde(rename="parentHash")] pub parent_hash: H256, /// Hash of the uncles #[serde(rename="sha3Uncles")] pub uncles_hash: H256, /// Authors address pub author: H160, // TODO: get rid of this one /// ? pub miner: H160, /// State root hash #[serde(rename="stateRoot")] pub state_root: H256, /// Transactions root hash #[serde(rename="transactionsRoot")] pub transactions_root: H256, /// Transactions receipts root hash #[serde(rename="receiptsRoot")] pub receipts_root: H256, /// Block number pub number: Option, /// Gas Used #[serde(rename="gasUsed")] pub gas_used: U256, /// Gas Limit #[serde(rename="gasLimit")] pub gas_limit: U256, /// Extra data #[serde(rename="extraData")] pub extra_data: Bytes, /// Logs bloom #[serde(rename="logsBloom")] pub logs_bloom: H2048, /// Timestamp pub timestamp: U256, /// Difficulty pub difficulty: U256, /// Seal fields #[serde(rename="sealFields")] pub seal_fields: Vec, /// Size in bytes pub size: Option, } impl From for Header { fn from(h: EthHeader) -> Self { (&h).into() } } impl<'a> From<&'a EthHeader> for Header { fn from(h: &'a EthHeader) -> Self { Header { hash: Some(h.hash().into()), size: Some(h.rlp().as_raw().len().into()), parent_hash: h.parent_hash().into(), uncles_hash: h.uncles_hash().into(), author: h.author().into(), miner: h.author().into(), state_root: h.state_root().into(), transactions_root: h.transactions_root().into(), receipts_root: h.receipts_root().into(), number: Some(h.number().into()), gas_used: h.gas_used().into(), gas_limit: h.gas_limit().into(), logs_bloom: h.log_bloom().into(), timestamp: h.timestamp().into(), difficulty: h.difficulty().into(), seal_fields: h.seal().into_iter().map(Into::into).collect(), extra_data: h.extra_data().into(), } } } /// Block representation with additional info. pub type RichBlock = Rich; /// Header representation with additional info. pub type RichHeader = Rich
; /// Value representation with additional info #[derive(Debug, PartialEq, Eq)] pub struct Rich { /// Standard value. pub inner: T, /// Engine-specific fields with additional description. /// Should be included directly to serialized block object. // TODO [ToDr] #[serde(skip_serializing)] pub extra_info: BTreeMap, } impl Deref for Rich { type Target = T; fn deref(&self) -> &Self::Target { &self.inner } } impl Serialize for Rich { fn serialize(&self, serializer: S) -> Result where S: Serializer { use serde_json::{to_value, Value}; let serialized = (to_value(&self.inner), to_value(&self.extra_info)); if let (Ok(Value::Object(mut value)), Ok(Value::Object(extras))) = serialized { // join two objects value.extend(extras); // and serialize value.serialize(serializer) } else { Err(S::Error::custom("Unserializable structures.")) } } } #[cfg(test)] mod tests { use std::collections::BTreeMap; use serde_json; use v1::types::{Transaction, H64, H160, H256, H2048, Bytes, U256}; use super::{Block, RichBlock, BlockTransactions, Header, RichHeader}; #[test] fn test_serialize_block_transactions() { let t = BlockTransactions::Full(vec![Transaction::default()]); let serialized = serde_json::to_string(&t).unwrap(); assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"networkId":null,"standardV":"0x0","v":"0x0","r":"0x0","s":"0x0","condition":null}]"#); let t = BlockTransactions::Hashes(vec![H256::default().into()]); let serialized = serde_json::to_string(&t).unwrap(); assert_eq!(serialized, r#"["0x0000000000000000000000000000000000000000000000000000000000000000"]"#); } #[test] fn test_serialize_block() { let block = Block { hash: Some(H256::default()), parent_hash: H256::default(), uncles_hash: H256::default(), author: H160::default(), miner: H160::default(), state_root: H256::default(), transactions_root: H256::default(), receipts_root: H256::default(), number: Some(U256::default()), gas_used: U256::default(), gas_limit: U256::default(), extra_data: Bytes::default(), logs_bloom: H2048::default(), timestamp: U256::default(), difficulty: U256::default(), total_difficulty: Some(U256::default()), seal_fields: vec![Bytes::default(), Bytes::default()], uncles: vec![], transactions: BlockTransactions::Hashes(vec![].into()), size: Some(69.into()), }; let serialized_block = serde_json::to_string(&block).unwrap(); let rich_block = RichBlock { inner: block, extra_info: map![ "mixHash".into() => format!("0x{:?}", H256::default()), "nonce".into() => format!("0x{:?}", H64::default()) ], }; let serialized_rich_block = serde_json::to_string(&rich_block).unwrap(); assert_eq!(serialized_block, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x0","gasUsed":"0x0","gasLimit":"0x0","extraData":"0x","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","difficulty":"0x0","totalDifficulty":"0x0","sealFields":["0x","0x"],"uncles":[],"transactions":[],"size":"0x45"}"#); assert_eq!(serialized_rich_block, r#"{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x0","extraData":"0x","gasLimit":"0x0","gasUsed":"0x0","hash":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","sealFields":["0x","0x"],"sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","size":"0x45","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","totalDifficulty":"0x0","transactions":[],"transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","uncles":[]}"#); } #[test] fn none_size_null() { let block = Block { hash: Some(H256::default()), parent_hash: H256::default(), uncles_hash: H256::default(), author: H160::default(), miner: H160::default(), state_root: H256::default(), transactions_root: H256::default(), receipts_root: H256::default(), number: Some(U256::default()), gas_used: U256::default(), gas_limit: U256::default(), extra_data: Bytes::default(), logs_bloom: H2048::default(), timestamp: U256::default(), difficulty: U256::default(), total_difficulty: Some(U256::default()), seal_fields: vec![Bytes::default(), Bytes::default()], uncles: vec![], transactions: BlockTransactions::Hashes(vec![].into()), size: None, }; let serialized_block = serde_json::to_string(&block).unwrap(); let rich_block = RichBlock { inner: block, extra_info: map![ "mixHash".into() => format!("0x{:?}", H256::default()), "nonce".into() => format!("0x{:?}", H64::default()) ], }; let serialized_rich_block = serde_json::to_string(&rich_block).unwrap(); assert_eq!(serialized_block, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x0","gasUsed":"0x0","gasLimit":"0x0","extraData":"0x","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","difficulty":"0x0","totalDifficulty":"0x0","sealFields":["0x","0x"],"uncles":[],"transactions":[],"size":null}"#); assert_eq!(serialized_rich_block, r#"{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x0","extraData":"0x","gasLimit":"0x0","gasUsed":"0x0","hash":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","sealFields":["0x","0x"],"sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","size":null,"stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","totalDifficulty":"0x0","transactions":[],"transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","uncles":[]}"#); } #[test] fn test_serialize_header() { let header = Header { hash: Some(H256::default()), parent_hash: H256::default(), uncles_hash: H256::default(), author: H160::default(), miner: H160::default(), state_root: H256::default(), transactions_root: H256::default(), receipts_root: H256::default(), number: Some(U256::default()), gas_used: U256::default(), gas_limit: U256::default(), extra_data: Bytes::default(), logs_bloom: H2048::default(), timestamp: U256::default(), difficulty: U256::default(), seal_fields: vec![Bytes::default(), Bytes::default()], size: Some(69.into()), }; let serialized_header = serde_json::to_string(&header).unwrap(); let rich_header = RichHeader { inner: header, extra_info: map![ "mixHash".into() => format!("0x{:?}", H256::default()), "nonce".into() => format!("0x{:?}", H64::default()) ], }; let serialized_rich_header = serde_json::to_string(&rich_header).unwrap(); assert_eq!(serialized_header, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","author":"0x0000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","number":"0x0","gasUsed":"0x0","gasLimit":"0x0","extraData":"0x","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","difficulty":"0x0","sealFields":["0x","0x"],"size":"0x45"}"#); assert_eq!(serialized_rich_header, r#"{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x0","extraData":"0x","gasLimit":"0x0","gasUsed":"0x0","hash":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","number":"0x0","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","sealFields":["0x","0x"],"sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","size":"0x45","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","timestamp":"0x0","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#); } }