reth_seismic_node/
engine.rs

1//! Ethereum specific engine API types and impls.
2
3use std::sync::Arc;
4
5use alloy_rpc_types_engine::{ExecutionData, ExecutionPayload, ExecutionPayloadEnvelopeV5};
6pub use alloy_rpc_types_engine::{
7    ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4,
8    ExecutionPayloadV1, PayloadAttributes,
9};
10use reth_chainspec::ChainSpec;
11use reth_engine_primitives::EngineTypes;
12use reth_ethereum_payload_builder::EthereumExecutionPayloadValidator;
13use reth_node_api::{
14    validate_execution_requests, validate_version_specific_fields, EngineApiMessageVersion,
15    EngineObjectValidationError, EngineValidator, NewPayloadError, PayloadOrAttributes,
16    PayloadValidator,
17};
18use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes};
19use reth_payload_primitives::{BuiltPayload, PayloadTypes};
20use reth_primitives_traits::{NodePrimitives, RecoveredBlock, SealedBlock};
21use reth_seismic_primitives::SeismicPrimitives;
22
23/// The types used in the default mainnet ethereum beacon consensus engine.
24#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
25#[non_exhaustive]
26pub struct SeismicEngineTypes<T: PayloadTypes = SeismicPayloadTypes> {
27    _marker: core::marker::PhantomData<T>,
28}
29
30impl<
31        T: PayloadTypes<
32            ExecutionData = ExecutionData,
33            BuiltPayload: BuiltPayload<
34                Primitives: NodePrimitives<Block = reth_seismic_primitives::SeismicBlock>,
35            >,
36        >,
37    > PayloadTypes for SeismicEngineTypes<T>
38{
39    type ExecutionData = T::ExecutionData;
40    type BuiltPayload = T::BuiltPayload;
41    type PayloadAttributes = T::PayloadAttributes;
42    type PayloadBuilderAttributes = T::PayloadBuilderAttributes;
43
44    fn block_to_payload(
45        block: SealedBlock<
46            <<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
47        >,
48    ) -> Self::ExecutionData {
49        let (payload, sidecar) =
50            ExecutionPayload::from_block_unchecked(block.hash(), &block.into_block());
51        ExecutionData { payload, sidecar }
52    }
53}
54
55impl<T> EngineTypes for SeismicEngineTypes<T>
56where
57    T: PayloadTypes<ExecutionData = ExecutionData>,
58    T::BuiltPayload: BuiltPayload<Primitives: NodePrimitives<Block = reth_seismic_primitives::SeismicBlock>>
59        + TryInto<ExecutionPayloadV1>
60        + TryInto<ExecutionPayloadEnvelopeV2>
61        + TryInto<ExecutionPayloadEnvelopeV3>
62        + TryInto<ExecutionPayloadEnvelopeV4>
63        + TryInto<ExecutionPayloadEnvelopeV5>,
64{
65    type ExecutionPayloadEnvelopeV1 = ExecutionPayloadV1;
66    type ExecutionPayloadEnvelopeV2 = ExecutionPayloadEnvelopeV2;
67    type ExecutionPayloadEnvelopeV3 = ExecutionPayloadEnvelopeV3;
68    type ExecutionPayloadEnvelopeV4 = ExecutionPayloadEnvelopeV4;
69    type ExecutionPayloadEnvelopeV5 = ExecutionPayloadEnvelopeV5;
70}
71
72/// A default payload type for [`EthEngineTypes`]
73#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
74#[non_exhaustive]
75pub struct SeismicPayloadTypes;
76
77impl PayloadTypes for SeismicPayloadTypes {
78    type BuiltPayload = EthBuiltPayload<SeismicPrimitives>;
79    type PayloadAttributes = PayloadAttributes;
80    type PayloadBuilderAttributes = EthPayloadBuilderAttributes;
81    type ExecutionData = ExecutionData;
82
83    fn block_to_payload(
84        block: SealedBlock<
85            <<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
86        >,
87    ) -> Self::ExecutionData {
88        let (payload, sidecar) =
89            ExecutionPayload::from_block_unchecked(block.hash(), &block.into_block());
90        ExecutionData { payload, sidecar }
91    }
92}
93
94/// Validator for the ethereum engine API.
95#[derive(Debug, Clone)]
96pub struct SeismicEngineValidator {
97    inner: EthereumExecutionPayloadValidator<ChainSpec>,
98}
99
100impl SeismicEngineValidator {
101    /// Instantiates a new validator.
102    pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
103        Self { inner: EthereumExecutionPayloadValidator::new(chain_spec) }
104    }
105
106    /// Returns the chain spec used by the validator.
107    #[inline]
108    fn chain_spec(&self) -> &ChainSpec {
109        self.inner.chain_spec()
110    }
111}
112
113impl PayloadValidator for SeismicEngineValidator {
114    type Block = reth_seismic_primitives::SeismicBlock;
115    type ExecutionData = ExecutionData;
116
117    fn ensure_well_formed_payload(
118        &self,
119        payload: ExecutionData,
120    ) -> Result<RecoveredBlock<Self::Block>, NewPayloadError> {
121        let sealed_block = self.inner.ensure_well_formed_payload(payload)?;
122        sealed_block.try_recover().map_err(|e| NewPayloadError::Other(e.into()))
123    }
124}
125
126impl<Types> EngineValidator<Types> for SeismicEngineValidator
127where
128    Types: PayloadTypes<PayloadAttributes = PayloadAttributes, ExecutionData = ExecutionData>,
129{
130    fn validate_version_specific_fields(
131        &self,
132        version: EngineApiMessageVersion,
133        payload_or_attrs: PayloadOrAttributes<'_, Self::ExecutionData, PayloadAttributes>,
134    ) -> Result<(), EngineObjectValidationError> {
135        payload_or_attrs
136            .execution_requests()
137            .map(|requests| validate_execution_requests(requests))
138            .transpose()?;
139
140        validate_version_specific_fields(self.chain_spec(), version, payload_or_attrs)
141    }
142
143    fn ensure_well_formed_attributes(
144        &self,
145        version: EngineApiMessageVersion,
146        attributes: &PayloadAttributes,
147    ) -> Result<(), EngineObjectValidationError> {
148        validate_version_specific_fields(
149            self.chain_spec(),
150            version,
151            PayloadOrAttributes::<Self::ExecutionData, PayloadAttributes>::PayloadAttributes(
152                attributes,
153            ),
154        )
155    }
156}