1use crate::prelude::*;
2use crate::types::{Bytes, H160, H2048, H256, H64, U256, U64};
3use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
4
5#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
7pub struct BlockHeader {
8 pub hash: Option<H256>,
10 #[serde(rename = "parentHash")]
12 pub parent_hash: H256,
13 #[serde(rename = "sha3Uncles")]
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 pub gas_limit: U256,
36 #[serde(rename = "baseFeePerGas", skip_serializing_if = "Option::is_none")]
38 pub base_fee_per_gas: Option<U256>,
39 #[serde(rename = "extraData")]
41 pub extra_data: Bytes,
42 #[serde(rename = "logsBloom")]
44 pub logs_bloom: H2048,
45 pub timestamp: U256,
47 pub difficulty: U256,
49 #[serde(rename = "mixHash")]
51 pub mix_hash: Option<H256>,
52 pub nonce: Option<H64>,
54}
55
56#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)]
59pub struct Block<TX> {
60 pub hash: Option<H256>,
62 #[serde(rename = "parentHash")]
64 pub parent_hash: H256,
65 #[serde(rename = "sha3Uncles")]
67 pub uncles_hash: H256,
68 #[serde(rename = "miner", default, deserialize_with = "null_to_default")]
70 pub author: H160,
71 #[serde(rename = "stateRoot")]
73 pub state_root: H256,
74 #[serde(rename = "transactionsRoot")]
76 pub transactions_root: H256,
77 #[serde(rename = "receiptsRoot")]
79 pub receipts_root: H256,
80 pub number: Option<U64>,
82 #[serde(rename = "gasUsed")]
84 pub gas_used: U256,
85 #[serde(rename = "gasLimit")]
87 pub gas_limit: U256,
88 #[serde(rename = "baseFeePerGas", skip_serializing_if = "Option::is_none")]
90 pub base_fee_per_gas: Option<U256>,
91 #[serde(rename = "extraData")]
93 pub extra_data: Bytes,
94 #[serde(rename = "logsBloom")]
96 pub logs_bloom: Option<H2048>,
97 pub timestamp: U256,
99 pub difficulty: U256,
101 #[serde(rename = "totalDifficulty")]
103 pub total_difficulty: Option<U256>,
104 #[serde(default, rename = "sealFields")]
106 pub seal_fields: Vec<Bytes>,
107 pub uncles: Vec<H256>,
109 pub transactions: Vec<TX>,
111 pub size: Option<U256>,
113 #[serde(rename = "mixHash")]
115 pub mix_hash: Option<H256>,
116 pub nonce: Option<H64>,
118}
119
120fn null_to_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
121where
122 T: Default + Deserialize<'de>,
123 D: Deserializer<'de>,
124{
125 let option = Option::deserialize(deserializer)?;
126 Ok(option.unwrap_or_default())
127}
128
129#[derive(Copy, Clone, Debug, PartialEq)]
131pub enum BlockNumber {
132 Latest,
134 Earliest,
136 Pending,
138 Number(U64),
140}
141
142impl<T: Into<U64>> From<T> for BlockNumber {
143 fn from(num: T) -> Self {
144 BlockNumber::Number(num.into())
145 }
146}
147
148impl Serialize for BlockNumber {
149 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
150 where
151 S: Serializer,
152 {
153 match *self {
154 BlockNumber::Number(ref x) => serializer.serialize_str(&format!("0x{:x}", x)),
155 BlockNumber::Latest => serializer.serialize_str("latest"),
156 BlockNumber::Earliest => serializer.serialize_str("earliest"),
157 BlockNumber::Pending => serializer.serialize_str("pending"),
158 }
159 }
160}
161
162impl<'a> Deserialize<'a> for BlockNumber {
163 fn deserialize<D>(deserializer: D) -> Result<BlockNumber, D::Error>
164 where
165 D: Deserializer<'a>,
166 {
167 let value = String::deserialize(deserializer)?;
168 match value.as_str() {
169 "latest" => Ok(BlockNumber::Latest),
170 "earliest" => Ok(BlockNumber::Earliest),
171 "pending" => Ok(BlockNumber::Pending),
172 _ if value.starts_with("0x") => U64::from_str_radix(&value[2..], 16)
173 .map(BlockNumber::Number)
174 .map_err(|e| D::Error::custom(format!("invalid block number: {}", e))),
175 _ => Err(D::Error::custom("invalid block number: missing 0x prefix".to_string())),
176 }
177 }
178}
179
180#[derive(Copy, Clone, Debug, PartialEq)]
182pub enum BlockId {
183 Hash(H256),
185 Number(BlockNumber),
187}
188
189impl Serialize for BlockId {
190 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
191 where
192 S: Serializer,
193 {
194 match *self {
195 BlockId::Hash(ref x) => {
196 let mut s = serializer.serialize_struct("BlockIdEip1898", 1)?;
197 s.serialize_field("blockHash", &format!("{:?}", x))?;
198 s.end()
199 }
200 BlockId::Number(ref num) => num.serialize(serializer),
201 }
202 }
203}
204
205impl From<U64> for BlockId {
206 fn from(num: U64) -> Self {
207 BlockNumber::Number(num).into()
208 }
209}
210
211impl From<BlockNumber> for BlockId {
212 fn from(num: BlockNumber) -> Self {
213 BlockId::Number(num)
214 }
215}
216
217impl From<H256> for BlockId {
218 fn from(hash: H256) -> Self {
219 BlockId::Hash(hash)
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226 use serde_json::Value;
227
228 #[test]
229 fn block_miner() {
230 let mut json = serde_json::json!(
231 {
232 "miner": "0x0000000000000000000000000000000000000001",
233 "number": "0x1b4",
234 "hash": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
235 "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
236 "mixHash": "0x1010101010101010101010101010101010101010101010101010101010101010",
237 "nonce": "0x0000000000000000",
238 "sealFields": [
239 "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
240 "0x0000000000000042"
241 ],
242 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
243 "logsBloom": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
244 "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
245 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
246 "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
247 "difficulty": "0x27f07",
248 "totalDifficulty": "0x27f07",
249 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
250 "size": "0x27f07",
251 "gasLimit": "0x9f759",
252 "minGasPrice": "0x9f759",
253 "gasUsed": "0x9f759",
254 "timestamp": "0x54e34e8e",
255 "transactions": [],
256 "uncles": []
257 }
258 );
259
260 let block: Block<()> = serde_json::from_value(json.clone()).unwrap();
261 assert_eq!(block.author, H160::from_low_u64_be(1));
262 assert!(block.base_fee_per_gas.is_none());
263
264 json.as_object_mut().unwrap().insert("miner".to_string(), Value::Null);
268 let block: Block<()> = serde_json::from_value(json.clone()).unwrap();
269 assert_eq!(block.author, Default::default());
270
271 json.as_object_mut().unwrap().remove("miner");
273 let block: Block<()> = serde_json::from_value(json).unwrap();
274 assert_eq!(block.author, Default::default());
275 }
276
277 #[test]
278 fn post_london_block() {
279 let json = serde_json::json!(
280 {
281 "baseFeePerGas": "0x7",
282 "miner": "0x0000000000000000000000000000000000000001",
283 "number": "0x1b4",
284 "hash": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
285 "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
286 "mixHash": "0x1010101010101010101010101010101010101010101010101010101010101010",
287 "nonce": "0x0000000000000000",
288 "sealFields": [
289 "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
290 "0x0000000000000042"
291 ],
292 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
293 "logsBloom": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
294 "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
295 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
296 "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
297 "difficulty": "0x27f07",
298 "totalDifficulty": "0x27f07",
299 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
300 "size": "0x27f07",
301 "gasLimit": "0x9f759",
302 "minGasPrice": "0x9f759",
303 "gasUsed": "0x9f759",
304 "timestamp": "0x54e34e8e",
305 "transactions": [],
306 "uncles": []
307 }
308 );
309
310 let block: Block<()> = serde_json::from_value(json).unwrap();
311 assert_eq!(block.base_fee_per_gas, Some(U256::from(7)));
312 }
313
314 #[test]
315 fn serialize_deserialize_block_number() {
316 let serialized = serde_json::to_value(BlockNumber::Latest).unwrap();
318 assert_eq!(serialized, "latest");
319 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
320 assert_eq!(deserialized, BlockNumber::Latest);
321
322 let serialized = serde_json::to_value(BlockNumber::Earliest).unwrap();
324 assert_eq!(serialized, "earliest");
325 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
326 assert_eq!(deserialized, BlockNumber::Earliest);
327
328 let serialized = serde_json::to_value(BlockNumber::Pending).unwrap();
330 assert_eq!(serialized, "pending");
331 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
332 assert_eq!(deserialized, BlockNumber::Pending);
333
334 let serialized = serde_json::to_value(BlockNumber::Number(100.into())).unwrap();
336 assert_eq!(serialized, "0x64");
337 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
338 assert_eq!(deserialized, BlockNumber::Number(100.into()));
339 let deserialized = serde_json::from_value::<BlockNumber>("64".into());
340 assert_eq!(
341 deserialized.unwrap_err().to_string(),
342 "invalid block number: missing 0x prefix"
343 );
344 }
345}