alloy_consensus/block/
header.rs

1use crate::{
2    block::HeaderInfo,
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};
18use core::mem;
19
20/// Ethereum Block header
21#[derive(Clone, Debug, PartialEq, Eq, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
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()
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    /// Check if the ommers hash equals to empty hash list.
190    pub fn ommers_hash_is_empty(&self) -> bool {
191        self.ommers_hash == EMPTY_OMMER_ROOT_HASH
192    }
193
194    /// Check if the transaction root equals to empty root.
195    pub fn transaction_root_is_empty(&self) -> bool {
196        self.transactions_root == EMPTY_ROOT_HASH
197    }
198
199    /// Returns the blob fee for _this_ block according to the EIP-4844 spec.
200    ///
201    /// Returns `None` if `excess_blob_gas` is None
202    pub fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
203        Some(blob_params.calc_blob_fee(self.excess_blob_gas?))
204    }
205
206    /// Returns the blob fee for the next block according to the EIP-4844 spec.
207    ///
208    /// Returns `None` if `excess_blob_gas` is None.
209    ///
210    /// See also [Self::next_block_excess_blob_gas]
211    pub fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
212        Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
213    }
214
215    /// Calculate base fee for next block according to the EIP-1559 spec.
216    ///
217    /// Returns a `None` if no base fee is set, no EIP-1559 support
218    pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
219        Some(calc_next_block_base_fee(
220            self.gas_used,
221            self.gas_limit,
222            self.base_fee_per_gas?,
223            base_fee_params,
224        ))
225    }
226
227    /// Calculate excess blob gas for the next block according to the EIP-4844
228    /// spec.
229    ///
230    /// Returns a `None` if no excess blob gas is set, no EIP-4844 support
231    pub fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
232        Some(blob_params.next_block_excess_blob_gas_osaka(
233            self.excess_blob_gas?,
234            self.blob_gas_used?,
235            self.base_fee_per_gas?,
236        ))
237    }
238
239    /// Calculate a heuristic for the in-memory size of the [Header].
240    #[inline]
241    pub fn size(&self) -> usize {
242        mem::size_of::<B256>() + // parent hash
243        mem::size_of::<B256>() + // ommers hash
244        mem::size_of::<Address>() + // beneficiary
245        mem::size_of::<B256>() + // state root
246        mem::size_of::<B256>() + // transactions root
247        mem::size_of::<B256>() + // receipts root
248        mem::size_of::<Option<B256>>() + // withdrawals root
249        mem::size_of::<Bloom>() + // logs bloom
250        mem::size_of::<U256>() + // difficulty
251        mem::size_of::<BlockNumber>() + // number
252        mem::size_of::<u128>() + // gas limit
253        mem::size_of::<u128>() + // gas used
254        mem::size_of::<u64>() + // timestamp
255        mem::size_of::<B256>() + // mix hash
256        mem::size_of::<u64>() + // nonce
257        mem::size_of::<Option<u128>>() + // base fee per gas
258        mem::size_of::<Option<u128>>() + // blob gas used
259        mem::size_of::<Option<u128>>() + // excess blob gas
260        mem::size_of::<Option<B256>>() + // parent beacon block root
261        mem::size_of::<Option<B256>>() + // requests root
262        self.extra_data.len() // extra data
263    }
264
265    fn header_payload_length(&self) -> usize {
266        let mut length = 0;
267        length += self.parent_hash.length();
268        length += self.ommers_hash.length();
269        length += self.beneficiary.length();
270        length += self.state_root.length();
271        length += self.transactions_root.length();
272        length += self.receipts_root.length();
273        length += self.logs_bloom.length();
274        length += self.difficulty.length();
275        length += U256::from(self.number).length();
276        length += U256::from(self.gas_limit).length();
277        length += U256::from(self.gas_used).length();
278        length += self.timestamp.length();
279        length += self.extra_data.length();
280        length += self.mix_hash.length();
281        length += self.nonce.length();
282
283        if let Some(base_fee) = self.base_fee_per_gas {
284            // Adding base fee length if it exists.
285            length += U256::from(base_fee).length();
286        }
287
288        if let Some(root) = self.withdrawals_root {
289            // Adding withdrawals_root length if it exists.
290            length += root.length();
291        }
292
293        if let Some(blob_gas_used) = self.blob_gas_used {
294            // Adding blob_gas_used length if it exists.
295            length += U256::from(blob_gas_used).length();
296        }
297
298        if let Some(excess_blob_gas) = self.excess_blob_gas {
299            // Adding excess_blob_gas length if it exists.
300            length += U256::from(excess_blob_gas).length();
301        }
302
303        if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
304            length += parent_beacon_block_root.length();
305        }
306
307        if let Some(requests_hash) = self.requests_hash {
308            length += requests_hash.length();
309        }
310
311        length
312    }
313
314    /// Returns the parent block's number and hash
315    ///
316    /// Note: for the genesis block the parent number is 0 and the parent hash is the zero hash.
317    pub const fn parent_num_hash(&self) -> BlockNumHash {
318        BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
319    }
320
321    /// Returns the block's number and hash.
322    ///
323    /// Note: this hashes the header.
324    pub fn num_hash_slow(&self) -> BlockNumHash {
325        BlockNumHash { number: self.number, hash: self.hash_slow() }
326    }
327
328    /// Returns the block's number and hash with the parent hash.
329    ///
330    /// Note: this hashes the header.
331    pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
332        BlockWithParent::new(self.parent_hash, self.num_hash_slow())
333    }
334
335    /// Seal the header with a known hash.
336    ///
337    /// WARNING: This method does not perform validation whether the hash is correct.
338    #[inline]
339    pub const fn seal(self, hash: B256) -> Sealed<Self> {
340        Sealed::new_unchecked(self, hash)
341    }
342
343    /// True if the shanghai hardfork is active.
344    ///
345    /// This function checks that the withdrawals root field is present.
346    pub const fn shanghai_active(&self) -> bool {
347        self.withdrawals_root.is_some()
348    }
349
350    /// True if the Cancun hardfork is active.
351    ///
352    /// This function checks that the blob gas used field is present.
353    pub const fn cancun_active(&self) -> bool {
354        self.blob_gas_used.is_some()
355    }
356
357    /// True if the Prague hardfork is active.
358    ///
359    /// This function checks that the requests hash is present.
360    pub const fn prague_active(&self) -> bool {
361        self.requests_hash.is_some()
362    }
363}
364
365impl Encodable for Header {
366    fn encode(&self, out: &mut dyn BufMut) {
367        let list_header =
368            alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
369        list_header.encode(out);
370        self.parent_hash.encode(out);
371        self.ommers_hash.encode(out);
372        self.beneficiary.encode(out);
373        self.state_root.encode(out);
374        self.transactions_root.encode(out);
375        self.receipts_root.encode(out);
376        self.logs_bloom.encode(out);
377        self.difficulty.encode(out);
378        U256::from(self.number).encode(out);
379        U256::from(self.gas_limit).encode(out);
380        U256::from(self.gas_used).encode(out);
381        self.timestamp.encode(out);
382        self.extra_data.encode(out);
383        self.mix_hash.encode(out);
384        self.nonce.encode(out);
385
386        // Encode all the fork specific fields
387        if let Some(ref base_fee) = self.base_fee_per_gas {
388            U256::from(*base_fee).encode(out);
389        }
390
391        if let Some(ref root) = self.withdrawals_root {
392            root.encode(out);
393        }
394
395        if let Some(ref blob_gas_used) = self.blob_gas_used {
396            U256::from(*blob_gas_used).encode(out);
397        }
398
399        if let Some(ref excess_blob_gas) = self.excess_blob_gas {
400            U256::from(*excess_blob_gas).encode(out);
401        }
402
403        if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
404            parent_beacon_block_root.encode(out);
405        }
406
407        if let Some(ref requests_hash) = self.requests_hash {
408            requests_hash.encode(out);
409        }
410    }
411
412    fn length(&self) -> usize {
413        let mut length = 0;
414        length += self.header_payload_length();
415        length += length_of_length(length);
416        length
417    }
418}
419
420impl Decodable for Header {
421    fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
422        let rlp_head = alloy_rlp::Header::decode(buf)?;
423        if !rlp_head.list {
424            return Err(alloy_rlp::Error::UnexpectedString);
425        }
426        let started_len = buf.len();
427        let mut this = Self {
428            parent_hash: Decodable::decode(buf)?,
429            ommers_hash: Decodable::decode(buf)?,
430            beneficiary: Decodable::decode(buf)?,
431            state_root: Decodable::decode(buf)?,
432            transactions_root: Decodable::decode(buf)?,
433            receipts_root: Decodable::decode(buf)?,
434            logs_bloom: Decodable::decode(buf)?,
435            difficulty: Decodable::decode(buf)?,
436            number: u64::decode(buf)?,
437            gas_limit: u64::decode(buf)?,
438            gas_used: u64::decode(buf)?,
439            timestamp: Decodable::decode(buf)?,
440            extra_data: Decodable::decode(buf)?,
441            mix_hash: Decodable::decode(buf)?,
442            nonce: B64::decode(buf)?,
443            base_fee_per_gas: None,
444            withdrawals_root: None,
445            blob_gas_used: None,
446            excess_blob_gas: None,
447            parent_beacon_block_root: None,
448            requests_hash: None,
449        };
450        if started_len - buf.len() < rlp_head.payload_length {
451            this.base_fee_per_gas = Some(u64::decode(buf)?);
452        }
453
454        // Withdrawals root for post-shanghai headers
455        if started_len - buf.len() < rlp_head.payload_length {
456            this.withdrawals_root = Some(Decodable::decode(buf)?);
457        }
458
459        // Blob gas used and excess blob gas for post-cancun headers
460        if started_len - buf.len() < rlp_head.payload_length {
461            this.blob_gas_used = Some(u64::decode(buf)?);
462        }
463
464        if started_len - buf.len() < rlp_head.payload_length {
465            this.excess_blob_gas = Some(u64::decode(buf)?);
466        }
467
468        // Decode parent beacon block root.
469        if started_len - buf.len() < rlp_head.payload_length {
470            this.parent_beacon_block_root = Some(B256::decode(buf)?);
471        }
472
473        // Decode requests hash.
474        if started_len - buf.len() < rlp_head.payload_length {
475            this.requests_hash = Some(B256::decode(buf)?);
476        }
477
478        let consumed = started_len - buf.len();
479        if consumed != rlp_head.payload_length {
480            return Err(alloy_rlp::Error::ListLengthMismatch {
481                expected: rlp_head.payload_length,
482                got: consumed,
483            });
484        }
485        Ok(this)
486    }
487}
488
489/// Generates a header which is valid __with respect to past and future forks__. This means, for
490/// example, that if the withdrawals root is present, the base fee per gas is also present.
491///
492/// If blob gas used were present, then the excess blob gas and parent beacon block root are also
493/// present. In this example, the withdrawals root would also be present.
494///
495/// This __does not, and should not guarantee__ that the header is valid with respect to __anything
496/// else__.
497#[cfg(any(test, feature = "arbitrary"))]
498pub(crate) const fn generate_valid_header(
499    mut header: Header,
500    eip_4844_active: bool,
501    blob_gas_used: u64,
502    excess_blob_gas: u64,
503    parent_beacon_block_root: B256,
504) -> Header {
505    // Clear all related fields if EIP-1559 is inactive
506    if header.base_fee_per_gas.is_none() {
507        header.withdrawals_root = None;
508    }
509
510    // Set fields based on EIP-4844 being active
511    if eip_4844_active {
512        header.blob_gas_used = Some(blob_gas_used);
513        header.excess_blob_gas = Some(excess_blob_gas);
514        header.parent_beacon_block_root = Some(parent_beacon_block_root);
515    } else {
516        header.blob_gas_used = None;
517        header.excess_blob_gas = None;
518        header.parent_beacon_block_root = None;
519    }
520
521    // Placeholder for future EIP adjustments
522    header.requests_hash = None;
523
524    header
525}
526
527#[cfg(any(test, feature = "arbitrary"))]
528impl<'a> arbitrary::Arbitrary<'a> for Header {
529    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
530        // Generate an arbitrary header, passing it to the generate_valid_header function to make
531        // sure it is valid _with respect to hardforks only_.
532        let base = Self {
533            parent_hash: u.arbitrary()?,
534            ommers_hash: u.arbitrary()?,
535            beneficiary: u.arbitrary()?,
536            state_root: u.arbitrary()?,
537            transactions_root: u.arbitrary()?,
538            receipts_root: u.arbitrary()?,
539            logs_bloom: u.arbitrary()?,
540            difficulty: u.arbitrary()?,
541            number: u.arbitrary()?,
542            gas_limit: u.arbitrary()?,
543            gas_used: u.arbitrary()?,
544            timestamp: u.arbitrary()?,
545            extra_data: u.arbitrary()?,
546            mix_hash: u.arbitrary()?,
547            nonce: u.arbitrary()?,
548            base_fee_per_gas: u.arbitrary()?,
549            blob_gas_used: u.arbitrary()?,
550            excess_blob_gas: u.arbitrary()?,
551            parent_beacon_block_root: u.arbitrary()?,
552            requests_hash: u.arbitrary()?,
553            withdrawals_root: u.arbitrary()?,
554        };
555
556        Ok(generate_valid_header(
557            base,
558            u.arbitrary()?,
559            u.arbitrary()?,
560            u.arbitrary()?,
561            u.arbitrary()?,
562        ))
563    }
564}
565
566/// Trait for extracting specific Ethereum block data from a header
567#[auto_impl::auto_impl(&, Arc)]
568pub trait BlockHeader {
569    /// Extracts essential information into one container type.
570    fn header_info(&self) -> HeaderInfo {
571        HeaderInfo {
572            number: self.number(),
573            beneficiary: self.beneficiary(),
574            timestamp: self.timestamp(),
575            gas_limit: self.gas_limit(),
576            base_fee_per_gas: self.base_fee_per_gas(),
577            excess_blob_gas: self.excess_blob_gas(),
578            blob_gas_used: self.blob_gas_used(),
579            difficulty: self.difficulty(),
580            mix_hash: self.mix_hash(),
581        }
582    }
583
584    /// Retrieves the parent hash of the block
585    fn parent_hash(&self) -> B256;
586
587    /// Retrieves the ommers hash of the block
588    fn ommers_hash(&self) -> B256;
589
590    /// Retrieves the beneficiary (miner) of the block
591    fn beneficiary(&self) -> Address;
592
593    /// Retrieves the state root hash of the block
594    fn state_root(&self) -> B256;
595
596    /// Retrieves the transactions root hash of the block
597    fn transactions_root(&self) -> B256;
598
599    /// Retrieves the receipts root hash of the block
600    fn receipts_root(&self) -> B256;
601
602    /// Retrieves the withdrawals root hash of the block, if available
603    fn withdrawals_root(&self) -> Option<B256>;
604
605    /// Retrieves the logs bloom filter of the block
606    fn logs_bloom(&self) -> Bloom;
607
608    /// Retrieves the difficulty of the block
609    fn difficulty(&self) -> U256;
610
611    /// Retrieves the block number
612    fn number(&self) -> BlockNumber;
613
614    /// Retrieves the gas limit of the block
615    fn gas_limit(&self) -> u64;
616
617    /// Retrieves the gas used by the block
618    fn gas_used(&self) -> u64;
619
620    /// Retrieves the timestamp of the block
621    fn timestamp(&self) -> u64;
622
623    /// Retrieves the mix hash of the block, if available
624    fn mix_hash(&self) -> Option<B256>;
625
626    /// Retrieves the nonce of the block, if available
627    fn nonce(&self) -> Option<B64>;
628
629    /// Retrieves the base fee per gas of the block, if available
630    fn base_fee_per_gas(&self) -> Option<u64>;
631
632    /// Retrieves the blob gas used by the block, if available
633    fn blob_gas_used(&self) -> Option<u64>;
634
635    /// Retrieves the excess blob gas of the block, if available
636    fn excess_blob_gas(&self) -> Option<u64>;
637
638    /// Retrieves the parent beacon block root of the block, if available
639    fn parent_beacon_block_root(&self) -> Option<B256>;
640
641    /// Retrieves the requests hash of the block, if available
642    fn requests_hash(&self) -> Option<B256>;
643
644    /// Retrieves the block's extra data field
645    fn extra_data(&self) -> &Bytes;
646
647    /// Returns the blob fee for _this_ block according to the EIP-4844 spec.
648    ///
649    /// Returns `None` if `excess_blob_gas` is None
650    fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
651        Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
652    }
653
654    /// Calculate excess blob gas for the next block according to the EIP-4844
655    /// spec.
656    ///
657    /// Returns a `None` if no excess blob gas is set, no EIP-4844 support
658    fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
659        Some(blob_params.next_block_excess_blob_gas_osaka(
660            self.excess_blob_gas()?,
661            self.blob_gas_used()?,
662            self.base_fee_per_gas()?,
663        ))
664    }
665
666    /// Convenience function for [`Self::next_block_excess_blob_gas`] with an optional
667    /// [`BlobParams`] argument.
668    ///
669    /// Returns `None` if the `blob_params` are `None`.
670    fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
671        self.next_block_excess_blob_gas(blob_params?)
672    }
673
674    /// Returns the blob fee for the next block according to the EIP-4844 spec.
675    ///
676    /// Returns `None` if `excess_blob_gas` is None.
677    ///
678    /// See also [BlockHeader::next_block_excess_blob_gas]
679    fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
680        Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
681    }
682
683    /// Convenience function for [`Self::next_block_blob_fee`] with an optional [`BlobParams`]
684    /// argument.
685    ///
686    /// Returns `None` if the `blob_params` are `None`.
687    fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
688        self.next_block_blob_fee(blob_params?)
689    }
690
691    /// Calculate base fee for next block according to the EIP-1559 spec.
692    ///
693    /// Returns a `None` if no base fee is set, no EIP-1559 support
694    fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
695        Some(calc_next_block_base_fee(
696            self.gas_used(),
697            self.gas_limit(),
698            self.base_fee_per_gas()?,
699            base_fee_params,
700        ))
701    }
702
703    /// Returns the parent block's number and hash
704    ///
705    /// Note: for the genesis block the parent number is 0 and the parent hash is the zero hash.
706    fn parent_num_hash(&self) -> BlockNumHash {
707        BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
708    }
709
710    /// Checks if the header is considered empty - has no transactions, no ommers or withdrawals
711    fn is_empty(&self) -> bool {
712        let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
713            && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
714        self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
715            txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
716        })
717    }
718
719    /// Checks if the block's difficulty is set to zero, indicating a Proof-of-Stake header.
720    ///
721    /// This function is linked to EIP-3675, proposing the consensus upgrade to Proof-of-Stake:
722    /// [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0)
723    ///
724    /// Verifies whether, as per the EIP, the block's difficulty is updated to zero,
725    /// signifying the transition to a Proof-of-Stake mechanism.
726    ///
727    /// Returns `true` if the block's difficulty matches the constant zero set by the EIP.
728    fn is_zero_difficulty(&self) -> bool {
729        self.difficulty().is_zero()
730    }
731
732    /// Checks if the block's timestamp is in the future based on the present timestamp.
733    ///
734    /// Clock can drift but this can be consensus issue.
735    ///
736    /// Note: This check is relevant only pre-merge.
737    fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
738        self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
739    }
740
741    /// Checks if the nonce exists, and if it exists, if it's zero.
742    ///
743    /// If the nonce is `None`, then this returns `false`.
744    fn is_nonce_zero(&self) -> bool {
745        self.nonce().is_some_and(|nonce| nonce.is_zero())
746    }
747}
748
749impl BlockHeader for Header {
750    fn parent_hash(&self) -> B256 {
751        self.parent_hash
752    }
753
754    fn ommers_hash(&self) -> B256 {
755        self.ommers_hash
756    }
757
758    fn beneficiary(&self) -> Address {
759        self.beneficiary
760    }
761
762    fn state_root(&self) -> B256 {
763        self.state_root
764    }
765
766    fn transactions_root(&self) -> B256 {
767        self.transactions_root
768    }
769
770    fn receipts_root(&self) -> B256 {
771        self.receipts_root
772    }
773
774    fn withdrawals_root(&self) -> Option<B256> {
775        self.withdrawals_root
776    }
777
778    fn logs_bloom(&self) -> Bloom {
779        self.logs_bloom
780    }
781
782    fn difficulty(&self) -> U256 {
783        self.difficulty
784    }
785
786    fn number(&self) -> BlockNumber {
787        self.number
788    }
789
790    fn gas_limit(&self) -> u64 {
791        self.gas_limit
792    }
793
794    fn gas_used(&self) -> u64 {
795        self.gas_used
796    }
797
798    fn timestamp(&self) -> u64 {
799        self.timestamp
800    }
801
802    fn mix_hash(&self) -> Option<B256> {
803        Some(self.mix_hash)
804    }
805
806    fn nonce(&self) -> Option<B64> {
807        Some(self.nonce)
808    }
809
810    fn base_fee_per_gas(&self) -> Option<u64> {
811        self.base_fee_per_gas
812    }
813
814    fn blob_gas_used(&self) -> Option<u64> {
815        self.blob_gas_used
816    }
817
818    fn excess_blob_gas(&self) -> Option<u64> {
819        self.excess_blob_gas
820    }
821
822    fn parent_beacon_block_root(&self) -> Option<B256> {
823        self.parent_beacon_block_root
824    }
825
826    fn requests_hash(&self) -> Option<B256> {
827        self.requests_hash
828    }
829
830    fn extra_data(&self) -> &Bytes {
831        &self.extra_data
832    }
833}
834
835#[cfg(feature = "serde")]
836impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
837    fn parent_hash(&self) -> B256 {
838        self.inner.parent_hash()
839    }
840
841    fn ommers_hash(&self) -> B256 {
842        self.inner.ommers_hash()
843    }
844
845    fn beneficiary(&self) -> Address {
846        self.inner.beneficiary()
847    }
848
849    fn state_root(&self) -> B256 {
850        self.inner.state_root()
851    }
852
853    fn transactions_root(&self) -> B256 {
854        self.inner.transactions_root()
855    }
856
857    fn receipts_root(&self) -> B256 {
858        self.inner.receipts_root()
859    }
860
861    fn withdrawals_root(&self) -> Option<B256> {
862        self.inner.withdrawals_root()
863    }
864
865    fn logs_bloom(&self) -> Bloom {
866        self.inner.logs_bloom()
867    }
868
869    fn difficulty(&self) -> U256 {
870        self.inner.difficulty()
871    }
872
873    fn number(&self) -> u64 {
874        self.inner.number()
875    }
876
877    fn gas_limit(&self) -> u64 {
878        self.inner.gas_limit()
879    }
880
881    fn gas_used(&self) -> u64 {
882        self.inner.gas_used()
883    }
884
885    fn timestamp(&self) -> u64 {
886        self.inner.timestamp()
887    }
888
889    fn mix_hash(&self) -> Option<B256> {
890        self.inner.mix_hash()
891    }
892
893    fn nonce(&self) -> Option<B64> {
894        self.inner.nonce()
895    }
896
897    fn base_fee_per_gas(&self) -> Option<u64> {
898        self.inner.base_fee_per_gas()
899    }
900
901    fn blob_gas_used(&self) -> Option<u64> {
902        self.inner.blob_gas_used()
903    }
904
905    fn excess_blob_gas(&self) -> Option<u64> {
906        self.inner.excess_blob_gas()
907    }
908
909    fn parent_beacon_block_root(&self) -> Option<B256> {
910        self.inner.parent_beacon_block_root()
911    }
912
913    fn requests_hash(&self) -> Option<B256> {
914        self.inner.requests_hash()
915    }
916
917    fn extra_data(&self) -> &Bytes {
918        self.inner.extra_data()
919    }
920
921    fn is_empty(&self) -> bool {
922        self.inner.is_empty()
923    }
924}
925
926/// Bincode-compatible [`Header`] serde implementation.
927#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
928pub(crate) mod serde_bincode_compat {
929    use alloc::borrow::Cow;
930    use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
931    use serde::{Deserialize, Deserializer, Serialize, Serializer};
932    use serde_with::{DeserializeAs, SerializeAs};
933
934    /// Bincode-compatible [`super::Header`] serde implementation.
935    ///
936    /// Intended to use with the [`serde_with::serde_as`] macro in the following way:
937    /// ```rust
938    /// use alloy_consensus::{serde_bincode_compat, Header};
939    /// use serde::{Deserialize, Serialize};
940    /// use serde_with::serde_as;
941    ///
942    /// #[serde_as]
943    /// #[derive(Serialize, Deserialize)]
944    /// struct Data {
945    ///     #[serde_as(as = "serde_bincode_compat::Header")]
946    ///     header: Header,
947    /// }
948    /// ```
949    #[derive(Debug, Serialize, Deserialize)]
950    pub struct Header<'a> {
951        parent_hash: B256,
952        ommers_hash: B256,
953        beneficiary: Address,
954        state_root: B256,
955        transactions_root: B256,
956        receipts_root: B256,
957        #[serde(default)]
958        withdrawals_root: Option<B256>,
959        logs_bloom: Bloom,
960        difficulty: U256,
961        number: BlockNumber,
962        gas_limit: u64,
963        gas_used: u64,
964        timestamp: u64,
965        mix_hash: B256,
966        nonce: B64,
967        #[serde(default)]
968        base_fee_per_gas: Option<u64>,
969        #[serde(default)]
970        blob_gas_used: Option<u64>,
971        #[serde(default)]
972        excess_blob_gas: Option<u64>,
973        #[serde(default)]
974        parent_beacon_block_root: Option<B256>,
975        #[serde(default)]
976        requests_hash: Option<B256>,
977        extra_data: Cow<'a, Bytes>,
978    }
979
980    impl<'a> From<&'a super::Header> for Header<'a> {
981        fn from(value: &'a super::Header) -> Self {
982            Self {
983                parent_hash: value.parent_hash,
984                ommers_hash: value.ommers_hash,
985                beneficiary: value.beneficiary,
986                state_root: value.state_root,
987                transactions_root: value.transactions_root,
988                receipts_root: value.receipts_root,
989                withdrawals_root: value.withdrawals_root,
990                logs_bloom: value.logs_bloom,
991                difficulty: value.difficulty,
992                number: value.number,
993                gas_limit: value.gas_limit,
994                gas_used: value.gas_used,
995                timestamp: value.timestamp,
996                mix_hash: value.mix_hash,
997                nonce: value.nonce,
998                base_fee_per_gas: value.base_fee_per_gas,
999                blob_gas_used: value.blob_gas_used,
1000                excess_blob_gas: value.excess_blob_gas,
1001                parent_beacon_block_root: value.parent_beacon_block_root,
1002                requests_hash: value.requests_hash,
1003                extra_data: Cow::Borrowed(&value.extra_data),
1004            }
1005        }
1006    }
1007
1008    impl<'a> From<Header<'a>> for super::Header {
1009        fn from(value: Header<'a>) -> Self {
1010            Self {
1011                parent_hash: value.parent_hash,
1012                ommers_hash: value.ommers_hash,
1013                beneficiary: value.beneficiary,
1014                state_root: value.state_root,
1015                transactions_root: value.transactions_root,
1016                receipts_root: value.receipts_root,
1017                withdrawals_root: value.withdrawals_root,
1018                logs_bloom: value.logs_bloom,
1019                difficulty: value.difficulty,
1020                number: value.number,
1021                gas_limit: value.gas_limit,
1022                gas_used: value.gas_used,
1023                timestamp: value.timestamp,
1024                mix_hash: value.mix_hash,
1025                nonce: value.nonce,
1026                base_fee_per_gas: value.base_fee_per_gas,
1027                blob_gas_used: value.blob_gas_used,
1028                excess_blob_gas: value.excess_blob_gas,
1029                parent_beacon_block_root: value.parent_beacon_block_root,
1030                requests_hash: value.requests_hash,
1031                extra_data: value.extra_data.into_owned(),
1032            }
1033        }
1034    }
1035
1036    impl SerializeAs<super::Header> for Header<'_> {
1037        fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
1038        where
1039            S: Serializer,
1040        {
1041            Header::from(source).serialize(serializer)
1042        }
1043    }
1044
1045    impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1046        fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1047        where
1048            D: Deserializer<'de>,
1049        {
1050            Header::deserialize(deserializer).map(Into::into)
1051        }
1052    }
1053
1054    #[cfg(test)]
1055    mod tests {
1056        use super::super::{serde_bincode_compat, Header};
1057        use arbitrary::Arbitrary;
1058        use bincode::config;
1059        use rand::Rng;
1060        use serde::{Deserialize, Serialize};
1061        use serde_with::serde_as;
1062
1063        #[test]
1064        fn test_header_bincode_roundtrip() {
1065            #[serde_as]
1066            #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1067            struct Data {
1068                #[serde_as(as = "serde_bincode_compat::Header")]
1069                header: Header,
1070            }
1071
1072            let mut bytes = [0u8; 1024];
1073            rand::thread_rng().fill(bytes.as_mut_slice());
1074            let data = Data {
1075                header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1076            };
1077
1078            let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
1079            let (decoded, _) =
1080                bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
1081            assert_eq!(decoded, data);
1082        }
1083    }
1084}
1085
1086#[cfg(all(test, feature = "serde"))]
1087mod tests {
1088    use super::*;
1089    use alloy_primitives::b256;
1090
1091    #[test]
1092    fn test_header_serde_json_roundtrip() {
1093        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"}"#;
1094        let header = Header {
1095            base_fee_per_gas: Some(1),
1096            withdrawals_root: Some(EMPTY_ROOT_HASH),
1097            ..Default::default()
1098        };
1099
1100        let encoded = serde_json::to_string(&header).unwrap();
1101        assert_eq!(encoded, raw);
1102
1103        let decoded: Header = serde_json::from_str(&encoded).unwrap();
1104        assert_eq!(decoded, header);
1105
1106        // Create a vector to store the encoded RLP
1107        let mut encoded_rlp = Vec::new();
1108
1109        // Encode the header data
1110        decoded.encode(&mut encoded_rlp);
1111
1112        // Decode the RLP data
1113        let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1114
1115        // Check that the decoded RLP data matches the original header data
1116        assert_eq!(decoded_rlp, decoded);
1117    }
1118
1119    #[test]
1120    fn serde_rlp_prague() {
1121        // Note: Some fields are renamed from eth_getHeaderByHash
1122        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"}
1123"#;
1124        let header = serde_json::from_str::<Header>(raw).unwrap();
1125        let hash = header.hash_slow();
1126        assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1127        let mut v = Vec::new();
1128        header.encode(&mut v);
1129        let decoded = Header::decode(&mut v.as_slice()).unwrap();
1130        assert_eq!(decoded, header);
1131    }
1132}