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