Skip to main content

reth_engine_primitives/
lib.rs

1//! Traits, validation methods, and helper types used to abstract over engine types.
2
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
5    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
6    issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
7)]
8#![cfg_attr(not(test), warn(unused_crate_dependencies))]
9#![cfg_attr(docsrs, feature(doc_cfg))]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12extern crate alloc;
13
14use alloy_consensus::BlockHeader;
15use reth_errors::ConsensusError;
16use reth_payload_primitives::{
17    EngineApiMessageVersion, EngineObjectValidationError, InvalidPayloadAttributesError,
18    NewPayloadError, PayloadAttributes, PayloadOrAttributes, PayloadTypes,
19};
20use reth_primitives_traits::{Block, RecoveredBlock, SealedBlock};
21use reth_trie_common::HashedPostState;
22use serde::{de::DeserializeOwned, Serialize};
23
24// Re-export [`ExecutionPayload`] moved to `reth_payload_primitives`
25#[cfg(feature = "std")]
26pub use reth_evm::{ConfigureEngineEvm, ConvertTx, ExecutableTxIterator, ExecutableTxTuple};
27pub use reth_payload_primitives::ExecutionPayload;
28
29mod error;
30pub use error::*;
31
32mod forkchoice;
33pub use forkchoice::{ForkchoiceStateHash, ForkchoiceStateTracker, ForkchoiceStatus};
34
35#[cfg(feature = "std")]
36mod message;
37#[cfg(feature = "std")]
38pub use message::*;
39
40mod event;
41pub use event::*;
42
43mod invalid_block_hook;
44pub use invalid_block_hook::{InvalidBlockHook, InvalidBlockHooks, NoopInvalidBlockHook};
45
46pub mod config;
47pub use config::*;
48
49/// This type defines the versioned types of the engine API based on the [ethereum engine API](https://github.com/ethereum/execution-apis/tree/main/src/engine).
50///
51/// This includes the execution payload types and payload attributes that are used to trigger a
52/// payload job. Hence this trait is also [`PayloadTypes`].
53///
54/// Implementations of this type are intended to be stateless and just define the types as
55/// associated types.
56/// This type is intended for non-ethereum chains that closely mirror the ethereum engine API spec,
57/// but may have different payload, for example opstack, but structurally equivalent otherwise (same
58/// engine API RPC endpoints for example).
59pub trait EngineTypes:
60    PayloadTypes<
61        BuiltPayload: TryInto<Self::ExecutionPayloadEnvelopeV1>
62                          + TryInto<Self::ExecutionPayloadEnvelopeV2>
63                          + TryInto<Self::ExecutionPayloadEnvelopeV3>
64                          + TryInto<Self::ExecutionPayloadEnvelopeV4>
65                          + TryInto<Self::ExecutionPayloadEnvelopeV5>
66                          + TryInto<Self::ExecutionPayloadEnvelopeV6>,
67    > + DeserializeOwned
68    + Serialize
69{
70    /// Execution Payload V1 envelope type.
71    type ExecutionPayloadEnvelopeV1: DeserializeOwned
72        + Serialize
73        + Clone
74        + Unpin
75        + Send
76        + Sync
77        + 'static;
78    /// Execution Payload V2  envelope type.
79    type ExecutionPayloadEnvelopeV2: DeserializeOwned
80        + Serialize
81        + Clone
82        + Unpin
83        + Send
84        + Sync
85        + 'static;
86    /// Execution Payload V3 envelope type.
87    type ExecutionPayloadEnvelopeV3: DeserializeOwned
88        + Serialize
89        + Clone
90        + Unpin
91        + Send
92        + Sync
93        + 'static;
94    /// Execution Payload V4 envelope type.
95    type ExecutionPayloadEnvelopeV4: DeserializeOwned
96        + Serialize
97        + Clone
98        + Unpin
99        + Send
100        + Sync
101        + 'static;
102    /// Execution Payload V5 envelope type.
103    type ExecutionPayloadEnvelopeV5: DeserializeOwned
104        + Serialize
105        + Clone
106        + Unpin
107        + Send
108        + Sync
109        + 'static;
110    /// Execution Payload V6 envelope type.
111    type ExecutionPayloadEnvelopeV6: DeserializeOwned
112        + Serialize
113        + Clone
114        + Unpin
115        + Send
116        + Sync
117        + 'static;
118}
119
120/// Validates engine API requests at the RPC layer, before payloads and attributes
121/// are forwarded to the engine for processing.
122///
123/// - [`validate_version_specific_fields`](Self::validate_version_specific_fields): Enforced in each
124///   `engine_newPayloadVN` RPC handler to verify the payload contains the correct fields for the
125///   engine API version (e.g., blob fields in V3+, requests in V4+).
126///
127/// - [`ensure_well_formed_attributes`](Self::ensure_well_formed_attributes): Enforced in
128///   `engine_forkchoiceUpdatedVN` RPC handlers to validate payload attributes are well-formed for
129///   the given version before forwarding to the engine.
130///
131/// After this validation passes, the engine performs the full consensus validation
132/// pipeline (header, pre-execution, execution, post-execution).
133pub trait EngineApiValidator<Types: PayloadTypes>: Send + Sync + Unpin + 'static {
134    /// Validates the presence or exclusion of fork-specific fields based on the payload attributes
135    /// and the message version.
136    fn validate_version_specific_fields(
137        &self,
138        version: EngineApiMessageVersion,
139        payload_or_attrs: PayloadOrAttributes<'_, Types::ExecutionData, Types::PayloadAttributes>,
140    ) -> Result<(), EngineObjectValidationError>;
141
142    /// Ensures that the payload attributes are valid for the given [`EngineApiMessageVersion`].
143    fn ensure_well_formed_attributes(
144        &self,
145        version: EngineApiMessageVersion,
146        attributes: &Types::PayloadAttributes,
147    ) -> Result<(), EngineObjectValidationError>;
148}
149
150/// Type that validates an [`ExecutionPayload`].
151///
152/// This trait handles validation at the engine API boundary — converting payloads
153/// into blocks and validating payload attributes for block building.
154///
155/// # Methods and when they're used
156///
157/// - [`convert_payload_to_block`](Self::convert_payload_to_block): Used during `engine_newPayload`
158///   processing to decode the payload into a [`SealedBlock`]. Also used to validate payload
159///   structure during backfill buffering. In the engine tree, this runs concurrently with state
160///   setup on a background thread.
161///
162/// - [`ensure_well_formed_payload`](Self::ensure_well_formed_payload): Converts payload and
163///   recovers transaction signatures. Used when recovered senders are needed immediately.
164///
165/// - [`validate_payload_attributes_against_header`](Self::validate_payload_attributes_against_header):
166///   Enforced as part of the engine's `forkchoiceUpdated` handling when payload attributes
167///   are provided. Gates whether a payload build job is started.
168///
169/// - [`validate_block_post_execution_with_hashed_state`](Self::validate_block_post_execution_with_hashed_state):
170///   Called after block execution in the engine's payload validation pipeline.
171///   No-op on L1, used by L2s (e.g., OP Stack) for additional post-execution checks.
172///
173/// # Relationship to consensus traits
174///
175/// This trait does NOT replace the consensus traits (`Consensus`, `FullConsensus` from
176/// `reth-consensus`). Those handle the actual consensus rule
177/// validation (header checks, pre/post-execution). This trait handles engine API-specific
178/// concerns: payload encoding/decoding and attribute validation.
179#[auto_impl::auto_impl(&, Arc)]
180pub trait PayloadValidator<Types: PayloadTypes>: Send + Sync + Unpin + 'static {
181    /// The block type used by the engine.
182    type Block: Block;
183
184    /// Converts the given payload into a sealed block without recovering signatures.
185    ///
186    /// This function validates the payload and converts it into a [`SealedBlock`] which contains
187    /// the block hash but does not perform signature recovery on transactions.
188    ///
189    /// This is more efficient than [`Self::ensure_well_formed_payload`] when signature recovery
190    /// is not needed immediately or will be performed later.
191    ///
192    /// Implementers should ensure that the checks are done in the order that conforms with the
193    /// engine-API specification.
194    fn convert_payload_to_block(
195        &self,
196        payload: Types::ExecutionData,
197    ) -> Result<SealedBlock<Self::Block>, NewPayloadError>;
198
199    /// Ensures that the given payload does not violate any consensus rules that concern the block's
200    /// layout.
201    ///
202    /// This function must convert the payload into the executable block and pre-validate its
203    /// fields.
204    ///
205    /// Implementers should ensure that the checks are done in the order that conforms with the
206    /// engine-API specification.
207    fn ensure_well_formed_payload(
208        &self,
209        payload: Types::ExecutionData,
210    ) -> Result<RecoveredBlock<Self::Block>, NewPayloadError> {
211        let sealed_block = self.convert_payload_to_block(payload)?;
212        sealed_block.try_recover().map_err(|e| NewPayloadError::Other(e.into()))
213    }
214
215    /// Verifies payload post-execution w.r.t. hashed state updates.
216    fn validate_block_post_execution_with_hashed_state(
217        &self,
218        _state_updates: &HashedPostState,
219        _block: &RecoveredBlock<Self::Block>,
220    ) -> Result<(), ConsensusError> {
221        // method not used by l1
222        Ok(())
223    }
224
225    /// Validates the payload attributes with respect to the header.
226    ///
227    /// By default, this enforces that the payload attributes timestamp is greater than the
228    /// timestamp according to:
229    ///   > 7. Client software MUST ensure that payloadAttributes.timestamp is greater than
230    ///   > timestamp
231    ///   > of a block referenced by forkchoiceState.headBlockHash.
232    ///
233    /// See also: <https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#specification-1>
234    ///
235    /// Enforced as part of the engine's `forkchoiceUpdated` handling when the consensus layer
236    /// provides payload attributes. If this returns an error, the forkchoice state update itself
237    /// is NOT rolled back, but no payload build job is started — the response includes
238    /// `INVALID_PAYLOAD_ATTRIBUTES`.
239    fn validate_payload_attributes_against_header(
240        &self,
241        attr: &Types::PayloadAttributes,
242        header: &<Self::Block as Block>::Header,
243    ) -> Result<(), InvalidPayloadAttributesError> {
244        if attr.timestamp() <= header.timestamp() {
245            return Err(InvalidPayloadAttributesError::InvalidTimestamp);
246        }
247        Ok(())
248    }
249}