reth_payload_validator/
cancun.rs1use alloy_consensus::{BlockBody, Transaction, Typed2718};
4use alloy_rpc_types_engine::{CancunPayloadFields, PayloadError};
5use reth_primitives_traits::{AlloyBlockHeader, Block, SealedBlock};
6
7#[inline]
14pub fn ensure_well_formed_fields<T, B>(
15 block: &SealedBlock<B>,
16 cancun_sidecar_fields: Option<&CancunPayloadFields>,
17 is_cancun_active: bool,
18) -> Result<(), PayloadError>
19where
20 T: Transaction + Typed2718,
21 B: Block<Body = BlockBody<T>>,
22{
23 ensure_well_formed_header_and_sidecar_fields(block, cancun_sidecar_fields, is_cancun_active)?;
24 ensure_well_formed_transactions_field_with_sidecar(
25 block.body(),
26 cancun_sidecar_fields,
27 is_cancun_active,
28 )
29}
30
31#[inline]
33pub fn ensure_well_formed_header_and_sidecar_fields<T: Block>(
34 block: &SealedBlock<T>,
35 cancun_sidecar_fields: Option<&CancunPayloadFields>,
36 is_cancun_active: bool,
37) -> Result<(), PayloadError> {
38 if is_cancun_active {
39 if block.blob_gas_used().is_none() {
40 return Err(PayloadError::PostCancunBlockWithoutBlobGasUsed)
42 }
43 if block.excess_blob_gas().is_none() {
44 return Err(PayloadError::PostCancunBlockWithoutExcessBlobGas)
46 }
47 if cancun_sidecar_fields.is_none() {
48 return Err(PayloadError::PostCancunWithoutCancunFields)
50 }
51 } else {
52 if block.blob_gas_used().is_some() {
53 return Err(PayloadError::PreCancunBlockWithBlobGasUsed)
55 }
56 if block.excess_blob_gas().is_some() {
57 return Err(PayloadError::PreCancunBlockWithExcessBlobGas)
59 }
60 if cancun_sidecar_fields.is_some() {
61 return Err(PayloadError::PreCancunWithCancunFields)
63 }
64 }
65
66 Ok(())
67}
68
69#[inline]
75pub fn ensure_well_formed_transactions_field_with_sidecar<T: Transaction + Typed2718>(
76 block_body: &BlockBody<T>,
77 cancun_sidecar_fields: Option<&CancunPayloadFields>,
78 is_cancun_active: bool,
79) -> Result<(), PayloadError> {
80 if is_cancun_active {
81 ensure_matching_blob_versioned_hashes(block_body, cancun_sidecar_fields)?
82 } else if block_body.has_eip4844_transactions() {
83 return Err(PayloadError::PreCancunBlockWithBlobTransactions)
84 }
85
86 Ok(())
87}
88
89pub fn ensure_matching_blob_versioned_hashes<T: Transaction + Typed2718>(
93 block_body: &BlockBody<T>,
94 cancun_sidecar_fields: Option<&CancunPayloadFields>,
95) -> Result<(), PayloadError> {
96 let num_blob_versioned_hashes = block_body.blob_versioned_hashes_iter().count();
97 if let Some(versioned_hashes) = cancun_sidecar_fields.map(|fields| &fields.versioned_hashes) {
99 if num_blob_versioned_hashes != versioned_hashes.len() {
100 return Err(PayloadError::InvalidVersionedHashes)
102 }
103 for (payload_versioned_hash, block_versioned_hash) in
105 versioned_hashes.iter().zip(block_body.blob_versioned_hashes_iter())
106 {
107 if payload_versioned_hash != block_versioned_hash {
108 return Err(PayloadError::InvalidVersionedHashes)
109 }
110 }
111 } else {
112 if num_blob_versioned_hashes > 0 {
114 return Err(PayloadError::InvalidVersionedHashes)
115 }
116 }
117
118 Ok(())
119}