Skip to main content

reth_rpc_engine_api/
reth_engine_api.rs

1use crate::EngineApiError;
2use alloy_rlp::Decodable;
3use alloy_rpc_types_engine::{ForkchoiceState, ForkchoiceUpdated};
4use async_trait::async_trait;
5use jsonrpsee_core::RpcResult;
6use reth_engine_primitives::ConsensusEngineHandle;
7use reth_payload_primitives::{EngineApiMessageVersion, PayloadTypes};
8use reth_primitives_traits::SealedBlock;
9use reth_rpc_api::{RethEngineApiServer, RethNewPayloadInput, RethPayloadStatus};
10use tracing::trace;
11
12/// Standalone implementation of the `reth_` engine API namespace.
13///
14/// Provides the `reth_newPayload` endpoint that accepts either `ExecutionData` directly or an
15/// RLP-encoded block, waits for persistence, execution cache, and sparse trie locks before
16/// processing, and returns timing breakdowns with server-measured execution latency.
17#[derive(Debug)]
18pub struct RethEngineApi<Payload: PayloadTypes> {
19    beacon_engine_handle: ConsensusEngineHandle<Payload>,
20}
21
22impl<Payload: PayloadTypes> RethEngineApi<Payload> {
23    /// Creates a new [`RethEngineApi`].
24    pub const fn new(beacon_engine_handle: ConsensusEngineHandle<Payload>) -> Self {
25        Self { beacon_engine_handle }
26    }
27}
28
29#[async_trait]
30impl<Payload: PayloadTypes> RethEngineApiServer<Payload::ExecutionData> for RethEngineApi<Payload> {
31    async fn reth_new_payload(
32        &self,
33        input: RethNewPayloadInput<Payload::ExecutionData>,
34    ) -> RpcResult<RethPayloadStatus> {
35        trace!(target: "rpc::engine", "Serving reth_newPayload");
36
37        let payload = match input {
38            RethNewPayloadInput::ExecutionData(data) => data,
39            RethNewPayloadInput::BlockRlp(rlp) => {
40                let block = Decodable::decode(&mut rlp.as_ref())
41                    .map_err(|err| EngineApiError::Internal(Box::new(err)))?;
42                Payload::block_to_payload(SealedBlock::new_unhashed(block))
43            }
44        };
45
46        let (status, timings) = self
47            .beacon_engine_handle
48            .reth_new_payload(payload)
49            .await
50            .map_err(EngineApiError::from)?;
51        Ok(RethPayloadStatus {
52            status,
53            latency_us: timings.latency.as_micros() as u64,
54            persistence_wait_us: timings.persistence_wait.map(|d| d.as_micros() as u64),
55            execution_cache_wait_us: timings.execution_cache_wait.as_micros() as u64,
56            sparse_trie_wait_us: timings.sparse_trie_wait.as_micros() as u64,
57        })
58    }
59
60    async fn reth_forkchoice_updated(
61        &self,
62        forkchoice_state: ForkchoiceState,
63    ) -> RpcResult<ForkchoiceUpdated> {
64        trace!(target: "rpc::engine", "Serving reth_forkchoiceUpdated");
65        self.beacon_engine_handle
66            .fork_choice_updated(forkchoice_state, None, EngineApiMessageVersion::V3)
67            .await
68            .map_err(|e| EngineApiError::from(e).into())
69    }
70}