1use alloy_consensus::{BlockHeader, Header};
2use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
3
4#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
7#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
10pub struct AnyHeader {
11 pub parent_hash: B256,
13 #[cfg_attr(feature = "serde", serde(rename = "sha3Uncles"))]
15 pub ommers_hash: B256,
16 #[cfg_attr(feature = "serde", serde(rename = "miner"))]
18 pub beneficiary: Address,
19 pub state_root: B256,
21 pub transactions_root: B256,
23 pub receipts_root: B256,
25 pub logs_bloom: Bloom,
27 pub difficulty: U256,
29 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
31 pub number: u64,
32 #[cfg_attr(feature = "serde", serde(default, with = "alloy_serde::quantity"))]
34 pub gas_limit: u64,
35 #[cfg_attr(feature = "serde", serde(default, with = "alloy_serde::quantity"))]
37 pub gas_used: u64,
38 #[cfg_attr(feature = "serde", serde(default, with = "alloy_serde::quantity"))]
40 pub timestamp: u64,
41 pub extra_data: Bytes,
43 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
55 pub mix_hash: Option<B256>,
56 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
58 pub nonce: Option<B64>,
59 #[cfg_attr(
61 feature = "serde",
62 serde(
63 default,
64 skip_serializing_if = "Option::is_none",
65 with = "alloy_serde::quantity::opt"
66 )
67 )]
68 pub base_fee_per_gas: Option<u64>,
69 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
71 pub withdrawals_root: Option<B256>,
72 #[cfg_attr(
74 feature = "serde",
75 serde(
76 default,
77 skip_serializing_if = "Option::is_none",
78 with = "alloy_serde::quantity::opt"
79 )
80 )]
81 pub blob_gas_used: Option<u64>,
82 #[cfg_attr(
84 feature = "serde",
85 serde(
86 default,
87 skip_serializing_if = "Option::is_none",
88 with = "alloy_serde::quantity::opt"
89 )
90 )]
91 pub excess_blob_gas: Option<u64>,
92 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
94 pub parent_beacon_block_root: Option<B256>,
95 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
97 pub requests_hash: Option<B256>,
98}
99
100impl AnyHeader {
101 pub fn try_into_header(self) -> Result<Header, Self> {
109 if self.nonce.is_none() || self.mix_hash.is_none() {
110 return Err(self);
111 }
112
113 let Self {
114 parent_hash,
115 ommers_hash,
116 beneficiary,
117 state_root,
118 transactions_root,
119 receipts_root,
120 logs_bloom,
121 difficulty,
122 number,
123 gas_limit,
124 gas_used,
125 timestamp,
126 extra_data,
127 mix_hash,
128 nonce,
129 base_fee_per_gas,
130 withdrawals_root,
131 blob_gas_used,
132 excess_blob_gas,
133 parent_beacon_block_root,
134 requests_hash,
135 } = self;
136
137 Ok(Header {
138 parent_hash,
139 ommers_hash,
140 beneficiary,
141 state_root,
142 transactions_root,
143 receipts_root,
144 logs_bloom,
145 difficulty,
146 number,
147 gas_limit,
148 gas_used,
149 timestamp,
150 extra_data,
151 mix_hash: mix_hash.unwrap(),
152 nonce: nonce.unwrap(),
153 base_fee_per_gas,
154 withdrawals_root,
155 blob_gas_used,
156 excess_blob_gas,
157 parent_beacon_block_root,
158 requests_hash,
159 })
160 }
161
162 pub fn into_header_with_defaults(self) -> Header {
166 let Self {
167 parent_hash,
168 ommers_hash,
169 beneficiary,
170 state_root,
171 transactions_root,
172 receipts_root,
173 logs_bloom,
174 difficulty,
175 number,
176 gas_limit,
177 gas_used,
178 timestamp,
179 extra_data,
180 mix_hash,
181 nonce,
182 base_fee_per_gas,
183 withdrawals_root,
184 blob_gas_used,
185 excess_blob_gas,
186 parent_beacon_block_root,
187 requests_hash,
188 } = self;
189
190 Header {
191 parent_hash,
192 ommers_hash,
193 beneficiary,
194 state_root,
195 transactions_root,
196 receipts_root,
197 logs_bloom,
198 difficulty,
199 number,
200 gas_limit,
201 gas_used,
202 timestamp,
203 extra_data,
204 mix_hash: mix_hash.unwrap_or_default(),
205 nonce: nonce.unwrap_or_default(),
206 base_fee_per_gas,
207 withdrawals_root,
208 blob_gas_used,
209 excess_blob_gas,
210 parent_beacon_block_root,
211 requests_hash,
212 }
213 }
214}
215
216impl BlockHeader for AnyHeader {
217 fn parent_hash(&self) -> B256 {
218 self.parent_hash
219 }
220
221 fn ommers_hash(&self) -> B256 {
222 self.ommers_hash
223 }
224
225 fn beneficiary(&self) -> Address {
226 self.beneficiary
227 }
228
229 fn state_root(&self) -> B256 {
230 self.state_root
231 }
232
233 fn transactions_root(&self) -> B256 {
234 self.transactions_root
235 }
236
237 fn receipts_root(&self) -> B256 {
238 self.receipts_root
239 }
240
241 fn withdrawals_root(&self) -> Option<B256> {
242 self.withdrawals_root
243 }
244
245 fn logs_bloom(&self) -> Bloom {
246 self.logs_bloom
247 }
248
249 fn difficulty(&self) -> U256 {
250 self.difficulty
251 }
252
253 fn number(&self) -> BlockNumber {
254 self.number
255 }
256
257 fn gas_limit(&self) -> u64 {
258 self.gas_limit
259 }
260
261 fn gas_used(&self) -> u64 {
262 self.gas_used
263 }
264
265 fn timestamp(&self) -> u64 {
266 self.timestamp
267 }
268
269 fn mix_hash(&self) -> Option<B256> {
270 self.mix_hash
271 }
272
273 fn nonce(&self) -> Option<B64> {
274 self.nonce
275 }
276
277 fn base_fee_per_gas(&self) -> Option<u64> {
278 self.base_fee_per_gas
279 }
280
281 fn blob_gas_used(&self) -> Option<u64> {
282 self.blob_gas_used
283 }
284
285 fn excess_blob_gas(&self) -> Option<u64> {
286 self.excess_blob_gas
287 }
288
289 fn parent_beacon_block_root(&self) -> Option<B256> {
290 self.parent_beacon_block_root
291 }
292
293 fn requests_hash(&self) -> Option<B256> {
294 self.requests_hash
295 }
296
297 fn extra_data(&self) -> &Bytes {
298 &self.extra_data
299 }
300}
301
302impl From<Header> for AnyHeader {
303 fn from(value: Header) -> Self {
304 let Header {
305 parent_hash,
306 ommers_hash,
307 beneficiary,
308 state_root,
309 transactions_root,
310 receipts_root,
311 logs_bloom,
312 difficulty,
313 number,
314 gas_limit,
315 gas_used,
316 timestamp,
317 extra_data,
318 mix_hash,
319 nonce,
320 base_fee_per_gas,
321 withdrawals_root,
322 blob_gas_used,
323 excess_blob_gas,
324 parent_beacon_block_root,
325 requests_hash,
326 } = value;
327
328 Self {
329 parent_hash,
330 ommers_hash,
331 beneficiary,
332 state_root,
333 transactions_root,
334 receipts_root,
335 logs_bloom,
336 difficulty,
337 number,
338 gas_limit,
339 gas_used,
340 timestamp,
341 extra_data,
342 mix_hash: Some(mix_hash),
343 nonce: Some(nonce),
344 base_fee_per_gas,
345 withdrawals_root,
346 blob_gas_used,
347 excess_blob_gas,
348 parent_beacon_block_root,
349 requests_hash,
350 }
351 }
352}
353
354impl TryFrom<AnyHeader> for Header {
355 type Error = AnyHeader;
356
357 fn try_from(value: AnyHeader) -> Result<Self, Self::Error> {
358 value.try_into_header()
359 }
360}