Skip to main content

alloy_consensus/block/
header.rs

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