1use 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 Hashes(Vec<H256>),
25 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 pub hash: H256,
80 pub parent_hash: H256,
82 pub height: U256,
84 pub miner: RpcAddress,
86 pub deferred_state_root: H256,
88 pub deferred_receipts_root: H256,
90 pub deferred_logs_bloom_hash: H256,
92 pub blame: U64,
97 pub transactions_root: H256,
99 pub epoch_number: Option<U256>,
101 pub block_number: Option<U256>,
103 pub gas_limit: U256,
105 pub gas_used: Option<U256>,
107 #[serde(skip_serializing_if = "Option::is_none")]
109 pub base_fee_per_gas: Option<U256>,
110 pub timestamp: U256,
112 pub difficulty: U256,
114 pub pow_quality: Option<U256>,
117 pub referee_hashes: Vec<H256>,
119 pub adaptive: bool,
121 pub nonce: U256,
123 pub transactions: BlockTransactions,
125 pub size: Option<U256>,
127 pub custom: Vec<Bytes>,
129 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#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
189#[serde(rename_all = "camelCase")]
190pub struct Header {
191 pub hash: H256,
193 pub parent_hash: H256,
195 pub height: U256,
197 pub miner: RpcAddress,
199 pub deferred_state_root: H256,
201 pub deferred_receipts_root: H256,
203 pub deferred_logs_bloom_hash: H256,
205 pub blame: U64,
210 pub transactions_root: H256,
212 pub epoch_number: Option<U256>,
214 pub block_number: Option<U256>,
216 pub gas_limit: U256,
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub base_fee_per_gas: Option<U256>,
221 pub timestamp: U256,
223 pub difficulty: U256,
225 pub pow_quality: Option<U256>,
227 pub referee_hashes: Vec<H256>,
229 pub adaptive: bool,
231 pub nonce: U256,
233 pub custom: Vec<Bytes>,
235 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}