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_osaka(
233 self.excess_blob_gas?,
234 self.blob_gas_used?,
235 self.base_fee_per_gas?,
236 ))
237 }
238
239 #[inline]
241 pub fn size(&self) -> usize {
242 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() }
264
265 fn header_payload_length(&self) -> usize {
266 let mut length = 0;
267 length += self.parent_hash.length();
268 length += self.ommers_hash.length();
269 length += self.beneficiary.length();
270 length += self.state_root.length();
271 length += self.transactions_root.length();
272 length += self.receipts_root.length();
273 length += self.logs_bloom.length();
274 length += self.difficulty.length();
275 length += U256::from(self.number).length();
276 length += U256::from(self.gas_limit).length();
277 length += U256::from(self.gas_used).length();
278 length += self.timestamp.length();
279 length += self.extra_data.length();
280 length += self.mix_hash.length();
281 length += self.nonce.length();
282
283 if let Some(base_fee) = self.base_fee_per_gas {
284 length += U256::from(base_fee).length();
286 }
287
288 if let Some(root) = self.withdrawals_root {
289 length += root.length();
291 }
292
293 if let Some(blob_gas_used) = self.blob_gas_used {
294 length += U256::from(blob_gas_used).length();
296 }
297
298 if let Some(excess_blob_gas) = self.excess_blob_gas {
299 length += U256::from(excess_blob_gas).length();
301 }
302
303 if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
304 length += parent_beacon_block_root.length();
305 }
306
307 if let Some(requests_hash) = self.requests_hash {
308 length += requests_hash.length();
309 }
310
311 length
312 }
313
314 pub const fn parent_num_hash(&self) -> BlockNumHash {
318 BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
319 }
320
321 pub fn num_hash_slow(&self) -> BlockNumHash {
325 BlockNumHash { number: self.number, hash: self.hash_slow() }
326 }
327
328 pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
332 BlockWithParent::new(self.parent_hash, self.num_hash_slow())
333 }
334
335 #[inline]
339 pub const fn seal(self, hash: B256) -> Sealed<Self> {
340 Sealed::new_unchecked(self, hash)
341 }
342
343 pub const fn shanghai_active(&self) -> bool {
347 self.withdrawals_root.is_some()
348 }
349
350 pub const fn cancun_active(&self) -> bool {
354 self.blob_gas_used.is_some()
355 }
356
357 pub const fn prague_active(&self) -> bool {
361 self.requests_hash.is_some()
362 }
363}
364
365impl Encodable for Header {
366 fn encode(&self, out: &mut dyn BufMut) {
367 let list_header =
368 alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
369 list_header.encode(out);
370 self.parent_hash.encode(out);
371 self.ommers_hash.encode(out);
372 self.beneficiary.encode(out);
373 self.state_root.encode(out);
374 self.transactions_root.encode(out);
375 self.receipts_root.encode(out);
376 self.logs_bloom.encode(out);
377 self.difficulty.encode(out);
378 U256::from(self.number).encode(out);
379 U256::from(self.gas_limit).encode(out);
380 U256::from(self.gas_used).encode(out);
381 self.timestamp.encode(out);
382 self.extra_data.encode(out);
383 self.mix_hash.encode(out);
384 self.nonce.encode(out);
385
386 if let Some(ref base_fee) = self.base_fee_per_gas {
388 U256::from(*base_fee).encode(out);
389 }
390
391 if let Some(ref root) = self.withdrawals_root {
392 root.encode(out);
393 }
394
395 if let Some(ref blob_gas_used) = self.blob_gas_used {
396 U256::from(*blob_gas_used).encode(out);
397 }
398
399 if let Some(ref excess_blob_gas) = self.excess_blob_gas {
400 U256::from(*excess_blob_gas).encode(out);
401 }
402
403 if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
404 parent_beacon_block_root.encode(out);
405 }
406
407 if let Some(ref requests_hash) = self.requests_hash {
408 requests_hash.encode(out);
409 }
410 }
411
412 fn length(&self) -> usize {
413 let mut length = 0;
414 length += self.header_payload_length();
415 length += length_of_length(length);
416 length
417 }
418}
419
420impl Decodable for Header {
421 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
422 let rlp_head = alloy_rlp::Header::decode(buf)?;
423 if !rlp_head.list {
424 return Err(alloy_rlp::Error::UnexpectedString);
425 }
426 let started_len = buf.len();
427 let mut this = Self {
428 parent_hash: Decodable::decode(buf)?,
429 ommers_hash: Decodable::decode(buf)?,
430 beneficiary: Decodable::decode(buf)?,
431 state_root: Decodable::decode(buf)?,
432 transactions_root: Decodable::decode(buf)?,
433 receipts_root: Decodable::decode(buf)?,
434 logs_bloom: Decodable::decode(buf)?,
435 difficulty: Decodable::decode(buf)?,
436 number: u64::decode(buf)?,
437 gas_limit: u64::decode(buf)?,
438 gas_used: u64::decode(buf)?,
439 timestamp: Decodable::decode(buf)?,
440 extra_data: Decodable::decode(buf)?,
441 mix_hash: Decodable::decode(buf)?,
442 nonce: B64::decode(buf)?,
443 base_fee_per_gas: None,
444 withdrawals_root: None,
445 blob_gas_used: None,
446 excess_blob_gas: None,
447 parent_beacon_block_root: None,
448 requests_hash: None,
449 };
450 if started_len - buf.len() < rlp_head.payload_length {
451 this.base_fee_per_gas = Some(u64::decode(buf)?);
452 }
453
454 if started_len - buf.len() < rlp_head.payload_length {
456 this.withdrawals_root = Some(Decodable::decode(buf)?);
457 }
458
459 if started_len - buf.len() < rlp_head.payload_length {
461 this.blob_gas_used = Some(u64::decode(buf)?);
462 }
463
464 if started_len - buf.len() < rlp_head.payload_length {
465 this.excess_blob_gas = Some(u64::decode(buf)?);
466 }
467
468 if started_len - buf.len() < rlp_head.payload_length {
470 this.parent_beacon_block_root = Some(B256::decode(buf)?);
471 }
472
473 if started_len - buf.len() < rlp_head.payload_length {
475 this.requests_hash = Some(B256::decode(buf)?);
476 }
477
478 let consumed = started_len - buf.len();
479 if consumed != rlp_head.payload_length {
480 return Err(alloy_rlp::Error::ListLengthMismatch {
481 expected: rlp_head.payload_length,
482 got: consumed,
483 });
484 }
485 Ok(this)
486 }
487}
488
489#[cfg(any(test, feature = "arbitrary"))]
498pub(crate) const fn generate_valid_header(
499 mut header: Header,
500 eip_4844_active: bool,
501 blob_gas_used: u64,
502 excess_blob_gas: u64,
503 parent_beacon_block_root: B256,
504) -> Header {
505 if header.base_fee_per_gas.is_none() {
507 header.withdrawals_root = None;
508 }
509
510 if eip_4844_active {
512 header.blob_gas_used = Some(blob_gas_used);
513 header.excess_blob_gas = Some(excess_blob_gas);
514 header.parent_beacon_block_root = Some(parent_beacon_block_root);
515 } else {
516 header.blob_gas_used = None;
517 header.excess_blob_gas = None;
518 header.parent_beacon_block_root = None;
519 }
520
521 header.requests_hash = None;
523
524 header
525}
526
527#[cfg(any(test, feature = "arbitrary"))]
528impl<'a> arbitrary::Arbitrary<'a> for Header {
529 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
530 let base = Self {
533 parent_hash: u.arbitrary()?,
534 ommers_hash: u.arbitrary()?,
535 beneficiary: u.arbitrary()?,
536 state_root: u.arbitrary()?,
537 transactions_root: u.arbitrary()?,
538 receipts_root: u.arbitrary()?,
539 logs_bloom: u.arbitrary()?,
540 difficulty: u.arbitrary()?,
541 number: u.arbitrary()?,
542 gas_limit: u.arbitrary()?,
543 gas_used: u.arbitrary()?,
544 timestamp: u.arbitrary()?,
545 extra_data: u.arbitrary()?,
546 mix_hash: u.arbitrary()?,
547 nonce: u.arbitrary()?,
548 base_fee_per_gas: u.arbitrary()?,
549 blob_gas_used: u.arbitrary()?,
550 excess_blob_gas: u.arbitrary()?,
551 parent_beacon_block_root: u.arbitrary()?,
552 requests_hash: u.arbitrary()?,
553 withdrawals_root: u.arbitrary()?,
554 };
555
556 Ok(generate_valid_header(
557 base,
558 u.arbitrary()?,
559 u.arbitrary()?,
560 u.arbitrary()?,
561 u.arbitrary()?,
562 ))
563 }
564}
565
566#[auto_impl::auto_impl(&, Arc)]
568pub trait BlockHeader {
569 fn header_info(&self) -> HeaderInfo {
571 HeaderInfo {
572 number: self.number(),
573 beneficiary: self.beneficiary(),
574 timestamp: self.timestamp(),
575 gas_limit: self.gas_limit(),
576 base_fee_per_gas: self.base_fee_per_gas(),
577 excess_blob_gas: self.excess_blob_gas(),
578 blob_gas_used: self.blob_gas_used(),
579 difficulty: self.difficulty(),
580 mix_hash: self.mix_hash(),
581 }
582 }
583
584 fn parent_hash(&self) -> B256;
586
587 fn ommers_hash(&self) -> B256;
589
590 fn beneficiary(&self) -> Address;
592
593 fn state_root(&self) -> B256;
595
596 fn transactions_root(&self) -> B256;
598
599 fn receipts_root(&self) -> B256;
601
602 fn withdrawals_root(&self) -> Option<B256>;
604
605 fn logs_bloom(&self) -> Bloom;
607
608 fn difficulty(&self) -> U256;
610
611 fn number(&self) -> BlockNumber;
613
614 fn gas_limit(&self) -> u64;
616
617 fn gas_used(&self) -> u64;
619
620 fn timestamp(&self) -> u64;
622
623 fn mix_hash(&self) -> Option<B256>;
625
626 fn nonce(&self) -> Option<B64>;
628
629 fn base_fee_per_gas(&self) -> Option<u64>;
631
632 fn blob_gas_used(&self) -> Option<u64>;
634
635 fn excess_blob_gas(&self) -> Option<u64>;
637
638 fn parent_beacon_block_root(&self) -> Option<B256>;
640
641 fn requests_hash(&self) -> Option<B256>;
643
644 fn extra_data(&self) -> &Bytes;
646
647 fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
651 Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
652 }
653
654 fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
659 Some(blob_params.next_block_excess_blob_gas_osaka(
660 self.excess_blob_gas()?,
661 self.blob_gas_used()?,
662 self.base_fee_per_gas()?,
663 ))
664 }
665
666 fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
671 self.next_block_excess_blob_gas(blob_params?)
672 }
673
674 fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
680 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
681 }
682
683 fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
688 self.next_block_blob_fee(blob_params?)
689 }
690
691 fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
695 Some(calc_next_block_base_fee(
696 self.gas_used(),
697 self.gas_limit(),
698 self.base_fee_per_gas()?,
699 base_fee_params,
700 ))
701 }
702
703 fn parent_num_hash(&self) -> BlockNumHash {
707 BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
708 }
709
710 fn is_empty(&self) -> bool {
712 let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
713 && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
714 self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
715 txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
716 })
717 }
718
719 fn is_zero_difficulty(&self) -> bool {
729 self.difficulty().is_zero()
730 }
731
732 fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
738 self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
739 }
740
741 fn is_nonce_zero(&self) -> bool {
745 self.nonce().is_some_and(|nonce| nonce.is_zero())
746 }
747}
748
749impl BlockHeader for Header {
750 fn parent_hash(&self) -> B256 {
751 self.parent_hash
752 }
753
754 fn ommers_hash(&self) -> B256 {
755 self.ommers_hash
756 }
757
758 fn beneficiary(&self) -> Address {
759 self.beneficiary
760 }
761
762 fn state_root(&self) -> B256 {
763 self.state_root
764 }
765
766 fn transactions_root(&self) -> B256 {
767 self.transactions_root
768 }
769
770 fn receipts_root(&self) -> B256 {
771 self.receipts_root
772 }
773
774 fn withdrawals_root(&self) -> Option<B256> {
775 self.withdrawals_root
776 }
777
778 fn logs_bloom(&self) -> Bloom {
779 self.logs_bloom
780 }
781
782 fn difficulty(&self) -> U256 {
783 self.difficulty
784 }
785
786 fn number(&self) -> BlockNumber {
787 self.number
788 }
789
790 fn gas_limit(&self) -> u64 {
791 self.gas_limit
792 }
793
794 fn gas_used(&self) -> u64 {
795 self.gas_used
796 }
797
798 fn timestamp(&self) -> u64 {
799 self.timestamp
800 }
801
802 fn mix_hash(&self) -> Option<B256> {
803 Some(self.mix_hash)
804 }
805
806 fn nonce(&self) -> Option<B64> {
807 Some(self.nonce)
808 }
809
810 fn base_fee_per_gas(&self) -> Option<u64> {
811 self.base_fee_per_gas
812 }
813
814 fn blob_gas_used(&self) -> Option<u64> {
815 self.blob_gas_used
816 }
817
818 fn excess_blob_gas(&self) -> Option<u64> {
819 self.excess_blob_gas
820 }
821
822 fn parent_beacon_block_root(&self) -> Option<B256> {
823 self.parent_beacon_block_root
824 }
825
826 fn requests_hash(&self) -> Option<B256> {
827 self.requests_hash
828 }
829
830 fn extra_data(&self) -> &Bytes {
831 &self.extra_data
832 }
833}
834
835#[cfg(feature = "serde")]
836impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
837 fn parent_hash(&self) -> B256 {
838 self.inner.parent_hash()
839 }
840
841 fn ommers_hash(&self) -> B256 {
842 self.inner.ommers_hash()
843 }
844
845 fn beneficiary(&self) -> Address {
846 self.inner.beneficiary()
847 }
848
849 fn state_root(&self) -> B256 {
850 self.inner.state_root()
851 }
852
853 fn transactions_root(&self) -> B256 {
854 self.inner.transactions_root()
855 }
856
857 fn receipts_root(&self) -> B256 {
858 self.inner.receipts_root()
859 }
860
861 fn withdrawals_root(&self) -> Option<B256> {
862 self.inner.withdrawals_root()
863 }
864
865 fn logs_bloom(&self) -> Bloom {
866 self.inner.logs_bloom()
867 }
868
869 fn difficulty(&self) -> U256 {
870 self.inner.difficulty()
871 }
872
873 fn number(&self) -> u64 {
874 self.inner.number()
875 }
876
877 fn gas_limit(&self) -> u64 {
878 self.inner.gas_limit()
879 }
880
881 fn gas_used(&self) -> u64 {
882 self.inner.gas_used()
883 }
884
885 fn timestamp(&self) -> u64 {
886 self.inner.timestamp()
887 }
888
889 fn mix_hash(&self) -> Option<B256> {
890 self.inner.mix_hash()
891 }
892
893 fn nonce(&self) -> Option<B64> {
894 self.inner.nonce()
895 }
896
897 fn base_fee_per_gas(&self) -> Option<u64> {
898 self.inner.base_fee_per_gas()
899 }
900
901 fn blob_gas_used(&self) -> Option<u64> {
902 self.inner.blob_gas_used()
903 }
904
905 fn excess_blob_gas(&self) -> Option<u64> {
906 self.inner.excess_blob_gas()
907 }
908
909 fn parent_beacon_block_root(&self) -> Option<B256> {
910 self.inner.parent_beacon_block_root()
911 }
912
913 fn requests_hash(&self) -> Option<B256> {
914 self.inner.requests_hash()
915 }
916
917 fn extra_data(&self) -> &Bytes {
918 self.inner.extra_data()
919 }
920
921 fn is_empty(&self) -> bool {
922 self.inner.is_empty()
923 }
924}
925
926#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
928pub(crate) mod serde_bincode_compat {
929 use alloc::borrow::Cow;
930 use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
931 use serde::{Deserialize, Deserializer, Serialize, Serializer};
932 use serde_with::{DeserializeAs, SerializeAs};
933
934 #[derive(Debug, Serialize, Deserialize)]
950 pub struct Header<'a> {
951 parent_hash: B256,
952 ommers_hash: B256,
953 beneficiary: Address,
954 state_root: B256,
955 transactions_root: B256,
956 receipts_root: B256,
957 #[serde(default)]
958 withdrawals_root: Option<B256>,
959 logs_bloom: Bloom,
960 difficulty: U256,
961 number: BlockNumber,
962 gas_limit: u64,
963 gas_used: u64,
964 timestamp: u64,
965 mix_hash: B256,
966 nonce: B64,
967 #[serde(default)]
968 base_fee_per_gas: Option<u64>,
969 #[serde(default)]
970 blob_gas_used: Option<u64>,
971 #[serde(default)]
972 excess_blob_gas: Option<u64>,
973 #[serde(default)]
974 parent_beacon_block_root: Option<B256>,
975 #[serde(default)]
976 requests_hash: Option<B256>,
977 extra_data: Cow<'a, Bytes>,
978 }
979
980 impl<'a> From<&'a super::Header> for Header<'a> {
981 fn from(value: &'a super::Header) -> Self {
982 Self {
983 parent_hash: value.parent_hash,
984 ommers_hash: value.ommers_hash,
985 beneficiary: value.beneficiary,
986 state_root: value.state_root,
987 transactions_root: value.transactions_root,
988 receipts_root: value.receipts_root,
989 withdrawals_root: value.withdrawals_root,
990 logs_bloom: value.logs_bloom,
991 difficulty: value.difficulty,
992 number: value.number,
993 gas_limit: value.gas_limit,
994 gas_used: value.gas_used,
995 timestamp: value.timestamp,
996 mix_hash: value.mix_hash,
997 nonce: value.nonce,
998 base_fee_per_gas: value.base_fee_per_gas,
999 blob_gas_used: value.blob_gas_used,
1000 excess_blob_gas: value.excess_blob_gas,
1001 parent_beacon_block_root: value.parent_beacon_block_root,
1002 requests_hash: value.requests_hash,
1003 extra_data: Cow::Borrowed(&value.extra_data),
1004 }
1005 }
1006 }
1007
1008 impl<'a> From<Header<'a>> for super::Header {
1009 fn from(value: Header<'a>) -> Self {
1010 Self {
1011 parent_hash: value.parent_hash,
1012 ommers_hash: value.ommers_hash,
1013 beneficiary: value.beneficiary,
1014 state_root: value.state_root,
1015 transactions_root: value.transactions_root,
1016 receipts_root: value.receipts_root,
1017 withdrawals_root: value.withdrawals_root,
1018 logs_bloom: value.logs_bloom,
1019 difficulty: value.difficulty,
1020 number: value.number,
1021 gas_limit: value.gas_limit,
1022 gas_used: value.gas_used,
1023 timestamp: value.timestamp,
1024 mix_hash: value.mix_hash,
1025 nonce: value.nonce,
1026 base_fee_per_gas: value.base_fee_per_gas,
1027 blob_gas_used: value.blob_gas_used,
1028 excess_blob_gas: value.excess_blob_gas,
1029 parent_beacon_block_root: value.parent_beacon_block_root,
1030 requests_hash: value.requests_hash,
1031 extra_data: value.extra_data.into_owned(),
1032 }
1033 }
1034 }
1035
1036 impl SerializeAs<super::Header> for Header<'_> {
1037 fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
1038 where
1039 S: Serializer,
1040 {
1041 Header::from(source).serialize(serializer)
1042 }
1043 }
1044
1045 impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1046 fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1047 where
1048 D: Deserializer<'de>,
1049 {
1050 Header::deserialize(deserializer).map(Into::into)
1051 }
1052 }
1053
1054 #[cfg(test)]
1055 mod tests {
1056 use super::super::{serde_bincode_compat, Header};
1057 use arbitrary::Arbitrary;
1058 use bincode::config;
1059 use rand::Rng;
1060 use serde::{Deserialize, Serialize};
1061 use serde_with::serde_as;
1062
1063 #[test]
1064 fn test_header_bincode_roundtrip() {
1065 #[serde_as]
1066 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1067 struct Data {
1068 #[serde_as(as = "serde_bincode_compat::Header")]
1069 header: Header,
1070 }
1071
1072 let mut bytes = [0u8; 1024];
1073 rand::thread_rng().fill(bytes.as_mut_slice());
1074 let data = Data {
1075 header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1076 };
1077
1078 let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
1079 let (decoded, _) =
1080 bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
1081 assert_eq!(decoded, data);
1082 }
1083 }
1084}
1085
1086#[cfg(all(test, feature = "serde"))]
1087mod tests {
1088 use super::*;
1089 use alloy_primitives::b256;
1090
1091 #[test]
1092 fn test_header_serde_json_roundtrip() {
1093 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"}"#;
1094 let header = Header {
1095 base_fee_per_gas: Some(1),
1096 withdrawals_root: Some(EMPTY_ROOT_HASH),
1097 ..Default::default()
1098 };
1099
1100 let encoded = serde_json::to_string(&header).unwrap();
1101 assert_eq!(encoded, raw);
1102
1103 let decoded: Header = serde_json::from_str(&encoded).unwrap();
1104 assert_eq!(decoded, header);
1105
1106 let mut encoded_rlp = Vec::new();
1108
1109 decoded.encode(&mut encoded_rlp);
1111
1112 let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1114
1115 assert_eq!(decoded_rlp, decoded);
1117 }
1118
1119 #[test]
1120 fn serde_rlp_prague() {
1121 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"}
1123"#;
1124 let header = serde_json::from_str::<Header>(raw).unwrap();
1125 let hash = header.hash_slow();
1126 assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1127 let mut v = Vec::new();
1128 header.encode(&mut v);
1129 let decoded = Header::decode(&mut v.as_slice()).unwrap();
1130 assert_eq!(decoded, header);
1131 }
1132}