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