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::{
9 calc_next_block_base_fee, calculate_block_gas_limit_with_bound_divisor, BaseFeeParams,
10 GAS_LIMIT_BOUND_DIVISOR,
11 },
12 eip1898::BlockWithParent,
13 eip7840::BlobParams,
14 merge::ALLOWED_FUTURE_BLOCK_TIME_SECONDS,
15 BlockNumHash,
16};
17use alloy_primitives::{
18 keccak256, Address, BlockNumber, Bloom, Bytes, Sealable, Sealed, B256, B64, U256,
19};
20use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable};
21
22#[derive(Clone, Debug, PartialEq, Eq, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
26#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
27pub struct Header {
28 pub parent_hash: B256,
31 #[cfg_attr(feature = "serde", serde(rename = "sha3Uncles", alias = "ommersHash"))]
33 pub ommers_hash: B256,
34 #[cfg_attr(feature = "serde", serde(rename = "miner", alias = "beneficiary"))]
37 pub beneficiary: Address,
38 pub state_root: B256,
41 pub transactions_root: B256,
44 pub receipts_root: B256,
47 pub logs_bloom: Bloom,
51 pub difficulty: U256,
54 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
57 pub number: BlockNumber,
58 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
60 pub gas_limit: u64,
61 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
63 pub gas_used: u64,
64 #[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity"))]
67 pub timestamp: u64,
68 pub extra_data: Bytes,
71 pub mix_hash: B256,
75 pub nonce: B64,
78 #[cfg_attr(
85 feature = "serde",
86 serde(
87 default,
88 with = "alloy_serde::quantity::opt",
89 skip_serializing_if = "Option::is_none"
90 )
91 )]
92 pub base_fee_per_gas: Option<u64>,
93 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
96 pub withdrawals_root: Option<B256>,
97 #[cfg_attr(
100 feature = "serde",
101 serde(
102 default,
103 with = "alloy_serde::quantity::opt",
104 skip_serializing_if = "Option::is_none"
105 )
106 )]
107 pub blob_gas_used: Option<u64>,
108 #[cfg_attr(
112 feature = "serde",
113 serde(
114 default,
115 with = "alloy_serde::quantity::opt",
116 skip_serializing_if = "Option::is_none"
117 )
118 )]
119 pub excess_blob_gas: Option<u64>,
120 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
128 pub parent_beacon_block_root: Option<B256>,
129 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
134 pub requests_hash: Option<B256>,
135 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
143 pub block_access_list_hash: Option<B256>,
144 #[cfg_attr(
148 feature = "serde",
149 serde(
150 default,
151 with = "alloy_serde::quantity::opt",
152 skip_serializing_if = "Option::is_none"
153 )
154 )]
155 pub slot_number: Option<u64>,
156}
157
158impl AsRef<Self> for Header {
159 fn as_ref(&self) -> &Self {
160 self
161 }
162}
163
164impl Default for Header {
165 fn default() -> Self {
166 Self {
167 parent_hash: Default::default(),
168 ommers_hash: EMPTY_OMMER_ROOT_HASH,
169 beneficiary: Default::default(),
170 state_root: EMPTY_ROOT_HASH,
171 transactions_root: EMPTY_ROOT_HASH,
172 receipts_root: EMPTY_ROOT_HASH,
173 logs_bloom: Default::default(),
174 difficulty: Default::default(),
175 number: 0,
176 gas_limit: 0,
177 gas_used: 0,
178 timestamp: 0,
179 extra_data: Default::default(),
180 mix_hash: Default::default(),
181 nonce: B64::ZERO,
182 base_fee_per_gas: None,
183 withdrawals_root: None,
184 blob_gas_used: None,
185 excess_blob_gas: None,
186 parent_beacon_block_root: None,
187 requests_hash: None,
188 block_access_list_hash: None,
189 slot_number: None,
190 }
191 }
192}
193
194impl Sealable for Header {
195 fn hash_slow(&self) -> B256 {
196 Self::hash_slow(self)
197 }
198}
199
200impl Header {
201 pub const fn into_block<T>(self, body: BlockBody<T>) -> Block<T> {
203 body.into_block(self)
204 }
205
206 pub fn hash_slow(&self) -> B256 {
210 let mut out = Vec::<u8>::new();
211 self.encode(&mut out);
212 keccak256(&out)
213 }
214
215 pub fn decode_sealed(buf: &mut &[u8]) -> alloy_rlp::Result<Sealed<Self>> {
220 let start = *buf;
221 let header = Self::decode(buf)?;
222 let hash = keccak256(&start[..start.len() - buf.len()]);
223 Ok(header.seal_unchecked(hash))
224 }
225
226 pub fn ommers_hash_is_empty(&self) -> bool {
228 self.ommers_hash == EMPTY_OMMER_ROOT_HASH
229 }
230
231 pub fn transaction_root_is_empty(&self) -> bool {
233 self.transactions_root == EMPTY_ROOT_HASH
234 }
235
236 pub fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
240 Some(blob_params.calc_blob_fee(self.excess_blob_gas?))
241 }
242
243 pub fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
249 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
250 }
251
252 pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
256 Some(calc_next_block_base_fee(
257 self.gas_used,
258 self.gas_limit,
259 self.base_fee_per_gas?,
260 base_fee_params,
261 ))
262 }
263
264 pub fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
269 Some(blob_params.next_block_excess_blob_gas_osaka(
270 self.excess_blob_gas?,
271 self.blob_gas_used?,
272 self.base_fee_per_gas?,
273 ))
274 }
275
276 #[inline]
278 pub fn size(&self) -> usize {
279 size_of::<Self>() + self.extra_data.len()
280 }
281
282 fn header_payload_length(&self) -> usize {
283 let mut length = 0;
284 length += self.parent_hash.length();
285 length += self.ommers_hash.length();
286 length += self.beneficiary.length();
287 length += self.state_root.length();
288 length += self.transactions_root.length();
289 length += self.receipts_root.length();
290 length += self.logs_bloom.length();
291 length += self.difficulty.length();
292 length += U256::from(self.number).length();
293 length += U256::from(self.gas_limit).length();
294 length += U256::from(self.gas_used).length();
295 length += self.timestamp.length();
296 length += self.extra_data.length();
297 length += self.mix_hash.length();
298 length += self.nonce.length();
299
300 if let Some(base_fee) = self.base_fee_per_gas {
301 length += U256::from(base_fee).length();
303 }
304
305 if let Some(root) = self.withdrawals_root {
306 length += root.length();
308 }
309
310 if let Some(blob_gas_used) = self.blob_gas_used {
311 length += U256::from(blob_gas_used).length();
313 }
314
315 if let Some(excess_blob_gas) = self.excess_blob_gas {
316 length += U256::from(excess_blob_gas).length();
318 }
319
320 if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
321 length += parent_beacon_block_root.length();
322 }
323
324 if let Some(requests_hash) = self.requests_hash {
325 length += requests_hash.length();
326 }
327
328 if let Some(block_access_list_hash) = self.block_access_list_hash {
329 length += block_access_list_hash.length();
330 }
331
332 if let Some(slot_number) = self.slot_number {
333 length += U256::from(slot_number).length();
334 }
335
336 length
337 }
338
339 pub const fn parent_num_hash(&self) -> BlockNumHash {
343 BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
344 }
345
346 pub fn num_hash_slow(&self) -> BlockNumHash {
350 BlockNumHash { number: self.number, hash: self.hash_slow() }
351 }
352
353 pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
357 BlockWithParent::new(self.parent_hash, self.num_hash_slow())
358 }
359
360 #[inline]
364 pub const fn seal(self, hash: B256) -> Sealed<Self> {
365 Sealed::new_unchecked(self, hash)
366 }
367
368 pub const fn shanghai_active(&self) -> bool {
372 self.withdrawals_root.is_some()
373 }
374
375 pub const fn cancun_active(&self) -> bool {
379 self.blob_gas_used.is_some()
380 }
381
382 pub const fn prague_active(&self) -> bool {
386 self.requests_hash.is_some()
387 }
388
389 pub const fn amsterdam_active(&self) -> bool {
393 self.block_access_list_hash.is_some()
394 }
395}
396
397impl Encodable for Header {
398 fn encode(&self, out: &mut dyn BufMut) {
399 let list_header =
400 alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
401 list_header.encode(out);
402 self.parent_hash.encode(out);
403 self.ommers_hash.encode(out);
404 self.beneficiary.encode(out);
405 self.state_root.encode(out);
406 self.transactions_root.encode(out);
407 self.receipts_root.encode(out);
408 self.logs_bloom.encode(out);
409 self.difficulty.encode(out);
410 U256::from(self.number).encode(out);
411 U256::from(self.gas_limit).encode(out);
412 U256::from(self.gas_used).encode(out);
413 self.timestamp.encode(out);
414 self.extra_data.encode(out);
415 self.mix_hash.encode(out);
416 self.nonce.encode(out);
417
418 if let Some(ref base_fee) = self.base_fee_per_gas {
420 U256::from(*base_fee).encode(out);
421 }
422
423 if let Some(ref root) = self.withdrawals_root {
424 root.encode(out);
425 }
426
427 if let Some(ref blob_gas_used) = self.blob_gas_used {
428 U256::from(*blob_gas_used).encode(out);
429 }
430
431 if let Some(ref excess_blob_gas) = self.excess_blob_gas {
432 U256::from(*excess_blob_gas).encode(out);
433 }
434
435 if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
436 parent_beacon_block_root.encode(out);
437 }
438
439 if let Some(ref requests_hash) = self.requests_hash {
440 requests_hash.encode(out);
441 }
442
443 if let Some(ref block_access_list_hash) = self.block_access_list_hash {
444 block_access_list_hash.encode(out);
445 }
446
447 if let Some(ref slot_number) = self.slot_number {
448 U256::from(*slot_number).encode(out);
449 }
450 }
451
452 fn length(&self) -> usize {
453 let mut length = 0;
454 length += self.header_payload_length();
455 length += length_of_length(length);
456 length
457 }
458}
459
460impl Decodable for Header {
461 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
462 let rlp_head = alloy_rlp::Header::decode(buf)?;
463 if !rlp_head.list {
464 return Err(alloy_rlp::Error::UnexpectedString);
465 }
466 let started_len = buf.len();
467 let mut this = Self {
468 parent_hash: Decodable::decode(buf)?,
469 ommers_hash: Decodable::decode(buf)?,
470 beneficiary: Decodable::decode(buf)?,
471 state_root: Decodable::decode(buf)?,
472 transactions_root: Decodable::decode(buf)?,
473 receipts_root: Decodable::decode(buf)?,
474 logs_bloom: Decodable::decode(buf)?,
475 difficulty: Decodable::decode(buf)?,
476 number: u64::decode(buf)?,
477 gas_limit: u64::decode(buf)?,
478 gas_used: u64::decode(buf)?,
479 timestamp: Decodable::decode(buf)?,
480 extra_data: Decodable::decode(buf)?,
481 mix_hash: Decodable::decode(buf)?,
482 nonce: B64::decode(buf)?,
483 base_fee_per_gas: None,
484 withdrawals_root: None,
485 blob_gas_used: None,
486 excess_blob_gas: None,
487 parent_beacon_block_root: None,
488 requests_hash: None,
489 block_access_list_hash: None,
490 slot_number: None,
491 };
492 if started_len - buf.len() < rlp_head.payload_length {
493 this.base_fee_per_gas = Some(u64::decode(buf)?);
494 }
495
496 if started_len - buf.len() < rlp_head.payload_length {
498 this.withdrawals_root = Some(Decodable::decode(buf)?);
499 }
500
501 if started_len - buf.len() < rlp_head.payload_length {
503 this.blob_gas_used = Some(u64::decode(buf)?);
504 }
505
506 if started_len - buf.len() < rlp_head.payload_length {
507 this.excess_blob_gas = Some(u64::decode(buf)?);
508 }
509
510 if started_len - buf.len() < rlp_head.payload_length {
512 this.parent_beacon_block_root = Some(B256::decode(buf)?);
513 }
514
515 if started_len - buf.len() < rlp_head.payload_length {
517 this.requests_hash = Some(B256::decode(buf)?);
518 }
519
520 if started_len - buf.len() < rlp_head.payload_length {
522 this.block_access_list_hash = Some(B256::decode(buf)?);
523 }
524
525 if started_len - buf.len() < rlp_head.payload_length {
527 this.slot_number = Some(u64::decode(buf)?);
528 }
529
530 let consumed = started_len - buf.len();
531 if consumed != rlp_head.payload_length {
532 return Err(alloy_rlp::Error::ListLengthMismatch {
533 expected: rlp_head.payload_length,
534 got: consumed,
535 });
536 }
537 Ok(this)
538 }
539}
540
541#[cfg(any(test, feature = "arbitrary"))]
542impl<'a> arbitrary::Arbitrary<'a> for Header {
543 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
544 let is_prague = u.arbitrary::<bool>()?;
545 let is_cancun = is_prague || u.arbitrary::<bool>()?;
546 let is_shanghai = is_cancun || u.arbitrary::<bool>()?;
547 let is_london = is_shanghai || u.arbitrary::<bool>()?;
548
549 Ok(Self {
550 parent_hash: u.arbitrary()?,
551 ommers_hash: u.arbitrary()?,
552 beneficiary: u.arbitrary()?,
553 state_root: u.arbitrary()?,
554 transactions_root: u.arbitrary()?,
555 receipts_root: u.arbitrary()?,
556 logs_bloom: u.arbitrary()?,
557 difficulty: u.arbitrary()?,
558 number: u.arbitrary()?,
559 gas_limit: u.arbitrary()?,
560 gas_used: u.arbitrary()?,
561 timestamp: u.arbitrary()?,
562 extra_data: u.arbitrary()?,
563 mix_hash: u.arbitrary()?,
564 nonce: u.arbitrary()?,
565 base_fee_per_gas: if is_london { Some(u.arbitrary()?) } else { None },
566 withdrawals_root: if is_shanghai { Some(u.arbitrary()?) } else { None },
567 blob_gas_used: if is_cancun { Some(u.arbitrary()?) } else { None },
568 excess_blob_gas: if is_cancun { Some(u.arbitrary()?) } else { None },
569 parent_beacon_block_root: if is_cancun { Some(u.arbitrary()?) } else { None },
570 requests_hash: if is_prague { Some(u.arbitrary()?) } else { None },
571 block_access_list_hash: None,
573 slot_number: None,
574 })
575 }
576}
577
578#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
581#[error("gas limit mismatch: got {got}, expected {expected}")]
582pub struct GasLimitMismatch {
583 pub got: u64,
585 pub expected: u64,
587}
588
589#[auto_impl::auto_impl(&, Arc)]
591pub trait BlockHeader {
592 fn header_info(&self) -> HeaderInfo {
594 HeaderInfo {
595 number: self.number(),
596 beneficiary: self.beneficiary(),
597 timestamp: self.timestamp(),
598 gas_limit: self.gas_limit(),
599 base_fee_per_gas: self.base_fee_per_gas(),
600 excess_blob_gas: self.excess_blob_gas(),
601 blob_gas_used: self.blob_gas_used(),
602 difficulty: self.difficulty(),
603 mix_hash: self.mix_hash(),
604 slot_number: self.slot_number(),
605 }
606 }
607
608 fn header_roots(&self) -> HeaderRoots {
610 HeaderRoots {
611 state_root: self.state_root(),
612 transactions_root: self.transactions_root(),
613 receipts_root: self.receipts_root(),
614 withdrawals_root: self.withdrawals_root(),
615 parent_beacon_block_root: self.parent_beacon_block_root(),
616 logs_bloom: self.logs_bloom(),
617 }
618 }
619
620 fn parent_hash(&self) -> B256;
622
623 fn ommers_hash(&self) -> B256;
625
626 fn beneficiary(&self) -> Address;
628
629 fn state_root(&self) -> B256;
631
632 fn transactions_root(&self) -> B256;
634
635 fn receipts_root(&self) -> B256;
637
638 fn withdrawals_root(&self) -> Option<B256>;
640
641 fn logs_bloom(&self) -> Bloom;
643
644 fn difficulty(&self) -> U256;
646
647 fn number(&self) -> BlockNumber;
649
650 fn gas_limit(&self) -> u64;
652
653 fn gas_used(&self) -> u64;
655
656 fn timestamp(&self) -> u64;
658
659 fn mix_hash(&self) -> Option<B256>;
661
662 fn nonce(&self) -> Option<B64>;
664
665 fn base_fee_per_gas(&self) -> Option<u64>;
667
668 fn blob_gas_used(&self) -> Option<u64>;
670
671 fn excess_blob_gas(&self) -> Option<u64>;
673
674 fn parent_beacon_block_root(&self) -> Option<B256>;
676
677 fn requests_hash(&self) -> Option<B256>;
679
680 fn block_access_list_hash(&self) -> Option<B256>;
684
685 fn slot_number(&self) -> Option<u64>;
689
690 fn extra_data(&self) -> &Bytes;
692
693 fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
697 Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
698 }
699
700 fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
705 Some(blob_params.next_block_excess_blob_gas_osaka(
706 self.excess_blob_gas()?,
707 self.blob_gas_used()?,
708 self.base_fee_per_gas()?,
709 ))
710 }
711
712 fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
717 self.next_block_excess_blob_gas(blob_params?)
718 }
719
720 fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
726 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
727 }
728
729 fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
734 self.next_block_blob_fee(blob_params?)
735 }
736
737 fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
741 Some(calc_next_block_base_fee(
742 self.gas_used(),
743 self.gas_limit(),
744 self.base_fee_per_gas()?,
745 base_fee_params,
746 ))
747 }
748
749 fn validate_gas_limit(
756 &self,
757 desired_gas_limit: u64,
758 gas_limit: u64,
759 ) -> Result<(), GasLimitMismatch> {
760 self.validate_gas_limit_with_bound_divisor(
761 desired_gas_limit,
762 gas_limit,
763 GAS_LIMIT_BOUND_DIVISOR,
764 )
765 }
766
767 fn validate_gas_limit_with_bound_divisor(
776 &self,
777 desired_gas_limit: u64,
778 gas_limit: u64,
779 gas_limit_bound_divisor: u64,
780 ) -> Result<(), GasLimitMismatch> {
781 let expected = calculate_block_gas_limit_with_bound_divisor(
782 self.gas_limit(),
783 desired_gas_limit,
784 gas_limit_bound_divisor,
785 );
786
787 if gas_limit != expected {
788 return Err(GasLimitMismatch { got: gas_limit, expected });
789 }
790
791 Ok(())
792 }
793
794 fn parent_num_hash(&self) -> BlockNumHash {
798 BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
799 }
800
801 fn is_empty(&self) -> bool {
803 let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
804 && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
805 self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
806 txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
807 })
808 }
809
810 fn is_zero_difficulty(&self) -> bool {
820 self.difficulty().is_zero()
821 }
822
823 fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
829 self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
830 }
831
832 fn is_nonce_zero(&self) -> bool {
836 self.nonce().is_some_and(|nonce| nonce.is_zero())
837 }
838}
839
840impl BlockHeader for Header {
841 fn parent_hash(&self) -> B256 {
842 self.parent_hash
843 }
844
845 fn ommers_hash(&self) -> B256 {
846 self.ommers_hash
847 }
848
849 fn beneficiary(&self) -> Address {
850 self.beneficiary
851 }
852
853 fn state_root(&self) -> B256 {
854 self.state_root
855 }
856
857 fn transactions_root(&self) -> B256 {
858 self.transactions_root
859 }
860
861 fn receipts_root(&self) -> B256 {
862 self.receipts_root
863 }
864
865 fn withdrawals_root(&self) -> Option<B256> {
866 self.withdrawals_root
867 }
868
869 fn logs_bloom(&self) -> Bloom {
870 self.logs_bloom
871 }
872
873 fn difficulty(&self) -> U256 {
874 self.difficulty
875 }
876
877 fn number(&self) -> BlockNumber {
878 self.number
879 }
880
881 fn gas_limit(&self) -> u64 {
882 self.gas_limit
883 }
884
885 fn gas_used(&self) -> u64 {
886 self.gas_used
887 }
888
889 fn timestamp(&self) -> u64 {
890 self.timestamp
891 }
892
893 fn mix_hash(&self) -> Option<B256> {
894 Some(self.mix_hash)
895 }
896
897 fn nonce(&self) -> Option<B64> {
898 Some(self.nonce)
899 }
900
901 fn base_fee_per_gas(&self) -> Option<u64> {
902 self.base_fee_per_gas
903 }
904
905 fn blob_gas_used(&self) -> Option<u64> {
906 self.blob_gas_used
907 }
908
909 fn excess_blob_gas(&self) -> Option<u64> {
910 self.excess_blob_gas
911 }
912
913 fn parent_beacon_block_root(&self) -> Option<B256> {
914 self.parent_beacon_block_root
915 }
916
917 fn requests_hash(&self) -> Option<B256> {
918 self.requests_hash
919 }
920
921 fn block_access_list_hash(&self) -> Option<B256> {
922 self.block_access_list_hash
923 }
924
925 fn slot_number(&self) -> Option<u64> {
926 self.slot_number
927 }
928
929 fn extra_data(&self) -> &Bytes {
930 &self.extra_data
931 }
932}
933
934#[cfg(feature = "serde")]
935impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
936 fn parent_hash(&self) -> B256 {
937 self.inner.parent_hash()
938 }
939
940 fn ommers_hash(&self) -> B256 {
941 self.inner.ommers_hash()
942 }
943
944 fn beneficiary(&self) -> Address {
945 self.inner.beneficiary()
946 }
947
948 fn state_root(&self) -> B256 {
949 self.inner.state_root()
950 }
951
952 fn transactions_root(&self) -> B256 {
953 self.inner.transactions_root()
954 }
955
956 fn receipts_root(&self) -> B256 {
957 self.inner.receipts_root()
958 }
959
960 fn withdrawals_root(&self) -> Option<B256> {
961 self.inner.withdrawals_root()
962 }
963
964 fn logs_bloom(&self) -> Bloom {
965 self.inner.logs_bloom()
966 }
967
968 fn difficulty(&self) -> U256 {
969 self.inner.difficulty()
970 }
971
972 fn number(&self) -> u64 {
973 self.inner.number()
974 }
975
976 fn gas_limit(&self) -> u64 {
977 self.inner.gas_limit()
978 }
979
980 fn gas_used(&self) -> u64 {
981 self.inner.gas_used()
982 }
983
984 fn timestamp(&self) -> u64 {
985 self.inner.timestamp()
986 }
987
988 fn mix_hash(&self) -> Option<B256> {
989 self.inner.mix_hash()
990 }
991
992 fn nonce(&self) -> Option<B64> {
993 self.inner.nonce()
994 }
995
996 fn base_fee_per_gas(&self) -> Option<u64> {
997 self.inner.base_fee_per_gas()
998 }
999
1000 fn blob_gas_used(&self) -> Option<u64> {
1001 self.inner.blob_gas_used()
1002 }
1003
1004 fn excess_blob_gas(&self) -> Option<u64> {
1005 self.inner.excess_blob_gas()
1006 }
1007
1008 fn parent_beacon_block_root(&self) -> Option<B256> {
1009 self.inner.parent_beacon_block_root()
1010 }
1011
1012 fn requests_hash(&self) -> Option<B256> {
1013 self.inner.requests_hash()
1014 }
1015
1016 fn block_access_list_hash(&self) -> Option<B256> {
1017 self.inner.block_access_list_hash()
1018 }
1019
1020 fn slot_number(&self) -> Option<u64> {
1021 self.inner.slot_number()
1022 }
1023
1024 fn extra_data(&self) -> &Bytes {
1025 self.inner.extra_data()
1026 }
1027
1028 fn is_empty(&self) -> bool {
1029 self.inner.is_empty()
1030 }
1031}
1032
1033#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
1035pub(crate) mod serde_bincode_compat {
1036 use alloc::borrow::Cow;
1037 use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
1038 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1039 use serde_with::{DeserializeAs, SerializeAs};
1040
1041 #[derive(Debug, Serialize, Deserialize)]
1057 pub struct Header<'a> {
1058 parent_hash: B256,
1059 ommers_hash: B256,
1060 beneficiary: Address,
1061 state_root: B256,
1062 transactions_root: B256,
1063 receipts_root: B256,
1064 #[serde(default)]
1065 withdrawals_root: Option<B256>,
1066 logs_bloom: Bloom,
1067 difficulty: U256,
1068 number: BlockNumber,
1069 gas_limit: u64,
1070 gas_used: u64,
1071 timestamp: u64,
1072 mix_hash: B256,
1073 nonce: B64,
1074 #[serde(default)]
1075 base_fee_per_gas: Option<u64>,
1076 #[serde(default)]
1077 blob_gas_used: Option<u64>,
1078 #[serde(default)]
1079 excess_blob_gas: Option<u64>,
1080 #[serde(default)]
1081 parent_beacon_block_root: Option<B256>,
1082 #[serde(default)]
1083 requests_hash: Option<B256>,
1084 #[serde(default)]
1085 block_access_list_hash: Option<B256>,
1086 #[serde(default)]
1087 slot_number: Option<u64>,
1088 extra_data: Cow<'a, Bytes>,
1089 }
1090
1091 impl<'a> From<&'a super::Header> for Header<'a> {
1092 fn from(value: &'a super::Header) -> Self {
1093 Self {
1094 parent_hash: value.parent_hash,
1095 ommers_hash: value.ommers_hash,
1096 beneficiary: value.beneficiary,
1097 state_root: value.state_root,
1098 transactions_root: value.transactions_root,
1099 receipts_root: value.receipts_root,
1100 withdrawals_root: value.withdrawals_root,
1101 logs_bloom: value.logs_bloom,
1102 difficulty: value.difficulty,
1103 number: value.number,
1104 gas_limit: value.gas_limit,
1105 gas_used: value.gas_used,
1106 timestamp: value.timestamp,
1107 mix_hash: value.mix_hash,
1108 nonce: value.nonce,
1109 base_fee_per_gas: value.base_fee_per_gas,
1110 blob_gas_used: value.blob_gas_used,
1111 excess_blob_gas: value.excess_blob_gas,
1112 parent_beacon_block_root: value.parent_beacon_block_root,
1113 requests_hash: value.requests_hash,
1114 block_access_list_hash: value.block_access_list_hash,
1115 slot_number: value.slot_number,
1116 extra_data: Cow::Borrowed(&value.extra_data),
1117 }
1118 }
1119 }
1120
1121 impl<'a> From<Header<'a>> for super::Header {
1122 fn from(value: Header<'a>) -> Self {
1123 Self {
1124 parent_hash: value.parent_hash,
1125 ommers_hash: value.ommers_hash,
1126 beneficiary: value.beneficiary,
1127 state_root: value.state_root,
1128 transactions_root: value.transactions_root,
1129 receipts_root: value.receipts_root,
1130 withdrawals_root: value.withdrawals_root,
1131 logs_bloom: value.logs_bloom,
1132 difficulty: value.difficulty,
1133 number: value.number,
1134 gas_limit: value.gas_limit,
1135 gas_used: value.gas_used,
1136 timestamp: value.timestamp,
1137 mix_hash: value.mix_hash,
1138 nonce: value.nonce,
1139 base_fee_per_gas: value.base_fee_per_gas,
1140 blob_gas_used: value.blob_gas_used,
1141 excess_blob_gas: value.excess_blob_gas,
1142 parent_beacon_block_root: value.parent_beacon_block_root,
1143 requests_hash: value.requests_hash,
1144 block_access_list_hash: value.block_access_list_hash,
1145 slot_number: value.slot_number,
1146 extra_data: value.extra_data.into_owned(),
1147 }
1148 }
1149 }
1150
1151 impl SerializeAs<super::Header> for Header<'_> {
1152 fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
1153 where
1154 S: Serializer,
1155 {
1156 Header::from(source).serialize(serializer)
1157 }
1158 }
1159
1160 impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1161 fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1162 where
1163 D: Deserializer<'de>,
1164 {
1165 Header::deserialize(deserializer).map(Into::into)
1166 }
1167 }
1168
1169 #[cfg(test)]
1170 mod tests {
1171 use super::super::{serde_bincode_compat, Header};
1172 use arbitrary::Arbitrary;
1173 use bincode::config;
1174 use rand::Rng;
1175 use serde::{Deserialize, Serialize};
1176 use serde_with::serde_as;
1177
1178 #[test]
1179 fn test_header_bincode_roundtrip() {
1180 #[serde_as]
1181 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1182 struct Data {
1183 #[serde_as(as = "serde_bincode_compat::Header")]
1184 header: Header,
1185 }
1186
1187 let mut bytes = [0u8; 1024];
1188 rand::thread_rng().fill(bytes.as_mut_slice());
1189 let data = Data {
1190 header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1191 };
1192
1193 let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
1194 let (decoded, _) =
1195 bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
1196 assert_eq!(decoded, data);
1197 }
1198 }
1199}
1200
1201#[cfg(test)]
1202mod tests {
1203 use super::*;
1204 use alloy_primitives::{b256, hex};
1205
1206 #[test]
1207 fn validate_gas_limit() {
1208 let parent = Header { gas_limit: 30_000_000, ..Default::default() };
1209
1210 assert_eq!(parent.validate_gas_limit(30_000_000, 30_000_000), Ok(()));
1211 assert_eq!(parent.validate_gas_limit(20_000_000, 29_970_705), Ok(()));
1212
1213 let err = parent.validate_gas_limit(40_000_000, 30_000_000).unwrap_err();
1214 assert_eq!(err, GasLimitMismatch { got: 30_000_000, expected: 30_029_295 });
1215 assert_eq!(err.to_string(), "gas limit mismatch: got 30000000, expected 30029295");
1216 }
1217
1218 #[test]
1219 fn validate_gas_limit_with_custom_bound_divisor() {
1220 let parent = Header { gas_limit: 1_000, ..Default::default() };
1221
1222 assert_eq!(parent.validate_gas_limit_with_bound_divisor(2_000, 1_099, 10), Ok(()));
1223 assert_eq!(
1224 parent.validate_gas_limit_with_bound_divisor(2_000, 1_098, 10),
1225 Err(GasLimitMismatch { got: 1_098, expected: 1_099 })
1226 );
1227 }
1228
1229 #[test]
1230 fn decode_header_rlp() {
1231 let raw = hex!("0xf90212a00d84d79f59fc384a1f6402609a5b7253b4bfe7a4ae12608ed107273e5422b6dda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479471562b71999873db5b286df957af199ec94617f7a0f496f3d199c51a1aaee67dac95f24d92ac13c60d25181e1eecd6eca5ddf32ac0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808206a4840365908a808468e975f09ad983011003846765746888676f312e32352e308664617277696ea06f485a167165ec12e0ab3e6ab59a7b88560b90306ac98a26eb294abf95a8c59b88000000000000000007");
1233 let header = Header::decode(&mut raw.as_slice()).unwrap();
1234 assert_eq!(
1235 header.hash_slow(),
1236 b256!("0x4f05e4392969fc82e41f6d6a8cea379323b0b2d3ddf7def1a33eec03883e3a33")
1237 );
1238 }
1239}
1240
1241#[cfg(all(test, feature = "serde"))]
1242mod serde_tests {
1243 use super::*;
1244 use alloy_primitives::b256;
1245
1246 #[test]
1247 fn test_header_serde_json_roundtrip() {
1248 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"}"#;
1249 let header = Header {
1250 base_fee_per_gas: Some(1),
1251 withdrawals_root: Some(EMPTY_ROOT_HASH),
1252 ..Default::default()
1253 };
1254
1255 let encoded = serde_json::to_string(&header).unwrap();
1256 assert_eq!(encoded, raw);
1257
1258 let decoded: Header = serde_json::from_str(&encoded).unwrap();
1259 assert_eq!(decoded, header);
1260
1261 let mut encoded_rlp = Vec::new();
1263
1264 decoded.encode(&mut encoded_rlp);
1266
1267 let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1269
1270 assert_eq!(decoded_rlp, decoded);
1272 }
1273
1274 #[test]
1275 fn serde_rlp_prague() {
1276 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"}
1278"#;
1279 let header = serde_json::from_str::<Header>(raw).unwrap();
1280 let hash = header.hash_slow();
1281 assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1282 let mut v = Vec::new();
1283 header.encode(&mut v);
1284 let decoded = Header::decode(&mut v.as_slice()).unwrap();
1285 assert_eq!(decoded, header);
1286 }
1287}