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 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"))]
489pub(crate) const fn generate_valid_header(
490 mut header: Header,
491 eip_4844_active: bool,
492 blob_gas_used: u64,
493 excess_blob_gas: u64,
494 parent_beacon_block_root: B256,
495) -> Header {
496 if header.base_fee_per_gas.is_none() {
498 header.withdrawals_root = None;
499 }
500
501 if eip_4844_active {
503 header.blob_gas_used = Some(blob_gas_used);
504 header.excess_blob_gas = Some(excess_blob_gas);
505 header.parent_beacon_block_root = Some(parent_beacon_block_root);
506 } else {
507 header.blob_gas_used = None;
508 header.excess_blob_gas = None;
509 header.parent_beacon_block_root = None;
510 }
511
512 header.requests_hash = None;
514
515 header
516}
517
518#[cfg(any(test, feature = "arbitrary"))]
519impl<'a> arbitrary::Arbitrary<'a> for Header {
520 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
521 let base = Self {
524 parent_hash: u.arbitrary()?,
525 ommers_hash: u.arbitrary()?,
526 beneficiary: u.arbitrary()?,
527 state_root: u.arbitrary()?,
528 transactions_root: u.arbitrary()?,
529 receipts_root: u.arbitrary()?,
530 logs_bloom: u.arbitrary()?,
531 difficulty: u.arbitrary()?,
532 number: u.arbitrary()?,
533 gas_limit: u.arbitrary()?,
534 gas_used: u.arbitrary()?,
535 timestamp: u.arbitrary()?,
536 extra_data: u.arbitrary()?,
537 mix_hash: u.arbitrary()?,
538 nonce: u.arbitrary()?,
539 base_fee_per_gas: u.arbitrary()?,
540 blob_gas_used: u.arbitrary()?,
541 excess_blob_gas: u.arbitrary()?,
542 parent_beacon_block_root: u.arbitrary()?,
543 requests_hash: u.arbitrary()?,
544 withdrawals_root: u.arbitrary()?,
545 };
546
547 Ok(generate_valid_header(
548 base,
549 u.arbitrary()?,
550 u.arbitrary()?,
551 u.arbitrary()?,
552 u.arbitrary()?,
553 ))
554 }
555}
556
557#[auto_impl::auto_impl(&, Arc)]
559pub trait BlockHeader {
560 fn header_info(&self) -> HeaderInfo {
562 HeaderInfo {
563 number: self.number(),
564 beneficiary: self.beneficiary(),
565 timestamp: self.timestamp(),
566 gas_limit: self.gas_limit(),
567 base_fee_per_gas: self.base_fee_per_gas(),
568 excess_blob_gas: self.excess_blob_gas(),
569 blob_gas_used: self.blob_gas_used(),
570 difficulty: self.difficulty(),
571 mix_hash: self.mix_hash(),
572 }
573 }
574
575 fn header_roots(&self) -> HeaderRoots {
577 HeaderRoots {
578 state_root: self.state_root(),
579 transactions_root: self.transactions_root(),
580 receipts_root: self.receipts_root(),
581 withdrawals_root: self.withdrawals_root(),
582 parent_beacon_block_root: self.parent_beacon_block_root(),
583 logs_bloom: self.logs_bloom(),
584 }
585 }
586
587 fn parent_hash(&self) -> B256;
589
590 fn ommers_hash(&self) -> B256;
592
593 fn beneficiary(&self) -> Address;
595
596 fn state_root(&self) -> B256;
598
599 fn transactions_root(&self) -> B256;
601
602 fn receipts_root(&self) -> B256;
604
605 fn withdrawals_root(&self) -> Option<B256>;
607
608 fn logs_bloom(&self) -> Bloom;
610
611 fn difficulty(&self) -> U256;
613
614 fn number(&self) -> BlockNumber;
616
617 fn gas_limit(&self) -> u64;
619
620 fn gas_used(&self) -> u64;
622
623 fn timestamp(&self) -> u64;
625
626 fn mix_hash(&self) -> Option<B256>;
628
629 fn nonce(&self) -> Option<B64>;
631
632 fn base_fee_per_gas(&self) -> Option<u64>;
634
635 fn blob_gas_used(&self) -> Option<u64>;
637
638 fn excess_blob_gas(&self) -> Option<u64>;
640
641 fn parent_beacon_block_root(&self) -> Option<B256>;
643
644 fn requests_hash(&self) -> Option<B256>;
646
647 fn extra_data(&self) -> &Bytes;
649
650 fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
654 Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
655 }
656
657 fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
662 Some(blob_params.next_block_excess_blob_gas_osaka(
663 self.excess_blob_gas()?,
664 self.blob_gas_used()?,
665 self.base_fee_per_gas()?,
666 ))
667 }
668
669 fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
674 self.next_block_excess_blob_gas(blob_params?)
675 }
676
677 fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
683 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
684 }
685
686 fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
691 self.next_block_blob_fee(blob_params?)
692 }
693
694 fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
698 Some(calc_next_block_base_fee(
699 self.gas_used(),
700 self.gas_limit(),
701 self.base_fee_per_gas()?,
702 base_fee_params,
703 ))
704 }
705
706 fn parent_num_hash(&self) -> BlockNumHash {
710 BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
711 }
712
713 fn is_empty(&self) -> bool {
715 let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
716 && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
717 self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
718 txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
719 })
720 }
721
722 fn is_zero_difficulty(&self) -> bool {
732 self.difficulty().is_zero()
733 }
734
735 fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
741 self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
742 }
743
744 fn is_nonce_zero(&self) -> bool {
748 self.nonce().is_some_and(|nonce| nonce.is_zero())
749 }
750}
751
752impl BlockHeader for Header {
753 fn parent_hash(&self) -> B256 {
754 self.parent_hash
755 }
756
757 fn ommers_hash(&self) -> B256 {
758 self.ommers_hash
759 }
760
761 fn beneficiary(&self) -> Address {
762 self.beneficiary
763 }
764
765 fn state_root(&self) -> B256 {
766 self.state_root
767 }
768
769 fn transactions_root(&self) -> B256 {
770 self.transactions_root
771 }
772
773 fn receipts_root(&self) -> B256 {
774 self.receipts_root
775 }
776
777 fn withdrawals_root(&self) -> Option<B256> {
778 self.withdrawals_root
779 }
780
781 fn logs_bloom(&self) -> Bloom {
782 self.logs_bloom
783 }
784
785 fn difficulty(&self) -> U256 {
786 self.difficulty
787 }
788
789 fn number(&self) -> BlockNumber {
790 self.number
791 }
792
793 fn gas_limit(&self) -> u64 {
794 self.gas_limit
795 }
796
797 fn gas_used(&self) -> u64 {
798 self.gas_used
799 }
800
801 fn timestamp(&self) -> u64 {
802 self.timestamp
803 }
804
805 fn mix_hash(&self) -> Option<B256> {
806 Some(self.mix_hash)
807 }
808
809 fn nonce(&self) -> Option<B64> {
810 Some(self.nonce)
811 }
812
813 fn base_fee_per_gas(&self) -> Option<u64> {
814 self.base_fee_per_gas
815 }
816
817 fn blob_gas_used(&self) -> Option<u64> {
818 self.blob_gas_used
819 }
820
821 fn excess_blob_gas(&self) -> Option<u64> {
822 self.excess_blob_gas
823 }
824
825 fn parent_beacon_block_root(&self) -> Option<B256> {
826 self.parent_beacon_block_root
827 }
828
829 fn requests_hash(&self) -> Option<B256> {
830 self.requests_hash
831 }
832
833 fn extra_data(&self) -> &Bytes {
834 &self.extra_data
835 }
836}
837
838#[cfg(feature = "serde")]
839impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
840 fn parent_hash(&self) -> B256 {
841 self.inner.parent_hash()
842 }
843
844 fn ommers_hash(&self) -> B256 {
845 self.inner.ommers_hash()
846 }
847
848 fn beneficiary(&self) -> Address {
849 self.inner.beneficiary()
850 }
851
852 fn state_root(&self) -> B256 {
853 self.inner.state_root()
854 }
855
856 fn transactions_root(&self) -> B256 {
857 self.inner.transactions_root()
858 }
859
860 fn receipts_root(&self) -> B256 {
861 self.inner.receipts_root()
862 }
863
864 fn withdrawals_root(&self) -> Option<B256> {
865 self.inner.withdrawals_root()
866 }
867
868 fn logs_bloom(&self) -> Bloom {
869 self.inner.logs_bloom()
870 }
871
872 fn difficulty(&self) -> U256 {
873 self.inner.difficulty()
874 }
875
876 fn number(&self) -> u64 {
877 self.inner.number()
878 }
879
880 fn gas_limit(&self) -> u64 {
881 self.inner.gas_limit()
882 }
883
884 fn gas_used(&self) -> u64 {
885 self.inner.gas_used()
886 }
887
888 fn timestamp(&self) -> u64 {
889 self.inner.timestamp()
890 }
891
892 fn mix_hash(&self) -> Option<B256> {
893 self.inner.mix_hash()
894 }
895
896 fn nonce(&self) -> Option<B64> {
897 self.inner.nonce()
898 }
899
900 fn base_fee_per_gas(&self) -> Option<u64> {
901 self.inner.base_fee_per_gas()
902 }
903
904 fn blob_gas_used(&self) -> Option<u64> {
905 self.inner.blob_gas_used()
906 }
907
908 fn excess_blob_gas(&self) -> Option<u64> {
909 self.inner.excess_blob_gas()
910 }
911
912 fn parent_beacon_block_root(&self) -> Option<B256> {
913 self.inner.parent_beacon_block_root()
914 }
915
916 fn requests_hash(&self) -> Option<B256> {
917 self.inner.requests_hash()
918 }
919
920 fn extra_data(&self) -> &Bytes {
921 self.inner.extra_data()
922 }
923
924 fn is_empty(&self) -> bool {
925 self.inner.is_empty()
926 }
927}
928
929#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
931pub(crate) mod serde_bincode_compat {
932 use alloc::borrow::Cow;
933 use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
934 use serde::{Deserialize, Deserializer, Serialize, Serializer};
935 use serde_with::{DeserializeAs, SerializeAs};
936
937 #[derive(Debug, Serialize, Deserialize)]
953 pub struct Header<'a> {
954 parent_hash: B256,
955 ommers_hash: B256,
956 beneficiary: Address,
957 state_root: B256,
958 transactions_root: B256,
959 receipts_root: B256,
960 #[serde(default)]
961 withdrawals_root: Option<B256>,
962 logs_bloom: Bloom,
963 difficulty: U256,
964 number: BlockNumber,
965 gas_limit: u64,
966 gas_used: u64,
967 timestamp: u64,
968 mix_hash: B256,
969 nonce: B64,
970 #[serde(default)]
971 base_fee_per_gas: Option<u64>,
972 #[serde(default)]
973 blob_gas_used: Option<u64>,
974 #[serde(default)]
975 excess_blob_gas: Option<u64>,
976 #[serde(default)]
977 parent_beacon_block_root: Option<B256>,
978 #[serde(default)]
979 requests_hash: Option<B256>,
980 extra_data: Cow<'a, Bytes>,
981 }
982
983 impl<'a> From<&'a super::Header> for Header<'a> {
984 fn from(value: &'a super::Header) -> Self {
985 Self {
986 parent_hash: value.parent_hash,
987 ommers_hash: value.ommers_hash,
988 beneficiary: value.beneficiary,
989 state_root: value.state_root,
990 transactions_root: value.transactions_root,
991 receipts_root: value.receipts_root,
992 withdrawals_root: value.withdrawals_root,
993 logs_bloom: value.logs_bloom,
994 difficulty: value.difficulty,
995 number: value.number,
996 gas_limit: value.gas_limit,
997 gas_used: value.gas_used,
998 timestamp: value.timestamp,
999 mix_hash: value.mix_hash,
1000 nonce: value.nonce,
1001 base_fee_per_gas: value.base_fee_per_gas,
1002 blob_gas_used: value.blob_gas_used,
1003 excess_blob_gas: value.excess_blob_gas,
1004 parent_beacon_block_root: value.parent_beacon_block_root,
1005 requests_hash: value.requests_hash,
1006 extra_data: Cow::Borrowed(&value.extra_data),
1007 }
1008 }
1009 }
1010
1011 impl<'a> From<Header<'a>> for super::Header {
1012 fn from(value: Header<'a>) -> Self {
1013 Self {
1014 parent_hash: value.parent_hash,
1015 ommers_hash: value.ommers_hash,
1016 beneficiary: value.beneficiary,
1017 state_root: value.state_root,
1018 transactions_root: value.transactions_root,
1019 receipts_root: value.receipts_root,
1020 withdrawals_root: value.withdrawals_root,
1021 logs_bloom: value.logs_bloom,
1022 difficulty: value.difficulty,
1023 number: value.number,
1024 gas_limit: value.gas_limit,
1025 gas_used: value.gas_used,
1026 timestamp: value.timestamp,
1027 mix_hash: value.mix_hash,
1028 nonce: value.nonce,
1029 base_fee_per_gas: value.base_fee_per_gas,
1030 blob_gas_used: value.blob_gas_used,
1031 excess_blob_gas: value.excess_blob_gas,
1032 parent_beacon_block_root: value.parent_beacon_block_root,
1033 requests_hash: value.requests_hash,
1034 extra_data: value.extra_data.into_owned(),
1035 }
1036 }
1037 }
1038
1039 impl SerializeAs<super::Header> for Header<'_> {
1040 fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
1041 where
1042 S: Serializer,
1043 {
1044 Header::from(source).serialize(serializer)
1045 }
1046 }
1047
1048 impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1049 fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1050 where
1051 D: Deserializer<'de>,
1052 {
1053 Header::deserialize(deserializer).map(Into::into)
1054 }
1055 }
1056
1057 #[cfg(test)]
1058 mod tests {
1059 use super::super::{serde_bincode_compat, Header};
1060 use arbitrary::Arbitrary;
1061 use bincode::config;
1062 use rand::Rng;
1063 use serde::{Deserialize, Serialize};
1064 use serde_with::serde_as;
1065
1066 #[test]
1067 fn test_header_bincode_roundtrip() {
1068 #[serde_as]
1069 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1070 struct Data {
1071 #[serde_as(as = "serde_bincode_compat::Header")]
1072 header: Header,
1073 }
1074
1075 let mut bytes = [0u8; 1024];
1076 rand::thread_rng().fill(bytes.as_mut_slice());
1077 let data = Data {
1078 header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1079 };
1080
1081 let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
1082 let (decoded, _) =
1083 bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
1084 assert_eq!(decoded, data);
1085 }
1086 }
1087}
1088
1089#[cfg(test)]
1090mod tests {
1091 use super::*;
1092 use alloy_primitives::{b256, hex};
1093
1094 #[test]
1095 fn decode_header_rlp() {
1096 let raw = hex!("0xf90212a00d84d79f59fc384a1f6402609a5b7253b4bfe7a4ae12608ed107273e5422b6dda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479471562b71999873db5b286df957af199ec94617f7a0f496f3d199c51a1aaee67dac95f24d92ac13c60d25181e1eecd6eca5ddf32ac0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808206a4840365908a808468e975f09ad983011003846765746888676f312e32352e308664617277696ea06f485a167165ec12e0ab3e6ab59a7b88560b90306ac98a26eb294abf95a8c59b88000000000000000007");
1098 let header = Header::decode(&mut raw.as_slice()).unwrap();
1099 assert_eq!(
1100 header.hash_slow(),
1101 b256!("0x4f05e4392969fc82e41f6d6a8cea379323b0b2d3ddf7def1a33eec03883e3a33")
1102 );
1103 }
1104}
1105
1106#[cfg(all(test, feature = "serde"))]
1107mod serde_tests {
1108 use super::*;
1109 use alloy_primitives::b256;
1110
1111 #[test]
1112 fn test_header_serde_json_roundtrip() {
1113 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"}"#;
1114 let header = Header {
1115 base_fee_per_gas: Some(1),
1116 withdrawals_root: Some(EMPTY_ROOT_HASH),
1117 ..Default::default()
1118 };
1119
1120 let encoded = serde_json::to_string(&header).unwrap();
1121 assert_eq!(encoded, raw);
1122
1123 let decoded: Header = serde_json::from_str(&encoded).unwrap();
1124 assert_eq!(decoded, header);
1125
1126 let mut encoded_rlp = Vec::new();
1128
1129 decoded.encode(&mut encoded_rlp);
1131
1132 let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1134
1135 assert_eq!(decoded_rlp, decoded);
1137 }
1138
1139 #[test]
1140 fn serde_rlp_prague() {
1141 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"}
1143"#;
1144 let header = serde_json::from_str::<Header>(raw).unwrap();
1145 let hash = header.hash_slow();
1146 assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1147 let mut v = Vec::new();
1148 header.encode(&mut v);
1149 let decoded = Header::decode(&mut v.as_slice()).unwrap();
1150 assert_eq!(decoded, header);
1151 }
1152}