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 #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
140 pub block_access_list_hash: Option<B256>,
141 #[cfg_attr(
145 feature = "serde",
146 serde(
147 default,
148 with = "alloy_serde::quantity::opt",
149 skip_serializing_if = "Option::is_none"
150 )
151 )]
152 pub slot_number: Option<u64>,
153}
154
155impl AsRef<Self> for Header {
156 fn as_ref(&self) -> &Self {
157 self
158 }
159}
160
161impl Default for Header {
162 fn default() -> Self {
163 Self {
164 parent_hash: Default::default(),
165 ommers_hash: EMPTY_OMMER_ROOT_HASH,
166 beneficiary: Default::default(),
167 state_root: EMPTY_ROOT_HASH,
168 transactions_root: EMPTY_ROOT_HASH,
169 receipts_root: EMPTY_ROOT_HASH,
170 logs_bloom: Default::default(),
171 difficulty: Default::default(),
172 number: 0,
173 gas_limit: 0,
174 gas_used: 0,
175 timestamp: 0,
176 extra_data: Default::default(),
177 mix_hash: Default::default(),
178 nonce: B64::ZERO,
179 base_fee_per_gas: None,
180 withdrawals_root: None,
181 blob_gas_used: None,
182 excess_blob_gas: None,
183 parent_beacon_block_root: None,
184 requests_hash: None,
185 block_access_list_hash: None,
186 slot_number: None,
187 }
188 }
189}
190
191impl Sealable for Header {
192 fn hash_slow(&self) -> B256 {
193 Self::hash_slow(self)
194 }
195}
196
197impl Header {
198 pub const fn into_block<T>(self, body: BlockBody<T>) -> Block<T> {
200 body.into_block(self)
201 }
202
203 pub fn hash_slow(&self) -> B256 {
207 let mut out = Vec::<u8>::new();
208 self.encode(&mut out);
209 keccak256(&out)
210 }
211
212 pub fn decode_sealed(buf: &mut &[u8]) -> alloy_rlp::Result<Sealed<Self>> {
217 let start = *buf;
218 let header = Self::decode(buf)?;
219 let hash = keccak256(&start[..start.len() - buf.len()]);
220 Ok(header.seal_unchecked(hash))
221 }
222
223 pub fn ommers_hash_is_empty(&self) -> bool {
225 self.ommers_hash == EMPTY_OMMER_ROOT_HASH
226 }
227
228 pub fn transaction_root_is_empty(&self) -> bool {
230 self.transactions_root == EMPTY_ROOT_HASH
231 }
232
233 pub fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
237 Some(blob_params.calc_blob_fee(self.excess_blob_gas?))
238 }
239
240 pub fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
246 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
247 }
248
249 pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
253 Some(calc_next_block_base_fee(
254 self.gas_used,
255 self.gas_limit,
256 self.base_fee_per_gas?,
257 base_fee_params,
258 ))
259 }
260
261 pub fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
266 Some(blob_params.next_block_excess_blob_gas_osaka(
267 self.excess_blob_gas?,
268 self.blob_gas_used?,
269 self.base_fee_per_gas?,
270 ))
271 }
272
273 #[inline]
275 pub fn size(&self) -> usize {
276 size_of::<Self>() + self.extra_data.len()
277 }
278
279 fn header_payload_length(&self) -> usize {
280 let mut length = 0;
281 length += self.parent_hash.length();
282 length += self.ommers_hash.length();
283 length += self.beneficiary.length();
284 length += self.state_root.length();
285 length += self.transactions_root.length();
286 length += self.receipts_root.length();
287 length += self.logs_bloom.length();
288 length += self.difficulty.length();
289 length += U256::from(self.number).length();
290 length += U256::from(self.gas_limit).length();
291 length += U256::from(self.gas_used).length();
292 length += self.timestamp.length();
293 length += self.extra_data.length();
294 length += self.mix_hash.length();
295 length += self.nonce.length();
296
297 if let Some(base_fee) = self.base_fee_per_gas {
298 length += U256::from(base_fee).length();
300 }
301
302 if let Some(root) = self.withdrawals_root {
303 length += root.length();
305 }
306
307 if let Some(blob_gas_used) = self.blob_gas_used {
308 length += U256::from(blob_gas_used).length();
310 }
311
312 if let Some(excess_blob_gas) = self.excess_blob_gas {
313 length += U256::from(excess_blob_gas).length();
315 }
316
317 if let Some(parent_beacon_block_root) = self.parent_beacon_block_root {
318 length += parent_beacon_block_root.length();
319 }
320
321 if let Some(requests_hash) = self.requests_hash {
322 length += requests_hash.length();
323 }
324
325 if let Some(block_access_list_hash) = self.block_access_list_hash {
326 length += block_access_list_hash.length();
327 }
328
329 if let Some(slot_number) = self.slot_number {
330 length += U256::from(slot_number).length();
331 }
332
333 length
334 }
335
336 pub const fn parent_num_hash(&self) -> BlockNumHash {
340 BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash }
341 }
342
343 pub fn num_hash_slow(&self) -> BlockNumHash {
347 BlockNumHash { number: self.number, hash: self.hash_slow() }
348 }
349
350 pub fn num_hash_with_parent_slow(&self) -> BlockWithParent {
354 BlockWithParent::new(self.parent_hash, self.num_hash_slow())
355 }
356
357 #[inline]
361 pub const fn seal(self, hash: B256) -> Sealed<Self> {
362 Sealed::new_unchecked(self, hash)
363 }
364
365 pub const fn shanghai_active(&self) -> bool {
369 self.withdrawals_root.is_some()
370 }
371
372 pub const fn cancun_active(&self) -> bool {
376 self.blob_gas_used.is_some()
377 }
378
379 pub const fn prague_active(&self) -> bool {
383 self.requests_hash.is_some()
384 }
385
386 pub const fn amsterdam_active(&self) -> bool {
390 self.block_access_list_hash.is_some()
391 }
392}
393
394impl Encodable for Header {
395 fn encode(&self, out: &mut dyn BufMut) {
396 let list_header =
397 alloy_rlp::Header { list: true, payload_length: self.header_payload_length() };
398 list_header.encode(out);
399 self.parent_hash.encode(out);
400 self.ommers_hash.encode(out);
401 self.beneficiary.encode(out);
402 self.state_root.encode(out);
403 self.transactions_root.encode(out);
404 self.receipts_root.encode(out);
405 self.logs_bloom.encode(out);
406 self.difficulty.encode(out);
407 U256::from(self.number).encode(out);
408 U256::from(self.gas_limit).encode(out);
409 U256::from(self.gas_used).encode(out);
410 self.timestamp.encode(out);
411 self.extra_data.encode(out);
412 self.mix_hash.encode(out);
413 self.nonce.encode(out);
414
415 if let Some(ref base_fee) = self.base_fee_per_gas {
417 U256::from(*base_fee).encode(out);
418 }
419
420 if let Some(ref root) = self.withdrawals_root {
421 root.encode(out);
422 }
423
424 if let Some(ref blob_gas_used) = self.blob_gas_used {
425 U256::from(*blob_gas_used).encode(out);
426 }
427
428 if let Some(ref excess_blob_gas) = self.excess_blob_gas {
429 U256::from(*excess_blob_gas).encode(out);
430 }
431
432 if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root {
433 parent_beacon_block_root.encode(out);
434 }
435
436 if let Some(ref requests_hash) = self.requests_hash {
437 requests_hash.encode(out);
438 }
439
440 if let Some(ref block_access_list_hash) = self.block_access_list_hash {
441 block_access_list_hash.encode(out);
442 }
443
444 if let Some(ref slot_number) = self.slot_number {
445 U256::from(*slot_number).encode(out);
446 }
447 }
448
449 fn length(&self) -> usize {
450 let mut length = 0;
451 length += self.header_payload_length();
452 length += length_of_length(length);
453 length
454 }
455}
456
457impl Decodable for Header {
458 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
459 let rlp_head = alloy_rlp::Header::decode(buf)?;
460 if !rlp_head.list {
461 return Err(alloy_rlp::Error::UnexpectedString);
462 }
463 let started_len = buf.len();
464 let mut this = Self {
465 parent_hash: Decodable::decode(buf)?,
466 ommers_hash: Decodable::decode(buf)?,
467 beneficiary: Decodable::decode(buf)?,
468 state_root: Decodable::decode(buf)?,
469 transactions_root: Decodable::decode(buf)?,
470 receipts_root: Decodable::decode(buf)?,
471 logs_bloom: Decodable::decode(buf)?,
472 difficulty: Decodable::decode(buf)?,
473 number: u64::decode(buf)?,
474 gas_limit: u64::decode(buf)?,
475 gas_used: u64::decode(buf)?,
476 timestamp: Decodable::decode(buf)?,
477 extra_data: Decodable::decode(buf)?,
478 mix_hash: Decodable::decode(buf)?,
479 nonce: B64::decode(buf)?,
480 base_fee_per_gas: None,
481 withdrawals_root: None,
482 blob_gas_used: None,
483 excess_blob_gas: None,
484 parent_beacon_block_root: None,
485 requests_hash: None,
486 block_access_list_hash: None,
487 slot_number: None,
488 };
489 if started_len - buf.len() < rlp_head.payload_length {
490 this.base_fee_per_gas = Some(u64::decode(buf)?);
491 }
492
493 if started_len - buf.len() < rlp_head.payload_length {
495 this.withdrawals_root = Some(Decodable::decode(buf)?);
496 }
497
498 if started_len - buf.len() < rlp_head.payload_length {
500 this.blob_gas_used = Some(u64::decode(buf)?);
501 }
502
503 if started_len - buf.len() < rlp_head.payload_length {
504 this.excess_blob_gas = Some(u64::decode(buf)?);
505 }
506
507 if started_len - buf.len() < rlp_head.payload_length {
509 this.parent_beacon_block_root = Some(B256::decode(buf)?);
510 }
511
512 if started_len - buf.len() < rlp_head.payload_length {
514 this.requests_hash = Some(B256::decode(buf)?);
515 }
516
517 if started_len - buf.len() < rlp_head.payload_length {
519 this.block_access_list_hash = Some(B256::decode(buf)?);
520 }
521
522 if started_len - buf.len() < rlp_head.payload_length {
524 this.slot_number = Some(u64::decode(buf)?);
525 }
526
527 let consumed = started_len - buf.len();
528 if consumed != rlp_head.payload_length {
529 return Err(alloy_rlp::Error::ListLengthMismatch {
530 expected: rlp_head.payload_length,
531 got: consumed,
532 });
533 }
534 Ok(this)
535 }
536}
537
538#[cfg(any(test, feature = "arbitrary"))]
539impl<'a> arbitrary::Arbitrary<'a> for Header {
540 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
541 let is_prague = u.arbitrary::<bool>()?;
542 let is_cancun = is_prague || u.arbitrary::<bool>()?;
543 let is_shanghai = is_cancun || u.arbitrary::<bool>()?;
544 let is_london = is_shanghai || u.arbitrary::<bool>()?;
545
546 Ok(Self {
547 parent_hash: u.arbitrary()?,
548 ommers_hash: u.arbitrary()?,
549 beneficiary: u.arbitrary()?,
550 state_root: u.arbitrary()?,
551 transactions_root: u.arbitrary()?,
552 receipts_root: u.arbitrary()?,
553 logs_bloom: u.arbitrary()?,
554 difficulty: u.arbitrary()?,
555 number: u.arbitrary()?,
556 gas_limit: u.arbitrary()?,
557 gas_used: u.arbitrary()?,
558 timestamp: u.arbitrary()?,
559 extra_data: u.arbitrary()?,
560 mix_hash: u.arbitrary()?,
561 nonce: u.arbitrary()?,
562 base_fee_per_gas: if is_london { Some(u.arbitrary()?) } else { None },
563 withdrawals_root: if is_shanghai { Some(u.arbitrary()?) } else { None },
564 blob_gas_used: if is_cancun { Some(u.arbitrary()?) } else { None },
565 excess_blob_gas: if is_cancun { Some(u.arbitrary()?) } else { None },
566 parent_beacon_block_root: if is_cancun { Some(u.arbitrary()?) } else { None },
567 requests_hash: if is_prague { Some(u.arbitrary()?) } else { None },
568 block_access_list_hash: None,
570 slot_number: None,
571 })
572 }
573}
574
575#[auto_impl::auto_impl(&, Arc)]
577pub trait BlockHeader {
578 fn header_info(&self) -> HeaderInfo {
580 HeaderInfo {
581 number: self.number(),
582 beneficiary: self.beneficiary(),
583 timestamp: self.timestamp(),
584 gas_limit: self.gas_limit(),
585 base_fee_per_gas: self.base_fee_per_gas(),
586 excess_blob_gas: self.excess_blob_gas(),
587 blob_gas_used: self.blob_gas_used(),
588 difficulty: self.difficulty(),
589 mix_hash: self.mix_hash(),
590 slot_number: self.slot_number(),
591 }
592 }
593
594 fn header_roots(&self) -> HeaderRoots {
596 HeaderRoots {
597 state_root: self.state_root(),
598 transactions_root: self.transactions_root(),
599 receipts_root: self.receipts_root(),
600 withdrawals_root: self.withdrawals_root(),
601 parent_beacon_block_root: self.parent_beacon_block_root(),
602 logs_bloom: self.logs_bloom(),
603 }
604 }
605
606 fn parent_hash(&self) -> B256;
608
609 fn ommers_hash(&self) -> B256;
611
612 fn beneficiary(&self) -> Address;
614
615 fn state_root(&self) -> B256;
617
618 fn transactions_root(&self) -> B256;
620
621 fn receipts_root(&self) -> B256;
623
624 fn withdrawals_root(&self) -> Option<B256>;
626
627 fn logs_bloom(&self) -> Bloom;
629
630 fn difficulty(&self) -> U256;
632
633 fn number(&self) -> BlockNumber;
635
636 fn gas_limit(&self) -> u64;
638
639 fn gas_used(&self) -> u64;
641
642 fn timestamp(&self) -> u64;
644
645 fn mix_hash(&self) -> Option<B256>;
647
648 fn nonce(&self) -> Option<B64>;
650
651 fn base_fee_per_gas(&self) -> Option<u64>;
653
654 fn blob_gas_used(&self) -> Option<u64>;
656
657 fn excess_blob_gas(&self) -> Option<u64>;
659
660 fn parent_beacon_block_root(&self) -> Option<B256>;
662
663 fn requests_hash(&self) -> Option<B256>;
665
666 fn block_access_list_hash(&self) -> Option<B256>;
670
671 fn slot_number(&self) -> Option<u64>;
675
676 fn extra_data(&self) -> &Bytes;
678
679 fn blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
683 Some(blob_params.calc_blob_fee(self.excess_blob_gas()?))
684 }
685
686 fn next_block_excess_blob_gas(&self, blob_params: BlobParams) -> Option<u64> {
691 Some(blob_params.next_block_excess_blob_gas_osaka(
692 self.excess_blob_gas()?,
693 self.blob_gas_used()?,
694 self.base_fee_per_gas()?,
695 ))
696 }
697
698 fn maybe_next_block_excess_blob_gas(&self, blob_params: Option<BlobParams>) -> Option<u64> {
703 self.next_block_excess_blob_gas(blob_params?)
704 }
705
706 fn next_block_blob_fee(&self, blob_params: BlobParams) -> Option<u128> {
712 Some(blob_params.calc_blob_fee(self.next_block_excess_blob_gas(blob_params)?))
713 }
714
715 fn maybe_next_block_blob_fee(&self, blob_params: Option<BlobParams>) -> Option<u128> {
720 self.next_block_blob_fee(blob_params?)
721 }
722
723 fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option<u64> {
727 Some(calc_next_block_base_fee(
728 self.gas_used(),
729 self.gas_limit(),
730 self.base_fee_per_gas()?,
731 base_fee_params,
732 ))
733 }
734
735 fn parent_num_hash(&self) -> BlockNumHash {
739 BlockNumHash { number: self.number().saturating_sub(1), hash: self.parent_hash() }
740 }
741
742 fn is_empty(&self) -> bool {
744 let txs_and_ommers_empty = self.transactions_root() == EMPTY_ROOT_HASH
745 && self.ommers_hash() == EMPTY_OMMER_ROOT_HASH;
746 self.withdrawals_root().map_or(txs_and_ommers_empty, |withdrawals_root| {
747 txs_and_ommers_empty && withdrawals_root == EMPTY_ROOT_HASH
748 })
749 }
750
751 fn is_zero_difficulty(&self) -> bool {
761 self.difficulty().is_zero()
762 }
763
764 fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool {
770 self.timestamp() > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS
771 }
772
773 fn is_nonce_zero(&self) -> bool {
777 self.nonce().is_some_and(|nonce| nonce.is_zero())
778 }
779}
780
781impl BlockHeader for Header {
782 fn parent_hash(&self) -> B256 {
783 self.parent_hash
784 }
785
786 fn ommers_hash(&self) -> B256 {
787 self.ommers_hash
788 }
789
790 fn beneficiary(&self) -> Address {
791 self.beneficiary
792 }
793
794 fn state_root(&self) -> B256 {
795 self.state_root
796 }
797
798 fn transactions_root(&self) -> B256 {
799 self.transactions_root
800 }
801
802 fn receipts_root(&self) -> B256 {
803 self.receipts_root
804 }
805
806 fn withdrawals_root(&self) -> Option<B256> {
807 self.withdrawals_root
808 }
809
810 fn logs_bloom(&self) -> Bloom {
811 self.logs_bloom
812 }
813
814 fn difficulty(&self) -> U256 {
815 self.difficulty
816 }
817
818 fn number(&self) -> BlockNumber {
819 self.number
820 }
821
822 fn gas_limit(&self) -> u64 {
823 self.gas_limit
824 }
825
826 fn gas_used(&self) -> u64 {
827 self.gas_used
828 }
829
830 fn timestamp(&self) -> u64 {
831 self.timestamp
832 }
833
834 fn mix_hash(&self) -> Option<B256> {
835 Some(self.mix_hash)
836 }
837
838 fn nonce(&self) -> Option<B64> {
839 Some(self.nonce)
840 }
841
842 fn base_fee_per_gas(&self) -> Option<u64> {
843 self.base_fee_per_gas
844 }
845
846 fn blob_gas_used(&self) -> Option<u64> {
847 self.blob_gas_used
848 }
849
850 fn excess_blob_gas(&self) -> Option<u64> {
851 self.excess_blob_gas
852 }
853
854 fn parent_beacon_block_root(&self) -> Option<B256> {
855 self.parent_beacon_block_root
856 }
857
858 fn requests_hash(&self) -> Option<B256> {
859 self.requests_hash
860 }
861
862 fn block_access_list_hash(&self) -> Option<B256> {
863 self.block_access_list_hash
864 }
865
866 fn slot_number(&self) -> Option<u64> {
867 self.slot_number
868 }
869
870 fn extra_data(&self) -> &Bytes {
871 &self.extra_data
872 }
873}
874
875#[cfg(feature = "serde")]
876impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
877 fn parent_hash(&self) -> B256 {
878 self.inner.parent_hash()
879 }
880
881 fn ommers_hash(&self) -> B256 {
882 self.inner.ommers_hash()
883 }
884
885 fn beneficiary(&self) -> Address {
886 self.inner.beneficiary()
887 }
888
889 fn state_root(&self) -> B256 {
890 self.inner.state_root()
891 }
892
893 fn transactions_root(&self) -> B256 {
894 self.inner.transactions_root()
895 }
896
897 fn receipts_root(&self) -> B256 {
898 self.inner.receipts_root()
899 }
900
901 fn withdrawals_root(&self) -> Option<B256> {
902 self.inner.withdrawals_root()
903 }
904
905 fn logs_bloom(&self) -> Bloom {
906 self.inner.logs_bloom()
907 }
908
909 fn difficulty(&self) -> U256 {
910 self.inner.difficulty()
911 }
912
913 fn number(&self) -> u64 {
914 self.inner.number()
915 }
916
917 fn gas_limit(&self) -> u64 {
918 self.inner.gas_limit()
919 }
920
921 fn gas_used(&self) -> u64 {
922 self.inner.gas_used()
923 }
924
925 fn timestamp(&self) -> u64 {
926 self.inner.timestamp()
927 }
928
929 fn mix_hash(&self) -> Option<B256> {
930 self.inner.mix_hash()
931 }
932
933 fn nonce(&self) -> Option<B64> {
934 self.inner.nonce()
935 }
936
937 fn base_fee_per_gas(&self) -> Option<u64> {
938 self.inner.base_fee_per_gas()
939 }
940
941 fn blob_gas_used(&self) -> Option<u64> {
942 self.inner.blob_gas_used()
943 }
944
945 fn excess_blob_gas(&self) -> Option<u64> {
946 self.inner.excess_blob_gas()
947 }
948
949 fn parent_beacon_block_root(&self) -> Option<B256> {
950 self.inner.parent_beacon_block_root()
951 }
952
953 fn requests_hash(&self) -> Option<B256> {
954 self.inner.requests_hash()
955 }
956
957 fn block_access_list_hash(&self) -> Option<B256> {
958 self.inner.block_access_list_hash()
959 }
960
961 fn slot_number(&self) -> Option<u64> {
962 self.inner.slot_number()
963 }
964
965 fn extra_data(&self) -> &Bytes {
966 self.inner.extra_data()
967 }
968
969 fn is_empty(&self) -> bool {
970 self.inner.is_empty()
971 }
972}
973
974#[cfg(all(feature = "serde", feature = "serde-bincode-compat"))]
976pub(crate) mod serde_bincode_compat {
977 use alloc::borrow::Cow;
978 use alloy_primitives::{Address, BlockNumber, Bloom, Bytes, B256, B64, U256};
979 use serde::{Deserialize, Deserializer, Serialize, Serializer};
980 use serde_with::{DeserializeAs, SerializeAs};
981
982 #[derive(Debug, Serialize, Deserialize)]
998 pub struct Header<'a> {
999 parent_hash: B256,
1000 ommers_hash: B256,
1001 beneficiary: Address,
1002 state_root: B256,
1003 transactions_root: B256,
1004 receipts_root: B256,
1005 #[serde(default)]
1006 withdrawals_root: Option<B256>,
1007 logs_bloom: Bloom,
1008 difficulty: U256,
1009 number: BlockNumber,
1010 gas_limit: u64,
1011 gas_used: u64,
1012 timestamp: u64,
1013 mix_hash: B256,
1014 nonce: B64,
1015 #[serde(default)]
1016 base_fee_per_gas: Option<u64>,
1017 #[serde(default)]
1018 blob_gas_used: Option<u64>,
1019 #[serde(default)]
1020 excess_blob_gas: Option<u64>,
1021 #[serde(default)]
1022 parent_beacon_block_root: Option<B256>,
1023 #[serde(default)]
1024 requests_hash: Option<B256>,
1025 #[serde(default)]
1026 block_access_list_hash: Option<B256>,
1027 #[serde(default)]
1028 slot_number: Option<u64>,
1029 extra_data: Cow<'a, Bytes>,
1030 }
1031
1032 impl<'a> From<&'a super::Header> for Header<'a> {
1033 fn from(value: &'a super::Header) -> Self {
1034 Self {
1035 parent_hash: value.parent_hash,
1036 ommers_hash: value.ommers_hash,
1037 beneficiary: value.beneficiary,
1038 state_root: value.state_root,
1039 transactions_root: value.transactions_root,
1040 receipts_root: value.receipts_root,
1041 withdrawals_root: value.withdrawals_root,
1042 logs_bloom: value.logs_bloom,
1043 difficulty: value.difficulty,
1044 number: value.number,
1045 gas_limit: value.gas_limit,
1046 gas_used: value.gas_used,
1047 timestamp: value.timestamp,
1048 mix_hash: value.mix_hash,
1049 nonce: value.nonce,
1050 base_fee_per_gas: value.base_fee_per_gas,
1051 blob_gas_used: value.blob_gas_used,
1052 excess_blob_gas: value.excess_blob_gas,
1053 parent_beacon_block_root: value.parent_beacon_block_root,
1054 requests_hash: value.requests_hash,
1055 block_access_list_hash: value.block_access_list_hash,
1056 slot_number: value.slot_number,
1057 extra_data: Cow::Borrowed(&value.extra_data),
1058 }
1059 }
1060 }
1061
1062 impl<'a> From<Header<'a>> for super::Header {
1063 fn from(value: Header<'a>) -> Self {
1064 Self {
1065 parent_hash: value.parent_hash,
1066 ommers_hash: value.ommers_hash,
1067 beneficiary: value.beneficiary,
1068 state_root: value.state_root,
1069 transactions_root: value.transactions_root,
1070 receipts_root: value.receipts_root,
1071 withdrawals_root: value.withdrawals_root,
1072 logs_bloom: value.logs_bloom,
1073 difficulty: value.difficulty,
1074 number: value.number,
1075 gas_limit: value.gas_limit,
1076 gas_used: value.gas_used,
1077 timestamp: value.timestamp,
1078 mix_hash: value.mix_hash,
1079 nonce: value.nonce,
1080 base_fee_per_gas: value.base_fee_per_gas,
1081 blob_gas_used: value.blob_gas_used,
1082 excess_blob_gas: value.excess_blob_gas,
1083 parent_beacon_block_root: value.parent_beacon_block_root,
1084 requests_hash: value.requests_hash,
1085 block_access_list_hash: value.block_access_list_hash,
1086 slot_number: value.slot_number,
1087 extra_data: value.extra_data.into_owned(),
1088 }
1089 }
1090 }
1091
1092 impl SerializeAs<super::Header> for Header<'_> {
1093 fn serialize_as<S>(source: &super::Header, serializer: S) -> Result<S::Ok, S::Error>
1094 where
1095 S: Serializer,
1096 {
1097 Header::from(source).serialize(serializer)
1098 }
1099 }
1100
1101 impl<'de> DeserializeAs<'de, super::Header> for Header<'de> {
1102 fn deserialize_as<D>(deserializer: D) -> Result<super::Header, D::Error>
1103 where
1104 D: Deserializer<'de>,
1105 {
1106 Header::deserialize(deserializer).map(Into::into)
1107 }
1108 }
1109
1110 #[cfg(test)]
1111 mod tests {
1112 use super::super::{serde_bincode_compat, Header};
1113 use arbitrary::Arbitrary;
1114 use bincode::config;
1115 use rand::Rng;
1116 use serde::{Deserialize, Serialize};
1117 use serde_with::serde_as;
1118
1119 #[test]
1120 fn test_header_bincode_roundtrip() {
1121 #[serde_as]
1122 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1123 struct Data {
1124 #[serde_as(as = "serde_bincode_compat::Header")]
1125 header: Header,
1126 }
1127
1128 let mut bytes = [0u8; 1024];
1129 rand::thread_rng().fill(bytes.as_mut_slice());
1130 let data = Data {
1131 header: Header::arbitrary(&mut arbitrary::Unstructured::new(&bytes)).unwrap(),
1132 };
1133
1134 let encoded = bincode::serde::encode_to_vec(&data, config::legacy()).unwrap();
1135 let (decoded, _) =
1136 bincode::serde::decode_from_slice::<Data, _>(&encoded, config::legacy()).unwrap();
1137 assert_eq!(decoded, data);
1138 }
1139 }
1140}
1141
1142#[cfg(test)]
1143mod tests {
1144 use super::*;
1145 use alloy_primitives::{b256, hex};
1146
1147 #[test]
1148 fn decode_header_rlp() {
1149 let raw = hex!("0xf90212a00d84d79f59fc384a1f6402609a5b7253b4bfe7a4ae12608ed107273e5422b6dda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479471562b71999873db5b286df957af199ec94617f7a0f496f3d199c51a1aaee67dac95f24d92ac13c60d25181e1eecd6eca5ddf32ac0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808206a4840365908a808468e975f09ad983011003846765746888676f312e32352e308664617277696ea06f485a167165ec12e0ab3e6ab59a7b88560b90306ac98a26eb294abf95a8c59b88000000000000000007");
1151 let header = Header::decode(&mut raw.as_slice()).unwrap();
1152 assert_eq!(
1153 header.hash_slow(),
1154 b256!("0x4f05e4392969fc82e41f6d6a8cea379323b0b2d3ddf7def1a33eec03883e3a33")
1155 );
1156 }
1157}
1158
1159#[cfg(all(test, feature = "serde"))]
1160mod serde_tests {
1161 use super::*;
1162 use alloy_primitives::b256;
1163
1164 #[test]
1165 fn test_header_serde_json_roundtrip() {
1166 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"}"#;
1167 let header = Header {
1168 base_fee_per_gas: Some(1),
1169 withdrawals_root: Some(EMPTY_ROOT_HASH),
1170 ..Default::default()
1171 };
1172
1173 let encoded = serde_json::to_string(&header).unwrap();
1174 assert_eq!(encoded, raw);
1175
1176 let decoded: Header = serde_json::from_str(&encoded).unwrap();
1177 assert_eq!(decoded, header);
1178
1179 let mut encoded_rlp = Vec::new();
1181
1182 decoded.encode(&mut encoded_rlp);
1184
1185 let decoded_rlp = Header::decode(&mut encoded_rlp.as_slice()).unwrap();
1187
1188 assert_eq!(decoded_rlp, decoded);
1190 }
1191
1192 #[test]
1193 fn serde_rlp_prague() {
1194 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"}
1196"#;
1197 let header = serde_json::from_str::<Header>(raw).unwrap();
1198 let hash = header.hash_slow();
1199 assert_eq!(hash, b256!("661da523f3e44725f3a1cee38183d35424155a05674609a9f6ed81243adf9e26"));
1200 let mut v = Vec::new();
1201 header.encode(&mut v);
1202 let decoded = Header::decode(&mut v.as_slice()).unwrap();
1203 assert_eq!(decoded, header);
1204 }
1205}