1//! Cancun rules for new payloads.
23use alloy_consensus::{BlockBody, Transaction, Typed2718};
4use alloy_rpc_types_engine::{CancunPayloadFields, PayloadError};
5use reth_primitives_traits::{AlloyBlockHeader, Block, SealedBlock};
67/// Checks block and sidecar w.r.t new Cancun fields and new transaction type EIP-4844.
8///
9/// Checks that:
10/// - Cancun fields are present if Cancun is active
11/// - doesn't contain EIP-4844 transactions unless Cancun is active
12/// - checks blob versioned hashes in block and sidecar match
13#[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
20T: Transaction + Typed2718,
21 B: Block<Body = BlockBody<T>>,
22{
23ensure_well_formed_header_and_sidecar_fields(block, cancun_sidecar_fields, is_cancun_active)?;
24ensure_well_formed_transactions_field_with_sidecar(
25block.body(),
26cancun_sidecar_fields,
27is_cancun_active,
28 )
29}
3031/// Checks that Cancun fields on block header and sidecar are present if Cancun is active and vv.
32#[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> {
38if is_cancun_active {
39if block.blob_gas_used().is_none() {
40// cancun active but blob gas used not present
41return Err(PayloadError::PostCancunBlockWithoutBlobGasUsed)
42 }
43if block.excess_blob_gas().is_none() {
44// cancun active but excess blob gas not present
45return Err(PayloadError::PostCancunBlockWithoutExcessBlobGas)
46 }
47if cancun_sidecar_fields.is_none() {
48// cancun active but cancun fields not present
49return Err(PayloadError::PostCancunWithoutCancunFields)
50 }
51 } else {
52if block.blob_gas_used().is_some() {
53// cancun not active but blob gas used present
54return Err(PayloadError::PreCancunBlockWithBlobGasUsed)
55 }
56if block.excess_blob_gas().is_some() {
57// cancun not active but excess blob gas present
58return Err(PayloadError::PreCancunBlockWithExcessBlobGas)
59 }
60if cancun_sidecar_fields.is_some() {
61// cancun not active but cancun fields present
62return Err(PayloadError::PreCancunWithCancunFields)
63 }
64 }
6566Ok(())
67}
6869/// Checks transactions field and sidecar w.r.t new Cancun fields and new transaction type EIP-4844.
70///
71/// Checks that:
72/// - doesn't contain EIP-4844 transactions unless Cancun is active
73/// - checks blob versioned hashes in block and sidecar match
74#[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> {
80if is_cancun_active {
81ensure_matching_blob_versioned_hashes(block_body, cancun_sidecar_fields)?
82} else if block_body.has_eip4844_transactions() {
83return Err(PayloadError::PreCancunBlockWithBlobTransactions)
84 }
8586Ok(())
87}
8889/// Ensures that the number of blob versioned hashes of a EIP-4844 transactions in block, matches
90/// the number hashes included in the _separate_ `block_versioned_hashes` of the cancun payload
91/// fields on the sidecar.
92pub fn ensure_matching_blob_versioned_hashes<T: Transaction + Typed2718>(
93 block_body: &BlockBody<T>,
94 cancun_sidecar_fields: Option<&CancunPayloadFields>,
95) -> Result<(), PayloadError> {
96let num_blob_versioned_hashes = block_body.blob_versioned_hashes_iter().count();
97// Additional Cancun checks for blob transactions
98if let Some(versioned_hashes) = cancun_sidecar_fields.map(|fields| &fields.versioned_hashes) {
99if num_blob_versioned_hashes != versioned_hashes.len() {
100// Number of blob versioned hashes does not match
101return Err(PayloadError::InvalidVersionedHashes)
102 }
103// we can use `zip` safely here because we already compared their length
104for (payload_versioned_hash, block_versioned_hash) in
105versioned_hashes.iter().zip(block_body.blob_versioned_hashes_iter())
106 {
107if payload_versioned_hash != block_versioned_hash {
108return Err(PayloadError::InvalidVersionedHashes)
109 }
110 }
111 } else {
112// No Cancun fields, if block includes any blobs, this is an error
113if num_blob_versioned_hashes > 0 {
114return Err(PayloadError::InvalidVersionedHashes)
115 }
116 }
117118Ok(())
119}