Skip to main content

alloy_consensus/block/
header.rs

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