1use crate::{
2 block::HeaderInfo,
3 constants::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH},
4 Block, BlockBody,
5};
6use alloc::vec::Vec;
7use alloy_eips::{
8 eip1559::{calc_next_block_base_fee, BaseFeeParams},
9 eip1898::BlockWithParent,
10 eip7840::BlobParams,
11 merge::ALLOWED_FUTURE_BLOCK_TIME_SECONDS,
12 BlockNumHash,
13};
14use alloy_primitives::{
15 keccak256, Address, BlockNumber, Bloom, Bytes, Sealable, Sealed, B256, B64, U256,
16};
17use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable};
18use core::mem;
19
20#[derive(Clone, Debug, PartialEq, Eq, Hash)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
24#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
25pub struct Header {
26 pub parent_hash: B256,
29 #[cfg_attr(feature = "serde", serde(rename = "sha3Uncles", alias = "ommersHash"))]
31 pub ommers_hash: B256,
32 #[cfg_attr(feature = "serde", serde(rename = "miner", alias = "beneficiary"))]
35 pub beneficiary: Address,
36 pub state_root: B256,
39 pub transactions_root: B256,
42 pub receipts_root: B256,
45 pub logs_bloom: Bloom,
49 pub difficulty: U256,
52 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
55 pub number: BlockNumber,
56 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
58 pub gas_limit: u64,
59 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
61 pub gas_used: u64,
62 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
65 pub timestamp: u64,
66 pub extra_data: Bytes,
69 pub mix_hash: B256,
73 pub nonce: B64,
76 #[cfg_attr(
83 feature = "serde",
84 serde(
85 default,
86 with = "alloy_serde::quantity::opt",
87 skip_serializing_if = "Option::is_none"
88 )
89 )]
90 pub base_fee_per_gas: Option<u64>,
91 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
94 pub withdrawals_root: Option<B256>,
95 #[cfg_attr(
98 feature = "serde",
99 serde(
100 default,
101 with = "alloy_serde::quantity::opt",
102 skip_serializing_if = "Option::is_none"
103 )
104 )]
105 pub blob_gas_used: Option<u64>,
106 #[cfg_attr(
110 feature = "serde",
111 serde(
112 default,
113 with = "alloy_serde::quantity::opt",
114 skip_serializing_if = "Option::is_none"
115 )
116 )]
117 pub excess_blob_gas: Option<u64>,
118 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
126 pub parent_beacon_block_root: Option<B256>,
127 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
132 pub requests_hash: Option<B256>,
133}
134
135impl AsRef<Self> for Header {
136 fn as_ref(&self) -> &Self {
137 self
138 }
139}
140
141impl Default for Header {
142 fn default() -> Self {
143 Self {
144 parent_hash: Default::default(),
145 ommers_hash: EMPTY_OMMER_ROOT_HASH,
146 beneficiary: Default::default(),
147 state_root: EMPTY_ROOT_HASH,
148 transactions_root: EMPTY_ROOT_HASH,
149 receipts_root: EMPTY_ROOT_HASH,
150 logs_bloom: Default::default(),
151 difficulty: Default::default(),
152 number: 0,
153 gas_limit: 0,
154 gas_used: 0,
155 timestamp: 0,
156 extra_data: Default::default(),
157 mix_hash: Default::default(),
158 nonce: B64::ZERO,
159 base_fee_per_gas: None,
160 withdrawals_root: None,
161 blob_gas_used: None,
162 excess_blob_gas: None,
163 parent_beacon_block_root: None,
164 requests_hash: None,
165 }
166 }
167}
168
169impl Sealable for Header {
170 fn hash_slow(&self) -> B256 {
171 self.hash_slow()
172 }
173}
174
175impl Header {
176 pub const fn into_block<T>(self, body: BlockBody<T>) -> Block<T> {
178 body.into_block(self)
179 }
180
181 pub fn hash_slow(&self) -> B256 {
185 let mut out = Vec::<u8>::new();
186 self.encode(&mut out);
187 keccak256(&out)
188 }
189
190 pub fn ommers_hash_is_empty(&self) -> bool {
192 self.ommers_hash == EMPTY_OMMER_ROOT_HASH
193 }
194
195 pub fn transaction_root_is_empty(&self) -> bool {
197 self.transactions_root == EMPTY_ROOT_HASH
198 }
199
200 pub fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
204 Some(blob_params.calc_blob_fee(self.excess_blob_gas?))
205 }
206
207 pub fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
213 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
214 }
215
216 pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
220 Some(calc_next_block_base_fee(
221 self.gas_used,
222 self.gas_limit,
223 self.base_fee_per_gas?,
224 base_fee_params,
225 ))
226 }
227
228 pub fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
233 Some(blob_params.next_block_excess_blob_gas_osaka(
234 self.excess_blob_gas?,
235 self.blob_gas_used?,
236 self.base_fee_per_gas?,
237 ))
238 }
239
240 #[inline]
242 pub fn size(&self) -> usize {
243 mem::size_of::<B256>() + mem::size_of::<B256>() + mem::size_of::<Address>() + mem::size_of::<B256>() + mem::size_of::<B256>() + mem::size_of::<B256>() + mem::size_of::<Option<B256>>() + mem::size_of::<Bloom>() + mem::size_of::<U256>() + mem::size_of::<BlockNumber>() + mem::size_of::<u64>() + mem::size_of::<u64>() + mem::size_of::<u64>() + mem::size_of::<B256>() + mem::size_of::<u64>() + mem::size_of::<Option<u64>>() + mem::size_of::<Option<u64>>() + mem::size_of::<Option<u64>>() + mem::size_of::<Option<B256>>() + mem::size_of::<Option<B256>>() + self.extra_data.len() }
265
266 fn header_payload_length(&self) -> usize {
267 let mut length = 0;
268 length += self.parent_hash.length();
269 length += self.ommers_hash.length();
270 length += self.beneficiary.length();
271 length += self.state_root.length();
272 length += self.transactions_root.length();
273 length += self.receipts_root.length();
274 length += self.logs_bloom.length();
275 length += self.difficulty.length();
276 length += U256::from(self.number).length();
277 length += U256::from(self.gas_limit).length();
278 length += U256::from(self.gas_used).length();
279 length += self.timestamp.length();
280 length += self.extra_data.length();
281 length += self.mix_hash.length();
282 length += self.nonce.length();
283
284 if let Some(base_fee) = self.base_fee_per_gas {
285 length += U256::from(base_fee).length();
287 }
288
289 if let Some(root) = self.withdrawals_root {
290 length += root.length();
292 }
293
294 if let Some(blob_gas_used) = self.blob_gas_used {
295 length += U256::from(blob_gas_used).length();
297 }
298
299 if let Some(excess_blob_gas) = self.excess_blob_gas {
300 length += U256::from(excess_blob_gas).length();
302 }
303
304 if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
305 length += parent_beacon_block_root.length();
306 }
307
308 if let Some(requests_hash) = self.requests_hash {
309 length += requests_hash.length();
310 }
311
312 length
313 }
314
315 pub const fn parent_num_hash(&self) -> BlockNumHash {
319 BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
320 }
321
322 pub fn num_hash_slow(&self) -> BlockNumHash {
326 BlockNumHash { number: self.number, hash: self.hash_slow() }
327 }
328
329 pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
333 BlockWithParent::new(self.parent_hash, self.num_hash_slow())
334 }
335
336 #[inline]
340 pub const fn seal(self, hash: B256) -> Sealed<Self> {
341 Sealed::new_unchecked(self, hash)
342 }
343
344 pub const fn shanghai_active(&self) -> bool {
348 self.withdrawals_root.is_some()
349 }
350
351 pub const fn cancun_active(&self) -> bool {
355 self.blob_gas_used.is_some()
356 }
357
358 pub const fn prague_active(&self) -> bool {
362 self.requests_hash.is_some()
363 }
364}
365
366impl Encodable for Header {
367 fn encode(&self, out: &mut dyn BufMut) {
368 let list_header =
369 alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
370 list_header.encode(out);
371 self.parent_hash.encode(out);
372 self.ommers_hash.encode(out);
373 self.beneficiary.encode(out);
374 self.state_root.encode(out);
375 self.transactions_root.encode(out);
376 self.receipts_root.encode(out);
377 self.logs_bloom.encode(out);
378 self.difficulty.encode(out);
379 U256::from(self.number).encode(out);
380 U256::from(self.gas_limit).encode(out);
381 U256::from(self.gas_used).encode(out);
382 self.timestamp.encode(out);
383 self.extra_data.encode(out);
384 self.mix_hash.encode(out);
385 self.nonce.encode(out);
386
387 if let Some(ref base_fee) = self.base_fee_per_gas {
389 U256::from(*base_fee).encode(out);
390 }
391
392 if let Some(ref root) = self.withdrawals_root {
393 root.encode(out);
394 }
395
396 if let Some(ref blob_gas_used) = self.blob_gas_used {
397 U256::from(*blob_gas_used).encode(out);
398 }
399
400 if let Some(ref excess_blob_gas) = self.excess_blob_gas {
401 U256::from(*excess_blob_gas).encode(out);
402 }
403
404 if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
405 parent_beacon_block_root.encode(out);
406 }
407
408 if let Some(ref requests_hash) = self.requests_hash {
409 requests_hash.encode(out);
410 }
411 }
412
413 fn length(&self) -> usize {
414 let mut length = 0;
415 length += self.header_payload_length();
416 length += length_of_length(length);
417 length
418 }
419}
420
421impl Decodable for Header {
422 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
423 let rlp_head = alloy_rlp::Header::decode(buf)?;
424 if !rlp_head.list {
425 return Err(alloy_rlp::Error::UnexpectedString);
426 }
427 let started_len = buf.len();
428 let mut this = Self {
429 parent_hash: Decodable::decode(buf)?,
430 ommers_hash: Decodable::decode(buf)?,
431 beneficiary: Decodable::decode(buf)?,
432 state_root: Decodable::decode(buf)?,
433 transactions_root: Decodable::decode(buf)?,
434 receipts_root: Decodable::decode(buf)?,
435 logs_bloom: Decodable::decode(buf)?,
436 difficulty: Decodable::decode(buf)?,
437 number: u64::decode(buf)?,
438 gas_limit: u64::decode(buf)?,
439 gas_used: u64::decode(buf)?,
440 timestamp: Decodable::decode(buf)?,
441 extra_data: Decodable::decode(buf)?,
442 mix_hash: Decodable::decode(buf)?,
443 nonce: B64::decode(buf)?,
444 base_fee_per_gas: None,
445 withdrawals_root: None,
446 blob_gas_used: None,
447 excess_blob_gas: None,
448 parent_beacon_block_root: None,
449 requests_hash: None,
450 };
451 if started_len - buf.len() < rlp_head.payload_length {
452 this.base_fee_per_gas = Some(u64::decode(buf)?);
453 }
454
455 if started_len - buf.len() < rlp_head.payload_length {
457 this.withdrawals_root = Some(Decodable::decode(buf)?);
458 }
459
460 if started_len - buf.len() < rlp_head.payload_length {
462 this.blob_gas_used = Some(u64::decode(buf)?);
463 }
464
465 if started_len - buf.len() < rlp_head.payload_length {
466 this.excess_blob_gas = Some(u64::decode(buf)?);
467 }
468
469 if started_len - buf.len() < rlp_head.payload_length {
471 this.parent_beacon_block_root = Some(B256::decode(buf)?);
472 }
473
474 if started_len - buf.len() < rlp_head.payload_length {
476 this.requests_hash = Some(B256::decode(buf)?);
477 }
478
479 let consumed = started_len - buf.len();
480 if consumed != rlp_head.payload_length {
481 return Err(alloy_rlp::Error::ListLengthMismatch {
482 expected: rlp_head.payload_length,
483 got: consumed,
484 });
485 }
486 Ok(this)
487 }
488}
489
490#[cfg(any(test, feature = "arbitrary"))]
499pub(crate) const fn generate_valid_header(
500 mut header: Header,
501 eip_4844_active: bool,
502 blob_gas_used: u64,
503 excess_blob_gas: u64,
504 parent_beacon_block_root: B256,
505) -> Header {
506 if header.base_fee_per_gas.is_none() {
508 header.withdrawals_root = None;
509 }
510
511 if eip_4844_active {
513 header.blob_gas_used = Some(blob_gas_used);
514 header.excess_blob_gas = Some(excess_blob_gas);
515 header.parent_beacon_block_root = Some(parent_beacon_block_root);
516 } else {
517 header.blob_gas_used = None;
518 header.excess_blob_gas = None;
519 header.parent_beacon_block_root = None;
520 }
521
522 header.requests_hash = None;
524
525 header
526}
527
528#[cfg(any(test, feature = "arbitrary"))]
529impl<'a> arbitrary::Arbitrary<'a> for Header {
530 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
531 let base = Self {
534 parent_hash: u.arbitrary()?,
535 ommers_hash: u.arbitrary()?,
536 beneficiary: u.arbitrary()?,
537 state_root: u.arbitrary()?,
538 transactions_root: u.arbitrary()?,
539 receipts_root: u.arbitrary()?,
540 logs_bloom: u.arbitrary()?,
541 difficulty: u.arbitrary()?,
542 number: u.arbitrary()?,
543 gas_limit: u.arbitrary()?,
544 gas_used: u.arbitrary()?,
545 timestamp: u.arbitrary()?,
546 extra_data: u.arbitrary()?,
547 mix_hash: u.arbitrary()?,
548 nonce: u.arbitrary()?,
549 base_fee_per_gas: u.arbitrary()?,
550 blob_gas_used: u.arbitrary()?,
551 excess_blob_gas: u.arbitrary()?,
552 parent_beacon_block_root: u.arbitrary()?,
553 requests_hash: u.arbitrary()?,
554 withdrawals_root: u.arbitrary()?,
555 };
556
557 Ok(generate_valid_header(
558 base,
559 u.arbitrary()?,
560 u.arbitrary()?,
561 u.arbitrary()?,
562 u.arbitrary()?,
563 ))
564 }
565}
566
567#[auto_impl::auto_impl(&, Arc)]
569pub trait BlockHeader {
570 fn header_info(&self) -> HeaderInfo {
572 HeaderInfo {
573 number: self.number(),
574 beneficiary: self.beneficiary(),
575 timestamp: self.timestamp(),
576 gas_limit: self.gas_limit(),
577 base_fee_per_gas: self.base_fee_per_gas(),
578 excess_blob_gas: self.excess_blob_gas(),
579 blob_gas_used: self.blob_gas_used(),
580 difficulty: self.difficulty(),
581 mix_hash: self.mix_hash(),
582 }
583 }
584
585 fn parent_hash(&self) -> B256;
587
588 fn ommers_hash(&self) -> B256;
590
591 fn beneficiary(&self) -> Address;
593
594 fn state_root(&self) -> B256;
596
597 fn transactions_root(&self) -> B256;
599
600 fn receipts_root(&self) -> B256;
602
603 fn withdrawals_root(&self) -> Option<B256>;
605
606 fn logs_bloom(&self) -> Bloom;
608
609 fn difficulty(&self) -> U256;
611
612 fn number(&self) -> BlockNumber;
614
615 fn gas_limit(&self) -> u64;
617
618 fn gas_used(&self) -> u64;
620
621 fn timestamp(&self) -> u64;
623
624 fn mix_hash(&self) -> Option<B256>;
626
627 fn nonce(&self) -> Option<B64>;
629
630 fn base_fee_per_gas(&self) -> Option<u64>;
632
633 fn blob_gas_used(&self) -> Option<u64>;
635
636 fn excess_blob_gas(&self) -> Option<u64>;
638
639 fn parent_beacon_block_root(&self) -> Option<B256>;
641
642 fn requests_hash(&self) -> Option<B256>;
644
645 fn extra_data(&self) -> &Bytes;
647
648 fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
652 Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
653 }
654
655 fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
660 Some(blob_params.next_block_excess_blob_gas_osaka(
661 self.excess_blob_gas()?,
662 self.blob_gas_used()?,
663 self.base_fee_per_gas()?,
664 ))
665 }
666
667 fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
672 self.next_block_excess_blob_gas(blob_params?)
673 }
674
675 fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
681 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
682 }
683
684 fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
689 self.next_block_blob_fee(blob_params?)
690 }
691
692 fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
696 Some(calc_next_block_base_fee(
697 self.gas_used(),
698 self.gas_limit(),
699 self.base_fee_per_gas()?,
700 base_fee_params,
701 ))
702 }
703
704 fn parent_num_hash(&self) -> BlockNumHash {
708 BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
709 }
710
711 fn is_empty(&self) -> bool {
713 let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
714 && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
715 self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
716 txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
717 })
718 }
719
720 fn is_zero_difficulty(&self) -> bool {
730 self.difficulty().is_zero()
731 }
732
733 fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
739 self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
740 }
741
742 fn is_nonce_zero(&self) -> bool {
746 self.nonce().is_some_and(|nonce| nonce.is_zero())
747 }
748}
749
750impl BlockHeader for Header {
751 fn parent_hash(&self) -> B256 {
752 self.parent_hash
753 }
754
755 fn ommers_hash(&self) -> B256 {
756 self.ommers_hash
757 }
758
759 fn beneficiary(&self) -> Address {
760 self.beneficiary
761 }
762
763 fn state_root(&self) -> B256 {
764 self.state_root
765 }
766
767 fn transactions_root(&self) -> B256 {
768 self.transactions_root
769 }
770
771 fn receipts_root(&self) -> B256 {
772 self.receipts_root
773 }
774
775 fn withdrawals_root(&self) -> Option<B256> {
776 self.withdrawals_root
777 }
778
779 fn logs_bloom(&self) -> Bloom {
780 self.logs_bloom
781 }
782
783 fn difficulty(&self) -> U256 {
784 self.difficulty
785 }
786
787 fn number(&self) -> BlockNumber {
788 self.number
789 }
790
791 fn gas_limit(&self) -> u64 {
792 self.gas_limit
793 }
794
795 fn gas_used(&self) -> u64 {
796 self.gas_used
797 }
798
799 fn timestamp(&self) -> u64 {
800 self.timestamp
801 }
802
803 fn mix_hash(&self) -> Option<B256> {
804 Some(self.mix_hash)
805 }
806
807 fn nonce(&self) -> Option<B64> {
808 Some(self.nonce)
809 }
810
811 fn base_fee_per_gas(&self) -> Option<u64> {
812 self.base_fee_per_gas
813 }
814
815 fn blob_gas_used(&self) -> Option<u64> {
816 self.blob_gas_used
817 }
818
819 fn excess_blob_gas(&self) -> Option<u64> {
820 self.excess_blob_gas
821 }
822
823 fn parent_beacon_block_root(&self) -> Option<B256> {
824 self.parent_beacon_block_root
825 }
826
827 fn requests_hash(&self) -> Option<B256> {
828 self.requests_hash
829 }
830
831 fn extra_data(&self) -> &Bytes {
832 &self.extra_data
833 }
834}
835
836#[cfg(feature = "serde")]
837impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
838 fn parent_hash(&self) -> B256 {
839 self.inner.parent_hash()
840 }
841
842 fn ommers_hash(&self) -> B256 {
843 self.inner.ommers_hash()
844 }
845
846 fn beneficiary(&self) -> Address {
847 self.inner.beneficiary()
848 }
849
850 fn state_root(&self) -> B256 {
851 self.inner.state_root()
852 }
853
854 fn transactions_root(&self) -> B256 {
855 self.inner.transactions_root()
856 }
857
858 fn receipts_root(&self) -> B256 {
859 self.inner.receipts_root()
860 }
861
862 fn withdrawals_root(&self) -> Option<B256> {
863 self.inner.withdrawals_root()
864 }
865
866 fn logs_bloom(&self) -> Bloom {
867 self.inner.logs_bloom()
868 }
869
870 fn difficulty(&self) -> U256 {
871 self.inner.difficulty()
872 }
873
874 fn number(&self) -> u64 {
875 self.inner.number()
876 }
877
878 fn gas_limit(&self) -> u64 {
879 self.inner.gas_limit()
880 }
881
882 fn gas_used(&self) -> u64 {
883 self.inner.gas_used()
884 }
885
886 fn timestamp(&self) -> u64 {
887 self.inner.timestamp()
888 }
889
890 fn mix_hash(&self) -> Option<B256> {
891 self.inner.mix_hash()
892 }
893
894 fn nonce(&self) -> Option<B64> {
895 self.inner.nonce()
896 }
897
898 fn base_fee_per_gas(&self) -> Option<u64> {
899 self.inner.base_fee_per_gas()
900 }
901
902 fn blob_gas_used(&self) -> Option<u64> {
903 self.inner.blob_gas_used()
904 }
905
906 fn excess_blob_gas(&self) -> Option<u64> {
907 self.inner.excess_blob_gas()
908 }
909
910 fn parent_beacon_block_root(&self) -> Option<B256> {
911 self.inner.parent_beacon_block_root()
912 }
913
914 fn requests_hash(&self) -> Option<B256> {
915 self.inner.requests_hash()
916 }
917
918 fn extra_data(&self) -> &Bytes {
919 self.inner.extra_data()
920 }
921
922 fn is_empty(&self) -> bool {
923 self.inner.is_empty()
924 }
925}
926
927#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
929pub(crate) mod serde_bincode_compat {
930 use alloc::borrow::Cow;
931 use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
932 use serde::{Deserialize, Deserializer, Serialize, Serializer};
933 use serde_with::{DeserializeAs, SerializeAs};
934
935 #[derive(Debug, Serialize, Deserialize)]
951 pub struct Header<'a> {
952 parent_hash: B256,
953 ommers_hash: B256,
954 beneficiary: Address,
955 state_root: B256,
956 transactions_root: B256,
957 receipts_root: B256,
958 #[serde(default)]
959 withdrawals_root: Option<B256>,
960 logs_bloom: Bloom,
961 difficulty: U256,
962 number: BlockNumber,
963 gas_limit: u64,
964 gas_used: u64,
965 timestamp: u64,
966 mix_hash: B256,
967 nonce: B64,
968 #[serde(default)]
969 base_fee_per_gas: Option<u64>,
970 #[serde(default)]
971 blob_gas_used: Option<u64>,
972 #[serde(default)]
973 excess_blob_gas: Option<u64>,
974 #[serde(default)]
975 parent_beacon_block_root: Option<B256>,
976 #[serde(default)]
977 requests_hash: Option<B256>,
978 extra_data: Cow<'a, Bytes>,
979 }
980
981 impl<'a> From<&'a super::Header> for Header<'a> {
982 fn from(value: &'a super::Header) -> Self {
983 Self {
984 parent_hash: value.parent_hash,
985 ommers_hash: value.ommers_hash,
986 beneficiary: value.beneficiary,
987 state_root: value.state_root,
988 transactions_root: value.transactions_root,
989 receipts_root: value.receipts_root,
990 withdrawals_root: value.withdrawals_root,
991 logs_bloom: value.logs_bloom,
992 difficulty: value.difficulty,
993 number: value.number,
994 gas_limit: value.gas_limit,
995 gas_used: value.gas_used,
996 timestamp: value.timestamp,
997 mix_hash: value.mix_hash,
998 nonce: value.nonce,
999 base_fee_per_gas: value.base_fee_per_gas,
1000 blob_gas_used: value.blob_gas_used,
1001 excess_blob_gas: value.excess_blob_gas,
1002 parent_beacon_block_root: value.parent_beacon_block_root,
1003 requests_hash: value.requests_hash,
1004 extra_data: Cow::Borrowed(&value.extra_data),
1005 }
1006 }
1007 }
1008
1009 impl<'a> From<Header<'a>> for super::Header {
1010 fn from(value: Header<'a>) -> Self {
1011 Self {
1012 parent_hash: value.parent_hash,
1013 ommers_hash: value.ommers_hash,
1014 beneficiary: value.beneficiary,
1015 state_root: value.state_root,
1016 transactions_root: value.transactions_root,
1017 receipts_root: value.receipts_root,
1018 withdrawals_root: value.withdrawals_root,
1019 logs_bloom: value.logs_bloom,
1020 difficulty: value.difficulty,
1021 number: value.number,
1022 gas_limit: value.gas_limit,
1023 gas_used: value.gas_used,
1024 timestamp: value.timestamp,
1025 mix_hash: value.mix_hash,
1026 nonce: value.nonce,
1027 base_fee_per_gas: value.base_fee_per_gas,
1028 blob_gas_used: value.blob_gas_used,
1029 excess_blob_gas: value.excess_blob_gas,
1030 parent_beacon_block_root: value.parent_beacon_block_root,
1031 requests_hash: value.requests_hash,
1032 extra_data: value.extra_data.into_owned(),
1033 }
1034 }
1035 }
1036
1037 impl SerializeAs<super::Header> for Header<'_> {
1038 fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
1039 where
1040 S: Serializer,
1041 {
1042 Header::from(source).serialize(serializer)
1043 }
1044 }
1045
1046 impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1047 fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1048 where
1049 D: Deserializer<'de>,
1050 {
1051 Header::deserialize(deserializer).map(Into::into)
1052 }
1053 }
1054
1055 #[cfg(test)]
1056 mod tests {
1057 use super::super::{serde_bincode_compat, Header};
1058 use arbitrary::Arbitrary;
1059 use bincode::config;
1060 use rand::Rng;
1061 use serde::{Deserialize, Serialize};
1062 use serde_with::serde_as;
1063
1064 #[test]
1065 fn test_header_bincode_roundtrip() {
1066 #[serde_as]
1067 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1068 struct Data {
1069 #[serde_as(as = "serde_bincode_compat::Header")]
1070 header: Header,
1071 }
1072
1073 let mut bytes = [0u8; 1024];
1074 rand::thread_rng().fill(bytes.as_mut_slice());
1075 let data = Data {
1076 header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1077 };
1078
1079 let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
1080 let (decoded, _) =
1081 bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
1082 assert_eq!(decoded, data);
1083 }
1084 }
1085}
1086
1087#[cfg(test)]
1088mod tests {
1089 use super::*;
1090 use alloy_primitives::{b256, hex};
1091
1092 #[test]
1093 fn decode_header_rlp() {
1094 let raw = hex!("0xf90212a00d84d79f59fc384a1f6402609a5b7253b4bfe7a4ae12608ed107273e5422b6dda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479471562b71999873db5b286df957af199ec94617f7a0f496f3d199c51a1aaee67dac95f24d92ac13c60d25181e1eecd6eca5ddf32ac0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808206a4840365908a808468e975f09ad983011003846765746888676f312e32352e308664617277696ea06f485a167165ec12e0ab3e6ab59a7b88560b90306ac98a26eb294abf95a8c59b88000000000000000007");
1096 let header = Header::decode(&mut raw.as_slice()).unwrap();
1097 assert_eq!(
1098 header.hash_slow(),
1099 b256!("0x4f05e4392969fc82e41f6d6a8cea379323b0b2d3ddf7def1a33eec03883e3a33")
1100 );
1101 }
1102}
1103
1104#[cfg(all(test, feature = "serde"))]
1105mod serde_tests {
1106 use super::*;
1107 use alloy_primitives::b256;
1108
1109 #[test]
1110 fn test_header_serde_json_roundtrip() {
1111 let raw = r#"{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x0","number":"0x0","gasLimit":"0x0","gasUsed":"0x0","timestamp":"0x0","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":"0x1","withdrawalsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"}"#;
1112 let header = Header {
1113 base_fee_per_gas: Some(1),
1114 withdrawals_root: Some(EMPTY_ROOT_HASH),
1115 ..Default::default()
1116 };
1117
1118 let encoded = serde_json::to_string(&header).unwrap();
1119 assert_eq!(encoded, raw);
1120
1121 let decoded: Header = serde_json::from_str(&encoded).unwrap();
1122 assert_eq!(decoded, header);
1123
1124 let mut encoded_rlp = Vec::new();
1126
1127 decoded.encode(&mut encoded_rlp);
1129
1130 let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1132
1133 assert_eq!(decoded_rlp, decoded);
1135 }
1136
1137 #[test]
1138 fn serde_rlp_prague() {
1139 let raw = r#"{"baseFeePerGas":"0x7","blobGasUsed":"0x20000","difficulty":"0x0","excessBlobGas":"0x40000","extraData":"0xd883010e0c846765746888676f312e32332e32856c696e7578","gasLimit":"0x1c9c380","gasUsed":"0x5208","hash":"0x661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xf97e180c050e5ab072211ad2c213eb5aee4df134","mixHash":"0xe6d9c084dd36560520d5776a5387a82fb44793c9cd1b69afb61d53af29ee64b0","nonce":"0x0000000000000000","number":"0x315","parentBeaconBlockRoot":"0xd0bdb48ab45028568e66c8ddd600ac4c2a52522714bbfbf00ea6d20ba40f3ae2","parentHash":"0x60f1563d2c572116091a4b91421d8d972118e39604d23455d841f9431cea4b6a","receiptsRoot":"0xeaa8c40899a61ae59615cf9985f5e2194f8fd2b57d273be63bde6733e89b12ab","requestsHash":"0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","stateRoot":"0x8101d88f2761eb9849634740f92fe09735551ad5a4d5e9da9bcae1ef4726a475","timestamp":"0x6712ba6e","transactionsRoot":"0xf543eb3d405d2d6320344d348b06703ff1abeef71288181a24061e53f89bb5ef","withdrawalsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"}
1141"#;
1142 let header = serde_json::from_str::<Header>(raw).unwrap();
1143 let hash = header.hash_slow();
1144 assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1145 let mut v = Vec::new();
1146 header.encode(&mut v);
1147 let decoded = Header::decode(&mut v.as_slice()).unwrap();
1148 assert_eq!(decoded, header);
1149 }
1150}