1use crate::{
2 block::{HeaderInfo, HeaderRoots},
3 constants::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH},
4 Block, BlockBody,
5};
6use alloc::vec::Vec;
7use alloy_eips::{
8 eip1559::{calc_next_block_base_fee, BaseFeeParams},
9 eip1898::BlockWithParent,
10 eip7840::BlobParams,
11 merge::ALLOWED_FUTURE_BLOCK_TIME_SECONDS,
12 BlockNumHash,
13};
14use alloy_primitives::{
15 keccak256, Address, BlockNumber, Bloom, Bytes, Sealable, Sealed, B256, B64, U256,
16};
17use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable};
18
19#[derive(Clone, Debug, PartialEq, Eq, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
23#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
24pub struct Header {
25 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 size_of::<Self>() + self.extra_data.len()
243 }
244
245 fn header_payload_length(&self) -> usize {
246 let mut length = 0;
247 length += self.parent_hash.length();
248 length += self.ommers_hash.length();
249 length += self.beneficiary.length();
250 length += self.state_root.length();
251 length += self.transactions_root.length();
252 length += self.receipts_root.length();
253 length += self.logs_bloom.length();
254 length += self.difficulty.length();
255 length += U256::from(self.number).length();
256 length += U256::from(self.gas_limit).length();
257 length += U256::from(self.gas_used).length();
258 length += self.timestamp.length();
259 length += self.extra_data.length();
260 length += self.mix_hash.length();
261 length += self.nonce.length();
262
263 if let Some(base_fee) = self.base_fee_per_gas {
264 length += U256::from(base_fee).length();
266 }
267
268 if let Some(root) = self.withdrawals_root {
269 length += root.length();
271 }
272
273 if let Some(blob_gas_used) = self.blob_gas_used {
274 length += U256::from(blob_gas_used).length();
276 }
277
278 if let Some(excess_blob_gas) = self.excess_blob_gas {
279 length += U256::from(excess_blob_gas).length();
281 }
282
283 if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
284 length += parent_beacon_block_root.length();
285 }
286
287 if let Some(requests_hash) = self.requests_hash {
288 length += requests_hash.length();
289 }
290
291 length
292 }
293
294 pub const fn parent_num_hash(&self) -> BlockNumHash {
298 BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
299 }
300
301 pub fn num_hash_slow(&self) -> BlockNumHash {
305 BlockNumHash { number: self.number, hash: self.hash_slow() }
306 }
307
308 pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
312 BlockWithParent::new(self.parent_hash, self.num_hash_slow())
313 }
314
315 #[inline]
319 pub const fn seal(self, hash: B256) -> Sealed<Self> {
320 Sealed::new_unchecked(self, hash)
321 }
322
323 pub const fn shanghai_active(&self) -> bool {
327 self.withdrawals_root.is_some()
328 }
329
330 pub const fn cancun_active(&self) -> bool {
334 self.blob_gas_used.is_some()
335 }
336
337 pub const fn prague_active(&self) -> bool {
341 self.requests_hash.is_some()
342 }
343}
344
345impl Encodable for Header {
346 fn encode(&self, out: &mut dyn BufMut) {
347 let list_header =
348 alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
349 list_header.encode(out);
350 self.parent_hash.encode(out);
351 self.ommers_hash.encode(out);
352 self.beneficiary.encode(out);
353 self.state_root.encode(out);
354 self.transactions_root.encode(out);
355 self.receipts_root.encode(out);
356 self.logs_bloom.encode(out);
357 self.difficulty.encode(out);
358 U256::from(self.number).encode(out);
359 U256::from(self.gas_limit).encode(out);
360 U256::from(self.gas_used).encode(out);
361 self.timestamp.encode(out);
362 self.extra_data.encode(out);
363 self.mix_hash.encode(out);
364 self.nonce.encode(out);
365
366 if let Some(ref base_fee) = self.base_fee_per_gas {
368 U256::from(*base_fee).encode(out);
369 }
370
371 if let Some(ref root) = self.withdrawals_root {
372 root.encode(out);
373 }
374
375 if let Some(ref blob_gas_used) = self.blob_gas_used {
376 U256::from(*blob_gas_used).encode(out);
377 }
378
379 if let Some(ref excess_blob_gas) = self.excess_blob_gas {
380 U256::from(*excess_blob_gas).encode(out);
381 }
382
383 if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
384 parent_beacon_block_root.encode(out);
385 }
386
387 if let Some(ref requests_hash) = self.requests_hash {
388 requests_hash.encode(out);
389 }
390 }
391
392 fn length(&self) -> usize {
393 let mut length = 0;
394 length += self.header_payload_length();
395 length += length_of_length(length);
396 length
397 }
398}
399
400impl Decodable for Header {
401 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
402 let rlp_head = alloy_rlp::Header::decode(buf)?;
403 if !rlp_head.list {
404 return Err(alloy_rlp::Error::UnexpectedString);
405 }
406 let started_len = buf.len();
407 let mut this = Self {
408 parent_hash: Decodable::decode(buf)?,
409 ommers_hash: Decodable::decode(buf)?,
410 beneficiary: Decodable::decode(buf)?,
411 state_root: Decodable::decode(buf)?,
412 transactions_root: Decodable::decode(buf)?,
413 receipts_root: Decodable::decode(buf)?,
414 logs_bloom: Decodable::decode(buf)?,
415 difficulty: Decodable::decode(buf)?,
416 number: u64::decode(buf)?,
417 gas_limit: u64::decode(buf)?,
418 gas_used: u64::decode(buf)?,
419 timestamp: Decodable::decode(buf)?,
420 extra_data: Decodable::decode(buf)?,
421 mix_hash: Decodable::decode(buf)?,
422 nonce: B64::decode(buf)?,
423 base_fee_per_gas: None,
424 withdrawals_root: None,
425 blob_gas_used: None,
426 excess_blob_gas: None,
427 parent_beacon_block_root: None,
428 requests_hash: None,
429 };
430 if started_len - buf.len() < rlp_head.payload_length {
431 this.base_fee_per_gas = Some(u64::decode(buf)?);
432 }
433
434 if started_len - buf.len() < rlp_head.payload_length {
436 this.withdrawals_root = Some(Decodable::decode(buf)?);
437 }
438
439 if started_len - buf.len() < rlp_head.payload_length {
441 this.blob_gas_used = Some(u64::decode(buf)?);
442 }
443
444 if started_len - buf.len() < rlp_head.payload_length {
445 this.excess_blob_gas = Some(u64::decode(buf)?);
446 }
447
448 if started_len - buf.len() < rlp_head.payload_length {
450 this.parent_beacon_block_root = Some(B256::decode(buf)?);
451 }
452
453 if started_len - buf.len() < rlp_head.payload_length {
455 this.requests_hash = Some(B256::decode(buf)?);
456 }
457
458 let consumed = started_len - buf.len();
459 if consumed != rlp_head.payload_length {
460 return Err(alloy_rlp::Error::ListLengthMismatch {
461 expected: rlp_head.payload_length,
462 got: consumed,
463 });
464 }
465 Ok(this)
466 }
467}
468
469#[cfg(any(test, feature = "arbitrary"))]
478pub(crate) const fn generate_valid_header(
479 mut header: Header,
480 eip_4844_active: bool,
481 blob_gas_used: u64,
482 excess_blob_gas: u64,
483 parent_beacon_block_root: B256,
484) -> Header {
485 if header.base_fee_per_gas.is_none() {
487 header.withdrawals_root = None;
488 }
489
490 if eip_4844_active {
492 header.blob_gas_used = Some(blob_gas_used);
493 header.excess_blob_gas = Some(excess_blob_gas);
494 header.parent_beacon_block_root = Some(parent_beacon_block_root);
495 } else {
496 header.blob_gas_used = None;
497 header.excess_blob_gas = None;
498 header.parent_beacon_block_root = None;
499 }
500
501 header.requests_hash = None;
503
504 header
505}
506
507#[cfg(any(test, feature = "arbitrary"))]
508impl<'a> arbitrary::Arbitrary<'a> for Header {
509 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
510 let base = Self {
513 parent_hash: u.arbitrary()?,
514 ommers_hash: u.arbitrary()?,
515 beneficiary: u.arbitrary()?,
516 state_root: u.arbitrary()?,
517 transactions_root: u.arbitrary()?,
518 receipts_root: u.arbitrary()?,
519 logs_bloom: u.arbitrary()?,
520 difficulty: u.arbitrary()?,
521 number: u.arbitrary()?,
522 gas_limit: u.arbitrary()?,
523 gas_used: u.arbitrary()?,
524 timestamp: u.arbitrary()?,
525 extra_data: u.arbitrary()?,
526 mix_hash: u.arbitrary()?,
527 nonce: u.arbitrary()?,
528 base_fee_per_gas: u.arbitrary()?,
529 blob_gas_used: u.arbitrary()?,
530 excess_blob_gas: u.arbitrary()?,
531 parent_beacon_block_root: u.arbitrary()?,
532 requests_hash: u.arbitrary()?,
533 withdrawals_root: u.arbitrary()?,
534 };
535
536 Ok(generate_valid_header(
537 base,
538 u.arbitrary()?,
539 u.arbitrary()?,
540 u.arbitrary()?,
541 u.arbitrary()?,
542 ))
543 }
544}
545
546#[auto_impl::auto_impl(&, Arc)]
548pub trait BlockHeader {
549 fn header_info(&self) -> HeaderInfo {
551 HeaderInfo {
552 number: self.number(),
553 beneficiary: self.beneficiary(),
554 timestamp: self.timestamp(),
555 gas_limit: self.gas_limit(),
556 base_fee_per_gas: self.base_fee_per_gas(),
557 excess_blob_gas: self.excess_blob_gas(),
558 blob_gas_used: self.blob_gas_used(),
559 difficulty: self.difficulty(),
560 mix_hash: self.mix_hash(),
561 }
562 }
563
564 fn header_roots(&self) -> HeaderRoots {
566 HeaderRoots {
567 state_root: self.state_root(),
568 transactions_root: self.transactions_root(),
569 receipts_root: self.receipts_root(),
570 withdrawals_root: self.withdrawals_root(),
571 parent_beacon_block_root: self.parent_beacon_block_root(),
572 logs_bloom: self.logs_bloom(),
573 }
574 }
575
576 fn parent_hash(&self) -> B256;
578
579 fn ommers_hash(&self) -> B256;
581
582 fn beneficiary(&self) -> Address;
584
585 fn state_root(&self) -> B256;
587
588 fn transactions_root(&self) -> B256;
590
591 fn receipts_root(&self) -> B256;
593
594 fn withdrawals_root(&self) -> Option<B256>;
596
597 fn logs_bloom(&self) -> Bloom;
599
600 fn difficulty(&self) -> U256;
602
603 fn number(&self) -> BlockNumber;
605
606 fn gas_limit(&self) -> u64;
608
609 fn gas_used(&self) -> u64;
611
612 fn timestamp(&self) -> u64;
614
615 fn mix_hash(&self) -> Option<B256>;
617
618 fn nonce(&self) -> Option<B64>;
620
621 fn base_fee_per_gas(&self) -> Option<u64>;
623
624 fn blob_gas_used(&self) -> Option<u64>;
626
627 fn excess_blob_gas(&self) -> Option<u64>;
629
630 fn parent_beacon_block_root(&self) -> Option<B256>;
632
633 fn requests_hash(&self) -> Option<B256>;
635
636 fn extra_data(&self) -> &Bytes;
638
639 fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
643 Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
644 }
645
646 fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
651 Some(blob_params.next_block_excess_blob_gas_osaka(
652 self.excess_blob_gas()?,
653 self.blob_gas_used()?,
654 self.base_fee_per_gas()?,
655 ))
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(test)]
1079mod tests {
1080 use super::*;
1081 use alloy_primitives::{b256, hex};
1082
1083 #[test]
1084 fn decode_header_rlp() {
1085 let raw = hex!("0xf90212a00d84d79f59fc384a1f6402609a5b7253b4bfe7a4ae12608ed107273e5422b6dda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479471562b71999873db5b286df957af199ec94617f7a0f496f3d199c51a1aaee67dac95f24d92ac13c60d25181e1eecd6eca5ddf32ac0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808206a4840365908a808468e975f09ad983011003846765746888676f312e32352e308664617277696ea06f485a167165ec12e0ab3e6ab59a7b88560b90306ac98a26eb294abf95a8c59b88000000000000000007");
1087 let header = Header::decode(&mut raw.as_slice()).unwrap();
1088 assert_eq!(
1089 header.hash_slow(),
1090 b256!("0x4f05e4392969fc82e41f6d6a8cea379323b0b2d3ddf7def1a33eec03883e3a33")
1091 );
1092 }
1093}
1094
1095#[cfg(all(test, feature = "serde"))]
1096mod serde_tests {
1097 use super::*;
1098 use alloy_primitives::b256;
1099
1100 #[test]
1101 fn test_header_serde_json_roundtrip() {
1102 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"}"#;
1103 let header = Header {
1104 base_fee_per_gas: Some(1),
1105 withdrawals_root: Some(EMPTY_ROOT_HASH),
1106 ..Default::default()
1107 };
1108
1109 let encoded = serde_json::to_string(&header).unwrap();
1110 assert_eq!(encoded, raw);
1111
1112 let decoded: Header = serde_json::from_str(&encoded).unwrap();
1113 assert_eq!(decoded, header);
1114
1115 let mut encoded_rlp = Vec::new();
1117
1118 decoded.encode(&mut encoded_rlp);
1120
1121 let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1123
1124 assert_eq!(decoded_rlp, decoded);
1126 }
1127
1128 #[test]
1129 fn serde_rlp_prague() {
1130 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"}
1132"#;
1133 let header = serde_json::from_str::<Header>(raw).unwrap();
1134 let hash = header.hash_slow();
1135 assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1136 let mut v = Vec::new();
1137 header.encode(&mut v);
1138 let decoded = Header::decode(&mut v.as_slice()).unwrap();
1139 assert_eq!(decoded, header);
1140 }
1141}