1use crate::{
2 constants::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH},
3 Block, BlockBody,
4};
5use alloc::vec::Vec;
6use alloy_eips::{
7 eip1559::{calc_next_block_base_fee, BaseFeeParams},
8 eip1898::BlockWithParent,
9 eip7840::BlobParams,
10 merge::ALLOWED_FUTURE_BLOCK_TIME_SECONDS,
11 BlockNumHash,
12};
13use alloy_primitives::{
14 keccak256, Address, BlockNumber, Bloom, Bytes, Sealable, Sealed, B256, B64, U256,
15};
16use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable};
17use core::mem;
18
19#[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"))]
23pub struct Header {
24 pub parent_hash: B256,
27 #[cfg_attr(feature = "serde", serde(rename = "sha3Uncles", alias = "ommersHash"))]
29 pub ommers_hash: B256,
30 #[cfg_attr(feature = "serde", serde(rename = "miner", alias = "beneficiary"))]
33 pub beneficiary: Address,
34 pub state_root: B256,
37 pub transactions_root: B256,
40 pub receipts_root: B256,
43 pub logs_bloom: Bloom,
47 pub difficulty: U256,
50 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
53 pub number: BlockNumber,
54 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
56 pub gas_limit: u64,
57 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
59 pub gas_used: u64,
60 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
63 pub timestamp: u64,
64 pub extra_data: Bytes,
67 pub mix_hash: B256,
71 pub nonce: B64,
74 #[cfg_attr(
81 feature = "serde",
82 serde(
83 default,
84 with = "alloy_serde::quantity::opt",
85 skip_serializing_if = "Option::is_none"
86 )
87 )]
88 pub base_fee_per_gas: Option<u64>,
89 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
92 pub withdrawals_root: Option<B256>,
93 #[cfg_attr(
96 feature = "serde",
97 serde(
98 default,
99 with = "alloy_serde::quantity::opt",
100 skip_serializing_if = "Option::is_none"
101 )
102 )]
103 pub blob_gas_used: Option<u64>,
104 #[cfg_attr(
108 feature = "serde",
109 serde(
110 default,
111 with = "alloy_serde::quantity::opt",
112 skip_serializing_if = "Option::is_none"
113 )
114 )]
115 pub excess_blob_gas: Option<u64>,
116 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
124 pub parent_beacon_block_root: Option<B256>,
125 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
130 pub requests_hash: Option<B256>,
131}
132
133impl AsRef<Self> for Header {
134 fn as_ref(&self) -> &Self {
135 self
136 }
137}
138
139impl Default for Header {
140 fn default() -> Self {
141 Self {
142 parent_hash: Default::default(),
143 ommers_hash: EMPTY_OMMER_ROOT_HASH,
144 beneficiary: Default::default(),
145 state_root: EMPTY_ROOT_HASH,
146 transactions_root: EMPTY_ROOT_HASH,
147 receipts_root: EMPTY_ROOT_HASH,
148 logs_bloom: Default::default(),
149 difficulty: Default::default(),
150 number: 0,
151 gas_limit: 0,
152 gas_used: 0,
153 timestamp: 0,
154 extra_data: Default::default(),
155 mix_hash: Default::default(),
156 nonce: B64::ZERO,
157 base_fee_per_gas: None,
158 withdrawals_root: None,
159 blob_gas_used: None,
160 excess_blob_gas: None,
161 parent_beacon_block_root: None,
162 requests_hash: None,
163 }
164 }
165}
166
167impl Sealable for Header {
168 fn hash_slow(&self) -> B256 {
169 self.hash_slow()
170 }
171}
172
173impl Header {
174 pub const fn into_block<T>(self, body: BlockBody<T>) -> Block<T> {
176 body.into_block(self)
177 }
178
179 pub fn hash_slow(&self) -> B256 {
183 let mut out = Vec::<u8>::new();
184 self.encode(&mut out);
185 keccak256(&out)
186 }
187
188 pub fn ommers_hash_is_empty(&self) -> bool {
190 self.ommers_hash == EMPTY_OMMER_ROOT_HASH
191 }
192
193 pub fn transaction_root_is_empty(&self) -> bool {
195 self.transactions_root == EMPTY_ROOT_HASH
196 }
197
198 pub fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
202 Some(blob_params.calc_blob_fee(self.excess_blob_gas?))
203 }
204
205 pub fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
211 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
212 }
213
214 pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
218 Some(calc_next_block_base_fee(
219 self.gas_used,
220 self.gas_limit,
221 self.base_fee_per_gas?,
222 base_fee_params,
223 ))
224 }
225
226 pub fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
231 Some(blob_params.next_block_excess_blob_gas(self.excess_blob_gas?, self.blob_gas_used?))
232 }
233
234 #[inline]
236 pub fn size(&self) -> usize {
237 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::<u128>() + mem::size_of::<u128>() + mem::size_of::<u64>() + mem::size_of::<B256>() + mem::size_of::<u64>() + mem::size_of::<Option<u128>>() + mem::size_of::<Option<u128>>() + mem::size_of::<Option<u128>>() + mem::size_of::<Option<B256>>() + mem::size_of::<Option<B256>>() + self.extra_data.len() }
259
260 fn header_payload_length(&self) -> usize {
261 let mut length = 0;
262 length += self.parent_hash.length();
263 length += self.ommers_hash.length();
264 length += self.beneficiary.length();
265 length += self.state_root.length();
266 length += self.transactions_root.length();
267 length += self.receipts_root.length();
268 length += self.logs_bloom.length();
269 length += self.difficulty.length();
270 length += U256::from(self.number).length();
271 length += U256::from(self.gas_limit).length();
272 length += U256::from(self.gas_used).length();
273 length += self.timestamp.length();
274 length += self.extra_data.length();
275 length += self.mix_hash.length();
276 length += self.nonce.length();
277
278 if let Some(base_fee) = self.base_fee_per_gas {
279 length += U256::from(base_fee).length();
281 }
282
283 if let Some(root) = self.withdrawals_root {
284 length += root.length();
286 }
287
288 if let Some(blob_gas_used) = self.blob_gas_used {
289 length += U256::from(blob_gas_used).length();
291 }
292
293 if let Some(excess_blob_gas) = self.excess_blob_gas {
294 length += U256::from(excess_blob_gas).length();
296 }
297
298 if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
299 length += parent_beacon_block_root.length();
300 }
301
302 if let Some(requests_hash) = self.requests_hash {
303 length += requests_hash.length();
304 }
305
306 length
307 }
308
309 pub const fn parent_num_hash(&self) -> BlockNumHash {
313 BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
314 }
315
316 pub fn num_hash_slow(&self) -> BlockNumHash {
320 BlockNumHash { number: self.number, hash: self.hash_slow() }
321 }
322
323 pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
327 BlockWithParent::new(self.parent_hash, self.num_hash_slow())
328 }
329
330 #[inline]
334 pub const fn seal(self, hash: B256) -> Sealed<Self> {
335 Sealed::new_unchecked(self, hash)
336 }
337
338 pub const fn shanghai_active(&self) -> bool {
342 self.withdrawals_root.is_some()
343 }
344
345 pub const fn cancun_active(&self) -> bool {
349 self.blob_gas_used.is_some()
350 }
351
352 pub const fn prague_active(&self) -> bool {
356 self.requests_hash.is_some()
357 }
358}
359
360impl Encodable for Header {
361 fn encode(&self, out: &mut dyn BufMut) {
362 let list_header =
363 alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
364 list_header.encode(out);
365 self.parent_hash.encode(out);
366 self.ommers_hash.encode(out);
367 self.beneficiary.encode(out);
368 self.state_root.encode(out);
369 self.transactions_root.encode(out);
370 self.receipts_root.encode(out);
371 self.logs_bloom.encode(out);
372 self.difficulty.encode(out);
373 U256::from(self.number).encode(out);
374 U256::from(self.gas_limit).encode(out);
375 U256::from(self.gas_used).encode(out);
376 self.timestamp.encode(out);
377 self.extra_data.encode(out);
378 self.mix_hash.encode(out);
379 self.nonce.encode(out);
380
381 if let Some(ref base_fee) = self.base_fee_per_gas {
383 U256::from(*base_fee).encode(out);
384 }
385
386 if let Some(ref root) = self.withdrawals_root {
387 root.encode(out);
388 }
389
390 if let Some(ref blob_gas_used) = self.blob_gas_used {
391 U256::from(*blob_gas_used).encode(out);
392 }
393
394 if let Some(ref excess_blob_gas) = self.excess_blob_gas {
395 U256::from(*excess_blob_gas).encode(out);
396 }
397
398 if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
399 parent_beacon_block_root.encode(out);
400 }
401
402 if let Some(ref requests_hash) = self.requests_hash {
403 requests_hash.encode(out);
404 }
405 }
406
407 fn length(&self) -> usize {
408 let mut length = 0;
409 length += self.header_payload_length();
410 length += length_of_length(length);
411 length
412 }
413}
414
415impl Decodable for Header {
416 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
417 let rlp_head = alloy_rlp::Header::decode(buf)?;
418 if !rlp_head.list {
419 return Err(alloy_rlp::Error::UnexpectedString);
420 }
421 let started_len = buf.len();
422 let mut this = Self {
423 parent_hash: Decodable::decode(buf)?,
424 ommers_hash: Decodable::decode(buf)?,
425 beneficiary: Decodable::decode(buf)?,
426 state_root: Decodable::decode(buf)?,
427 transactions_root: Decodable::decode(buf)?,
428 receipts_root: Decodable::decode(buf)?,
429 logs_bloom: Decodable::decode(buf)?,
430 difficulty: Decodable::decode(buf)?,
431 number: u64::decode(buf)?,
432 gas_limit: u64::decode(buf)?,
433 gas_used: u64::decode(buf)?,
434 timestamp: Decodable::decode(buf)?,
435 extra_data: Decodable::decode(buf)?,
436 mix_hash: Decodable::decode(buf)?,
437 nonce: B64::decode(buf)?,
438 base_fee_per_gas: None,
439 withdrawals_root: None,
440 blob_gas_used: None,
441 excess_blob_gas: None,
442 parent_beacon_block_root: None,
443 requests_hash: None,
444 };
445 if started_len - buf.len() < rlp_head.payload_length {
446 this.base_fee_per_gas = Some(u64::decode(buf)?);
447 }
448
449 if started_len - buf.len() < rlp_head.payload_length {
451 this.withdrawals_root = Some(Decodable::decode(buf)?);
452 }
453
454 if started_len - buf.len() < rlp_head.payload_length {
456 this.blob_gas_used = Some(u64::decode(buf)?);
457 }
458
459 if started_len - buf.len() < rlp_head.payload_length {
460 this.excess_blob_gas = Some(u64::decode(buf)?);
461 }
462
463 if started_len - buf.len() < rlp_head.payload_length {
465 this.parent_beacon_block_root = Some(B256::decode(buf)?);
466 }
467
468 if started_len - buf.len() < rlp_head.payload_length {
470 this.requests_hash = Some(B256::decode(buf)?);
471 }
472
473 let consumed = started_len - buf.len();
474 if consumed != rlp_head.payload_length {
475 return Err(alloy_rlp::Error::ListLengthMismatch {
476 expected: rlp_head.payload_length,
477 got: consumed,
478 });
479 }
480 Ok(this)
481 }
482}
483
484#[cfg(any(test, feature = "arbitrary"))]
493pub(crate) const fn generate_valid_header(
494 mut header: Header,
495 eip_4844_active: bool,
496 blob_gas_used: u64,
497 excess_blob_gas: u64,
498 parent_beacon_block_root: B256,
499) -> Header {
500 if header.base_fee_per_gas.is_none() {
502 header.withdrawals_root = None;
503 }
504
505 if eip_4844_active {
507 header.blob_gas_used = Some(blob_gas_used);
508 header.excess_blob_gas = Some(excess_blob_gas);
509 header.parent_beacon_block_root = Some(parent_beacon_block_root);
510 } else {
511 header.blob_gas_used = None;
512 header.excess_blob_gas = None;
513 header.parent_beacon_block_root = None;
514 }
515
516 header.requests_hash = None;
518
519 header
520}
521
522#[cfg(any(test, feature = "arbitrary"))]
523impl<'a> arbitrary::Arbitrary<'a> for Header {
524 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
525 let base = Self {
528 parent_hash: u.arbitrary()?,
529 ommers_hash: u.arbitrary()?,
530 beneficiary: u.arbitrary()?,
531 state_root: u.arbitrary()?,
532 transactions_root: u.arbitrary()?,
533 receipts_root: u.arbitrary()?,
534 logs_bloom: u.arbitrary()?,
535 difficulty: u.arbitrary()?,
536 number: u.arbitrary()?,
537 gas_limit: u.arbitrary()?,
538 gas_used: u.arbitrary()?,
539 timestamp: u.arbitrary()?,
540 extra_data: u.arbitrary()?,
541 mix_hash: u.arbitrary()?,
542 nonce: u.arbitrary()?,
543 base_fee_per_gas: u.arbitrary()?,
544 blob_gas_used: u.arbitrary()?,
545 excess_blob_gas: u.arbitrary()?,
546 parent_beacon_block_root: u.arbitrary()?,
547 requests_hash: u.arbitrary()?,
548 withdrawals_root: u.arbitrary()?,
549 };
550
551 Ok(generate_valid_header(
552 base,
553 u.arbitrary()?,
554 u.arbitrary()?,
555 u.arbitrary()?,
556 u.arbitrary()?,
557 ))
558 }
559}
560
561#[auto_impl::auto_impl(&, Arc)]
563pub trait BlockHeader {
564 fn parent_hash(&self) -> B256;
566
567 fn ommers_hash(&self) -> B256;
569
570 fn beneficiary(&self) -> Address;
572
573 fn state_root(&self) -> B256;
575
576 fn transactions_root(&self) -> B256;
578
579 fn receipts_root(&self) -> B256;
581
582 fn withdrawals_root(&self) -> Option<B256>;
584
585 fn logs_bloom(&self) -> Bloom;
587
588 fn difficulty(&self) -> U256;
590
591 fn number(&self) -> BlockNumber;
593
594 fn gas_limit(&self) -> u64;
596
597 fn gas_used(&self) -> u64;
599
600 fn timestamp(&self) -> u64;
602
603 fn mix_hash(&self) -> Option<B256>;
605
606 fn nonce(&self) -> Option<B64>;
608
609 fn base_fee_per_gas(&self) -> Option<u64>;
611
612 fn blob_gas_used(&self) -> Option<u64>;
614
615 fn excess_blob_gas(&self) -> Option<u64>;
617
618 fn parent_beacon_block_root(&self) -> Option<B256>;
620
621 fn requests_hash(&self) -> Option<B256>;
623
624 fn extra_data(&self) -> &Bytes;
626
627 fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
631 Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
632 }
633
634 fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
639 Some(blob_params.next_block_excess_blob_gas(self.excess_blob_gas()?, self.blob_gas_used()?))
640 }
641
642 fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
647 self.next_block_excess_blob_gas(blob_params?)
648 }
649
650 fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
656 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
657 }
658
659 fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
664 self.next_block_blob_fee(blob_params?)
665 }
666
667 fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
671 Some(calc_next_block_base_fee(
672 self.gas_used(),
673 self.gas_limit(),
674 self.base_fee_per_gas()?,
675 base_fee_params,
676 ))
677 }
678
679 fn parent_num_hash(&self) -> BlockNumHash {
683 BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
684 }
685
686 fn is_empty(&self) -> bool {
688 let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
689 && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
690 self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
691 txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
692 })
693 }
694
695 fn is_zero_difficulty(&self) -> bool {
705 self.difficulty().is_zero()
706 }
707
708 fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
714 self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
715 }
716
717 fn is_nonce_zero(&self) -> bool {
721 self.nonce().is_some_and(|nonce| nonce.is_zero())
722 }
723}
724
725impl BlockHeader for Header {
726 fn parent_hash(&self) -> B256 {
727 self.parent_hash
728 }
729
730 fn ommers_hash(&self) -> B256 {
731 self.ommers_hash
732 }
733
734 fn beneficiary(&self) -> Address {
735 self.beneficiary
736 }
737
738 fn state_root(&self) -> B256 {
739 self.state_root
740 }
741
742 fn transactions_root(&self) -> B256 {
743 self.transactions_root
744 }
745
746 fn receipts_root(&self) -> B256 {
747 self.receipts_root
748 }
749
750 fn withdrawals_root(&self) -> Option<B256> {
751 self.withdrawals_root
752 }
753
754 fn logs_bloom(&self) -> Bloom {
755 self.logs_bloom
756 }
757
758 fn difficulty(&self) -> U256 {
759 self.difficulty
760 }
761
762 fn number(&self) -> BlockNumber {
763 self.number
764 }
765
766 fn gas_limit(&self) -> u64 {
767 self.gas_limit
768 }
769
770 fn gas_used(&self) -> u64 {
771 self.gas_used
772 }
773
774 fn timestamp(&self) -> u64 {
775 self.timestamp
776 }
777
778 fn mix_hash(&self) -> Option<B256> {
779 Some(self.mix_hash)
780 }
781
782 fn nonce(&self) -> Option<B64> {
783 Some(self.nonce)
784 }
785
786 fn base_fee_per_gas(&self) -> Option<u64> {
787 self.base_fee_per_gas
788 }
789
790 fn blob_gas_used(&self) -> Option<u64> {
791 self.blob_gas_used
792 }
793
794 fn excess_blob_gas(&self) -> Option<u64> {
795 self.excess_blob_gas
796 }
797
798 fn parent_beacon_block_root(&self) -> Option<B256> {
799 self.parent_beacon_block_root
800 }
801
802 fn requests_hash(&self) -> Option<B256> {
803 self.requests_hash
804 }
805
806 fn extra_data(&self) -> &Bytes {
807 &self.extra_data
808 }
809}
810
811#[cfg(feature = "serde")]
812impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
813 fn parent_hash(&self) -> B256 {
814 self.inner.parent_hash()
815 }
816
817 fn ommers_hash(&self) -> B256 {
818 self.inner.ommers_hash()
819 }
820
821 fn beneficiary(&self) -> Address {
822 self.inner.beneficiary()
823 }
824
825 fn state_root(&self) -> B256 {
826 self.inner.state_root()
827 }
828
829 fn transactions_root(&self) -> B256 {
830 self.inner.transactions_root()
831 }
832
833 fn receipts_root(&self) -> B256 {
834 self.inner.receipts_root()
835 }
836
837 fn withdrawals_root(&self) -> Option<B256> {
838 self.inner.withdrawals_root()
839 }
840
841 fn logs_bloom(&self) -> Bloom {
842 self.inner.logs_bloom()
843 }
844
845 fn difficulty(&self) -> U256 {
846 self.inner.difficulty()
847 }
848
849 fn number(&self) -> u64 {
850 self.inner.number()
851 }
852
853 fn gas_limit(&self) -> u64 {
854 self.inner.gas_limit()
855 }
856
857 fn gas_used(&self) -> u64 {
858 self.inner.gas_used()
859 }
860
861 fn timestamp(&self) -> u64 {
862 self.inner.timestamp()
863 }
864
865 fn mix_hash(&self) -> Option<B256> {
866 self.inner.mix_hash()
867 }
868
869 fn nonce(&self) -> Option<B64> {
870 self.inner.nonce()
871 }
872
873 fn base_fee_per_gas(&self) -> Option<u64> {
874 self.inner.base_fee_per_gas()
875 }
876
877 fn blob_gas_used(&self) -> Option<u64> {
878 self.inner.blob_gas_used()
879 }
880
881 fn excess_blob_gas(&self) -> Option<u64> {
882 self.inner.excess_blob_gas()
883 }
884
885 fn parent_beacon_block_root(&self) -> Option<B256> {
886 self.inner.parent_beacon_block_root()
887 }
888
889 fn requests_hash(&self) -> Option<B256> {
890 self.inner.requests_hash()
891 }
892
893 fn extra_data(&self) -> &Bytes {
894 self.inner.extra_data()
895 }
896
897 fn is_empty(&self) -> bool {
898 self.inner.is_empty()
899 }
900}
901
902#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
904pub(crate) mod serde_bincode_compat {
905 use alloc::borrow::Cow;
906 use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
907 use serde::{Deserialize, Deserializer, Serialize, Serializer};
908 use serde_with::{DeserializeAs, SerializeAs};
909
910 #[derive(Debug, Serialize, Deserialize)]
926 pub struct Header<'a> {
927 parent_hash: B256,
928 ommers_hash: B256,
929 beneficiary: Address,
930 state_root: B256,
931 transactions_root: B256,
932 receipts_root: B256,
933 #[serde(default)]
934 withdrawals_root: Option<B256>,
935 logs_bloom: Bloom,
936 difficulty: U256,
937 number: BlockNumber,
938 gas_limit: u64,
939 gas_used: u64,
940 timestamp: u64,
941 mix_hash: B256,
942 nonce: B64,
943 #[serde(default)]
944 base_fee_per_gas: Option<u64>,
945 #[serde(default)]
946 blob_gas_used: Option<u64>,
947 #[serde(default)]
948 excess_blob_gas: Option<u64>,
949 #[serde(default)]
950 parent_beacon_block_root: Option<B256>,
951 #[serde(default)]
952 requests_hash: Option<B256>,
953 extra_data: Cow<'a, Bytes>,
954 }
955
956 impl<'a> From<&'a super::Header> for Header<'a> {
957 fn from(value: &'a super::Header) -> Self {
958 Self {
959 parent_hash: value.parent_hash,
960 ommers_hash: value.ommers_hash,
961 beneficiary: value.beneficiary,
962 state_root: value.state_root,
963 transactions_root: value.transactions_root,
964 receipts_root: value.receipts_root,
965 withdrawals_root: value.withdrawals_root,
966 logs_bloom: value.logs_bloom,
967 difficulty: value.difficulty,
968 number: value.number,
969 gas_limit: value.gas_limit,
970 gas_used: value.gas_used,
971 timestamp: value.timestamp,
972 mix_hash: value.mix_hash,
973 nonce: value.nonce,
974 base_fee_per_gas: value.base_fee_per_gas,
975 blob_gas_used: value.blob_gas_used,
976 excess_blob_gas: value.excess_blob_gas,
977 parent_beacon_block_root: value.parent_beacon_block_root,
978 requests_hash: value.requests_hash,
979 extra_data: Cow::Borrowed(&value.extra_data),
980 }
981 }
982 }
983
984 impl<'a> From<Header<'a>> for super::Header {
985 fn from(value: Header<'a>) -> Self {
986 Self {
987 parent_hash: value.parent_hash,
988 ommers_hash: value.ommers_hash,
989 beneficiary: value.beneficiary,
990 state_root: value.state_root,
991 transactions_root: value.transactions_root,
992 receipts_root: value.receipts_root,
993 withdrawals_root: value.withdrawals_root,
994 logs_bloom: value.logs_bloom,
995 difficulty: value.difficulty,
996 number: value.number,
997 gas_limit: value.gas_limit,
998 gas_used: value.gas_used,
999 timestamp: value.timestamp,
1000 mix_hash: value.mix_hash,
1001 nonce: value.nonce,
1002 base_fee_per_gas: value.base_fee_per_gas,
1003 blob_gas_used: value.blob_gas_used,
1004 excess_blob_gas: value.excess_blob_gas,
1005 parent_beacon_block_root: value.parent_beacon_block_root,
1006 requests_hash: value.requests_hash,
1007 extra_data: value.extra_data.into_owned(),
1008 }
1009 }
1010 }
1011
1012 impl SerializeAs<super::Header> for Header<'_> {
1013 fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
1014 where
1015 S: Serializer,
1016 {
1017 Header::from(source).serialize(serializer)
1018 }
1019 }
1020
1021 impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1022 fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1023 where
1024 D: Deserializer<'de>,
1025 {
1026 Header::deserialize(deserializer).map(Into::into)
1027 }
1028 }
1029
1030 #[cfg(test)]
1031 mod tests {
1032 use arbitrary::Arbitrary;
1033 use rand::Rng;
1034 use serde::{Deserialize, Serialize};
1035 use serde_with::serde_as;
1036
1037 use super::super::{serde_bincode_compat, Header};
1038
1039 #[test]
1040 fn test_header_bincode_roundtrip() {
1041 #[serde_as]
1042 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1043 struct Data {
1044 #[serde_as(as = "serde_bincode_compat::Header")]
1045 header: Header,
1046 }
1047
1048 let mut bytes = [0u8; 1024];
1049 rand::thread_rng().fill(bytes.as_mut_slice());
1050 let data = Data {
1051 header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1052 };
1053
1054 let encoded = bincode::serialize(&data).unwrap();
1055 let decoded: Data = bincode::deserialize(&encoded).unwrap();
1056 assert_eq!(decoded, data);
1057 }
1058 }
1059}
1060
1061#[cfg(all(test, feature = "serde"))]
1062mod tests {
1063 use super::*;
1064 use alloy_primitives::b256;
1065
1066 #[test]
1067 fn test_header_serde_json_roundtrip() {
1068 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"}"#;
1069 let header = Header {
1070 base_fee_per_gas: Some(1),
1071 withdrawals_root: Some(EMPTY_ROOT_HASH),
1072 ..Default::default()
1073 };
1074
1075 let encoded = serde_json::to_string(&header).unwrap();
1076 assert_eq!(encoded, raw);
1077
1078 let decoded: Header = serde_json::from_str(&encoded).unwrap();
1079 assert_eq!(decoded, header);
1080
1081 let mut encoded_rlp = Vec::new();
1083
1084 decoded.encode(&mut encoded_rlp);
1086
1087 let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1089
1090 assert_eq!(decoded_rlp, decoded);
1092 }
1093
1094 #[test]
1095 fn serde_rlp_prague() {
1096 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"}
1098"#;
1099 let header = serde_json::from_str::<Header>(raw).unwrap();
1100 let hash = header.hash_slow();
1101 assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1102 let mut v = Vec::new();
1103 header.encode(&mut v);
1104 let decoded = Header::decode(&mut v.as_slice()).unwrap();
1105 assert_eq!(decoded, header);
1106 }
1107}