feat(rpc): accept RLP-encoded blocks in reth_newPayload (#22533)

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Arsenii Kulikov <klkvrr@gmail.com>
This commit is contained in:
Georgios Konstantopoulos
2026-02-24 07:46:02 -08:00
committed by GitHub
parent c8c5f8886d
commit 7fc22f7b5b
4 changed files with 40 additions and 10 deletions

View File

@@ -48,7 +48,7 @@ pub mod servers {
net::NetApiServer,
otterscan::OtterscanServer,
reth::RethApiServer,
reth_engine::{RethEngineApiServer, RethPayloadStatus},
reth_engine::{RethEngineApiServer, RethNewPayloadInput, RethPayloadStatus},
rpc::RpcApiServer,
testing::TestingApiServer,
trace::TraceApiServer,

View File

@@ -1,5 +1,6 @@
//! Reth-specific engine API extensions.
use alloy_primitives::Bytes;
use alloy_rpc_types_engine::PayloadStatus;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use serde::{Deserialize, Serialize};
@@ -22,18 +23,34 @@ pub struct RethPayloadStatus {
pub sparse_trie_wait_us: u64,
}
/// Input for `reth_newPayload` that accepts either `ExecutionData` directly or an RLP-encoded
/// block.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RethNewPayloadInput<ExecutionData> {
/// Standard execution data (payload + sidecar).
ExecutionData(ExecutionData),
/// An RLP-encoded block.
BlockRlp(Bytes),
}
/// Reth-specific engine API extensions.
///
/// This trait provides a `reth_newPayload` endpoint that takes `ExecutionData` directly
/// (payload + sidecar), waiting for persistence and cache locks before processing.
/// This trait provides a `reth_newPayload` endpoint that accepts either `ExecutionData` directly
/// (payload + sidecar) or an RLP-encoded block, waiting for persistence and cache locks before
/// processing.
///
/// Responses include timing breakdowns with server-measured execution latency.
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "reth"))]
#[cfg_attr(feature = "client", rpc(server, client, namespace = "reth"))]
pub trait RethEngineApi<ExecutionData> {
/// Reth-specific newPayload that takes `ExecutionData` directly.
/// Reth-specific newPayload that accepts either `ExecutionData` directly or an RLP-encoded
/// block.
///
/// Waits for persistence, execution cache, and sparse trie locks before processing.
#[method(name = "newPayload")]
async fn reth_new_payload(&self, payload: ExecutionData) -> RpcResult<RethPayloadStatus>;
async fn reth_new_payload(
&self,
payload: RethNewPayloadInput<ExecutionData>,
) -> RpcResult<RethPayloadStatus>;
}

View File

@@ -28,6 +28,7 @@ reth-network-api.workspace = true
# ethereum
alloy-eips.workspace = true
alloy-primitives.workspace = true
alloy-rlp.workspace = true
alloy-rpc-types-engine.workspace = true
# async

View File

@@ -1,16 +1,18 @@
use crate::EngineApiError;
use alloy_rlp::Decodable;
use async_trait::async_trait;
use jsonrpsee_core::RpcResult;
use reth_engine_primitives::ConsensusEngineHandle;
use reth_payload_primitives::PayloadTypes;
use reth_rpc_api::{RethEngineApiServer, RethPayloadStatus};
use reth_primitives_traits::SealedBlock;
use reth_rpc_api::{RethEngineApiServer, RethNewPayloadInput, RethPayloadStatus};
use tracing::trace;
/// Standalone implementation of the `reth_` engine API namespace.
///
/// Provides the `reth_newPayload` endpoint that takes `ExecutionData` directly,
/// waits for persistence, execution cache, and sparse trie locks before processing,
/// and returns timing breakdowns with server-measured execution latency.
/// Provides the `reth_newPayload` endpoint that accepts either `ExecutionData` directly or an
/// RLP-encoded block, waits for persistence, execution cache, and sparse trie locks before
/// processing, and returns timing breakdowns with server-measured execution latency.
#[derive(Debug)]
pub struct RethEngineApi<Payload: PayloadTypes> {
beacon_engine_handle: ConsensusEngineHandle<Payload>,
@@ -27,9 +29,19 @@ impl<Payload: PayloadTypes> RethEngineApi<Payload> {
impl<Payload: PayloadTypes> RethEngineApiServer<Payload::ExecutionData> for RethEngineApi<Payload> {
async fn reth_new_payload(
&self,
payload: Payload::ExecutionData,
input: RethNewPayloadInput<Payload::ExecutionData>,
) -> RpcResult<RethPayloadStatus> {
trace!(target: "rpc::engine", "Serving reth_newPayload");
let payload = match input {
RethNewPayloadInput::ExecutionData(data) => data,
RethNewPayloadInput::BlockRlp(rlp) => {
let block = Decodable::decode(&mut rlp.as_ref())
.map_err(|err| EngineApiError::Internal(Box::new(err)))?;
Payload::block_to_payload(SealedBlock::new_unhashed(block))
}
};
let (status, timings) = self
.beacon_engine_handle
.reth_new_payload(payload)