Skip to main content

alloy_consensus/block/
header.rs

1use crate::{
2    block::{HeaderInfo, HeaderRoots},
3    constants::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH},
4    Block, BlockBody,
5};
6use alloc::vec::Vec;
7use alloy_eips::{
8    eip1559::{calc_next_block_base_fee, BaseFeeParams},
9    eip1898::BlockWithParent,
10    eip7840::BlobParams,
11    merge::ALLOWED_FUTURE_BLOCK_TIME_SECONDS,
12    BlockNumHash,
13};
14use alloy_primitives::{
15    keccak256, Address, BlockNumber, Bloom, Bytes, Sealable, Sealed, B256, B64, U256,
16};
17use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable};
18
19/// Ethereum Block header
20#[derive(Clone, Debug, PartialEq, Eq, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
23#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
24pub struct Header {
25    /// The Keccak 256-bit hash of the parent
26    /// block’s header, in its entirety; formally Hp.
27    pub parent_hash: B256,
28    /// The Keccak 256-bit hash of the ommers list portion of this block; formally Ho.
29    #[cfg_attr(feature = "serde", serde(rename = "sha3Uncles", alias = "ommersHash"))]
30    pub ommers_hash: B256,
31    /// The 160-bit address to which all fees collected from the successful mining of this block
32    /// be transferred; formally Hc.
33    #[cfg_attr(feature = "serde", serde(rename = "miner", alias = "beneficiary"))]
34    pub beneficiary: Address,
35    /// The Keccak 256-bit hash of the root node of the state trie, after all transactions are
36    /// executed and finalisations applied; formally Hr.
37    pub state_root: B256,
38    /// The Keccak 256-bit hash of the root node of the trie structure populated with each
39    /// transaction in the transactions list portion of the block; formally Ht.
40    pub transactions_root: B256,
41    /// The Keccak 256-bit hash of the root node of the trie structure populated with the receipts
42    /// of each transaction in the transactions list portion of the block; formally He.
43    pub receipts_root: B256,
44    /// The Bloom filter composed from indexable information (logger address and log topics)
45    /// contained in each log entry from the receipt of each transaction in the transactions list;
46    /// formally Hb.
47    pub logs_bloom: Bloom,
48    /// A scalar value corresponding to the difficulty level of this block. This can be calculated
49    /// from the previous block’s difficulty level and the timestamp; formally Hd.
50    pub difficulty: U256,
51    /// A scalar value equal to the number of ancestor blocks. The genesis block has a number of
52    /// zero; formally Hi.
53    #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
54    pub number: BlockNumber,
55    /// A scalar value equal to the current limit of gas expenditure per block; formally Hl.
56    #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
57    pub gas_limit: u64,
58    /// A scalar value equal to the total gas used in transactions in this block; formally Hg.
59    #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
60    pub gas_used: u64,
61    /// A scalar value equal to the reasonable output of Unix’s time() at this block’s inception;
62    /// formally Hs.
63    #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
64    pub timestamp: u64,
65    /// An arbitrary byte array containing data relevant to this block. This must be 32 bytes or
66    /// fewer; formally Hx.
67    pub extra_data: Bytes,
68    /// A 256-bit hash which, combined with the
69    /// nonce, proves that a sufficient amount of computation has been carried out on this block;
70    /// formally Hm.
71    pub mix_hash: B256,
72    /// A 64-bit value which, combined with the mixhash, proves that a sufficient amount of
73    /// computation has been carried out on this block; formally Hn.
74    pub nonce: B64,
75    /// A scalar representing EIP1559 base fee which can move up or down each block according
76    /// to a formula which is a function of gas used in parent block and gas target
77    /// (block gas limit divided by elasticity multiplier) of parent block.
78    /// The algorithm results in the base fee per gas increasing when blocks are
79    /// above the gas target, and decreasing when blocks are below the gas target. The base fee per
80    /// gas is burned.
81    #[cfg_attr(
82        feature = "serde",
83        serde(
84            default,
85            with = "alloy_serde::quantity::opt",
86            skip_serializing_if = "Option::is_none"
87        )
88    )]
89    pub base_fee_per_gas: Option<u64>,
90    /// The Keccak 256-bit hash of the withdrawals list portion of this block.
91    /// <https://eips.ethereum.org/EIPS/eip-4895>
92    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
93    pub withdrawals_root: Option<B256>,
94    /// The total amount of blob gas consumed by the transactions within the block, added in
95    /// EIP-4844.
96    #[cfg_attr(
97        feature = "serde",
98        serde(
99            default,
100            with = "alloy_serde::quantity::opt",
101            skip_serializing_if = "Option::is_none"
102        )
103    )]
104    pub blob_gas_used: Option<u64>,
105    /// A running total of blob gas consumed in excess of the target, prior to the block. Blocks
106    /// with above-target blob gas consumption increase this value, blocks with below-target blob
107    /// gas consumption decrease it (bounded at 0). This was added in EIP-4844.
108    #[cfg_attr(
109        feature = "serde",
110        serde(
111            default,
112            with = "alloy_serde::quantity::opt",
113            skip_serializing_if = "Option::is_none"
114        )
115    )]
116    pub excess_blob_gas: Option<u64>,
117    /// The hash of the parent beacon block's root is included in execution blocks, as proposed by
118    /// EIP-4788.
119    ///
120    /// This enables trust-minimized access to consensus state, supporting staking pools, bridges,
121    /// and more.
122    ///
123    /// The beacon roots contract handles root storage, enhancing Ethereum's functionalities.
124    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
125    pub parent_beacon_block_root: Option<B256>,
126    /// The Keccak 256-bit hash of the an RLP encoded list with each
127    /// [EIP-7685] request in the block body.
128    ///
129    /// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685
130    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
131    pub requests_hash: Option<B256>,
132}
133
134impl AsRef<Self> for Header {
135    fn as_ref(&self) -> &Self {
136        self
137    }
138}
139
140impl Default for Header {
141    fn default() -> Self {
142        Self {
143            parent_hash: Default::default(),
144            ommers_hash: EMPTY_OMMER_ROOT_HASH,
145            beneficiary: Default::default(),
146            state_root: EMPTY_ROOT_HASH,
147            transactions_root: EMPTY_ROOT_HASH,
148            receipts_root: EMPTY_ROOT_HASH,
149            logs_bloom: Default::default(),
150            difficulty: Default::default(),
151            number: 0,
152            gas_limit: 0,
153            gas_used: 0,
154            timestamp: 0,
155            extra_data: Default::default(),
156            mix_hash: Default::default(),
157            nonce: B64::ZERO,
158            base_fee_per_gas: None,
159            withdrawals_root: None,
160            blob_gas_used: None,
161            excess_blob_gas: None,
162            parent_beacon_block_root: None,
163            requests_hash: None,
164        }
165    }
166}
167
168impl Sealable for Header {
169    fn hash_slow(&self) -> B256 {
170        Self::hash_slow(self)
171    }
172}
173
174impl Header {
175    /// Create a [`Block`] from the body and its header.
176    pub const fn into_block<T>(self, body: BlockBody<T>) -> Block<T> {
177        body.into_block(self)
178    }
179
180    /// Heavy function that will calculate hash of data and will *not* save the change to metadata.
181    ///
182    /// Use [`Header::seal_slow`] and unlock if you need the hash to be persistent.
183    pub fn hash_slow(&self) -> B256 {
184        let mut out = Vec::<u8>::new();
185        self.encode(&mut out);
186        keccak256(&out)
187    }
188
189    /// Decodes the RLP-encoded header and computes the hash from the raw RLP bytes.
190    ///
191    /// This is more efficient than decoding and then re-encoding to compute the hash,
192    /// as it reuses the original RLP bytes for hashing.
193    pub fn decode_sealed(buf: &mut &[u8]) -> alloy_rlp::Result<Sealed<Self>> {
194        let start = *buf;
195        let header = Self::decode(buf)?;
196        let hash = keccak256(&start[..start.len() - buf.len()]);
197        Ok(header.seal_unchecked(hash))
198    }
199
200    /// Check if the ommers hash equals to empty hash list.
201    pub fn ommers_hash_is_empty(&self) -> bool {
202        self.ommers_hash == EMPTY_OMMER_ROOT_HASH
203    }
204
205    /// Check if the transaction root equals to empty root.
206    pub fn transaction_root_is_empty(&self) -> bool {
207        self.transactions_root == EMPTY_ROOT_HASH
208    }
209
210    /// Returns the blob fee for _this_ block according to the EIP-4844 spec.
211    ///
212    /// Returns `None` if `excess_blob_gas` is None
213    pub fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
214        Some(blob_params.calc_blob_fee(self.excess_blob_gas?))
215    }
216
217    /// Returns the blob fee for the next block according to the EIP-4844 spec.
218    ///
219    /// Returns `None` if `excess_blob_gas` is None.
220    ///
221    /// See also [Self::next_block_excess_blob_gas]
222    pub fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
223        Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
224    }
225
226    /// Calculate base fee for next block according to the EIP-1559 spec.
227    ///
228    /// Returns a `None` if no base fee is set, no EIP-1559 support
229    pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
230        Some(calc_next_block_base_fee(
231            self.gas_used,
232            self.gas_limit,
233            self.base_fee_per_gas?,
234            base_fee_params,
235        ))
236    }
237
238    /// Calculate excess blob gas for the next block according to the EIP-4844
239    /// spec.
240    ///
241    /// Returns `None` if `excess_blob_gas`, `blob_gas_used`, or `base_fee_per_gas` is not set.
242    pub fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
243        Some(blob_params.next_block_excess_blob_gas_osaka(
244            self.excess_blob_gas?,
245            self.blob_gas_used?,
246            self.base_fee_per_gas?,
247        ))
248    }
249
250    /// Calculate a heuristic for the in-memory size of the [Header].
251    #[inline]
252    pub fn size(&self) -> usize {
253        size_of::<Self>() + self.extra_data.len()
254    }
255
256    fn header_payload_length(&self) -> usize {
257        let mut length = 0;
258        length += self.parent_hash.length();
259        length += self.ommers_hash.length();
260        length += self.beneficiary.length();
261        length += self.state_root.length();
262        length += self.transactions_root.length();
263        length += self.receipts_root.length();
264        length += self.logs_bloom.length();
265        length += self.difficulty.length();
266        length += U256::from(self.number).length();
267        length += U256::from(self.gas_limit).length();
268        length += U256::from(self.gas_used).length();
269        length += self.timestamp.length();
270        length += self.extra_data.length();
271        length += self.mix_hash.length();
272        length += self.nonce.length();
273
274        if let Some(base_fee) = self.base_fee_per_gas {
275            // Adding base fee length if it exists.
276            length += U256::from(base_fee).length();
277        }
278
279        if let Some(root) = self.withdrawals_root {
280            // Adding withdrawals_root length if it exists.
281            length += root.length();
282        }
283
284        if let Some(blob_gas_used) = self.blob_gas_used {
285            // Adding blob_gas_used length if it exists.
286            length += U256::from(blob_gas_used).length();
287        }
288
289        if let Some(excess_blob_gas) = self.excess_blob_gas {
290            // Adding excess_blob_gas length if it exists.
291            length += U256::from(excess_blob_gas).length();
292        }
293
294        if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
295            length += parent_beacon_block_root.length();
296        }
297
298        if let Some(requests_hash) = self.requests_hash {
299            length += requests_hash.length();
300        }
301
302        length
303    }
304
305    /// Returns the parent block's number and hash
306    ///
307    /// Note: for the genesis block the parent number is 0 and the parent hash is the zero hash.
308    pub const fn parent_num_hash(&self) -> BlockNumHash {
309        BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
310    }
311
312    /// Returns the block's number and hash.
313    ///
314    /// Note: this hashes the header.
315    pub fn num_hash_slow(&self) -> BlockNumHash {
316        BlockNumHash { number: self.number, hash: self.hash_slow() }
317    }
318
319    /// Returns the block's number and hash with the parent hash.
320    ///
321    /// Note: this hashes the header.
322    pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
323        BlockWithParent::new(self.parent_hash, self.num_hash_slow())
324    }
325
326    /// Seal the header with a known hash.
327    ///
328    /// WARNING: This method does not perform validation whether the hash is correct.
329    #[inline]
330    pub const fn seal(self, hash: B256) -> Sealed<Self> {
331        Sealed::new_unchecked(self, hash)
332    }
333
334    /// True if the shanghai hardfork is active.
335    ///
336    /// This function checks that the withdrawals root field is present.
337    pub const fn shanghai_active(&self) -> bool {
338        self.withdrawals_root.is_some()
339    }
340
341    /// True if the Cancun hardfork is active.
342    ///
343    /// This function checks that the blob gas used field is present.
344    pub const fn cancun_active(&self) -> bool {
345        self.blob_gas_used.is_some()
346    }
347
348    /// True if the Prague hardfork is active.
349    ///
350    /// This function checks that the requests hash is present.
351    pub const fn prague_active(&self) -> bool {
352        self.requests_hash.is_some()
353    }
354}
355
356impl Encodable for Header {
357    fn encode(&self, out: &mut dyn BufMut) {
358        let list_header =
359            alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
360        list_header.encode(out);
361        self.parent_hash.encode(out);
362        self.ommers_hash.encode(out);
363        self.beneficiary.encode(out);
364        self.state_root.encode(out);
365        self.transactions_root.encode(out);
366        self.receipts_root.encode(out);
367        self.logs_bloom.encode(out);
368        self.difficulty.encode(out);
369        U256::from(self.number).encode(out);
370        U256::from(self.gas_limit).encode(out);
371        U256::from(self.gas_used).encode(out);
372        self.timestamp.encode(out);
373        self.extra_data.encode(out);
374        self.mix_hash.encode(out);
375        self.nonce.encode(out);
376
377        // Encode all the fork specific fields
378        if let Some(ref base_fee) = self.base_fee_per_gas {
379            U256::from(*base_fee).encode(out);
380        }
381
382        if let Some(ref root) = self.withdrawals_root {
383            root.encode(out);
384        }
385
386        if let Some(ref blob_gas_used) = self.blob_gas_used {
387            U256::from(*blob_gas_used).encode(out);
388        }
389
390        if let Some(ref excess_blob_gas) = self.excess_blob_gas {
391            U256::from(*excess_blob_gas).encode(out);
392        }
393
394        if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
395            parent_beacon_block_root.encode(out);
396        }
397
398        if let Some(ref requests_hash) = self.requests_hash {
399            requests_hash.encode(out);
400        }
401    }
402
403    fn length(&self) -> usize {
404        let mut length = 0;
405        length += self.header_payload_length();
406        length += length_of_length(length);
407        length
408    }
409}
410
411impl Decodable for Header {
412    fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
413        let rlp_head = alloy_rlp::Header::decode(buf)?;
414        if !rlp_head.list {
415            return Err(alloy_rlp::Error::UnexpectedString);
416        }
417        let started_len = buf.len();
418        let mut this = Self {
419            parent_hash: Decodable::decode(buf)?,
420            ommers_hash: Decodable::decode(buf)?,
421            beneficiary: Decodable::decode(buf)?,
422            state_root: Decodable::decode(buf)?,
423            transactions_root: Decodable::decode(buf)?,
424            receipts_root: Decodable::decode(buf)?,
425            logs_bloom: Decodable::decode(buf)?,
426            difficulty: Decodable::decode(buf)?,
427            number: u64::decode(buf)?,
428            gas_limit: u64::decode(buf)?,
429            gas_used: u64::decode(buf)?,
430            timestamp: Decodable::decode(buf)?,
431            extra_data: Decodable::decode(buf)?,
432            mix_hash: Decodable::decode(buf)?,
433            nonce: B64::decode(buf)?,
434            base_fee_per_gas: None,
435            withdrawals_root: None,
436            blob_gas_used: None,
437            excess_blob_gas: None,
438            parent_beacon_block_root: None,
439            requests_hash: None,
440        };
441        if started_len - buf.len() < rlp_head.payload_length {
442            this.base_fee_per_gas = Some(u64::decode(buf)?);
443        }
444
445        // Withdrawals root for post-shanghai headers
446        if started_len - buf.len() < rlp_head.payload_length {
447            this.withdrawals_root = Some(Decodable::decode(buf)?);
448        }
449
450        // Blob gas used and excess blob gas for post-cancun headers
451        if started_len - buf.len() < rlp_head.payload_length {
452            this.blob_gas_used = Some(u64::decode(buf)?);
453        }
454
455        if started_len - buf.len() < rlp_head.payload_length {
456            this.excess_blob_gas = Some(u64::decode(buf)?);
457        }
458
459        // Decode parent beacon block root.
460        if started_len - buf.len() < rlp_head.payload_length {
461            this.parent_beacon_block_root = Some(B256::decode(buf)?);
462        }
463
464        // Decode requests hash.
465        if started_len - buf.len() < rlp_head.payload_length {
466            this.requests_hash = Some(B256::decode(buf)?);
467        }
468
469        let consumed = started_len - buf.len();
470        if consumed != rlp_head.payload_length {
471            return Err(alloy_rlp::Error::ListLengthMismatch {
472                expected: rlp_head.payload_length,
473                got: consumed,
474            });
475        }
476        Ok(this)
477    }
478}
479
480#[cfg(any(test, feature = "arbitrary"))]
481impl<'a> arbitrary::Arbitrary<'a> for Header {
482    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
483        let is_prague = u.arbitrary::<bool>()?;
484        let is_cancun = is_prague || u.arbitrary::<bool>()?;
485        let is_shanghai = is_cancun || u.arbitrary::<bool>()?;
486        let is_london = is_shanghai || u.arbitrary::<bool>()?;
487
488        Ok(Self {
489            parent_hash: u.arbitrary()?,
490            ommers_hash: u.arbitrary()?,
491            beneficiary: u.arbitrary()?,
492            state_root: u.arbitrary()?,
493            transactions_root: u.arbitrary()?,
494            receipts_root: u.arbitrary()?,
495            logs_bloom: u.arbitrary()?,
496            difficulty: u.arbitrary()?,
497            number: u.arbitrary()?,
498            gas_limit: u.arbitrary()?,
499            gas_used: u.arbitrary()?,
500            timestamp: u.arbitrary()?,
501            extra_data: u.arbitrary()?,
502            mix_hash: u.arbitrary()?,
503            nonce: u.arbitrary()?,
504            base_fee_per_gas: if is_london { Some(u.arbitrary()?) } else { None },
505            withdrawals_root: if is_shanghai { Some(u.arbitrary()?) } else { None },
506            blob_gas_used: if is_cancun { Some(u.arbitrary()?) } else { None },
507            excess_blob_gas: if is_cancun { Some(u.arbitrary()?) } else { None },
508            parent_beacon_block_root: if is_cancun { Some(u.arbitrary()?) } else { None },
509            requests_hash: if is_prague { Some(u.arbitrary()?) } else { None },
510        })
511    }
512}
513
514/// Trait for extracting specific Ethereum block data from a header
515#[auto_impl::auto_impl(&, Arc)]
516pub trait BlockHeader {
517    /// Extracts essential information into one container type.
518    fn header_info(&self) -> HeaderInfo {
519        HeaderInfo {
520            number: self.number(),
521            beneficiary: self.beneficiary(),
522            timestamp: self.timestamp(),
523            gas_limit: self.gas_limit(),
524            base_fee_per_gas: self.base_fee_per_gas(),
525            excess_blob_gas: self.excess_blob_gas(),
526            blob_gas_used: self.blob_gas_used(),
527            difficulty: self.difficulty(),
528            mix_hash: self.mix_hash(),
529        }
530    }
531
532    /// Returns all roots contained in the header.
533    fn header_roots(&self) -> HeaderRoots {
534        HeaderRoots {
535            state_root: self.state_root(),
536            transactions_root: self.transactions_root(),
537            receipts_root: self.receipts_root(),
538            withdrawals_root: self.withdrawals_root(),
539            parent_beacon_block_root: self.parent_beacon_block_root(),
540            logs_bloom: self.logs_bloom(),
541        }
542    }
543
544    /// Retrieves the parent hash of the block
545    fn parent_hash(&self) -> B256;
546
547    /// Retrieves the ommers hash of the block
548    fn ommers_hash(&self) -> B256;
549
550    /// Retrieves the beneficiary (miner) of the block
551    fn beneficiary(&self) -> Address;
552
553    /// Retrieves the state root hash of the block
554    fn state_root(&self) -> B256;
555
556    /// Retrieves the transactions root hash of the block
557    fn transactions_root(&self) -> B256;
558
559    /// Retrieves the receipts root hash of the block
560    fn receipts_root(&self) -> B256;
561
562    /// Retrieves the withdrawals root hash of the block, if available
563    fn withdrawals_root(&self) -> Option<B256>;
564
565    /// Retrieves the logs bloom filter of the block
566    fn logs_bloom(&self) -> Bloom;
567
568    /// Retrieves the difficulty of the block
569    fn difficulty(&self) -> U256;
570
571    /// Retrieves the block number
572    fn number(&self) -> BlockNumber;
573
574    /// Retrieves the gas limit of the block
575    fn gas_limit(&self) -> u64;
576
577    /// Retrieves the gas used by the block
578    fn gas_used(&self) -> u64;
579
580    /// Retrieves the timestamp of the block
581    fn timestamp(&self) -> u64;
582
583    /// Retrieves the mix hash of the block, if available
584    fn mix_hash(&self) -> Option<B256>;
585
586    /// Retrieves the nonce of the block, if available
587    fn nonce(&self) -> Option<B64>;
588
589    /// Retrieves the base fee per gas of the block, if available
590    fn base_fee_per_gas(&self) -> Option<u64>;
591
592    /// Retrieves the blob gas used by the block, if available
593    fn blob_gas_used(&self) -> Option<u64>;
594
595    /// Retrieves the excess blob gas of the block, if available
596    fn excess_blob_gas(&self) -> Option<u64>;
597
598    /// Retrieves the parent beacon block root of the block, if available
599    fn parent_beacon_block_root(&self) -> Option<B256>;
600
601    /// Retrieves the requests hash of the block, if available
602    fn requests_hash(&self) -> Option<B256>;
603
604    /// Retrieves the block's extra data field
605    fn extra_data(&self) -> &Bytes;
606
607    /// Returns the blob fee for _this_ block according to the EIP-4844 spec.
608    ///
609    /// Returns `None` if `excess_blob_gas` is None
610    fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
611        Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
612    }
613
614    /// Calculate excess blob gas for the next block according to the EIP-4844
615    /// spec.
616    ///
617    /// Returns a `None` if no excess blob gas is set, no EIP-4844 support
618    fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
619        Some(blob_params.next_block_excess_blob_gas_osaka(
620            self.excess_blob_gas()?,
621            self.blob_gas_used()?,
622            self.base_fee_per_gas()?,
623        ))
624    }
625
626    /// Convenience function for [`Self::next_block_excess_blob_gas`] with an optional
627    /// [`BlobParams`] argument.
628    ///
629    /// Returns `None` if the `blob_params` are `None`.
630    fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
631        self.next_block_excess_blob_gas(blob_params?)
632    }
633
634    /// Returns the blob fee for the next block according to the EIP-4844 spec.
635    ///
636    /// Returns `None` if `excess_blob_gas` is None.
637    ///
638    /// See also [BlockHeader::next_block_excess_blob_gas]
639    fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
640        Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
641    }
642
643    /// Convenience function for [`Self::next_block_blob_fee`] with an optional [`BlobParams`]
644    /// argument.
645    ///
646    /// Returns `None` if the `blob_params` are `None`.
647    fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
648        self.next_block_blob_fee(blob_params?)
649    }
650
651    /// Calculate base fee for next block according to the EIP-1559 spec.
652    ///
653    /// Returns a `None` if no base fee is set, no EIP-1559 support
654    fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
655        Some(calc_next_block_base_fee(
656            self.gas_used(),
657            self.gas_limit(),
658            self.base_fee_per_gas()?,
659            base_fee_params,
660        ))
661    }
662
663    /// Returns the parent block's number and hash
664    ///
665    /// Note: for the genesis block the parent number is 0 and the parent hash is the zero hash.
666    fn parent_num_hash(&self) -> BlockNumHash {
667        BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
668    }
669
670    /// Checks if the header is considered empty - has no transactions, no ommers or withdrawals
671    fn is_empty(&self) -> bool {
672        let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
673            && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
674        self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
675            txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
676        })
677    }
678
679    /// Checks if the block's difficulty is set to zero, indicating a Proof-of-Stake header.
680    ///
681    /// This function is linked to EIP-3675, proposing the consensus upgrade to Proof-of-Stake:
682    /// [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0)
683    ///
684    /// Verifies whether, as per the EIP, the block's difficulty is updated to zero,
685    /// signifying the transition to a Proof-of-Stake mechanism.
686    ///
687    /// Returns `true` if the block's difficulty matches the constant zero set by the EIP.
688    fn is_zero_difficulty(&self) -> bool {
689        self.difficulty().is_zero()
690    }
691
692    /// Checks if the block's timestamp is in the future based on the present timestamp.
693    ///
694    /// Clock can drift but this can be consensus issue.
695    ///
696    /// Note: This check is relevant only pre-merge.
697    fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
698        self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
699    }
700
701    /// Checks if the nonce exists, and if it exists, if it's zero.
702    ///
703    /// If the nonce is `None`, then this returns `false`.
704    fn is_nonce_zero(&self) -> bool {
705        self.nonce().is_some_and(|nonce| nonce.is_zero())
706    }
707}
708
709impl BlockHeader for Header {
710    fn parent_hash(&self) -> B256 {
711        self.parent_hash
712    }
713
714    fn ommers_hash(&self) -> B256 {
715        self.ommers_hash
716    }
717
718    fn beneficiary(&self) -> Address {
719        self.beneficiary
720    }
721
722    fn state_root(&self) -> B256 {
723        self.state_root
724    }
725
726    fn transactions_root(&self) -> B256 {
727        self.transactions_root
728    }
729
730    fn receipts_root(&self) -> B256 {
731        self.receipts_root
732    }
733
734    fn withdrawals_root(&self) -> Option<B256> {
735        self.withdrawals_root
736    }
737
738    fn logs_bloom(&self) -> Bloom {
739        self.logs_bloom
740    }
741
742    fn difficulty(&self) -> U256 {
743        self.difficulty
744    }
745
746    fn number(&self) -> BlockNumber {
747        self.number
748    }
749
750    fn gas_limit(&self) -> u64 {
751        self.gas_limit
752    }
753
754    fn gas_used(&self) -> u64 {
755        self.gas_used
756    }
757
758    fn timestamp(&self) -> u64 {
759        self.timestamp
760    }
761
762    fn mix_hash(&self) -> Option<B256> {
763        Some(self.mix_hash)
764    }
765
766    fn nonce(&self) -> Option<B64> {
767        Some(self.nonce)
768    }
769
770    fn base_fee_per_gas(&self) -> Option<u64> {
771        self.base_fee_per_gas
772    }
773
774    fn blob_gas_used(&self) -> Option<u64> {
775        self.blob_gas_used
776    }
777
778    fn excess_blob_gas(&self) -> Option<u64> {
779        self.excess_blob_gas
780    }
781
782    fn parent_beacon_block_root(&self) -> Option<B256> {
783        self.parent_beacon_block_root
784    }
785
786    fn requests_hash(&self) -> Option<B256> {
787        self.requests_hash
788    }
789
790    fn extra_data(&self) -> &Bytes {
791        &self.extra_data
792    }
793}
794
795#[cfg(feature = "serde")]
796impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
797    fn parent_hash(&self) -> B256 {
798        self.inner.parent_hash()
799    }
800
801    fn ommers_hash(&self) -> B256 {
802        self.inner.ommers_hash()
803    }
804
805    fn beneficiary(&self) -> Address {
806        self.inner.beneficiary()
807    }
808
809    fn state_root(&self) -> B256 {
810        self.inner.state_root()
811    }
812
813    fn transactions_root(&self) -> B256 {
814        self.inner.transactions_root()
815    }
816
817    fn receipts_root(&self) -> B256 {
818        self.inner.receipts_root()
819    }
820
821    fn withdrawals_root(&self) -> Option<B256> {
822        self.inner.withdrawals_root()
823    }
824
825    fn logs_bloom(&self) -> Bloom {
826        self.inner.logs_bloom()
827    }
828
829    fn difficulty(&self) -> U256 {
830        self.inner.difficulty()
831    }
832
833    fn number(&self) -> u64 {
834        self.inner.number()
835    }
836
837    fn gas_limit(&self) -> u64 {
838        self.inner.gas_limit()
839    }
840
841    fn gas_used(&self) -> u64 {
842        self.inner.gas_used()
843    }
844
845    fn timestamp(&self) -> u64 {
846        self.inner.timestamp()
847    }
848
849    fn mix_hash(&self) -> Option<B256> {
850        self.inner.mix_hash()
851    }
852
853    fn nonce(&self) -> Option<B64> {
854        self.inner.nonce()
855    }
856
857    fn base_fee_per_gas(&self) -> Option<u64> {
858        self.inner.base_fee_per_gas()
859    }
860
861    fn blob_gas_used(&self) -> Option<u64> {
862        self.inner.blob_gas_used()
863    }
864
865    fn excess_blob_gas(&self) -> Option<u64> {
866        self.inner.excess_blob_gas()
867    }
868
869    fn parent_beacon_block_root(&self) -> Option<B256> {
870        self.inner.parent_beacon_block_root()
871    }
872
873    fn requests_hash(&self) -> Option<B256> {
874        self.inner.requests_hash()
875    }
876
877    fn extra_data(&self) -> &Bytes {
878        self.inner.extra_data()
879    }
880
881    fn is_empty(&self) -> bool {
882        self.inner.is_empty()
883    }
884}
885
886/// Bincode-compatible [`Header`] serde implementation.
887#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
888pub(crate) mod serde_bincode_compat {
889    use alloc::borrow::Cow;
890    use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
891    use serde::{Deserialize, Deserializer, Serialize, Serializer};
892    use serde_with::{DeserializeAs, SerializeAs};
893
894    /// Bincode-compatible [`super::Header`] serde implementation.
895    ///
896    /// Intended to use with the [`serde_with::serde_as`] macro in the following way:
897    /// ```rust
898    /// use alloy_consensus::{serde_bincode_compat, Header};
899    /// use serde::{Deserialize, Serialize};
900    /// use serde_with::serde_as;
901    ///
902    /// #[serde_as]
903    /// #[derive(Serialize, Deserialize)]
904    /// struct Data {
905    ///     #[serde_as(as = "serde_bincode_compat::Header")]
906    ///     header: Header,
907    /// }
908    /// ```
909    #[derive(Debug, Serialize, Deserialize)]
910    pub struct Header<'a> {
911        parent_hash: B256,
912        ommers_hash: B256,
913        beneficiary: Address,
914        state_root: B256,
915        transactions_root: B256,
916        receipts_root: B256,
917        #[serde(default)]
918        withdrawals_root: Option<B256>,
919        logs_bloom: Bloom,
920        difficulty: U256,
921        number: BlockNumber,
922        gas_limit: u64,
923        gas_used: u64,
924        timestamp: u64,
925        mix_hash: B256,
926        nonce: B64,
927        #[serde(default)]
928        base_fee_per_gas: Option<u64>,
929        #[serde(default)]
930        blob_gas_used: Option<u64>,
931        #[serde(default)]
932        excess_blob_gas: Option<u64>,
933        #[serde(default)]
934        parent_beacon_block_root: Option<B256>,
935        #[serde(default)]
936        requests_hash: Option<B256>,
937        extra_data: Cow<'a, Bytes>,
938    }
939
940    impl<'a> From<&'a super::Header> for Header<'a> {
941        fn from(value: &'a super::Header) -> Self {
942            Self {
943                parent_hash: value.parent_hash,
944                ommers_hash: value.ommers_hash,
945                beneficiary: value.beneficiary,
946                state_root: value.state_root,
947                transactions_root: value.transactions_root,
948                receipts_root: value.receipts_root,
949                withdrawals_root: value.withdrawals_root,
950                logs_bloom: value.logs_bloom,
951                difficulty: value.difficulty,
952                number: value.number,
953                gas_limit: value.gas_limit,
954                gas_used: value.gas_used,
955                timestamp: value.timestamp,
956                mix_hash: value.mix_hash,
957                nonce: value.nonce,
958                base_fee_per_gas: value.base_fee_per_gas,
959                blob_gas_used: value.blob_gas_used,
960                excess_blob_gas: value.excess_blob_gas,
961                parent_beacon_block_root: value.parent_beacon_block_root,
962                requests_hash: value.requests_hash,
963                extra_data: Cow::Borrowed(&value.extra_data),
964            }
965        }
966    }
967
968    impl<'a> From<Header<'a>> for super::Header {
969        fn from(value: Header<'a>) -> Self {
970            Self {
971                parent_hash: value.parent_hash,
972                ommers_hash: value.ommers_hash,
973                beneficiary: value.beneficiary,
974                state_root: value.state_root,
975                transactions_root: value.transactions_root,
976                receipts_root: value.receipts_root,
977                withdrawals_root: value.withdrawals_root,
978                logs_bloom: value.logs_bloom,
979                difficulty: value.difficulty,
980                number: value.number,
981                gas_limit: value.gas_limit,
982                gas_used: value.gas_used,
983                timestamp: value.timestamp,
984                mix_hash: value.mix_hash,
985                nonce: value.nonce,
986                base_fee_per_gas: value.base_fee_per_gas,
987                blob_gas_used: value.blob_gas_used,
988                excess_blob_gas: value.excess_blob_gas,
989                parent_beacon_block_root: value.parent_beacon_block_root,
990                requests_hash: value.requests_hash,
991                extra_data: value.extra_data.into_owned(),
992            }
993        }
994    }
995
996    impl SerializeAs<super::Header> for Header<'_> {
997        fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
998        where
999            S: Serializer,
1000        {
1001            Header::from(source).serialize(serializer)
1002        }
1003    }
1004
1005    impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1006        fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1007        where
1008            D: Deserializer<'de>,
1009        {
1010            Header::deserialize(deserializer).map(Into::into)
1011        }
1012    }
1013
1014    #[cfg(test)]
1015    mod tests {
1016        use super::super::{serde_bincode_compat, Header};
1017        use arbitrary::Arbitrary;
1018        use bincode::config;
1019        use rand::Rng;
1020        use serde::{Deserialize, Serialize};
1021        use serde_with::serde_as;
1022
1023        #[test]
1024        fn test_header_bincode_roundtrip() {
1025            #[serde_as]
1026            #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1027            struct Data {
1028                #[serde_as(as = "serde_bincode_compat::Header")]
1029                header: Header,
1030            }
1031
1032            let mut bytes = [0u8; 1024];
1033            rand::thread_rng().fill(bytes.as_mut_slice());
1034            let data = Data {
1035                header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1036            };
1037
1038            let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
1039            let (decoded, _) =
1040                bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
1041            assert_eq!(decoded, data);
1042        }
1043    }
1044}
1045
1046#[cfg(test)]
1047mod tests {
1048    use super::*;
1049    use alloy_primitives::{b256, hex};
1050
1051    #[test]
1052    fn decode_header_rlp() {
1053        // ronin header
1054        let raw = hex!("0xf90212a00d84d79f59fc384a1f6402609a5b7253b4bfe7a4ae12608ed107273e5422b6dda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479471562b71999873db5b286df957af199ec94617f7a0f496f3d199c51a1aaee67dac95f24d92ac13c60d25181e1eecd6eca5ddf32ac0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808206a4840365908a808468e975f09ad983011003846765746888676f312e32352e308664617277696ea06f485a167165ec12e0ab3e6ab59a7b88560b90306ac98a26eb294abf95a8c59b88000000000000000007");
1055        let header = Header::decode(&mut raw.as_slice()).unwrap();
1056        assert_eq!(
1057            header.hash_slow(),
1058            b256!("0x4f05e4392969fc82e41f6d6a8cea379323b0b2d3ddf7def1a33eec03883e3a33")
1059        );
1060    }
1061}
1062
1063#[cfg(all(test, feature = "serde"))]
1064mod serde_tests {
1065    use super::*;
1066    use alloy_primitives::b256;
1067
1068    #[test]
1069    fn test_header_serde_json_roundtrip() {
1070        let raw = r#"{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x0","gasUsed":"0x0","timestamp":"0x0","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1","withdrawalsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"}"#;
1071        let header = Header {
1072            base_fee_per_gas: Some(1),
1073            withdrawals_root: Some(EMPTY_ROOT_HASH),
1074            ..Default::default()
1075        };
1076
1077        let encoded = serde_json::to_string(&header).unwrap();
1078        assert_eq!(encoded, raw);
1079
1080        let decoded: Header = serde_json::from_str(&encoded).unwrap();
1081        assert_eq!(decoded, header);
1082
1083        // Create a vector to store the encoded RLP
1084        let mut encoded_rlp = Vec::new();
1085
1086        // Encode the header data
1087        decoded.encode(&mut encoded_rlp);
1088
1089        // Decode the RLP data
1090        let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1091
1092        // Check that the decoded RLP data matches the original header data
1093        assert_eq!(decoded_rlp, decoded);
1094    }
1095
1096    #[test]
1097    fn serde_rlp_prague() {
1098        // Note: Some fields are renamed from eth_getHeaderByHash
1099        let raw = r#"{"baseFeePerGas":"0x7","blobGasUsed":"0x20000","difficulty":"0x0","excessBlobGas":"0x40000","extraData":"0xd883010e0c846765746888676f312e32332e32856c696e7578","gasLimit":"0x1c9c380","gasUsed":"0x5208","hash":"0x661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xf97e180c050e5ab072211ad2c213eb5aee4df134","mixHash":"0xe6d9c084dd36560520d5776a5387a82fb44793c9cd1b69afb61d53af29ee64b0","nonce":"0x0000000000000000","number":"0x315","parentBeaconBlockRoot":"0xd0bdb48ab45028568e66c8ddd600ac4c2a52522714bbfbf00ea6d20ba40f3ae2","parentHash":"0x60f1563d2c572116091a4b91421d8d972118e39604d23455d841f9431cea4b6a","receiptsRoot":"0xeaa8c40899a61ae59615cf9985f5e2194f8fd2b57d273be63bde6733e89b12ab","requestsHash":"0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","stateRoot":"0x8101d88f2761eb9849634740f92fe09735551ad5a4d5e9da9bcae1ef4726a475","timestamp":"0x6712ba6e","transactionsRoot":"0xf543eb3d405d2d6320344d348b06703ff1abeef71288181a24061e53f89bb5ef","withdrawalsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"}
1100"#;
1101        let header = serde_json::from_str::<Header>(raw).unwrap();
1102        let hash = header.hash_slow();
1103        assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1104        let mut v = Vec::new();
1105        header.encode(&mut v);
1106        let decoded = Header::decode(&mut v.as_slice()).unwrap();
1107        assert_eq!(decoded, header);
1108    }
1109}