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(self)
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 decode_sealed(buf: &mut &[u8]) -> alloy_rlp::Result<Sealed<Self>> {
194 let start = *buf;
195 let header = Self::decode(buf)?;
196 let hash = keccak256(&start[..start.len() - buf.len()]);
197 Ok(header.seal_unchecked(hash))
198 }
199
200 pub fn ommers_hash_is_empty(&self) -> bool {
202 self.ommers_hash == EMPTY_OMMER_ROOT_HASH
203 }
204
205 pub fn transaction_root_is_empty(&self) -> bool {
207 self.transactions_root == EMPTY_ROOT_HASH
208 }
209
210 pub fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
214 Some(blob_params.calc_blob_fee(self.excess_blob_gas?))
215 }
216
217 pub fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
223 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
224 }
225
226 pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
230 Some(calc_next_block_base_fee(
231 self.gas_used,
232 self.gas_limit,
233 self.base_fee_per_gas?,
234 base_fee_params,
235 ))
236 }
237
238 pub fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
243 Some(blob_params.next_block_excess_blob_gas_osaka(
244 self.excess_blob_gas?,
245 self.blob_gas_used?,
246 self.base_fee_per_gas?,
247 ))
248 }
249
250 #[inline]
252 pub fn size(&self) -> usize {
253 size_of::<Self>() + self.extra_data.len()
254 }
255
256 fn header_payload_length(&self) -> usize {
257 let mut length = 0;
258 length += self.parent_hash.length();
259 length += self.ommers_hash.length();
260 length += self.beneficiary.length();
261 length += self.state_root.length();
262 length += self.transactions_root.length();
263 length += self.receipts_root.length();
264 length += self.logs_bloom.length();
265 length += self.difficulty.length();
266 length += U256::from(self.number).length();
267 length += U256::from(self.gas_limit).length();
268 length += U256::from(self.gas_used).length();
269 length += self.timestamp.length();
270 length += self.extra_data.length();
271 length += self.mix_hash.length();
272 length += self.nonce.length();
273
274 if let Some(base_fee) = self.base_fee_per_gas {
275 length += U256::from(base_fee).length();
277 }
278
279 if let Some(root) = self.withdrawals_root {
280 length += root.length();
282 }
283
284 if let Some(blob_gas_used) = self.blob_gas_used {
285 length += U256::from(blob_gas_used).length();
287 }
288
289 if let Some(excess_blob_gas) = self.excess_blob_gas {
290 length += U256::from(excess_blob_gas).length();
292 }
293
294 if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
295 length += parent_beacon_block_root.length();
296 }
297
298 if let Some(requests_hash) = self.requests_hash {
299 length += requests_hash.length();
300 }
301
302 length
303 }
304
305 pub const fn parent_num_hash(&self) -> BlockNumHash {
309 BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
310 }
311
312 pub fn num_hash_slow(&self) -> BlockNumHash {
316 BlockNumHash { number: self.number, hash: self.hash_slow() }
317 }
318
319 pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
323 BlockWithParent::new(self.parent_hash, self.num_hash_slow())
324 }
325
326 #[inline]
330 pub const fn seal(self, hash: B256) -> Sealed<Self> {
331 Sealed::new_unchecked(self, hash)
332 }
333
334 pub const fn shanghai_active(&self) -> bool {
338 self.withdrawals_root.is_some()
339 }
340
341 pub const fn cancun_active(&self) -> bool {
345 self.blob_gas_used.is_some()
346 }
347
348 pub const fn prague_active(&self) -> bool {
352 self.requests_hash.is_some()
353 }
354}
355
356impl Encodable for Header {
357 fn encode(&self, out: &mut dyn BufMut) {
358 let list_header =
359 alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
360 list_header.encode(out);
361 self.parent_hash.encode(out);
362 self.ommers_hash.encode(out);
363 self.beneficiary.encode(out);
364 self.state_root.encode(out);
365 self.transactions_root.encode(out);
366 self.receipts_root.encode(out);
367 self.logs_bloom.encode(out);
368 self.difficulty.encode(out);
369 U256::from(self.number).encode(out);
370 U256::from(self.gas_limit).encode(out);
371 U256::from(self.gas_used).encode(out);
372 self.timestamp.encode(out);
373 self.extra_data.encode(out);
374 self.mix_hash.encode(out);
375 self.nonce.encode(out);
376
377 if let Some(ref base_fee) = self.base_fee_per_gas {
379 U256::from(*base_fee).encode(out);
380 }
381
382 if let Some(ref root) = self.withdrawals_root {
383 root.encode(out);
384 }
385
386 if let Some(ref blob_gas_used) = self.blob_gas_used {
387 U256::from(*blob_gas_used).encode(out);
388 }
389
390 if let Some(ref excess_blob_gas) = self.excess_blob_gas {
391 U256::from(*excess_blob_gas).encode(out);
392 }
393
394 if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
395 parent_beacon_block_root.encode(out);
396 }
397
398 if let Some(ref requests_hash) = self.requests_hash {
399 requests_hash.encode(out);
400 }
401 }
402
403 fn length(&self) -> usize {
404 let mut length = 0;
405 length += self.header_payload_length();
406 length += length_of_length(length);
407 length
408 }
409}
410
411impl Decodable for Header {
412 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
413 let rlp_head = alloy_rlp::Header::decode(buf)?;
414 if !rlp_head.list {
415 return Err(alloy_rlp::Error::UnexpectedString);
416 }
417 let started_len = buf.len();
418 let mut this = Self {
419 parent_hash: Decodable::decode(buf)?,
420 ommers_hash: Decodable::decode(buf)?,
421 beneficiary: Decodable::decode(buf)?,
422 state_root: Decodable::decode(buf)?,
423 transactions_root: Decodable::decode(buf)?,
424 receipts_root: Decodable::decode(buf)?,
425 logs_bloom: Decodable::decode(buf)?,
426 difficulty: Decodable::decode(buf)?,
427 number: u64::decode(buf)?,
428 gas_limit: u64::decode(buf)?,
429 gas_used: u64::decode(buf)?,
430 timestamp: Decodable::decode(buf)?,
431 extra_data: Decodable::decode(buf)?,
432 mix_hash: Decodable::decode(buf)?,
433 nonce: B64::decode(buf)?,
434 base_fee_per_gas: None,
435 withdrawals_root: None,
436 blob_gas_used: None,
437 excess_blob_gas: None,
438 parent_beacon_block_root: None,
439 requests_hash: None,
440 };
441 if started_len - buf.len() < rlp_head.payload_length {
442 this.base_fee_per_gas = Some(u64::decode(buf)?);
443 }
444
445 if started_len - buf.len() < rlp_head.payload_length {
447 this.withdrawals_root = Some(Decodable::decode(buf)?);
448 }
449
450 if started_len - buf.len() < rlp_head.payload_length {
452 this.blob_gas_used = Some(u64::decode(buf)?);
453 }
454
455 if started_len - buf.len() < rlp_head.payload_length {
456 this.excess_blob_gas = Some(u64::decode(buf)?);
457 }
458
459 if started_len - buf.len() < rlp_head.payload_length {
461 this.parent_beacon_block_root = Some(B256::decode(buf)?);
462 }
463
464 if started_len - buf.len() < rlp_head.payload_length {
466 this.requests_hash = Some(B256::decode(buf)?);
467 }
468
469 let consumed = started_len - buf.len();
470 if consumed != rlp_head.payload_length {
471 return Err(alloy_rlp::Error::ListLengthMismatch {
472 expected: rlp_head.payload_length,
473 got: consumed,
474 });
475 }
476 Ok(this)
477 }
478}
479
480#[cfg(any(test, feature = "arbitrary"))]
481impl<'a> arbitrary::Arbitrary<'a> for Header {
482 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
483 let is_prague = u.arbitrary::<bool>()?;
484 let is_cancun = is_prague || u.arbitrary::<bool>()?;
485 let is_shanghai = is_cancun || u.arbitrary::<bool>()?;
486 let is_london = is_shanghai || u.arbitrary::<bool>()?;
487
488 Ok(Self {
489 parent_hash: u.arbitrary()?,
490 ommers_hash: u.arbitrary()?,
491 beneficiary: u.arbitrary()?,
492 state_root: u.arbitrary()?,
493 transactions_root: u.arbitrary()?,
494 receipts_root: u.arbitrary()?,
495 logs_bloom: u.arbitrary()?,
496 difficulty: u.arbitrary()?,
497 number: u.arbitrary()?,
498 gas_limit: u.arbitrary()?,
499 gas_used: u.arbitrary()?,
500 timestamp: u.arbitrary()?,
501 extra_data: u.arbitrary()?,
502 mix_hash: u.arbitrary()?,
503 nonce: u.arbitrary()?,
504 base_fee_per_gas: if is_london { Some(u.arbitrary()?) } else { None },
505 withdrawals_root: if is_shanghai { Some(u.arbitrary()?) } else { None },
506 blob_gas_used: if is_cancun { Some(u.arbitrary()?) } else { None },
507 excess_blob_gas: if is_cancun { Some(u.arbitrary()?) } else { None },
508 parent_beacon_block_root: if is_cancun { Some(u.arbitrary()?) } else { None },
509 requests_hash: if is_prague { Some(u.arbitrary()?) } else { None },
510 })
511 }
512}
513
514#[auto_impl::auto_impl(&, Arc)]
516pub trait BlockHeader {
517 fn header_info(&self) -> HeaderInfo {
519 HeaderInfo {
520 number: self.number(),
521 beneficiary: self.beneficiary(),
522 timestamp: self.timestamp(),
523 gas_limit: self.gas_limit(),
524 base_fee_per_gas: self.base_fee_per_gas(),
525 excess_blob_gas: self.excess_blob_gas(),
526 blob_gas_used: self.blob_gas_used(),
527 difficulty: self.difficulty(),
528 mix_hash: self.mix_hash(),
529 }
530 }
531
532 fn header_roots(&self) -> HeaderRoots {
534 HeaderRoots {
535 state_root: self.state_root(),
536 transactions_root: self.transactions_root(),
537 receipts_root: self.receipts_root(),
538 withdrawals_root: self.withdrawals_root(),
539 parent_beacon_block_root: self.parent_beacon_block_root(),
540 logs_bloom: self.logs_bloom(),
541 }
542 }
543
544 fn parent_hash(&self) -> B256;
546
547 fn ommers_hash(&self) -> B256;
549
550 fn beneficiary(&self) -> Address;
552
553 fn state_root(&self) -> B256;
555
556 fn transactions_root(&self) -> B256;
558
559 fn receipts_root(&self) -> B256;
561
562 fn withdrawals_root(&self) -> Option<B256>;
564
565 fn logs_bloom(&self) -> Bloom;
567
568 fn difficulty(&self) -> U256;
570
571 fn number(&self) -> BlockNumber;
573
574 fn gas_limit(&self) -> u64;
576
577 fn gas_used(&self) -> u64;
579
580 fn timestamp(&self) -> u64;
582
583 fn mix_hash(&self) -> Option<B256>;
585
586 fn nonce(&self) -> Option<B64>;
588
589 fn base_fee_per_gas(&self) -> Option<u64>;
591
592 fn blob_gas_used(&self) -> Option<u64>;
594
595 fn excess_blob_gas(&self) -> Option<u64>;
597
598 fn parent_beacon_block_root(&self) -> Option<B256>;
600
601 fn requests_hash(&self) -> Option<B256>;
603
604 fn extra_data(&self) -> &Bytes;
606
607 fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
611 Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
612 }
613
614 fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
619 Some(blob_params.next_block_excess_blob_gas_osaka(
620 self.excess_blob_gas()?,
621 self.blob_gas_used()?,
622 self.base_fee_per_gas()?,
623 ))
624 }
625
626 fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
631 self.next_block_excess_blob_gas(blob_params?)
632 }
633
634 fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
640 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
641 }
642
643 fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
648 self.next_block_blob_fee(blob_params?)
649 }
650
651 fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
655 Some(calc_next_block_base_fee(
656 self.gas_used(),
657 self.gas_limit(),
658 self.base_fee_per_gas()?,
659 base_fee_params,
660 ))
661 }
662
663 fn parent_num_hash(&self) -> BlockNumHash {
667 BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
668 }
669
670 fn is_empty(&self) -> bool {
672 let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
673 && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
674 self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
675 txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
676 })
677 }
678
679 fn is_zero_difficulty(&self) -> bool {
689 self.difficulty().is_zero()
690 }
691
692 fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
698 self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
699 }
700
701 fn is_nonce_zero(&self) -> bool {
705 self.nonce().is_some_and(|nonce| nonce.is_zero())
706 }
707}
708
709impl BlockHeader for Header {
710 fn parent_hash(&self) -> B256 {
711 self.parent_hash
712 }
713
714 fn ommers_hash(&self) -> B256 {
715 self.ommers_hash
716 }
717
718 fn beneficiary(&self) -> Address {
719 self.beneficiary
720 }
721
722 fn state_root(&self) -> B256 {
723 self.state_root
724 }
725
726 fn transactions_root(&self) -> B256 {
727 self.transactions_root
728 }
729
730 fn receipts_root(&self) -> B256 {
731 self.receipts_root
732 }
733
734 fn withdrawals_root(&self) -> Option<B256> {
735 self.withdrawals_root
736 }
737
738 fn logs_bloom(&self) -> Bloom {
739 self.logs_bloom
740 }
741
742 fn difficulty(&self) -> U256 {
743 self.difficulty
744 }
745
746 fn number(&self) -> BlockNumber {
747 self.number
748 }
749
750 fn gas_limit(&self) -> u64 {
751 self.gas_limit
752 }
753
754 fn gas_used(&self) -> u64 {
755 self.gas_used
756 }
757
758 fn timestamp(&self) -> u64 {
759 self.timestamp
760 }
761
762 fn mix_hash(&self) -> Option<B256> {
763 Some(self.mix_hash)
764 }
765
766 fn nonce(&self) -> Option<B64> {
767 Some(self.nonce)
768 }
769
770 fn base_fee_per_gas(&self) -> Option<u64> {
771 self.base_fee_per_gas
772 }
773
774 fn blob_gas_used(&self) -> Option<u64> {
775 self.blob_gas_used
776 }
777
778 fn excess_blob_gas(&self) -> Option<u64> {
779 self.excess_blob_gas
780 }
781
782 fn parent_beacon_block_root(&self) -> Option<B256> {
783 self.parent_beacon_block_root
784 }
785
786 fn requests_hash(&self) -> Option<B256> {
787 self.requests_hash
788 }
789
790 fn extra_data(&self) -> &Bytes {
791 &self.extra_data
792 }
793}
794
795#[cfg(feature = "serde")]
796impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
797 fn parent_hash(&self) -> B256 {
798 self.inner.parent_hash()
799 }
800
801 fn ommers_hash(&self) -> B256 {
802 self.inner.ommers_hash()
803 }
804
805 fn beneficiary(&self) -> Address {
806 self.inner.beneficiary()
807 }
808
809 fn state_root(&self) -> B256 {
810 self.inner.state_root()
811 }
812
813 fn transactions_root(&self) -> B256 {
814 self.inner.transactions_root()
815 }
816
817 fn receipts_root(&self) -> B256 {
818 self.inner.receipts_root()
819 }
820
821 fn withdrawals_root(&self) -> Option<B256> {
822 self.inner.withdrawals_root()
823 }
824
825 fn logs_bloom(&self) -> Bloom {
826 self.inner.logs_bloom()
827 }
828
829 fn difficulty(&self) -> U256 {
830 self.inner.difficulty()
831 }
832
833 fn number(&self) -> u64 {
834 self.inner.number()
835 }
836
837 fn gas_limit(&self) -> u64 {
838 self.inner.gas_limit()
839 }
840
841 fn gas_used(&self) -> u64 {
842 self.inner.gas_used()
843 }
844
845 fn timestamp(&self) -> u64 {
846 self.inner.timestamp()
847 }
848
849 fn mix_hash(&self) -> Option<B256> {
850 self.inner.mix_hash()
851 }
852
853 fn nonce(&self) -> Option<B64> {
854 self.inner.nonce()
855 }
856
857 fn base_fee_per_gas(&self) -> Option<u64> {
858 self.inner.base_fee_per_gas()
859 }
860
861 fn blob_gas_used(&self) -> Option<u64> {
862 self.inner.blob_gas_used()
863 }
864
865 fn excess_blob_gas(&self) -> Option<u64> {
866 self.inner.excess_blob_gas()
867 }
868
869 fn parent_beacon_block_root(&self) -> Option<B256> {
870 self.inner.parent_beacon_block_root()
871 }
872
873 fn requests_hash(&self) -> Option<B256> {
874 self.inner.requests_hash()
875 }
876
877 fn extra_data(&self) -> &Bytes {
878 self.inner.extra_data()
879 }
880
881 fn is_empty(&self) -> bool {
882 self.inner.is_empty()
883 }
884}
885
886#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
888pub(crate) mod serde_bincode_compat {
889 use alloc::borrow::Cow;
890 use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
891 use serde::{Deserialize, Deserializer, Serialize, Serializer};
892 use serde_with::{DeserializeAs, SerializeAs};
893
894 #[derive(Debug, Serialize, Deserialize)]
910 pub struct Header<'a> {
911 parent_hash: B256,
912 ommers_hash: B256,
913 beneficiary: Address,
914 state_root: B256,
915 transactions_root: B256,
916 receipts_root: B256,
917 #[serde(default)]
918 withdrawals_root: Option<B256>,
919 logs_bloom: Bloom,
920 difficulty: U256,
921 number: BlockNumber,
922 gas_limit: u64,
923 gas_used: u64,
924 timestamp: u64,
925 mix_hash: B256,
926 nonce: B64,
927 #[serde(default)]
928 base_fee_per_gas: Option<u64>,
929 #[serde(default)]
930 blob_gas_used: Option<u64>,
931 #[serde(default)]
932 excess_blob_gas: Option<u64>,
933 #[serde(default)]
934 parent_beacon_block_root: Option<B256>,
935 #[serde(default)]
936 requests_hash: Option<B256>,
937 extra_data: Cow<'a, Bytes>,
938 }
939
940 impl<'a> From<&'a super::Header> for Header<'a> {
941 fn from(value: &'a super::Header) -> Self {
942 Self {
943 parent_hash: value.parent_hash,
944 ommers_hash: value.ommers_hash,
945 beneficiary: value.beneficiary,
946 state_root: value.state_root,
947 transactions_root: value.transactions_root,
948 receipts_root: value.receipts_root,
949 withdrawals_root: value.withdrawals_root,
950 logs_bloom: value.logs_bloom,
951 difficulty: value.difficulty,
952 number: value.number,
953 gas_limit: value.gas_limit,
954 gas_used: value.gas_used,
955 timestamp: value.timestamp,
956 mix_hash: value.mix_hash,
957 nonce: value.nonce,
958 base_fee_per_gas: value.base_fee_per_gas,
959 blob_gas_used: value.blob_gas_used,
960 excess_blob_gas: value.excess_blob_gas,
961 parent_beacon_block_root: value.parent_beacon_block_root,
962 requests_hash: value.requests_hash,
963 extra_data: Cow::Borrowed(&value.extra_data),
964 }
965 }
966 }
967
968 impl<'a> From<Header<'a>> for super::Header {
969 fn from(value: Header<'a>) -> Self {
970 Self {
971 parent_hash: value.parent_hash,
972 ommers_hash: value.ommers_hash,
973 beneficiary: value.beneficiary,
974 state_root: value.state_root,
975 transactions_root: value.transactions_root,
976 receipts_root: value.receipts_root,
977 withdrawals_root: value.withdrawals_root,
978 logs_bloom: value.logs_bloom,
979 difficulty: value.difficulty,
980 number: value.number,
981 gas_limit: value.gas_limit,
982 gas_used: value.gas_used,
983 timestamp: value.timestamp,
984 mix_hash: value.mix_hash,
985 nonce: value.nonce,
986 base_fee_per_gas: value.base_fee_per_gas,
987 blob_gas_used: value.blob_gas_used,
988 excess_blob_gas: value.excess_blob_gas,
989 parent_beacon_block_root: value.parent_beacon_block_root,
990 requests_hash: value.requests_hash,
991 extra_data: value.extra_data.into_owned(),
992 }
993 }
994 }
995
996 impl SerializeAs<super::Header> for Header<'_> {
997 fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
998 where
999 S: Serializer,
1000 {
1001 Header::from(source).serialize(serializer)
1002 }
1003 }
1004
1005 impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1006 fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1007 where
1008 D: Deserializer<'de>,
1009 {
1010 Header::deserialize(deserializer).map(Into::into)
1011 }
1012 }
1013
1014 #[cfg(test)]
1015 mod tests {
1016 use super::super::{serde_bincode_compat, Header};
1017 use arbitrary::Arbitrary;
1018 use bincode::config;
1019 use rand::Rng;
1020 use serde::{Deserialize, Serialize};
1021 use serde_with::serde_as;
1022
1023 #[test]
1024 fn test_header_bincode_roundtrip() {
1025 #[serde_as]
1026 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1027 struct Data {
1028 #[serde_as(as = "serde_bincode_compat::Header")]
1029 header: Header,
1030 }
1031
1032 let mut bytes = [0u8; 1024];
1033 rand::thread_rng().fill(bytes.as_mut_slice());
1034 let data = Data {
1035 header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1036 };
1037
1038 let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
1039 let (decoded, _) =
1040 bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
1041 assert_eq!(decoded, data);
1042 }
1043 }
1044}
1045
1046#[cfg(test)]
1047mod tests {
1048 use super::*;
1049 use alloy_primitives::{b256, hex};
1050
1051 #[test]
1052 fn decode_header_rlp() {
1053 let raw = hex!("0xf90212a00d84d79f59fc384a1f6402609a5b7253b4bfe7a4ae12608ed107273e5422b6dda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479471562b71999873db5b286df957af199ec94617f7a0f496f3d199c51a1aaee67dac95f24d92ac13c60d25181e1eecd6eca5ddf32ac0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808206a4840365908a808468e975f09ad983011003846765746888676f312e32352e308664617277696ea06f485a167165ec12e0ab3e6ab59a7b88560b90306ac98a26eb294abf95a8c59b88000000000000000007");
1055 let header = Header::decode(&mut raw.as_slice()).unwrap();
1056 assert_eq!(
1057 header.hash_slow(),
1058 b256!("0x4f05e4392969fc82e41f6d6a8cea379323b0b2d3ddf7def1a33eec03883e3a33")
1059 );
1060 }
1061}
1062
1063#[cfg(all(test, feature = "serde"))]
1064mod serde_tests {
1065 use super::*;
1066 use alloy_primitives::b256;
1067
1068 #[test]
1069 fn test_header_serde_json_roundtrip() {
1070 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"}"#;
1071 let header = Header {
1072 base_fee_per_gas: Some(1),
1073 withdrawals_root: Some(EMPTY_ROOT_HASH),
1074 ..Default::default()
1075 };
1076
1077 let encoded = serde_json::to_string(&header).unwrap();
1078 assert_eq!(encoded, raw);
1079
1080 let decoded: Header = serde_json::from_str(&encoded).unwrap();
1081 assert_eq!(decoded, header);
1082
1083 let mut encoded_rlp = Vec::new();
1085
1086 decoded.encode(&mut encoded_rlp);
1088
1089 let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1091
1092 assert_eq!(decoded_rlp, decoded);
1094 }
1095
1096 #[test]
1097 fn serde_rlp_prague() {
1098 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"}
1100"#;
1101 let header = serde_json::from_str::<Header>(raw).unwrap();
1102 let hash = header.hash_slow();
1103 assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1104 let mut v = Vec::new();
1105 header.encode(&mut v);
1106 let decoded = Header::decode(&mut v.as_slice()).unwrap();
1107 assert_eq!(decoded, header);
1108 }
1109}