diff --git a/Cargo.lock b/Cargo.lock index b06164529e15..0107d4aedbdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6763,7 +6763,6 @@ dependencies = [ "reth-network-api", "reth-node-api", "reth-node-ethereum", - "reth-node-optimism", "reth-payload-builder", "reth-primitives", "reth-provider", @@ -7192,6 +7191,7 @@ dependencies = [ "futures", "jsonrpsee", "reth", + "reth-node-ethereum", "tokio", ] diff --git a/crates/node-api/src/engine/mod.rs b/crates/node-api/src/engine/mod.rs index 95425b141bb9..a58373846bfa 100644 --- a/crates/node-api/src/engine/mod.rs +++ b/crates/node-api/src/engine/mod.rs @@ -115,7 +115,7 @@ //! //! /// Custom engine types - uses a custom payload attributes RPC type, but uses the default //! /// payload builder attributes type. -//! #[derive(Clone, Debug, Default)] +//! #[derive(Clone, Debug, Default, serde::Deserialize)] //! #[non_exhaustive] //! pub struct CustomEngineTypes; //! @@ -150,7 +150,7 @@ pub mod payload; pub use payload::PayloadOrAttributes; /// The types that are used by the engine. -pub trait EngineTypes: Send + Sync { +pub trait EngineTypes: serde::de::DeserializeOwned + Send + Sync { /// The RPC payload attributes type the CL node emits via the engine API. type PayloadAttributes: PayloadAttributes + Unpin; diff --git a/crates/node-core/src/args/rpc_server_args.rs b/crates/node-core/src/args/rpc_server_args.rs index c5fc8a668ce7..c70fe3a0e8a8 100644 --- a/crates/node-core/src/args/rpc_server_args.rs +++ b/crates/node-core/src/args/rpc_server_args.rs @@ -273,7 +273,7 @@ impl RpcServerArgs { /// Returns the handles for the launched regular RPC server(s) (if any) and the server handle /// for the auth server that handles the `engine_` API that's accessed by the consensus /// layer. - pub async fn start_servers( + pub async fn start_servers( &self, components: &Reth, engine_api: Engine, @@ -281,8 +281,9 @@ impl RpcServerArgs { conf: &mut Conf, ) -> eyre::Result where - Reth: RethNodeComponents, + EngineT: EngineTypes + 'static, Engine: EngineApiServer, + Reth: RethNodeComponents, Conf: RethNodeCommandConfig, { let auth_config = self.auth_server_config(jwt_secret)?; diff --git a/crates/node-ethereum/src/engine.rs b/crates/node-ethereum/src/engine.rs index 75a98dbd2dc9..eb5f65b79dca 100644 --- a/crates/node-ethereum/src/engine.rs +++ b/crates/node-ethereum/src/engine.rs @@ -7,7 +7,7 @@ use reth_primitives::ChainSpec; use reth_rpc_types::engine::PayloadAttributes as EthPayloadAttributes; /// The types used in the default mainnet ethereum beacon consensus engine. -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, serde::Deserialize)] #[non_exhaustive] pub struct EthEngineTypes; diff --git a/crates/node-optimism/src/engine.rs b/crates/node-optimism/src/engine.rs index 8d1dadc67c7f..a65427e76501 100644 --- a/crates/node-optimism/src/engine.rs +++ b/crates/node-optimism/src/engine.rs @@ -7,7 +7,7 @@ use reth_primitives::{ChainSpec, Hardfork}; use reth_rpc_types::engine::OptimismPayloadAttributes; /// The types used in the optimism beacon consensus engine. -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, serde::Deserialize)] #[non_exhaustive] pub struct OptimismEngineTypes; diff --git a/crates/rpc/rpc-api/src/engine.rs b/crates/rpc/rpc-api/src/engine.rs index 87c7184d3410..15a6deb820e7 100644 --- a/crates/rpc/rpc-api/src/engine.rs +++ b/crates/rpc/rpc-api/src/engine.rs @@ -1,3 +1,8 @@ +//! Server traits for the engine API +//! +//! This contains the `engine_` namespace and the subset of the `eth_` namespace that is exposed to +//! the consensus client. + use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use reth_node_api::EngineTypes; use reth_primitives::{Address, BlockHash, BlockId, BlockNumberOrTag, Bytes, B256, U256, U64}; @@ -11,6 +16,13 @@ use reth_rpc_types::{ BlockOverrides, CallRequest, Filter, Log, RichBlock, SyncStatus, }; +// NOTE: We can't use associated types in the `EngineApi` trait because of jsonrpsee, so we use a +// generic here. It would be nice if the rpc macro would understand which types need to have serde. +// By default, if the trait has a generic, the rpc macro will add e.g. `Engine: DeserializeOwned` to +// the trait bounds, which is not what we want, because `Types` is not used directly in any of the +// trait methods. Instead, we have to add the bounds manually. This would be disastrous if we had +// more than one associated type used in the trait methods. + #[cfg_attr(not(feature = "client"), rpc(server, namespace = "engine"), server_bounds(Engine::PayloadAttributes: jsonrpsee::core::DeserializeOwned))] #[cfg_attr(feature = "client", rpc(server, client, namespace = "engine", client_bounds(Engine::PayloadAttributes: jsonrpsee::core::Serialize + Clone), server_bounds(Engine::PayloadAttributes: jsonrpsee::core::DeserializeOwned)))] pub trait EngineApi { @@ -148,13 +160,6 @@ pub trait EngineApi { async fn exchange_capabilities(&self, capabilities: Vec) -> RpcResult>; } -// NOTE: We can't use associated types in the `EngineApi` trait because of jsonrpsee, so we use a -// generic here. It would be nice if the rpc macro would understand which types need to have serde. -// By default, if the trait has a generic, the rpc macro will add e.g. `Engine: DeserializeOwned` to -// the trait bounds, which is not what we want, because `Types` is not used directly in any of the -// trait methods. Instead, we have to add the bounds manually. This would be disastrous if we had -// more than one associated type used in the trait methods. - /// A subset of the ETH rpc interface: /// /// Specifically for the engine auth server: diff --git a/crates/rpc/rpc-builder/Cargo.toml b/crates/rpc/rpc-builder/Cargo.toml index 375822514eec..3c278bafc1f4 100644 --- a/crates/rpc/rpc-builder/Cargo.toml +++ b/crates/rpc/rpc-builder/Cargo.toml @@ -13,21 +13,14 @@ workspace = true [dependencies] # reth -reth-primitives.workspace = true reth-ipc.workspace = true -reth-interfaces.workspace = true reth-network-api.workspace = true reth-provider.workspace = true reth-rpc.workspace = true reth-rpc-api.workspace = true -reth-rpc-engine-api.workspace = true -reth-rpc-types.workspace = true reth-tasks.workspace = true reth-transaction-pool.workspace = true -reth-rpc-types-compat.workspace = true reth-node-api.workspace = true -reth-node-optimism = { workspace = true, optional = true } -reth-node-ethereum.workspace = true # rpc/net jsonrpsee = { workspace = true, features = ["server"] } @@ -46,14 +39,19 @@ thiserror.workspace = true tracing.workspace = true [dev-dependencies] -reth-tracing.workspace = true -reth-rpc-api = { workspace = true, features = ["client"] } -reth-transaction-pool = { workspace = true, features = ["test-utils"] } -reth-provider = { workspace = true, features = ["test-utils"] } -reth-network-api.workspace = true -reth-interfaces = { workspace = true, features = ["test-utils"] } reth-beacon-consensus.workspace = true +reth-interfaces = { workspace = true, features = ["test-utils"] } +reth-network-api.workspace = true +reth-node-ethereum.workspace = true reth-payload-builder = { workspace = true, features = ["test-utils"] } +reth-primitives.workspace = true +reth-provider = { workspace = true, features = ["test-utils"] } +reth-rpc-api = { workspace = true, features = ["client"] } +reth-rpc-engine-api.workspace = true +reth-rpc-types.workspace = true +reth-rpc-types-compat.workspace = true +reth-tracing.workspace = true +reth-transaction-pool = { workspace = true, features = ["test-utils"] } tokio = { workspace = true, features = ["rt", "rt-multi-thread"] } serde_json.workspace = true diff --git a/crates/rpc/rpc-builder/src/auth.rs b/crates/rpc/rpc-builder/src/auth.rs index 5649784e3aa4..7626584903af 100644 --- a/crates/rpc/rpc-builder/src/auth.rs +++ b/crates/rpc/rpc-builder/src/auth.rs @@ -58,7 +58,7 @@ where Pool: TransactionPool + Clone + 'static, Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, - EngineT: EngineTypes, + EngineT: EngineTypes + 'static, EngineApi: EngineApiServer, EvmConfig: EvmEnvConfig + 'static, { @@ -113,7 +113,7 @@ where + 'static, Pool: TransactionPool + Clone + 'static, Network: NetworkInfo + Peers + Clone + 'static, - EngineT: EngineTypes, + EngineT: EngineTypes + 'static, EngineApi: EngineApiServer, EvmConfig: EvmEnvConfig + 'static, { @@ -267,7 +267,7 @@ impl AuthRpcModule { /// Create a new `AuthRpcModule` with the given `engine_api`. pub fn new(engine: EngineApi) -> Self where - EngineT: EngineTypes, + EngineT: EngineTypes + 'static, EngineApi: EngineApiServer, { let mut module = RpcModule::new(()); diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 39ae87153a0f..a9473cc25895 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -113,7 +113,7 @@ //! Network: NetworkInfo + Peers + Clone + 'static, //! Events: CanonStateSubscriptions + Clone + 'static, //! EngineApi: EngineApiServer, -//! EngineT: EngineTypes, +//! EngineT: EngineTypes + 'static, //! EvmConfig: EvmEnvConfig + 'static, //! { //! // configure the rpc module per transport @@ -168,13 +168,16 @@ use jsonrpsee::{ Methods, RpcModule, }; use reth_node_api::{EngineTypes, EvmEnvConfig}; -use reth_node_ethereum::EthEvmConfig; use serde::{Deserialize, Serialize, Serializer}; use strum::{AsRefStr, EnumIter, EnumVariantNames, IntoStaticStr, ParseError, VariantNames}; use tower::layer::util::{Identity, Stack}; use tower_http::cors::CorsLayer; use tracing::{instrument, trace}; +use crate::{ + auth::AuthRpcModule, error::WsHttpSamePortError, metrics::RpcServerMetrics, + RpcModuleSelection::Selection, +}; use constants::*; use error::{RpcError, ServerKind}; use reth_ipc::server::IpcServer; @@ -198,11 +201,6 @@ use reth_rpc::{ use reth_rpc_api::{servers::*, EngineApiServer}; use reth_tasks::{TaskSpawner, TokioTaskExecutor}; use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool}; - -use crate::{ - auth::AuthRpcModule, error::WsHttpSamePortError, metrics::RpcServerMetrics, - RpcModuleSelection::Selection, -}; // re-export for convenience pub use crate::eth::{EthConfig, EthHandlers}; @@ -448,7 +446,7 @@ where /// /// This behaves exactly as [RpcModuleBuilder::build] for the [TransportRpcModules], but also /// configures the auth (engine api) server, which exposes a subset of the `eth_` namespace. - pub fn build_with_auth_server( + pub fn build_with_auth_server( self, module_config: TransportRpcModuleConfig, engine: EngineApi, @@ -458,6 +456,7 @@ where RethModuleRegistry, ) where + EngineT: EngineTypes + 'static, EngineApi: EngineApiServer, { let mut modules = TransportRpcModules::default(); @@ -494,20 +493,24 @@ where /// /// ```no_run /// use reth_network_api::noop::NoopNetwork; + /// use reth_node_api::EvmEnvConfig; /// use reth_provider::test_utils::{NoopProvider, TestCanonStateSubscriptions}; /// use reth_rpc_builder::RpcModuleBuilder; /// use reth_tasks::TokioTaskExecutor; /// use reth_transaction_pool::noop::NoopTransactionPool; /// - /// let mut registry = RpcModuleBuilder::default() - /// .with_provider(NoopProvider::default()) - /// .with_pool(NoopTransactionPool::default()) - /// .with_network(NoopNetwork::default()) - /// .with_executor(TokioTaskExecutor::default()) - /// .with_events(TestCanonStateSubscriptions::default()) - /// .into_registry(Default::default()); - /// - /// let eth_api = registry.eth_api(); + /// fn init(evm: Evm) { + /// let mut registry = RpcModuleBuilder::default() + /// .with_provider(NoopProvider::default()) + /// .with_pool(NoopTransactionPool::default()) + /// .with_network(NoopNetwork::default()) + /// .with_executor(TokioTaskExecutor::default()) + /// .with_events(TestCanonStateSubscriptions::default()) + /// .with_evm_config(evm) + /// .into_registry(Default::default()); + /// + /// let eth_api = registry.eth_api(); + /// } /// ``` pub fn into_registry( self, @@ -549,9 +552,9 @@ where } } -impl Default for RpcModuleBuilder<(), (), (), (), (), EthEvmConfig> { +impl Default for RpcModuleBuilder<(), (), (), (), (), ()> { fn default() -> Self { - RpcModuleBuilder::new((), (), (), (), (), EthEvmConfig::default()) + RpcModuleBuilder::new((), (), (), (), (), ()) } } @@ -1101,7 +1104,7 @@ where /// Note: This does _not_ register the `engine_` in this registry. pub fn create_auth_module(&mut self, engine_api: EngineApi) -> AuthRpcModule where - EngineT: EngineTypes, + EngineT: EngineTypes + 'static, EngineApi: EngineApiServer, { let eth_handlers = self.eth_handlers(); diff --git a/examples/rpc-db/Cargo.toml b/examples/rpc-db/Cargo.toml index 9a23e7af8d28..84569620c294 100644 --- a/examples/rpc-db/Cargo.toml +++ b/examples/rpc-db/Cargo.toml @@ -9,5 +9,6 @@ license.workspace = true futures.workspace = true jsonrpsee.workspace = true reth.workspace = true +reth-node-ethereum.workspace = true tokio = { workspace = true, features = ["full"] } eyre.workspace = true diff --git a/examples/rpc-db/src/main.rs b/examples/rpc-db/src/main.rs index 6048a39bf4e2..79b801e02bb0 100644 --- a/examples/rpc-db/src/main.rs +++ b/examples/rpc-db/src/main.rs @@ -27,6 +27,7 @@ use reth::{ blockchain_tree::noop::NoopBlockchainTree, providers::test_utils::TestCanonStateSubscriptions, tasks::TokioTaskExecutor, }; +use reth_node_ethereum::EthEvmConfig; use std::{path::Path, sync::Arc}; // Custom rpc extension @@ -53,6 +54,7 @@ async fn main() -> eyre::Result<()> { .with_noop_pool() .with_noop_network() .with_executor(TokioTaskExecutor::default()) + .with_evm_config(EthEvmConfig::default()) .with_events(TestCanonStateSubscriptions::default()); // Pick which namespaces to expose.