alloy_consensus/block/
header.rs

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