diff --git a/Cargo.lock b/Cargo.lock index 5ba8118176f3..7b0b1b89f0a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,17 @@ dependencies = [ "regex", ] +[[package]] +name = "additional-rpc-namespace-in-cli" +version = "0.0.0" +dependencies = [ + "clap", + "eyre", + "jsonrpsee", + "reth", + "reth-transaction-pool", +] + [[package]] name = "addr2line" version = "0.20.0" @@ -5031,8 +5042,10 @@ dependencies = [ "reth-revm-inspectors", "reth-rlp", "reth-rpc", + "reth-rpc-api", "reth-rpc-builder", "reth-rpc-engine-api", + "reth-rpc-types", "reth-stages", "reth-tasks", "reth-tracing", diff --git a/Cargo.toml b/Cargo.toml index 738636e6b428..5b1333c2fb37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ members = [ "testing/ef-tests", "examples", + "examples/additional-rpc-namespace-in-cli", ] default-members = ["bin/reth"] @@ -84,6 +85,7 @@ revm-primitives = { git = "https://github.com/bluealloy/revm/", branch = "releas ## reth revm = { version = "3" } revm-primitives = "1.1" +reth = { path = "./bin/reth" } reth-primitives = { path = "./crates/primitives" } reth-interfaces = { path = "./crates/interfaces" } reth-provider = { path = "./crates/storage/provider" } diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 6a48f0be5a30..704955498688 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -26,6 +26,8 @@ reth-blockchain-tree = { path = "../../crates/blockchain-tree" } reth-rpc-engine-api = { path = "../../crates/rpc/rpc-engine-api" } reth-rpc-builder = { path = "../../crates/rpc/rpc-builder" } reth-rpc = { path = "../../crates/rpc/rpc" } +reth-rpc-types = { path = "../../crates/rpc/rpc-types" } +reth-rpc-api = { path = "../../crates/rpc/rpc-api" } reth-rlp.workspace = true reth-network = { path = "../../crates/net/network", features = ["serde"] } reth-network-api.workspace = true diff --git a/bin/reth/src/cli/mod.rs b/bin/reth/src/cli/mod.rs index 79a1f7b92417..19ffa3fb2153 100644 --- a/bin/reth/src/cli/mod.rs +++ b/bin/reth/src/cli/mod.rs @@ -57,7 +57,7 @@ pub struct Cli { verbosity: Verbosity, } -impl Cli { +impl Cli { /// Execute the configured cli command. pub fn run(mut self) -> eyre::Result<()> { // add network name to logs dir @@ -98,7 +98,7 @@ impl Cli { /// Convenience function for parsing CLI options, set up logging and run the chosen command. #[inline] pub fn run() -> eyre::Result<()> { - Cli::parse().run() + Cli::<()>::parse().run() } /// Commands to be executed diff --git a/bin/reth/src/lib.rs b/bin/reth/src/lib.rs index 60fb98df12cd..8320b6808321 100644 --- a/bin/reth/src/lib.rs +++ b/bin/reth/src/lib.rs @@ -40,5 +40,45 @@ pub mod test_vectors; pub mod utils; pub mod version; +/// Re-exported from `reth_provider`. +pub mod providers { + pub use reth_provider::*; +} + +/// Re-exported from `reth_tasks`. +pub mod tasks { + pub use reth_tasks::*; +} + +/// Re-exported from `reth_network`. +pub mod network { + pub use reth_network::*; + pub use reth_network_api::{noop, reputation, NetworkInfo, PeerKind, Peers, PeersInfo}; +} + +/// Re-exported from `reth_transaction_pool`. +pub mod transaction_pool { + pub use reth_transaction_pool::*; +} + +/// Re-export of `reth_rpc_*` crates. +pub mod rpc { + + /// Re-exported from `reth_rpc_builder`. + pub mod builder { + pub use reth_rpc_builder::*; + } + + /// Re-exported from `reth_rpc_types`. + pub mod types { + pub use reth_rpc_types::*; + } + + /// Re-exported from `reth_rpc_api`. + pub mod api { + pub use reth_rpc_api::*; + } +} + #[cfg(all(feature = "jemalloc", unix))] use jemallocator as _; diff --git a/bin/reth/src/node/mod.rs b/bin/reth/src/node/mod.rs index 8dc76f0fe234..4eb3978b812c 100644 --- a/bin/reth/src/node/mod.rs +++ b/bin/reth/src/node/mod.rs @@ -145,7 +145,7 @@ pub struct Command { dev: DevArgs, } -impl Command { +impl Command { /// Execute `node` command pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> { info!(target: "reth::cli", "reth {} starting", SHORT_VERSION); diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index c66636babb00..573bc67cae6b 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -731,6 +731,21 @@ impl } } + /// Returns a reference to the provider + pub fn pool(&self) -> &Pool { + &self.pool + } + + /// Returns a reference to the events type + pub fn events(&self) -> &Events { + &self.events + } + + /// Returns a reference to the tasks type + pub fn tasks(&self) -> &Tasks { + &self.executor + } + /// Returns all installed methods pub fn methods(&self) -> Vec { self.modules.values().cloned().collect() @@ -1499,8 +1514,8 @@ impl TransportRpcModules<()> { &mut self, other: impl Into, ) -> Result { - if let Some(ref mut http) = self.http { - return http.merge(other.into()).map(|_| true) + if let Some(ref mut ipc) = self.ipc { + return ipc.merge(other.into()).map(|_| true) } Ok(false) } diff --git a/examples/additional-rpc-namespace-in-cli/Cargo.toml b/examples/additional-rpc-namespace-in-cli/Cargo.toml new file mode 100644 index 000000000000..dadbe58587db --- /dev/null +++ b/examples/additional-rpc-namespace-in-cli/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "additional-rpc-namespace-in-cli" +version = "0.0.0" +publish = false +edition.workspace = true +license.workspace = true + +[dependencies] +reth.workspace = true +reth-transaction-pool.workspace = true + +clap = { version = "4", features = ["derive"] } +jsonrpsee = { workspace = true, features = ["server", "macros"] } +eyre = "0.6" \ No newline at end of file diff --git a/examples/additional-rpc-namespace-in-cli/src/main.rs b/examples/additional-rpc-namespace-in-cli/src/main.rs new file mode 100644 index 000000000000..46df9a6bb2be --- /dev/null +++ b/examples/additional-rpc-namespace-in-cli/src/main.rs @@ -0,0 +1,112 @@ +//! Example of how to use additional rpc namespaces in the reth CLI +//! +//! Run with +//! +//! ```not_rust +//! cargo run -p additional-rpc-namespace-in-cli -- node --http --ws --enable-ext +//! ``` +//! +//! This installs an additional RPC method `txpoolExt_transactionCount` that can queried via [cast](https://github.com/foundry-rs/foundry) +//! +//! ```sh +//! cast rpc txpoolExt_transactionCount +//! ``` +use clap::Parser; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use reth::{ + cli::{ + ext::{RethCliExt, RethRpcConfig, RethRpcServerArgsExt}, + Cli, + }, + network::{NetworkInfo, Peers}, + providers::{ + BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, + EvmEnvProvider, StateProviderFactory, + }, + rpc::builder::{RethModuleRegistry, TransportRpcModules}, + tasks::TaskSpawner, +}; +use reth_transaction_pool::TransactionPool; + +fn main() { + Cli::::parse().run().unwrap(); +} + +/// The type that tells the reth CLI what extensions to use +struct MyRethCliExt; + +impl RethCliExt for MyRethCliExt { + /// This tells the reth CLI to install the `txpool` rpc namespace via `RethCliTxpoolExt` + type RpcExt = RethCliTxpoolExt; +} + +/// Our custom cli args extension that adds one flag to reth default CLI. +#[derive(Debug, Clone, Copy, Default, clap::Args)] +struct RethCliTxpoolExt { + /// CLI flag to enable the txpool extension namespace + #[clap(long)] + pub enable_ext: bool, +} + +impl RethRpcServerArgsExt for RethCliTxpoolExt { + // This is the entrypoint for the CLI to extend the RPC server with custom rpc namespaces. + fn extend_rpc_modules( + &self, + _config: &Conf, + registry: &mut RethModuleRegistry, + modules: &mut TransportRpcModules<()>, + ) -> eyre::Result<()> + where + Conf: RethRpcConfig, + Provider: BlockReaderIdExt + + StateProviderFactory + + EvmEnvProvider + + ChainSpecProvider + + ChangeSetReader + + Clone + + Unpin + + 'static, + Pool: TransactionPool + Clone + 'static, + Network: NetworkInfo + Peers + Clone + 'static, + Tasks: TaskSpawner + Clone + 'static, + Events: CanonStateSubscriptions + Clone + 'static, + { + if !self.enable_ext { + return Ok(()) + } + + // here we get the configured pool type from the CLI. + let pool = registry.pool().clone(); + let ext = TxpoolExt { pool }; + + // now we merge our extension namespace into all configured transports + modules.merge_configured(ext.into_rpc())?; + + println!("txpool extension enabled"); + Ok(()) + } +} + +/// trait interface for a custom rpc namespace: `txpool` +/// +/// This defines an additional namespace where all methods are configured as trait functions. +#[rpc(server, namespace = "txpoolExt")] +pub trait TxpoolExtApi { + /// Returns the number of transactions in the pool. + #[method(name = "transactionCount")] + fn transaction_count(&self) -> RpcResult; +} + +/// The type that implements the `txpool` rpc namespace trait +pub struct TxpoolExt { + pool: Pool, +} + +impl TxpoolExtApiServer for TxpoolExt +where + Pool: TransactionPool + Clone + 'static, +{ + fn transaction_count(&self) -> RpcResult { + Ok(self.pool.pool_size().total) + } +}