client/rpc/types/cfx/
block.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use super::RpcAddress;
6use cfx_types::{H160, H256, U256, U64};
7use cfx_util_macros::bail;
8use jsonrpc_core::Error as RpcError;
9use primitives::{Block as PrimitiveBlock, BlockHeaderBuilder};
10use serde::{
11    de::{Deserializer, Error, Unexpected},
12    Deserialize, Serialize, Serializer,
13};
14use serde_json::Value;
15use std::{convert::TryInto, sync::Arc};
16
17use crate::rpc::types::{Bytes, Transaction};
18use primitives::pos::PosBlockId;
19
20#[derive(PartialEq, Debug)]
21pub enum BlockTransactions {
22    /// Only hashes
23    Hashes(Vec<H256>),
24    /// Full transactions
25    Full(Vec<Transaction>),
26}
27
28impl Serialize for BlockTransactions {
29    fn serialize<S: Serializer>(
30        &self, serializer: S,
31    ) -> Result<S::Ok, S::Error> {
32        match *self {
33            BlockTransactions::Hashes(ref hashes) => {
34                hashes.serialize(serializer)
35            }
36            BlockTransactions::Full(ref txs) => txs.serialize(serializer),
37        }
38    }
39}
40
41impl<'a> Deserialize<'a> for BlockTransactions {
42    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
43    where D: Deserializer<'a> {
44        let value = Value::deserialize(deserializer)?;
45        if let Value::Array(vec) = value {
46            if vec.is_empty() {
47                return Ok(BlockTransactions::Full(vec![]));
48            }
49            if let Value::String(_) = vec[0] {
50                let mut result = vec![];
51                for serialized_hash in vec {
52                    let hash = H256::deserialize(serialized_hash)
53                        .map_err(Error::custom)?;
54                    result.push(hash);
55                }
56                return Ok(BlockTransactions::Hashes(result));
57            } else {
58                let mut result = vec![];
59                for serialized_tx in vec {
60                    let tx = Transaction::deserialize(serialized_tx)
61                        .map_err(Error::custom)?;
62                    result.push(tx);
63                }
64                return Ok(BlockTransactions::Full(result));
65            }
66        }
67        Err(<D::Error as Error>::invalid_type(
68            Unexpected::Other("not array"),
69            &"array",
70        ))
71    }
72}
73
74#[derive(PartialEq, Debug, Serialize, Deserialize)]
75#[serde(rename_all = "camelCase")]
76pub struct Block {
77    /// Hash of the block
78    pub hash: H256,
79    /// Hash of the parent
80    pub parent_hash: H256,
81    /// Distance to genesis
82    pub height: U256,
83    /// Author's address
84    pub miner: RpcAddress,
85    /// State root hash
86    pub deferred_state_root: H256,
87    /// Root hash of all receipts in this block's epoch
88    pub deferred_receipts_root: H256,
89    /// Hash of aggregated bloom filter of all receipts in this block's epoch
90    pub deferred_logs_bloom_hash: H256,
91    /// Blame indicates the number of ancestors whose
92    /// state_root/receipts_root/logs_bloom_hash/blame are not correct.
93    /// It acts as a vote to help light client determining the
94    /// state_root/receipts_root/logs_bloom_hash are correct or not.
95    pub blame: U64,
96    /// Transactions root hash
97    pub transactions_root: H256,
98    /// Epoch number
99    pub epoch_number: Option<U256>,
100    /// Block number
101    pub block_number: Option<U256>,
102    /// Gas limit
103    pub gas_limit: U256,
104    /// Gas used
105    pub gas_used: Option<U256>,
106    /// Base fee
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub base_fee_per_gas: Option<U256>,
109    /// Timestamp
110    pub timestamp: U256,
111    /// Difficulty
112    pub difficulty: U256,
113    // TODO: We should change python test script and remove this field
114    /// PoW Quality
115    pub pow_quality: Option<U256>,
116    /// Referee hashes
117    pub referee_hashes: Vec<H256>,
118    /// Adaptive
119    pub adaptive: bool,
120    /// Nonce of the block
121    pub nonce: U256,
122    /// Transactions
123    pub transactions: BlockTransactions,
124    /// Size in bytes
125    pub size: Option<U256>,
126    /// Custom field
127    pub custom: Vec<Bytes>,
128    /// PoS reference.
129    pub pos_reference: Option<PosBlockId>,
130}
131
132impl Block {
133    pub fn into_primitive(self) -> Result<PrimitiveBlock, RpcError> {
134        let miner: H160 = match self.miner.try_into() {
135            Ok(m) => m,
136            Err(_) => bail!(RpcError::invalid_params(
137                "Invalid params: expected a valid base32-encoded Conflux address",
138            )),
139        };
140
141        match self.transactions {
142            BlockTransactions::Hashes(_) => Err(RpcError::invalid_params(
143                "Invalid params: expected a array of transaction objects.",
144            )),
145            BlockTransactions::Full(vec) => Ok(PrimitiveBlock::new(
146                BlockHeaderBuilder::new()
147                    .with_parent_hash(self.parent_hash.into())
148                    .with_height(self.height.as_usize() as u64)
149                    .with_timestamp(self.timestamp.as_usize() as u64)
150                    .with_author(miner)
151                    .with_transactions_root(self.transactions_root.into())
152                    .with_deferred_state_root(self.deferred_state_root.into())
153                    .with_deferred_receipts_root(
154                        self.deferred_receipts_root.into(),
155                    )
156                    .with_deferred_logs_bloom_hash(
157                        self.deferred_logs_bloom_hash.into(),
158                    )
159                    .with_blame(self.blame.as_u32())
160                    .with_difficulty(self.difficulty.into())
161                    .with_adaptive(self.adaptive)
162                    .with_gas_limit(self.gas_limit.into())
163                    .with_referee_hashes(
164                        self.referee_hashes
165                            .iter()
166                            .map(|x| x.clone().into())
167                            .collect(),
168                    )
169                    .with_nonce(self.nonce.into())
170                    .build(),
171                {
172                    let mut transactions = Vec::new();
173                    for tx in vec.into_iter() {
174                        let signed_tx = tx.into_signed().map_err(|e| {
175                            RpcError::invalid_params(format!("Invalid params: failed to convert from a rpc transaction to signed transaction {:?}", e))
176                        })?;
177                        transactions.push(Arc::new(signed_tx));
178                    }
179                    transactions
180                },
181            )),
182        }
183    }
184}
185
186/// Block header representation.
187#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
188#[serde(rename_all = "camelCase")]
189pub struct Header {
190    /// Hash of the block
191    pub hash: H256,
192    /// Hash of the parent
193    pub parent_hash: H256,
194    /// Distance to genesis
195    pub height: U256,
196    /// Miner's address
197    pub miner: RpcAddress,
198    /// State root hash
199    pub deferred_state_root: H256,
200    /// Root hash of all receipts in this block's epoch
201    pub deferred_receipts_root: H256,
202    /// Hash of aggregrated bloom filter of all receipts in the block's epoch
203    pub deferred_logs_bloom_hash: H256,
204    /// Blame indicates the number of ancestors whose
205    /// state_root/receipts_root/logs_bloom_hash/blame are not correct.
206    /// It acts as a vote to help light client determining the
207    /// state_root/receipts_root/logs_bloom_hash are correct or not.
208    pub blame: U64,
209    /// Transactions root hash
210    pub transactions_root: H256,
211    /// Epoch number
212    pub epoch_number: Option<U256>,
213    /// Block number
214    pub block_number: Option<U256>,
215    /// Gas Limit
216    pub gas_limit: U256,
217    /// Base fee
218    #[serde(skip_serializing_if = "Option::is_none")]
219    pub base_fee_per_gas: Option<U256>,
220    /// Timestamp
221    pub timestamp: U256,
222    /// Difficulty
223    pub difficulty: U256,
224    /// PoW Quality
225    pub pow_quality: Option<U256>,
226    /// Referee hashes
227    pub referee_hashes: Vec<H256>,
228    /// Adaptive
229    pub adaptive: bool,
230    /// Nonce of the block
231    pub nonce: U256,
232    /// Custom field
233    pub custom: Vec<Bytes>,
234    /// PoS reference.
235    pub pos_reference: Option<PosBlockId>,
236}
237
238#[cfg(test)]
239mod tests {
240    use super::{Block, BlockTransactions, Header, RpcAddress};
241    use crate::rpc::types::Transaction;
242    use cfx_addr::Network;
243    use cfx_types::{H256, U256};
244    use keccak_hash::KECCAK_EMPTY_LIST_RLP;
245    use serde_json;
246
247    #[test]
248    fn test_serialize_block_transactions() {
249        let t =
250            BlockTransactions::Full(vec![
251                Transaction::default(Network::Main).unwrap()
252            ]);
253        let serialized = serde_json::to_string(&t).unwrap();
254        assert_eq!(
255            serialized,
256            r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"transactionIndex":null,"from":"CFX:TYPE.NULL:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0SFBNJM2","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","contractCreated":null,"data":"0x","storageLimit":"0x0","epochHeight":"0x0","chainId":"0x1","status":null,"v":"0x0","r":"0x0","s":"0x0"}]"#
257        );
258
259        let t = BlockTransactions::Hashes(vec![H256::default()]);
260        let serialized = serde_json::to_string(&t).unwrap();
261        assert_eq!(
262            serialized,
263            r#"["0x0000000000000000000000000000000000000000000000000000000000000000"]"#
264        );
265    }
266
267    #[test]
268    fn test_deserialize_block_transactions() {
269        let result_block_transactions =
270            BlockTransactions::Hashes(vec![H256::default(), H256::default()]);
271        let serialized = r#"["0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000"]"#;
272        let deserialized_block_transactions: BlockTransactions =
273            serde_json::from_str(serialized).unwrap();
274        assert_eq!(result_block_transactions, deserialized_block_transactions);
275
276        let result_block_transactions = BlockTransactions::Full(vec![
277            Transaction::default(Network::Main).unwrap(),
278        ]);
279        let serialized = r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"CFX:TYPE.NULL:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0SFBNJM2","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","data":"0x","storageLimit":"0x0","epochHeight":"0x0","chainId":"0x1","status":null,"v":"0x0","r":"0x0","s":"0x0"}]"#;
280        let deserialized_block_transactions: BlockTransactions =
281            serde_json::from_str(serialized).unwrap();
282        assert_eq!(result_block_transactions, deserialized_block_transactions);
283    }
284
285    #[test]
286    fn test_serialize_block() {
287        let block = Block {
288            hash: H256::default(),
289            parent_hash: H256::default(),
290            height: 0.into(),
291            miner: RpcAddress::null(Network::Main).unwrap(),
292            deferred_state_root: Default::default(),
293            deferred_receipts_root: KECCAK_EMPTY_LIST_RLP.into(),
294            deferred_logs_bloom_hash: cfx_types::KECCAK_EMPTY_BLOOM.into(),
295            blame: 0.into(),
296            transactions_root: KECCAK_EMPTY_LIST_RLP.into(),
297            epoch_number: None,
298            block_number: None,
299            gas_limit: U256::default(),
300            base_fee_per_gas: None,
301            gas_used: None,
302            timestamp: 0.into(),
303            difficulty: U256::default(),
304            pow_quality: None,
305            referee_hashes: Vec::new(),
306            adaptive: false,
307            nonce: 0.into(),
308            transactions: BlockTransactions::Hashes(vec![]),
309            custom: vec![],
310            size: Some(69.into()),
311            pos_reference: Default::default(),
312        };
313        let serialized_block = serde_json::to_string(&block).unwrap();
314
315        assert_eq!(
316            serialized_block,
317            r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","height":"0x0","miner":"CFX:TYPE.NULL:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0SFBNJM2","deferredStateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","deferredReceiptsRoot":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","deferredLogsBloomHash":"0xd397b3b043d87fcd6fad1291ff0bfd16401c274896d8c63a923727f077b8e0b5","blame":"0x0","transactionsRoot":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","epochNumber":null,"blockNumber":null,"gasLimit":"0x0","gasUsed":null,"timestamp":"0x0","difficulty":"0x0","powQuality":null,"refereeHashes":[],"adaptive":false,"nonce":"0x0","transactions":[],"size":"0x45","custom":[],"posReference":null}"#
318        );
319    }
320
321    #[test]
322    fn test_deserialize_block() {
323        let serialized = r#"{"space":"Native","hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","height":"0x0","miner":"CFX:TYPE.NULL:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0SFBNJM2","deferredStateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","deferredReceiptsRoot":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","deferredLogsBloomHash":"0xd397b3b043d87fcd6fad1291ff0bfd16401c274896d8c63a923727f077b8e0b5","blame":"0x0","transactionsRoot":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","epochNumber":"0x0","blockNumber":"0x0","gasLimit":"0x0","timestamp":"0x0","difficulty":"0x0","refereeHashes":[],"stable":null,"adaptive":false,"nonce":"0x0","transactions":[],"size":"0x45","custom":[],"posReference":null}"#;
324        let result_block = Block {
325            hash: H256::default(),
326            parent_hash: H256::default(),
327            height: 0.into(),
328            miner: RpcAddress::null(Network::Main).unwrap(),
329            deferred_state_root: Default::default(),
330            deferred_receipts_root: KECCAK_EMPTY_LIST_RLP.into(),
331            deferred_logs_bloom_hash: cfx_types::KECCAK_EMPTY_BLOOM.into(),
332            blame: 0.into(),
333            transactions_root: KECCAK_EMPTY_LIST_RLP.into(),
334            epoch_number: Some(0.into()),
335            block_number: Some(0.into()),
336            base_fee_per_gas: None,
337            gas_limit: U256::default(),
338            gas_used: None,
339            timestamp: 0.into(),
340            difficulty: U256::default(),
341            pow_quality: None,
342            referee_hashes: Vec::new(),
343            adaptive: false,
344            nonce: 0.into(),
345            transactions: BlockTransactions::Full(vec![]),
346            custom: vec![],
347            size: Some(69.into()),
348            pos_reference: Default::default(),
349        };
350        let deserialized_block: Block =
351            serde_json::from_str(serialized).unwrap();
352        assert_eq!(deserialized_block, result_block);
353    }
354
355    #[test]
356    fn test_serialize_header() {
357        let header = Header {
358            hash: H256::default(),
359            parent_hash: H256::default(),
360            height: 0.into(),
361            miner: RpcAddress::null(Network::Main).unwrap(),
362            deferred_state_root: Default::default(),
363            deferred_receipts_root: KECCAK_EMPTY_LIST_RLP.into(),
364            deferred_logs_bloom_hash: cfx_types::KECCAK_EMPTY_BLOOM.into(),
365            blame: 0.into(),
366            transactions_root: KECCAK_EMPTY_LIST_RLP.into(),
367            epoch_number: None,
368            block_number: None,
369            base_fee_per_gas: None,
370            custom: vec![],
371            gas_limit: U256::default(),
372            timestamp: 0.into(),
373            difficulty: U256::default(),
374            pow_quality: None,
375            referee_hashes: Vec::new(),
376            adaptive: false,
377            nonce: 0.into(),
378            pos_reference: None,
379        };
380        let serialized_header = serde_json::to_string(&header).unwrap();
381
382        assert_eq!(
383            serialized_header,
384            r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","height":"0x0","miner":"CFX:TYPE.NULL:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0SFBNJM2","deferredStateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","deferredReceiptsRoot":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","deferredLogsBloomHash":"0xd397b3b043d87fcd6fad1291ff0bfd16401c274896d8c63a923727f077b8e0b5","blame":"0x0","transactionsRoot":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","epochNumber":null,"blockNumber":null,"gasLimit":"0x0","timestamp":"0x0","difficulty":"0x0","powQuality":null,"refereeHashes":[],"adaptive":false,"nonce":"0x0","custom":[],"posReference":null}"#
385        );
386    }
387}