reth_optimism_payload_builder/
validator.rs1use alloc::sync::Arc;
4use alloy_consensus::Block;
5use alloy_rpc_types_engine::PayloadError;
6use derive_more::{Constructor, Deref};
7use op_alloy_rpc_types_engine::{OpExecutionData, OpPayloadError};
8use reth_optimism_forks::OpHardforks;
9use reth_payload_validator::{cancun, prague, shanghai};
10use reth_primitives_traits::{Block as _, SealedBlock, SignedTransaction};
11
12#[derive(Clone, Debug, Deref, Constructor)]
14pub struct OpExecutionPayloadValidator<ChainSpec> {
15 #[deref]
17 inner: Arc<ChainSpec>,
18}
19
20impl<ChainSpec> OpExecutionPayloadValidator<ChainSpec>
21where
22 ChainSpec: OpHardforks,
23{
24 pub fn chain_spec(&self) -> &ChainSpec {
26 &self.inner
27 }
28
29 pub fn ensure_well_formed_payload<T: SignedTransaction>(
34 &self,
35 payload: OpExecutionData,
36 ) -> Result<SealedBlock<Block<T>>, OpPayloadError> {
37 ensure_well_formed_payload(self.chain_spec(), payload)
38 }
39}
40
41pub fn ensure_well_formed_payload<ChainSpec, T>(
60 chain_spec: ChainSpec,
61 payload: OpExecutionData,
62) -> Result<SealedBlock<Block<T>>, OpPayloadError>
63where
64 ChainSpec: OpHardforks,
65 T: SignedTransaction,
66{
67 let OpExecutionData { payload, sidecar } = payload;
68
69 let expected_hash = payload.block_hash();
70
71 let sealed_block = payload.try_into_block_with_sidecar(&sidecar)?.seal_slow();
73
74 if expected_hash != sealed_block.hash() {
76 return Err(PayloadError::BlockHash {
77 execution: sealed_block.hash(),
78 consensus: expected_hash,
79 })?
80 }
81
82 shanghai::ensure_well_formed_fields(
83 sealed_block.body(),
84 chain_spec.is_shanghai_active_at_timestamp(sealed_block.timestamp),
85 )?;
86
87 cancun::ensure_well_formed_header_and_sidecar_fields(
88 &sealed_block,
89 sidecar.ecotone(),
90 chain_spec.is_cancun_active_at_timestamp(sealed_block.timestamp),
91 )?;
92
93 prague::ensure_well_formed_fields(
94 sealed_block.body(),
95 sidecar.isthmus(),
96 chain_spec.is_prague_active_at_timestamp(sealed_block.timestamp),
97 )?;
98
99 Ok(sealed_block)
100}