1use 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 Hashes(Vec<H256>),
24 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 pub hash: H256,
79 pub parent_hash: H256,
81 pub height: U256,
83 pub miner: RpcAddress,
85 pub deferred_state_root: H256,
87 pub deferred_receipts_root: H256,
89 pub deferred_logs_bloom_hash: H256,
91 pub blame: U64,
96 pub transactions_root: H256,
98 pub epoch_number: Option<U256>,
100 pub block_number: Option<U256>,
102 pub gas_limit: U256,
104 pub gas_used: Option<U256>,
106 #[serde(skip_serializing_if = "Option::is_none")]
108 pub base_fee_per_gas: Option<U256>,
109 pub timestamp: U256,
111 pub difficulty: U256,
113 pub pow_quality: Option<U256>,
116 pub referee_hashes: Vec<H256>,
118 pub adaptive: bool,
120 pub nonce: U256,
122 pub transactions: BlockTransactions,
124 pub size: Option<U256>,
126 pub custom: Vec<Bytes>,
128 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#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
188#[serde(rename_all = "camelCase")]
189pub struct Header {
190 pub hash: H256,
192 pub parent_hash: H256,
194 pub height: U256,
196 pub miner: RpcAddress,
198 pub deferred_state_root: H256,
200 pub deferred_receipts_root: H256,
202 pub deferred_logs_bloom_hash: H256,
204 pub blame: U64,
209 pub transactions_root: H256,
211 pub epoch_number: Option<U256>,
213 pub block_number: Option<U256>,
215 pub gas_limit: U256,
217 #[serde(skip_serializing_if = "Option::is_none")]
219 pub base_fee_per_gas: Option<U256>,
220 pub timestamp: U256,
222 pub difficulty: U256,
224 pub pow_quality: Option<U256>,
226 pub referee_hashes: Vec<H256>,
228 pub adaptive: bool,
230 pub nonce: U256,
232 pub custom: Vec<Bytes>,
234 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}