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 pub uncles_hash: H256,
15 #[serde(rename = "miner", default, deserialize_with = "null_to_default")]
17 pub author: H160,
18 #[serde(rename = "stateRoot")]
20 pub state_root: H256,
21 #[serde(rename = "transactionsRoot")]
23 pub transactions_root: H256,
24 #[serde(rename = "receiptsRoot")]
26 pub receipts_root: H256,
27 pub number: Option<U64>,
29 #[serde(rename = "gasUsed")]
31 pub gas_used: U256,
32 #[serde(rename = "gasLimit")]
34 pub gas_limit: U256,
35 #[serde(rename = "baseFeePerGas", skip_serializing_if = "Option::is_none")]
37 pub base_fee_per_gas: Option<U256>,
38 #[serde(rename = "extraData")]
40 pub extra_data: Bytes,
41 #[serde(rename = "logsBloom")]
43 pub logs_bloom: H2048,
44 pub timestamp: U256,
46 pub difficulty: U256,
48 #[serde(rename = "mixHash")]
50 pub mix_hash: Option<H256>,
51 pub nonce: Option<H64>,
53}
54
55#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)]
58pub struct Block<TX> {
59 pub hash: Option<H256>,
61 #[serde(rename = "parentHash")]
63 pub parent_hash: H256,
64 #[serde(rename = "sha3Uncles")]
66 pub uncles_hash: H256,
67 #[serde(rename = "miner", default, deserialize_with = "null_to_default")]
69 pub author: H160,
70 #[serde(rename = "stateRoot")]
72 pub state_root: H256,
73 #[serde(rename = "transactionsRoot")]
75 pub transactions_root: H256,
76 #[serde(rename = "receiptsRoot")]
78 pub receipts_root: H256,
79 pub number: Option<U64>,
81 #[serde(rename = "gasUsed")]
83 pub gas_used: U256,
84 #[serde(rename = "gasLimit")]
86 pub gas_limit: U256,
87 #[serde(rename = "baseFeePerGas", skip_serializing_if = "Option::is_none")]
89 pub base_fee_per_gas: Option<U256>,
90 #[serde(rename = "extraData")]
92 pub extra_data: Bytes,
93 #[serde(rename = "logsBloom")]
95 pub logs_bloom: Option<H2048>,
96 pub timestamp: U256,
98 pub difficulty: U256,
100 #[serde(rename = "totalDifficulty")]
102 pub total_difficulty: Option<U256>,
103 #[serde(default, rename = "sealFields")]
105 pub seal_fields: Vec<Bytes>,
106 pub uncles: Vec<H256>,
108 pub transactions: Vec<TX>,
110 pub size: Option<U256>,
112 #[serde(rename = "mixHash")]
114 pub mix_hash: Option<H256>,
115 pub nonce: Option<H64>,
117}
118
119fn null_to_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
120where
121 T: Default + Deserialize<'de>,
122 D: Deserializer<'de>,
123{
124 let option = Option::deserialize(deserializer)?;
125 Ok(option.unwrap_or_default())
126}
127
128#[derive(Copy, Clone, Debug, PartialEq)]
130pub enum BlockNumber {
131 Latest,
133 Earliest,
135 Pending,
137 Number(U64),
139}
140
141impl<T: Into<U64>> From<T> for BlockNumber {
142 fn from(num: T) -> Self {
143 BlockNumber::Number(num.into())
144 }
145}
146
147impl Serialize for BlockNumber {
148 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
149 where
150 S: Serializer,
151 {
152 match *self {
153 BlockNumber::Number(ref x) => serializer.serialize_str(&format!("0x{:x}", x)),
154 BlockNumber::Latest => serializer.serialize_str("latest"),
155 BlockNumber::Earliest => serializer.serialize_str("earliest"),
156 BlockNumber::Pending => serializer.serialize_str("pending"),
157 }
158 }
159}
160
161impl<'a> Deserialize<'a> for BlockNumber {
162 fn deserialize<D>(deserializer: D) -> Result<BlockNumber, D::Error>
163 where
164 D: Deserializer<'a>,
165 {
166 let value = String::deserialize(deserializer)?;
167 match value.as_str() {
168 "latest" => Ok(BlockNumber::Latest),
169 "earliest" => Ok(BlockNumber::Earliest),
170 "pending" => Ok(BlockNumber::Pending),
171 _ if value.starts_with("0x") => U64::from_str_radix(&value[2..], 16)
172 .map(BlockNumber::Number)
173 .map_err(|e| D::Error::custom(format!("invalid block number: {}", e))),
174 _ => Err(D::Error::custom("invalid block number: missing 0x prefix".to_string())),
175 }
176 }
177}
178
179#[derive(Copy, Clone, Debug, PartialEq)]
181pub enum BlockId {
182 Hash(H256),
184 Number(BlockNumber),
186}
187
188impl Serialize for BlockId {
189 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
190 where
191 S: Serializer,
192 {
193 match *self {
194 BlockId::Hash(ref x) => {
195 let mut s = serializer.serialize_struct("BlockIdEip1898", 1)?;
196 s.serialize_field("blockHash", &format!("{:?}", x))?;
197 s.end()
198 }
199 BlockId::Number(ref num) => num.serialize(serializer),
200 }
201 }
202}
203
204impl From<U64> for BlockId {
205 fn from(num: U64) -> Self {
206 BlockNumber::Number(num).into()
207 }
208}
209
210impl From<BlockNumber> for BlockId {
211 fn from(num: BlockNumber) -> Self {
212 BlockId::Number(num)
213 }
214}
215
216impl From<H256> for BlockId {
217 fn from(hash: H256) -> Self {
218 BlockId::Hash(hash)
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225 use serde_json::Value;
226
227 #[test]
228 fn block_miner() {
229 let mut json = serde_json::json!(
230 {
231 "miner": "0x0000000000000000000000000000000000000001",
232 "number": "0x1b4",
233 "hash": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
234 "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
235 "mixHash": "0x1010101010101010101010101010101010101010101010101010101010101010",
236 "nonce": "0x0000000000000000",
237 "sealFields": [
238 "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
239 "0x0000000000000042"
240 ],
241 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
242 "logsBloom": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
243 "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
244 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
245 "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
246 "difficulty": "0x27f07",
247 "totalDifficulty": "0x27f07",
248 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
249 "size": "0x27f07",
250 "gasLimit": "0x9f759",
251 "minGasPrice": "0x9f759",
252 "gasUsed": "0x9f759",
253 "timestamp": "0x54e34e8e",
254 "transactions": [],
255 "uncles": []
256 }
257 );
258
259 let block: Block<()> = serde_json::from_value(json.clone()).unwrap();
260 assert_eq!(block.author, H160::from_low_u64_be(1));
261 assert!(block.base_fee_per_gas.is_none());
262
263 json.as_object_mut().unwrap().insert("miner".to_string(), Value::Null);
267 let block: Block<()> = serde_json::from_value(json.clone()).unwrap();
268 assert_eq!(block.author, Default::default());
269
270 json.as_object_mut().unwrap().remove("miner");
272 let block: Block<()> = serde_json::from_value(json).unwrap();
273 assert_eq!(block.author, Default::default());
274 }
275
276 #[test]
277 fn post_london_block() {
278 let json = serde_json::json!(
279 {
280 "baseFeePerGas": "0x7",
281 "miner": "0x0000000000000000000000000000000000000001",
282 "number": "0x1b4",
283 "hash": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
284 "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
285 "mixHash": "0x1010101010101010101010101010101010101010101010101010101010101010",
286 "nonce": "0x0000000000000000",
287 "sealFields": [
288 "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
289 "0x0000000000000042"
290 ],
291 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
292 "logsBloom": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
293 "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
294 "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
295 "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
296 "difficulty": "0x27f07",
297 "totalDifficulty": "0x27f07",
298 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
299 "size": "0x27f07",
300 "gasLimit": "0x9f759",
301 "minGasPrice": "0x9f759",
302 "gasUsed": "0x9f759",
303 "timestamp": "0x54e34e8e",
304 "transactions": [],
305 "uncles": []
306 }
307 );
308
309 let block: Block<()> = serde_json::from_value(json).unwrap();
310 assert_eq!(block.base_fee_per_gas, Some(U256::from(7)));
311 }
312
313 #[test]
314 fn serialize_deserialize_block_number() {
315 let serialized = serde_json::to_value(BlockNumber::Latest).unwrap();
317 assert_eq!(serialized, "latest");
318 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
319 assert_eq!(deserialized, BlockNumber::Latest);
320
321 let serialized = serde_json::to_value(BlockNumber::Earliest).unwrap();
323 assert_eq!(serialized, "earliest");
324 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
325 assert_eq!(deserialized, BlockNumber::Earliest);
326
327 let serialized = serde_json::to_value(BlockNumber::Pending).unwrap();
329 assert_eq!(serialized, "pending");
330 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
331 assert_eq!(deserialized, BlockNumber::Pending);
332
333 let serialized = serde_json::to_value(BlockNumber::Number(100.into())).unwrap();
335 assert_eq!(serialized, "0x64");
336 let deserialized = serde_json::from_value::<BlockNumber>(serialized).unwrap();
337 assert_eq!(deserialized, BlockNumber::Number(100.into()));
338 let deserialized = serde_json::from_value::<BlockNumber>("64".into());
339 assert_eq!(
340 deserialized.unwrap_err().to_string(),
341 "invalid block number: missing 0x prefix"
342 );
343 }
344}