1use crate::types::{Bytes, H160, H2048, H256, H64, U256, U64};
2use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
3
4#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
6pub struct BlockHeader {
7 pub hash: Option<H256>,
9 #[serde(rename = "parentHash")]
11 pub parent_hash: H256,
12 #[serde(rename = "sha3Uncles")]
14 #[cfg_attr(feature = "allow-missing-fields", serde(default))]
15 pub uncles_hash: H256,
16 #[serde(rename = "miner", default, deserialize_with = "null_to_default")]
18 pub author: H160,
19 #[serde(rename = "stateRoot")]
21 pub state_root: H256,
22 #[serde(rename = "transactionsRoot")]
24 pub transactions_root: H256,
25 #[serde(rename = "receiptsRoot")]
27 pub receipts_root: H256,
28 pub number: Option<U64>,
30 #[serde(rename = "gasUsed")]
32 pub gas_used: U256,
33 #[serde(rename = "gasLimit")]
35 #[cfg_attr(feature = "allow-missing-fields", serde(default))]
36 pub gas_limit: U256,
37 #[serde(rename = "baseFeePerGas", skip_serializing_if = "Option::is_none")]
39 pub base_fee_per_gas: Option<U256>,
40 #[serde(rename = "extraData")]
42 pub extra_data: Bytes,
43 #[serde(rename = "logsBloom")]
45 pub logs_bloom: H2048,
46 pub timestamp: U256,
48 #[cfg_attr(feature = "allow-missing-fields", serde(default))]
50 pub difficulty: U256,
51 #[serde(rename = "mixHash")]
53 pub mix_hash: Option<H256>,
54 pub nonce: Option<H64>,
56}
57
58#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)]
61pub struct Block<TX> {
62 pub hash: Option<H256>,
64 #[serde(rename = "parentHash")]
66 pub parent_hash: H256,
67 #[serde(rename = "sha3Uncles")]
69 #[cfg_attr(feature = "allow-missing-fields", serde(default))]
70 pub uncles_hash: H256,
71 #[serde(rename = "miner", default, deserialize_with = "null_to_default")]
73 pub author: H160,
74 #[serde(rename = "stateRoot")]
76 pub state_root: H256,
77 #[serde(rename = "transactionsRoot")]
79 pub transactions_root: H256,
80 #[serde(rename = "receiptsRoot")]
82 pub receipts_root: H256,
83 pub number: Option<U64>,
85 #[serde(rename = "gasUsed")]
87 pub gas_used: U256,
88 #[serde(rename = "gasLimit")]
90 #[cfg_attr(feature = "allow-missing-fields", serde(default))]
91 pub gas_limit: U256,
92 #[serde(rename = "baseFeePerGas", skip_serializing_if = "Option::is_none")]
94 pub base_fee_per_gas: Option<U256>,
95 #[serde(rename = "extraData")]
97 pub extra_data: Bytes,
98 #[serde(rename = "logsBloom")]
100 pub logs_bloom: Option<H2048>,
101 pub timestamp: U256,
103 #[cfg_attr(feature = "allow-missing-fields", serde(default))]
105 pub difficulty: U256,
106 #[serde(rename = "totalDifficulty")]
108 pub total_difficulty: Option<U256>,
109 #[serde(default, rename = "sealFields")]
111 pub seal_fields: Vec<Bytes>,
112 #[cfg_attr(feature = "allow-missing-fields", serde(default))]
114 pub uncles: Vec<H256>,
115 pub transactions: Vec<TX>,
117 pub size: Option<U256>,
119 #[serde(rename = "mixHash")]
121 pub mix_hash: Option<H256>,
122 pub nonce: Option<H64>,
124}
125
126fn null_to_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
127where
128 T: Default + Deserialize<'de>,
129 D: Deserializer<'de>,
130{
131 let option = Option::deserialize(deserializer)?;
132 Ok(option.unwrap_or_default())
133}
134
135#[derive(Copy, Clone, Debug, PartialEq)]
137pub enum BlockNumber {
138 Finalized,
140 Safe,
142 Latest,
144 Earliest,
146 Pending,
148 Number(U64),
150}
151
152impl<T: Into<U64>> From<T> for BlockNumber {
153 fn from(num: T) -> Self {
154 BlockNumber::Number(num.into())
155 }
156}
157
158impl Serialize for BlockNumber {
159 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
160 where
161 S: Serializer,
162 {
163 match *self {
164 BlockNumber::Number(ref x) => serializer.serialize_str(&format!("0x{:x}", x)),
165 BlockNumber::Latest => serializer.serialize_str("latest"),
166 BlockNumber::Earliest => serializer.serialize_str("earliest"),
167 BlockNumber::Pending => serializer.serialize_str("pending"),
168 BlockNumber::Finalized => serializer.serialize_str("finalized"),
169 BlockNumber::Safe => serializer.serialize_str("safe"),
170 }
171 }
172}
173
174impl<'a> Deserialize<'a> for BlockNumber {
175 fn deserialize<D>(deserializer: D) -> Result<BlockNumber, D::Error>
176 where
177 D: Deserializer<'a>,
178 {
179 let value = String::deserialize(deserializer)?;
180 match value.as_str() {
181 "latest" => Ok(BlockNumber::Latest),
182 "earliest" => Ok(BlockNumber::Earliest),
183 "pending" => Ok(BlockNumber::Pending),
184 "finalized" => Ok(BlockNumber::Finalized),
185 "safe" => Ok(BlockNumber::Safe),
186 _ if value.starts_with("0x") => U64::from_str_radix(&value[2..], 16)
187 .map(BlockNumber::Number)
188 .map_err(|e| D::Error::custom(format!("invalid block number: {}", e))),
189 _ => Err(D::Error::custom("invalid block number: missing 0x prefix".to_string())),
190 }
191 }
192}
193
194#[derive(Copy, Clone, Debug, PartialEq)]
196pub enum BlockId {
197 Hash(H256),
199 Number(BlockNumber),
201}
202
203impl Serialize for BlockId {
204 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
205 where
206 S: Serializer,
207 {
208 match *self {
209 BlockId::Hash(ref x) => {
210 let mut s = serializer.serialize_struct("BlockIdEip1898", 1)?;
211 s.serialize_field("blockHash", &format!("{:?}", x))?;
212 s.end()
213 }
214 BlockId::Number(ref num) => num.serialize(serializer),
215 }
216 }
217}
218
219impl From<U64> for BlockId {
220 fn from(num: U64) -> Self {
221 BlockNumber::Number(num).into()
222 }
223}
224
225impl From<BlockNumber> for BlockId {
226 fn from(num: BlockNumber) -> Self {
227 BlockId::Number(num)
228 }
229}
230
231impl From<H256> for BlockId {
232 fn from(hash: H256) -> Self {
233 BlockId::Hash(hash)
234 }
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240 use serde_json::Value;
241
242 #[test]
243 fn block_miner() {
244 let mut json = serde_json::json!(
245 {
246 "miner": "0x0000000000000000000000000000000000000001",
247 "number": "0x1b4",
248 "hash": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
249 "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
250 "mixHash": "0x1010101010101010101010101010101010101010101010101010101010101010",
251 "nonce": "0x0000000000000000",
252 "sealFields": [
253 "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
254 "0x0000000000000042"
255 ],
256 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
257 "logsBloom": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
258 "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
259 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
260 "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
261 "difficulty": "0x27f07",
262 "totalDifficulty": "0x27f07",
263 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
264 "size": "0x27f07",
265 "gasLimit": "0x9f759",
266 "minGasPrice": "0x9f759",
267 "gasUsed": "0x9f759",
268 "timestamp": "0x54e34e8e",
269 "transactions": [],
270 "uncles": []
271 }
272 );
273
274 let block: Block<()> = serde_json::from_value(json.clone()).unwrap();
275 assert_eq!(block.author, H160::from_low_u64_be(1));
276 assert!(block.base_fee_per_gas.is_none());
277
278 json.as_object_mut().unwrap().insert("miner".to_string(), Value::Null);
282 let block: Block<()> = serde_json::from_value(json.clone()).unwrap();
283 assert_eq!(block.author, Default::default());
284
285 json.as_object_mut().unwrap().remove("miner");
287 let block: Block<()> = serde_json::from_value(json).unwrap();
288 assert_eq!(block.author, Default::default());
289 }
290
291 #[test]
292 fn post_london_block() {
293 let json = serde_json::json!(
294 {
295 "baseFeePerGas": "0x7",
296 "miner": "0x0000000000000000000000000000000000000001",
297 "number": "0x1b4",
298 "hash": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
299 "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
300 "mixHash": "0x1010101010101010101010101010101010101010101010101010101010101010",
301 "nonce": "0x0000000000000000",
302 "sealFields": [
303 "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
304 "0x0000000000000042"
305 ],
306 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
307 "logsBloom": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
308 "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
309 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
310 "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
311 "difficulty": "0x27f07",
312 "totalDifficulty": "0x27f07",
313 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
314 "size": "0x27f07",
315 "gasLimit": "0x9f759",
316 "minGasPrice": "0x9f759",
317 "gasUsed": "0x9f759",
318 "timestamp": "0x54e34e8e",
319 "transactions": [],
320 "uncles": []
321 }
322 );
323
324 let block: Block<()> = serde_json::from_value(json).unwrap();
325 assert_eq!(block.base_fee_per_gas, Some(U256::from(7)));
326 }
327
328 #[test]
329 fn serialize_deserialize_block_number() {
330 let serialized = serde_json::to_value(BlockNumber::Latest).unwrap();
332 assert_eq!(serialized, "latest");
333 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
334 assert_eq!(deserialized, BlockNumber::Latest);
335
336 let serialized = serde_json::to_value(BlockNumber::Earliest).unwrap();
338 assert_eq!(serialized, "earliest");
339 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
340 assert_eq!(deserialized, BlockNumber::Earliest);
341
342 let serialized = serde_json::to_value(BlockNumber::Pending).unwrap();
344 assert_eq!(serialized, "pending");
345 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
346 assert_eq!(deserialized, BlockNumber::Pending);
347
348 let serialized = serde_json::to_value(BlockNumber::Finalized).unwrap();
350 assert_eq!(serialized, "finalized");
351 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
352 assert_eq!(deserialized, BlockNumber::Finalized);
353
354 let serialized = serde_json::to_value(BlockNumber::Safe).unwrap();
356 assert_eq!(serialized, "safe");
357 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
358 assert_eq!(deserialized, BlockNumber::Safe);
359
360 let serialized = serde_json::to_value(BlockNumber::Number(100.into())).unwrap();
362 assert_eq!(serialized, "0x64");
363 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
364 assert_eq!(deserialized, BlockNumber::Number(100.into()));
365 let deserialized = serde_json::from_value::<BlockNumber>("64".into());
366 assert_eq!(
367 deserialized.unwrap_err().to_string(),
368 "invalid block number: missing 0x prefix"
369 );
370 }
371}