feat(rpc): add engine eth subset rpc handler (#2317)

This commit is contained in:
Matthias Seitz
2023-04-20 17:45:04 +02:00
committed by GitHub
parent 7e965a3c79
commit 9a8d1022a6
6 changed files with 178 additions and 18 deletions

View File

@ -1,8 +1,14 @@
use jsonrpsee::{core::RpcResult as Result, proc_macros::rpc};
use reth_primitives::{BlockHash, U64};
use reth_rpc_types::engine::{
ExecutionPayload, ExecutionPayloadBodies, ExecutionPayloadEnvelope, ForkchoiceState,
ForkchoiceUpdated, PayloadAttributes, PayloadId, PayloadStatus, TransitionConfiguration,
use reth_primitives::{
filter::Filter, Address, BlockHash, BlockId, BlockNumberOrTag, Bytes, H256, U256, U64,
};
use reth_rpc_types::{
engine::{
ExecutionPayload, ExecutionPayloadBodies, ExecutionPayloadEnvelope, ForkchoiceState,
ForkchoiceUpdated, PayloadAttributes, PayloadId, PayloadStatus, TransitionConfiguration,
},
state::StateOverride,
CallRequest, Log, RichBlock, SyncStatus,
};
#[cfg_attr(not(feature = "client"), rpc(server))]
@ -81,3 +87,56 @@ pub trait EngineApi {
#[method(name = "engine_exchangeCapabilities")]
async fn exchange_capabilities(&self, capabilities: Vec<String>) -> Result<Vec<String>>;
}
/// A subset of the ETH rpc interface: <https://ethereum.github.io/execution-apis/api-documentation/>
///
/// Specifically for the engine auth server: <https://github.com/ethereum/execution-apis/blob/main/src/engine/common.md#underlying-protocol>
#[cfg_attr(not(feature = "client"), rpc(server))]
#[cfg_attr(feature = "client", rpc(server, client))]
#[async_trait]
pub trait EngineEthApi {
/// Returns an object with data about the sync status or false.
#[method(name = "eth_syncing")]
fn syncing(&self) -> Result<SyncStatus>;
/// Returns the chain ID of the current network.
#[method(name = "eth_chainId")]
async fn chain_id(&self) -> Result<Option<U64>>;
/// Returns the number of most recent block.
#[method(name = "eth_blockNumber")]
fn block_number(&self) -> Result<U256>;
/// Executes a new message call immediately without creating a transaction on the block chain.
#[method(name = "eth_call")]
async fn call(
&self,
request: CallRequest,
block_number: Option<BlockId>,
state_overrides: Option<StateOverride>,
) -> Result<Bytes>;
/// Returns code at a given address at given block number.
#[method(name = "eth_getCode")]
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes>;
/// Returns information about a block by hash.
#[method(name = "eth_getBlockByHash")]
async fn block_by_hash(&self, hash: H256, full: bool) -> Result<Option<RichBlock>>;
/// Returns information about a block by number.
#[method(name = "eth_getBlockByNumber")]
async fn block_by_number(
&self,
number: BlockNumberOrTag,
full: bool,
) -> Result<Option<RichBlock>>;
/// Sends signed transaction, returning its hash.
#[method(name = "eth_sendRawTransaction")]
async fn send_raw_transaction(&self, bytes: Bytes) -> Result<H256>;
/// Returns logs matching given filter object.
#[method(name = "eth_getLogs")]
async fn logs(&self, filter: Filter) -> Result<Vec<Log>>;
}

View File

@ -25,9 +25,15 @@ pub use servers::*;
/// Aggregates all server traits.
pub mod servers {
pub use crate::{
admin::AdminApiServer, debug::DebugApiServer, engine::EngineApiServer, eth::EthApiServer,
eth_filter::EthFilterApiServer, eth_pubsub::EthPubSubApiServer, net::NetApiServer,
trace::TraceApiServer, web3::Web3ApiServer,
admin::AdminApiServer,
debug::DebugApiServer,
engine::{EngineApiServer, EngineEthApiServer},
eth::EthApiServer,
eth_filter::EthFilterApiServer,
eth_pubsub::EthPubSubApiServer,
net::NetApiServer,
trace::TraceApiServer,
web3::Web3ApiServer,
};
}
@ -39,7 +45,12 @@ pub use clients::*;
#[cfg(feature = "client")]
pub mod clients {
pub use crate::{
admin::AdminApiClient, debug::DebugApiClient, engine::EngineApiClient, eth::EthApiClient,
net::NetApiClient, trace::TraceApiClient, web3::Web3ApiClient,
admin::AdminApiClient,
debug::DebugApiClient,
engine::{EngineApiClient, EngineEthApiClient},
eth::EthApiClient,
net::NetApiClient,
trace::TraceApiClient,
web3::Web3ApiClient,
};
}

View File

@ -11,7 +11,8 @@ use jsonrpsee::{
use reth_network_api::{NetworkInfo, Peers};
use reth_provider::{BlockProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory};
use reth_rpc::{
eth::cache::EthStateCache, AuthLayer, Claims, EthApi, EthFilter, JwtAuthValidator, JwtSecret,
eth::cache::EthStateCache, AuthLayer, Claims, EngineEthApi, EthApi, EthFilter,
JwtAuthValidator, JwtSecret,
};
use reth_rpc_api::{servers::*, EngineApiServer};
use reth_tasks::TaskSpawner;
@ -75,8 +76,8 @@ where
// Configure the module and start the server.
let mut module = RpcModule::new(());
module.merge(engine_api.into_rpc()).expect("No conflicting methods");
module.merge(eth_api.into_rpc()).expect("No conflicting methods");
module.merge(eth_filter.into_rpc()).expect("No conflicting methods");
let engine_eth = EngineEthApi::new(eth_api, eth_filter);
module.merge(engine_eth.into_rpc()).expect("No conflicting methods");
// Create auth middleware.
let middleware =

View File

@ -108,7 +108,7 @@ use reth_ipc::server::IpcServer;
use reth_network_api::{NetworkInfo, Peers};
use reth_provider::{BlockProvider, CanonStateSubscriptions, EvmEnvProvider, StateProviderFactory};
use reth_rpc::{
eth::cache::EthStateCache, AdminApi, DebugApi, EthApi, EthFilter, EthPubSub,
eth::cache::EthStateCache, AdminApi, DebugApi, EngineEthApi, EthApi, EthFilter, EthPubSub,
EthSubscriptionIdProvider, NetApi, TraceApi, TracingCallGuard, Web3Api,
};
use reth_rpc_api::{servers::*, EngineApiServer};
@ -643,10 +643,9 @@ where
module.merge(engine_api.into_rpc()).expect("No conflicting methods");
// also merge all `eth_` handlers
module.merge(eth_handlers.api.into_rpc()).expect("No conflicting methods");
module.merge(eth_handlers.filter.into_rpc()).expect("No conflicting methods");
module.merge(eth_handlers.pubsub.into_rpc()).expect("No conflicting methods");
// also merge a subset of `eth_` handlers
let engine_eth = EngineEthApi::new(eth_handlers.api.clone(), eth_handlers.filter);
module.merge(engine_eth.into_rpc()).expect("No conflicting methods");
AuthRpcModule { inner: module }
}

View File

@ -1,2 +1,92 @@
use jsonrpsee::core::RpcResult as Result;
use reth_primitives::{filter::Filter, Address, BlockId, BlockNumberOrTag, Bytes, H256, U256, U64};
use reth_rpc_api::{EngineEthApiServer, EthApiServer, EthFilterApiServer};
/// Re-export for convenience
pub use reth_rpc_engine_api::EngineApi;
use reth_rpc_types::{state::StateOverride, CallRequest, Log, RichBlock, SyncStatus};
use tracing::trace;
/// A wrapper type for the `EthApi` and `EthFilter` implementations that only expose the required
/// subset for the `eth_` namespace used in auth server alongside the `engine_` namespace.
#[derive(Debug, Clone)]
pub struct EngineEthApi<Eth, EthFilter> {
eth: Eth,
eth_filter: EthFilter,
}
impl<Eth, EthFilter> EngineEthApi<Eth, EthFilter> {
/// Create a new `EngineEthApi` instance.
pub fn new(eth: Eth, eth_filter: EthFilter) -> Self {
Self { eth, eth_filter }
}
}
#[async_trait::async_trait]
impl<Eth, EthFilter> EngineEthApiServer for EngineEthApi<Eth, EthFilter>
where
Eth: EthApiServer,
EthFilter: EthFilterApiServer,
{
/// Handler for: `eth_syncing`
fn syncing(&self) -> Result<SyncStatus> {
trace!(target: "rpc::eth", "Serving eth_syncing [engine]");
self.eth.syncing()
}
/// Handler for: `eth_chainId`
async fn chain_id(&self) -> Result<Option<U64>> {
trace!(target: "rpc::eth", "Serving eth_chainId [engine]");
self.eth.chain_id().await
}
/// Handler for: `eth_blockNumber`
fn block_number(&self) -> Result<U256> {
trace!(target: "rpc::eth", "Serving eth_blockNumber [engine]");
self.eth.block_number()
}
/// Handler for: `eth_call`
async fn call(
&self,
request: CallRequest,
block_number: Option<BlockId>,
state_overrides: Option<StateOverride>,
) -> Result<Bytes> {
trace!(target: "rpc::eth", "Serving eth_call [engine]");
self.eth.call(request, block_number, state_overrides).await
}
/// Handler for: `eth_getCode`
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes> {
trace!(target: "rpc::eth", "Serving eth_getCode [engine]");
self.eth.get_code(address, block_number).await
}
/// Handler for: `eth_getBlockByHash`
async fn block_by_hash(&self, hash: H256, full: bool) -> Result<Option<RichBlock>> {
trace!(target: "rpc::eth", "Serving eth_getBlockByHash [engine]");
self.eth.block_by_hash(hash, full).await
}
/// Handler for: `eth_getBlockByNumber`
async fn block_by_number(
&self,
number: BlockNumberOrTag,
full: bool,
) -> Result<Option<RichBlock>> {
trace!(target: "rpc::eth", "Serving eth_getBlockByNumber [engine]");
self.eth.block_by_number(number, full).await
}
/// Handler for: `eth_sendRawTransaction`
async fn send_raw_transaction(&self, bytes: Bytes) -> Result<H256> {
trace!(target: "rpc::eth", "Serving eth_sendRawTransaction [engine]");
self.eth.send_raw_transaction(bytes).await
}
/// Handler for `eth_getLogs`
async fn logs(&self, filter: Filter) -> Result<Vec<Log>> {
trace!(target: "rpc::eth", "Serving eth_getLogs [engine]");
self.eth_filter.logs(filter).await
}
}

View File

@ -24,7 +24,7 @@ mod web3;
pub use admin::AdminApi;
pub use call_guard::TracingCallGuard;
pub use debug::DebugApi;
pub use engine::EngineApi;
pub use engine::{EngineApi, EngineEthApi};
pub use eth::{EthApi, EthApiSpec, EthFilter, EthPubSub, EthSubscriptionIdProvider};
pub use layers::{AuthLayer, AuthValidator, Claims, JwtAuthValidator, JwtError, JwtSecret};
pub use net::NetApi;