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, H>(
15 block: &SealedBlock<B>,
16 cancun_sidecar_fields: Option<&CancunPayloadFields>,
17 is_cancun_active: bool,
18) -> Result<(), PayloadError>
19where
20 T: Transaction + Typed2718,
21 H: AlloyBlockHeader,
22 B: Block<Header = H, Body = BlockBody<T, H>>,
23{
24 ensure_well_formed_header_and_sidecar_fields(block, cancun_sidecar_fields, is_cancun_active)?;
25 ensure_well_formed_transactions_field_with_sidecar(
26 block.body(),
27 cancun_sidecar_fields,
28 is_cancun_active,
29 )
30}
31
32#[inline]
34pub fn ensure_well_formed_header_and_sidecar_fields<T: Block>(
35 block: &SealedBlock<T>,
36 cancun_sidecar_fields: Option<&CancunPayloadFields>,
37 is_cancun_active: bool,
38) -> Result<(), PayloadError> {
39 if is_cancun_active {
40 if block.blob_gas_used().is_none() {
41 return Err(PayloadError::PostCancunBlockWithoutBlobGasUsed)
43 }
44 if block.excess_blob_gas().is_none() {
45 return Err(PayloadError::PostCancunBlockWithoutExcessBlobGas)
47 }
48 if cancun_sidecar_fields.is_none() {
49 return Err(PayloadError::PostCancunWithoutCancunFields)
51 }
52 } else {
53 if block.blob_gas_used().is_some() {
54 return Err(PayloadError::PreCancunBlockWithBlobGasUsed)
56 }
57 if block.excess_blob_gas().is_some() {
58 return Err(PayloadError::PreCancunBlockWithExcessBlobGas)
60 }
61 if cancun_sidecar_fields.is_some() {
62 return Err(PayloadError::PreCancunWithCancunFields)
64 }
65 }
66
67 Ok(())
68}
69
70#[inline]
76pub fn ensure_well_formed_transactions_field_with_sidecar<T: Transaction + Typed2718, H>(
77 block_body: &BlockBody<T, H>,
78 cancun_sidecar_fields: Option<&CancunPayloadFields>,
79 is_cancun_active: bool,
80) -> Result<(), PayloadError> {
81 if is_cancun_active {
82 ensure_matching_blob_versioned_hashes(block_body, cancun_sidecar_fields)?
83 } else if block_body.has_eip4844_transactions() {
84 return Err(PayloadError::PreCancunBlockWithBlobTransactions)
85 }
86
87 Ok(())
88}
89
90pub fn ensure_matching_blob_versioned_hashes<T: Transaction + Typed2718, H>(
94 block_body: &BlockBody<T, H>,
95 cancun_sidecar_fields: Option<&CancunPayloadFields>,
96) -> Result<(), PayloadError> {
97 let num_blob_versioned_hashes = block_body.blob_versioned_hashes_iter().count();
98 if let Some(versioned_hashes) = cancun_sidecar_fields.map(|fields| &fields.versioned_hashes) {
100 if num_blob_versioned_hashes != versioned_hashes.len() {
101 return Err(PayloadError::InvalidVersionedHashes)
103 }
104 for (payload_versioned_hash, block_versioned_hash) in
106 versioned_hashes.iter().zip(block_body.blob_versioned_hashes_iter())
107 {
108 if payload_versioned_hash != block_versioned_hash {
109 return Err(PayloadError::InvalidVersionedHashes)
110 }
111 }
112 } else {
113 if num_blob_versioned_hashes > 0 {
115 return Err(PayloadError::InvalidVersionedHashes)
116 }
117 }
118
119 Ok(())
120}