alloy_consensus_any/block/
header.rs

1use alloy_consensus::{BlockHeader, Header};
2use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
3
4/// Block header representation with certain fields made optional to account for possible
5/// differences in network implementations.
6#[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    /// Hash of the parent
12    pub parent_hash: B256,
13    /// Hash of the uncles
14    #[cfg_attr(feature = "serde", serde(rename = "sha3Uncles"))]
15    pub ommers_hash: B256,
16    /// Alias of `author`
17    #[cfg_attr(feature = "serde", serde(rename = "miner"))]
18    pub beneficiary: Address,
19    /// State root hash
20    pub state_root: B256,
21    /// Transactions root hash
22    pub transactions_root: B256,
23    /// Transactions receipts root hash
24    pub receipts_root: B256,
25    /// Logs bloom
26    pub logs_bloom: Bloom,
27    /// Difficulty
28    pub difficulty: U256,
29    /// Block number
30    #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
31    pub number: u64,
32    /// Gas Limit
33    #[cfg_attr(feature = "serde", serde(default, with = "alloy_serde::quantity"))]
34    pub gas_limit: u64,
35    /// Gas Used
36    #[cfg_attr(feature = "serde", serde(default, with = "alloy_serde::quantity"))]
37    pub gas_used: u64,
38    /// Timestamp
39    #[cfg_attr(feature = "serde", serde(default, with = "alloy_serde::quantity"))]
40    pub timestamp: u64,
41    /// Extra data
42    pub extra_data: Bytes,
43    /// Mix Hash
44    ///
45    /// Before the merge this proves, combined with the nonce, that a sufficient amount of
46    /// computation has been carried out on this block: the Proof-of-Work (PoW).
47    ///
48    /// After the merge this is `prevRandao`: Randomness value for the generated payload.
49    ///
50    /// This is an Option because it is not always set by non-ethereum networks.
51    ///
52    /// See also <https://eips.ethereum.org/EIPS/eip-4399>
53    /// And <https://github.com/ethereum/execution-apis/issues/328>
54    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
55    pub mix_hash: Option<B256>,
56    /// Nonce
57    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
58    pub nonce: Option<B64>,
59    /// Base fee per unit of gas (if past London)
60    #[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    /// Withdrawals root hash added by EIP-4895 and is ignored in legacy headers.
70    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
71    pub withdrawals_root: Option<B256>,
72    /// Blob gas used
73    #[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    /// Excess blob gas
83    #[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    /// EIP-4788 parent beacon block root
93    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
94    pub parent_beacon_block_root: Option<B256>,
95    /// EIP-7685 requests hash.
96    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
97    pub requests_hash: Option<B256>,
98}
99
100impl AnyHeader {
101    /// Attempts to convert this header into a `Header`.
102    ///
103    /// This can fail if the header is missing required fields:
104    /// - nonce
105    /// - mix_hash
106    ///
107    /// If the conversion fails, the original [`AnyHeader`] is returned.
108    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    /// Converts this header into a [`Header`] with default values for missing mandatory fields:
163    /// - mix_hash
164    /// - nonce
165    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}