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, 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/// Type that validates the payloads processed by the engine API.
121pub trait EngineApiValidator<Types: PayloadTypes>: Send + Sync + Unpin + 'static {
122    /// Validates the presence or exclusion of fork-specific fields based on the payload attributes
123    /// and the message version.
124    fn validate_version_specific_fields(
125        &self,
126        version: EngineApiMessageVersion,
127        payload_or_attrs: PayloadOrAttributes<'_, Types::ExecutionData, Types::PayloadAttributes>,
128    ) -> Result<(), EngineObjectValidationError>;
129
130    /// Ensures that the payload attributes are valid for the given [`EngineApiMessageVersion`].
131    fn ensure_well_formed_attributes(
132        &self,
133        version: EngineApiMessageVersion,
134        attributes: &Types::PayloadAttributes,
135    ) -> Result<(), EngineObjectValidationError>;
136}
137
138/// Type that validates an [`ExecutionPayload`].
139#[auto_impl::auto_impl(&, Arc)]
140pub trait PayloadValidator<Types: PayloadTypes>: Send + Sync + Unpin + 'static {
141    /// The block type used by the engine.
142    type Block: Block;
143
144    /// Converts the given payload into a sealed block without recovering signatures.
145    ///
146    /// This function validates the payload and converts it into a [`SealedBlock`] which contains
147    /// the block hash but does not perform signature recovery on transactions.
148    ///
149    /// This is more efficient than [`Self::ensure_well_formed_payload`] when signature recovery
150    /// is not needed immediately or will be performed later.
151    ///
152    /// Implementers should ensure that the checks are done in the order that conforms with the
153    /// engine-API specification.
154    fn convert_payload_to_block(
155        &self,
156        payload: Types::ExecutionData,
157    ) -> Result<SealedBlock<Self::Block>, NewPayloadError>;
158
159    /// Ensures that the given payload does not violate any consensus rules that concern the block's
160    /// layout.
161    ///
162    /// This function must convert the payload into the executable block and pre-validate its
163    /// fields.
164    ///
165    /// Implementers should ensure that the checks are done in the order that conforms with the
166    /// engine-API specification.
167    fn ensure_well_formed_payload(
168        &self,
169        payload: Types::ExecutionData,
170    ) -> Result<RecoveredBlock<Self::Block>, NewPayloadError> {
171        let sealed_block = self.convert_payload_to_block(payload)?;
172        sealed_block.try_recover().map_err(|e| NewPayloadError::Other(e.into()))
173    }
174
175    /// Verifies payload post-execution w.r.t. hashed state updates.
176    fn validate_block_post_execution_with_hashed_state(
177        &self,
178        _state_updates: &HashedPostState,
179        _block: &RecoveredBlock<Self::Block>,
180    ) -> Result<(), ConsensusError> {
181        // method not used by l1
182        Ok(())
183    }
184
185    /// Validates the payload attributes with respect to the header.
186    ///
187    /// By default, this enforces that the payload attributes timestamp is greater than the
188    /// timestamp according to:
189    ///   > 7. Client software MUST ensure that payloadAttributes.timestamp is greater than
190    ///   > timestamp
191    ///   > of a block referenced by forkchoiceState.headBlockHash.
192    ///
193    /// See also: <https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#specification-1>
194    fn validate_payload_attributes_against_header(
195        &self,
196        attr: &Types::PayloadAttributes,
197        header: &<Self::Block as Block>::Header,
198    ) -> Result<(), InvalidPayloadAttributesError> {
199        if attr.timestamp() <= header.timestamp() {
200            return Err(InvalidPayloadAttributesError::InvalidTimestamp);
201        }
202        Ok(())
203    }
204}