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"))]
24pub struct Header {
25 pub parent_hash: B256,
28 #[cfg_attr(feature = "serde", serde(rename = "sha3Uncles", alias = "ommersHash"))]
30 pub ommers_hash: B256,
31 #[cfg_attr(feature = "serde", serde(rename = "miner", alias = "beneficiary"))]
34 pub beneficiary: Address,
35 pub state_root: B256,
38 pub transactions_root: B256,
41 pub receipts_root: B256,
44 pub logs_bloom: Bloom,
48 pub difficulty: U256,
51 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
54 pub number: BlockNumber,
55 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
57 pub gas_limit: u64,
58 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
60 pub gas_used: u64,
61 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
64 pub timestamp: u64,
65 pub extra_data: Bytes,
68 pub mix_hash: B256,
72 pub nonce: B64,
75 #[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 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
93 pub withdrawals_root: Option<B256>,
94 #[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 #[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 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
125 pub parent_beacon_block_root: Option<B256>,
126 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
131 pub requests_hash: Option<B256>,
132}
133
134impl AsRef<Self> for Header {
135 fn as_ref(&self) -> &Self {
136 self
137 }
138}
139
140impl Default for Header {
141 fn default() -> Self {
142 Self {
143 parent_hash: Default::default(),
144 ommers_hash: EMPTY_OMMER_ROOT_HASH,
145 beneficiary: Default::default(),
146 state_root: EMPTY_ROOT_HASH,
147 transactions_root: EMPTY_ROOT_HASH,
148 receipts_root: EMPTY_ROOT_HASH,
149 logs_bloom: Default::default(),
150 difficulty: Default::default(),
151 number: 0,
152 gas_limit: 0,
153 gas_used: 0,
154 timestamp: 0,
155 extra_data: Default::default(),
156 mix_hash: Default::default(),
157 nonce: B64::ZERO,
158 base_fee_per_gas: None,
159 withdrawals_root: None,
160 blob_gas_used: None,
161 excess_blob_gas: None,
162 parent_beacon_block_root: None,
163 requests_hash: None,
164 }
165 }
166}
167
168impl Sealable for Header {
169 fn hash_slow(&self) -> B256 {
170 self.hash_slow()
171 }
172}
173
174impl Header {
175 pub const fn into_block<T>(self, body: BlockBody<T>) -> Block<T> {
177 body.into_block(self)
178 }
179
180 pub fn hash_slow(&self) -> B256 {
184 let mut out = Vec::<u8>::new();
185 self.encode(&mut out);
186 keccak256(&out)
187 }
188
189 pub fn ommers_hash_is_empty(&self) -> bool {
191 self.ommers_hash == EMPTY_OMMER_ROOT_HASH
192 }
193
194 pub fn transaction_root_is_empty(&self) -> bool {
196 self.transactions_root == EMPTY_ROOT_HASH
197 }
198
199 pub fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
203 Some(blob_params.calc_blob_fee(self.excess_blob_gas?))
204 }
205
206 pub fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
212 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
213 }
214
215 pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
219 Some(calc_next_block_base_fee(
220 self.gas_used,
221 self.gas_limit,
222 self.base_fee_per_gas?,
223 base_fee_params,
224 ))
225 }
226
227 pub fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
232 Some(blob_params.next_block_excess_blob_gas(self.excess_blob_gas?, self.blob_gas_used?))
233 }
234
235 #[inline]
237 pub fn size(&self) -> usize {
238 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() }
260
261 fn header_payload_length(&self) -> usize {
262 let mut length = 0;
263 length += self.parent_hash.length();
264 length += self.ommers_hash.length();
265 length += self.beneficiary.length();
266 length += self.state_root.length();
267 length += self.transactions_root.length();
268 length += self.receipts_root.length();
269 length += self.logs_bloom.length();
270 length += self.difficulty.length();
271 length += U256::from(self.number).length();
272 length += U256::from(self.gas_limit).length();
273 length += U256::from(self.gas_used).length();
274 length += self.timestamp.length();
275 length += self.extra_data.length();
276 length += self.mix_hash.length();
277 length += self.nonce.length();
278
279 if let Some(base_fee) = self.base_fee_per_gas {
280 length += U256::from(base_fee).length();
282 }
283
284 if let Some(root) = self.withdrawals_root {
285 length += root.length();
287 }
288
289 if let Some(blob_gas_used) = self.blob_gas_used {
290 length += U256::from(blob_gas_used).length();
292 }
293
294 if let Some(excess_blob_gas) = self.excess_blob_gas {
295 length += U256::from(excess_blob_gas).length();
297 }
298
299 if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
300 length += parent_beacon_block_root.length();
301 }
302
303 if let Some(requests_hash) = self.requests_hash {
304 length += requests_hash.length();
305 }
306
307 length
308 }
309
310 pub const fn parent_num_hash(&self) -> BlockNumHash {
314 BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
315 }
316
317 pub fn num_hash_slow(&self) -> BlockNumHash {
321 BlockNumHash { number: self.number, hash: self.hash_slow() }
322 }
323
324 pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
328 BlockWithParent::new(self.parent_hash, self.num_hash_slow())
329 }
330
331 #[inline]
335 pub const fn seal(self, hash: B256) -> Sealed<Self> {
336 Sealed::new_unchecked(self, hash)
337 }
338
339 pub const fn shanghai_active(&self) -> bool {
343 self.withdrawals_root.is_some()
344 }
345
346 pub const fn cancun_active(&self) -> bool {
350 self.blob_gas_used.is_some()
351 }
352
353 pub const fn prague_active(&self) -> bool {
357 self.requests_hash.is_some()
358 }
359}
360
361impl Encodable for Header {
362 fn encode(&self, out: &mut dyn BufMut) {
363 let list_header =
364 alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
365 list_header.encode(out);
366 self.parent_hash.encode(out);
367 self.ommers_hash.encode(out);
368 self.beneficiary.encode(out);
369 self.state_root.encode(out);
370 self.transactions_root.encode(out);
371 self.receipts_root.encode(out);
372 self.logs_bloom.encode(out);
373 self.difficulty.encode(out);
374 U256::from(self.number).encode(out);
375 U256::from(self.gas_limit).encode(out);
376 U256::from(self.gas_used).encode(out);
377 self.timestamp.encode(out);
378 self.extra_data.encode(out);
379 self.mix_hash.encode(out);
380 self.nonce.encode(out);
381
382 if let Some(ref base_fee) = self.base_fee_per_gas {
384 U256::from(*base_fee).encode(out);
385 }
386
387 if let Some(ref root) = self.withdrawals_root {
388 root.encode(out);
389 }
390
391 if let Some(ref blob_gas_used) = self.blob_gas_used {
392 U256::from(*blob_gas_used).encode(out);
393 }
394
395 if let Some(ref excess_blob_gas) = self.excess_blob_gas {
396 U256::from(*excess_blob_gas).encode(out);
397 }
398
399 if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
400 parent_beacon_block_root.encode(out);
401 }
402
403 if let Some(ref requests_hash) = self.requests_hash {
404 requests_hash.encode(out);
405 }
406 }
407
408 fn length(&self) -> usize {
409 let mut length = 0;
410 length += self.header_payload_length();
411 length += length_of_length(length);
412 length
413 }
414}
415
416impl Decodable for Header {
417 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
418 let rlp_head = alloy_rlp::Header::decode(buf)?;
419 if !rlp_head.list {
420 return Err(alloy_rlp::Error::UnexpectedString);
421 }
422 let started_len = buf.len();
423 let mut this = Self {
424 parent_hash: Decodable::decode(buf)?,
425 ommers_hash: Decodable::decode(buf)?,
426 beneficiary: Decodable::decode(buf)?,
427 state_root: Decodable::decode(buf)?,
428 transactions_root: Decodable::decode(buf)?,
429 receipts_root: Decodable::decode(buf)?,
430 logs_bloom: Decodable::decode(buf)?,
431 difficulty: Decodable::decode(buf)?,
432 number: u64::decode(buf)?,
433 gas_limit: u64::decode(buf)?,
434 gas_used: u64::decode(buf)?,
435 timestamp: Decodable::decode(buf)?,
436 extra_data: Decodable::decode(buf)?,
437 mix_hash: Decodable::decode(buf)?,
438 nonce: B64::decode(buf)?,
439 base_fee_per_gas: None,
440 withdrawals_root: None,
441 blob_gas_used: None,
442 excess_blob_gas: None,
443 parent_beacon_block_root: None,
444 requests_hash: None,
445 };
446 if started_len - buf.len() < rlp_head.payload_length {
447 this.base_fee_per_gas = Some(u64::decode(buf)?);
448 }
449
450 if started_len - buf.len() < rlp_head.payload_length {
452 this.withdrawals_root = Some(Decodable::decode(buf)?);
453 }
454
455 if started_len - buf.len() < rlp_head.payload_length {
457 this.blob_gas_used = Some(u64::decode(buf)?);
458 }
459
460 if started_len - buf.len() < rlp_head.payload_length {
461 this.excess_blob_gas = Some(u64::decode(buf)?);
462 }
463
464 if started_len - buf.len() < rlp_head.payload_length {
466 this.parent_beacon_block_root = Some(B256::decode(buf)?);
467 }
468
469 if started_len - buf.len() < rlp_head.payload_length {
471 this.requests_hash = Some(B256::decode(buf)?);
472 }
473
474 let consumed = started_len - buf.len();
475 if consumed != rlp_head.payload_length {
476 return Err(alloy_rlp::Error::ListLengthMismatch {
477 expected: rlp_head.payload_length,
478 got: consumed,
479 });
480 }
481 Ok(this)
482 }
483}
484
485#[cfg(any(test, feature = "arbitrary"))]
494pub(crate) const fn generate_valid_header(
495 mut header: Header,
496 eip_4844_active: bool,
497 blob_gas_used: u64,
498 excess_blob_gas: u64,
499 parent_beacon_block_root: B256,
500) -> Header {
501 if header.base_fee_per_gas.is_none() {
503 header.withdrawals_root = None;
504 }
505
506 if eip_4844_active {
508 header.blob_gas_used = Some(blob_gas_used);
509 header.excess_blob_gas = Some(excess_blob_gas);
510 header.parent_beacon_block_root = Some(parent_beacon_block_root);
511 } else {
512 header.blob_gas_used = None;
513 header.excess_blob_gas = None;
514 header.parent_beacon_block_root = None;
515 }
516
517 header.requests_hash = None;
519
520 header
521}
522
523#[cfg(any(test, feature = "arbitrary"))]
524impl<'a> arbitrary::Arbitrary<'a> for Header {
525 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
526 let base = Self {
529 parent_hash: u.arbitrary()?,
530 ommers_hash: u.arbitrary()?,
531 beneficiary: u.arbitrary()?,
532 state_root: u.arbitrary()?,
533 transactions_root: u.arbitrary()?,
534 receipts_root: u.arbitrary()?,
535 logs_bloom: u.arbitrary()?,
536 difficulty: u.arbitrary()?,
537 number: u.arbitrary()?,
538 gas_limit: u.arbitrary()?,
539 gas_used: u.arbitrary()?,
540 timestamp: u.arbitrary()?,
541 extra_data: u.arbitrary()?,
542 mix_hash: u.arbitrary()?,
543 nonce: u.arbitrary()?,
544 base_fee_per_gas: u.arbitrary()?,
545 blob_gas_used: u.arbitrary()?,
546 excess_blob_gas: u.arbitrary()?,
547 parent_beacon_block_root: u.arbitrary()?,
548 requests_hash: u.arbitrary()?,
549 withdrawals_root: u.arbitrary()?,
550 };
551
552 Ok(generate_valid_header(
553 base,
554 u.arbitrary()?,
555 u.arbitrary()?,
556 u.arbitrary()?,
557 u.arbitrary()?,
558 ))
559 }
560}
561
562#[auto_impl::auto_impl(&, Arc)]
564pub trait BlockHeader {
565 fn header_info(&self) -> HeaderInfo {
567 HeaderInfo {
568 number: self.number(),
569 beneficiary: self.beneficiary(),
570 timestamp: self.timestamp(),
571 gas_limit: self.gas_limit(),
572 base_fee_per_gas: self.base_fee_per_gas(),
573 excess_blob_gas: self.excess_blob_gas(),
574 blob_gas_used: self.blob_gas_used(),
575 difficulty: self.difficulty(),
576 mix_hash: self.mix_hash(),
577 }
578 }
579
580 fn parent_hash(&self) -> B256;
582
583 fn ommers_hash(&self) -> B256;
585
586 fn beneficiary(&self) -> Address;
588
589 fn state_root(&self) -> B256;
591
592 fn transactions_root(&self) -> B256;
594
595 fn receipts_root(&self) -> B256;
597
598 fn withdrawals_root(&self) -> Option<B256>;
600
601 fn logs_bloom(&self) -> Bloom;
603
604 fn difficulty(&self) -> U256;
606
607 fn number(&self) -> BlockNumber;
609
610 fn gas_limit(&self) -> u64;
612
613 fn gas_used(&self) -> u64;
615
616 fn timestamp(&self) -> u64;
618
619 fn mix_hash(&self) -> Option<B256>;
621
622 fn nonce(&self) -> Option<B64>;
624
625 fn base_fee_per_gas(&self) -> Option<u64>;
627
628 fn blob_gas_used(&self) -> Option<u64>;
630
631 fn excess_blob_gas(&self) -> Option<u64>;
633
634 fn parent_beacon_block_root(&self) -> Option<B256>;
636
637 fn requests_hash(&self) -> Option<B256>;
639
640 fn extra_data(&self) -> &Bytes;
642
643 fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
647 Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
648 }
649
650 fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
655 Some(blob_params.next_block_excess_blob_gas(self.excess_blob_gas()?, self.blob_gas_used()?))
656 }
657
658 fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
663 self.next_block_excess_blob_gas(blob_params?)
664 }
665
666 fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
672 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
673 }
674
675 fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
680 self.next_block_blob_fee(blob_params?)
681 }
682
683 fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
687 Some(calc_next_block_base_fee(
688 self.gas_used(),
689 self.gas_limit(),
690 self.base_fee_per_gas()?,
691 base_fee_params,
692 ))
693 }
694
695 fn parent_num_hash(&self) -> BlockNumHash {
699 BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
700 }
701
702 fn is_empty(&self) -> bool {
704 let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
705 && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
706 self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
707 txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
708 })
709 }
710
711 fn is_zero_difficulty(&self) -> bool {
721 self.difficulty().is_zero()
722 }
723
724 fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
730 self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
731 }
732
733 fn is_nonce_zero(&self) -> bool {
737 self.nonce().is_some_and(|nonce| nonce.is_zero())
738 }
739}
740
741impl BlockHeader for Header {
742 fn parent_hash(&self) -> B256 {
743 self.parent_hash
744 }
745
746 fn ommers_hash(&self) -> B256 {
747 self.ommers_hash
748 }
749
750 fn beneficiary(&self) -> Address {
751 self.beneficiary
752 }
753
754 fn state_root(&self) -> B256 {
755 self.state_root
756 }
757
758 fn transactions_root(&self) -> B256 {
759 self.transactions_root
760 }
761
762 fn receipts_root(&self) -> B256 {
763 self.receipts_root
764 }
765
766 fn withdrawals_root(&self) -> Option<B256> {
767 self.withdrawals_root
768 }
769
770 fn logs_bloom(&self) -> Bloom {
771 self.logs_bloom
772 }
773
774 fn difficulty(&self) -> U256 {
775 self.difficulty
776 }
777
778 fn number(&self) -> BlockNumber {
779 self.number
780 }
781
782 fn gas_limit(&self) -> u64 {
783 self.gas_limit
784 }
785
786 fn gas_used(&self) -> u64 {
787 self.gas_used
788 }
789
790 fn timestamp(&self) -> u64 {
791 self.timestamp
792 }
793
794 fn mix_hash(&self) -> Option<B256> {
795 Some(self.mix_hash)
796 }
797
798 fn nonce(&self) -> Option<B64> {
799 Some(self.nonce)
800 }
801
802 fn base_fee_per_gas(&self) -> Option<u64> {
803 self.base_fee_per_gas
804 }
805
806 fn blob_gas_used(&self) -> Option<u64> {
807 self.blob_gas_used
808 }
809
810 fn excess_blob_gas(&self) -> Option<u64> {
811 self.excess_blob_gas
812 }
813
814 fn parent_beacon_block_root(&self) -> Option<B256> {
815 self.parent_beacon_block_root
816 }
817
818 fn requests_hash(&self) -> Option<B256> {
819 self.requests_hash
820 }
821
822 fn extra_data(&self) -> &Bytes {
823 &self.extra_data
824 }
825}
826
827#[cfg(feature = "serde")]
828impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
829 fn parent_hash(&self) -> B256 {
830 self.inner.parent_hash()
831 }
832
833 fn ommers_hash(&self) -> B256 {
834 self.inner.ommers_hash()
835 }
836
837 fn beneficiary(&self) -> Address {
838 self.inner.beneficiary()
839 }
840
841 fn state_root(&self) -> B256 {
842 self.inner.state_root()
843 }
844
845 fn transactions_root(&self) -> B256 {
846 self.inner.transactions_root()
847 }
848
849 fn receipts_root(&self) -> B256 {
850 self.inner.receipts_root()
851 }
852
853 fn withdrawals_root(&self) -> Option<B256> {
854 self.inner.withdrawals_root()
855 }
856
857 fn logs_bloom(&self) -> Bloom {
858 self.inner.logs_bloom()
859 }
860
861 fn difficulty(&self) -> U256 {
862 self.inner.difficulty()
863 }
864
865 fn number(&self) -> u64 {
866 self.inner.number()
867 }
868
869 fn gas_limit(&self) -> u64 {
870 self.inner.gas_limit()
871 }
872
873 fn gas_used(&self) -> u64 {
874 self.inner.gas_used()
875 }
876
877 fn timestamp(&self) -> u64 {
878 self.inner.timestamp()
879 }
880
881 fn mix_hash(&self) -> Option<B256> {
882 self.inner.mix_hash()
883 }
884
885 fn nonce(&self) -> Option<B64> {
886 self.inner.nonce()
887 }
888
889 fn base_fee_per_gas(&self) -> Option<u64> {
890 self.inner.base_fee_per_gas()
891 }
892
893 fn blob_gas_used(&self) -> Option<u64> {
894 self.inner.blob_gas_used()
895 }
896
897 fn excess_blob_gas(&self) -> Option<u64> {
898 self.inner.excess_blob_gas()
899 }
900
901 fn parent_beacon_block_root(&self) -> Option<B256> {
902 self.inner.parent_beacon_block_root()
903 }
904
905 fn requests_hash(&self) -> Option<B256> {
906 self.inner.requests_hash()
907 }
908
909 fn extra_data(&self) -> &Bytes {
910 self.inner.extra_data()
911 }
912
913 fn is_empty(&self) -> bool {
914 self.inner.is_empty()
915 }
916}
917
918#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
920pub(crate) mod serde_bincode_compat {
921 use alloc::borrow::Cow;
922 use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
923 use serde::{Deserialize, Deserializer, Serialize, Serializer};
924 use serde_with::{DeserializeAs, SerializeAs};
925
926 #[derive(Debug, Serialize, Deserialize)]
942 pub struct Header<'a> {
943 parent_hash: B256,
944 ommers_hash: B256,
945 beneficiary: Address,
946 state_root: B256,
947 transactions_root: B256,
948 receipts_root: B256,
949 #[serde(default)]
950 withdrawals_root: Option<B256>,
951 logs_bloom: Bloom,
952 difficulty: U256,
953 number: BlockNumber,
954 gas_limit: u64,
955 gas_used: u64,
956 timestamp: u64,
957 mix_hash: B256,
958 nonce: B64,
959 #[serde(default)]
960 base_fee_per_gas: Option<u64>,
961 #[serde(default)]
962 blob_gas_used: Option<u64>,
963 #[serde(default)]
964 excess_blob_gas: Option<u64>,
965 #[serde(default)]
966 parent_beacon_block_root: Option<B256>,
967 #[serde(default)]
968 requests_hash: Option<B256>,
969 extra_data: Cow<'a, Bytes>,
970 }
971
972 impl<'a> From<&'a super::Header> for Header<'a> {
973 fn from(value: &'a super::Header) -> Self {
974 Self {
975 parent_hash: value.parent_hash,
976 ommers_hash: value.ommers_hash,
977 beneficiary: value.beneficiary,
978 state_root: value.state_root,
979 transactions_root: value.transactions_root,
980 receipts_root: value.receipts_root,
981 withdrawals_root: value.withdrawals_root,
982 logs_bloom: value.logs_bloom,
983 difficulty: value.difficulty,
984 number: value.number,
985 gas_limit: value.gas_limit,
986 gas_used: value.gas_used,
987 timestamp: value.timestamp,
988 mix_hash: value.mix_hash,
989 nonce: value.nonce,
990 base_fee_per_gas: value.base_fee_per_gas,
991 blob_gas_used: value.blob_gas_used,
992 excess_blob_gas: value.excess_blob_gas,
993 parent_beacon_block_root: value.parent_beacon_block_root,
994 requests_hash: value.requests_hash,
995 extra_data: Cow::Borrowed(&value.extra_data),
996 }
997 }
998 }
999
1000 impl<'a> From<Header<'a>> for super::Header {
1001 fn from(value: Header<'a>) -> Self {
1002 Self {
1003 parent_hash: value.parent_hash,
1004 ommers_hash: value.ommers_hash,
1005 beneficiary: value.beneficiary,
1006 state_root: value.state_root,
1007 transactions_root: value.transactions_root,
1008 receipts_root: value.receipts_root,
1009 withdrawals_root: value.withdrawals_root,
1010 logs_bloom: value.logs_bloom,
1011 difficulty: value.difficulty,
1012 number: value.number,
1013 gas_limit: value.gas_limit,
1014 gas_used: value.gas_used,
1015 timestamp: value.timestamp,
1016 mix_hash: value.mix_hash,
1017 nonce: value.nonce,
1018 base_fee_per_gas: value.base_fee_per_gas,
1019 blob_gas_used: value.blob_gas_used,
1020 excess_blob_gas: value.excess_blob_gas,
1021 parent_beacon_block_root: value.parent_beacon_block_root,
1022 requests_hash: value.requests_hash,
1023 extra_data: value.extra_data.into_owned(),
1024 }
1025 }
1026 }
1027
1028 impl SerializeAs<super::Header> for Header<'_> {
1029 fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
1030 where
1031 S: Serializer,
1032 {
1033 Header::from(source).serialize(serializer)
1034 }
1035 }
1036
1037 impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1038 fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1039 where
1040 D: Deserializer<'de>,
1041 {
1042 Header::deserialize(deserializer).map(Into::into)
1043 }
1044 }
1045
1046 #[cfg(test)]
1047 mod tests {
1048 use super::super::{serde_bincode_compat, Header};
1049 use arbitrary::Arbitrary;
1050 use bincode::config;
1051 use rand::Rng;
1052 use serde::{Deserialize, Serialize};
1053 use serde_with::serde_as;
1054
1055 #[test]
1056 fn test_header_bincode_roundtrip() {
1057 #[serde_as]
1058 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1059 struct Data {
1060 #[serde_as(as = "serde_bincode_compat::Header")]
1061 header: Header,
1062 }
1063
1064 let mut bytes = [0u8; 1024];
1065 rand::thread_rng().fill(bytes.as_mut_slice());
1066 let data = Data {
1067 header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1068 };
1069
1070 let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
1071 let (decoded, _) =
1072 bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
1073 assert_eq!(decoded, data);
1074 }
1075 }
1076}
1077
1078#[cfg(all(test, feature = "serde"))]
1079mod tests {
1080 use super::*;
1081 use alloy_primitives::b256;
1082
1083 #[test]
1084 fn test_header_serde_json_roundtrip() {
1085 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"}"#;
1086 let header = Header {
1087 base_fee_per_gas: Some(1),
1088 withdrawals_root: Some(EMPTY_ROOT_HASH),
1089 ..Default::default()
1090 };
1091
1092 let encoded = serde_json::to_string(&header).unwrap();
1093 assert_eq!(encoded, raw);
1094
1095 let decoded: Header = serde_json::from_str(&encoded).unwrap();
1096 assert_eq!(decoded, header);
1097
1098 let mut encoded_rlp = Vec::new();
1100
1101 decoded.encode(&mut encoded_rlp);
1103
1104 let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1106
1107 assert_eq!(decoded_rlp, decoded);
1109 }
1110
1111 #[test]
1112 fn serde_rlp_prague() {
1113 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"}
1115"#;
1116 let header = serde_json::from_str::<Header>(raw).unwrap();
1117 let hash = header.hash_slow();
1118 assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1119 let mut v = Vec::new();
1120 header.encode(&mut v);
1121 let decoded = Header::decode(&mut v.as_slice()).unwrap();
1122 assert_eq!(decoded, header);
1123 }
1124}