From 5f329e78b6988dea29f4929dd421d43aaf3e684b Mon Sep 17 00:00:00 2001 From: Luca Provini Date: Fri, 8 Sep 2023 13:48:57 +0200 Subject: [PATCH] #2511: extended reth-rpc example with custom rpc ext (#4508) Co-authored-by: Matthias Seitz --- Cargo.lock | 11 ++++ Cargo.toml | 1 + bin/reth/src/lib.rs | 23 +++++++++ bin/reth/src/utils.rs | 5 ++ examples/Cargo.toml | 4 -- examples/rpc-db/Cargo.toml | 13 +++++ examples/{rpc-db.rs => rpc-db/src/main.rs} | 60 ++++++++++++++-------- examples/rpc-db/src/myrpc_ext.rs | 33 ++++++++++++ 8 files changed, 125 insertions(+), 25 deletions(-) create mode 100644 examples/rpc-db/Cargo.toml rename examples/{rpc-db.rs => rpc-db/src/main.rs} (64%) create mode 100644 examples/rpc-db/src/myrpc_ext.rs diff --git a/Cargo.lock b/Cargo.lock index 0a5efd77d..989a55bcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6327,6 +6327,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" +[[package]] +name = "rpc-db" +version = "0.0.0" +dependencies = [ + "eyre", + "futures", + "jsonrpsee", + "reth", + "tokio", +] + [[package]] name = "ruint" version = "1.10.1" diff --git a/Cargo.toml b/Cargo.toml index 529715acc..41bd2464b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ members = [ "crates/rpc/rpc-types-compat", "examples", "examples/additional-rpc-namespace-in-cli", + "examples/rpc-db", ] default-members = ["bin/reth"] diff --git a/bin/reth/src/lib.rs b/bin/reth/src/lib.rs index c9e02bc34..2f452eb46 100644 --- a/bin/reth/src/lib.rs +++ b/bin/reth/src/lib.rs @@ -46,6 +46,25 @@ pub mod providers { pub use reth_provider::*; } +/// Re-exported from `reth_primitives`. +pub mod primitives { + pub use reth_primitives::*; +} + +/// Re-exported from `reth_beacon_consensus`. +pub mod beacon_consensus { + pub use reth_beacon_consensus::*; +} +/// Re-exported from `reth_blockchain_tree`. +pub mod blockchain_tree { + pub use reth_blockchain_tree::*; +} + +/// Re-exported from `reth_revm`. +pub mod revm { + pub use reth_revm::*; +} + /// Re-exported from `reth_tasks`. pub mod tasks { pub use reth_tasks::*; @@ -79,6 +98,10 @@ pub mod rpc { pub mod api { pub use reth_rpc_api::*; } + /// Re-exported from `reth_rpc::eth`. + pub mod eth { + pub use reth_rpc::eth::*; + } } #[cfg(all(feature = "jemalloc", unix))] diff --git a/bin/reth/src/utils.rs b/bin/reth/src/utils.rs index a40e92625..64a798dc9 100644 --- a/bin/reth/src/utils.rs +++ b/bin/reth/src/utils.rs @@ -26,6 +26,11 @@ use std::{ }; use tracing::info; +/// Exposing `open_db_read_only` function +pub mod db { + pub use reth_db::open_db_read_only; +} + /// Get a single header from network pub async fn get_single_header( client: Client, diff --git a/examples/Cargo.toml b/examples/Cargo.toml index fd244ad0f..619935b49 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -28,10 +28,6 @@ futures.workspace = true async-trait.workspace = true tokio.workspace = true -[[example]] -name = "rpc-db" -path = "rpc-db.rs" - [[example]] name = "db-access" path = "db-access.rs" diff --git a/examples/rpc-db/Cargo.toml b/examples/rpc-db/Cargo.toml new file mode 100644 index 000000000..ed9cc88e7 --- /dev/null +++ b/examples/rpc-db/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "rpc-db" +version = "0.0.0" +publish = false +edition.workspace = true +license.workspace = true + +[dependencies] +futures.workspace = true +jsonrpsee.workspace = true +reth.workspace = true +tokio = { workspace = true, features = ["full"] } +eyre = "0.6.8" diff --git a/examples/rpc-db.rs b/examples/rpc-db/src/main.rs similarity index 64% rename from examples/rpc-db.rs rename to examples/rpc-db/src/main.rs index 86f890299..54aa243ac 100644 --- a/examples/rpc-db.rs +++ b/examples/rpc-db/src/main.rs @@ -1,31 +1,45 @@ -// Talking to the DB -use reth_db::open_db_read_only; -use reth_primitives::ChainSpecBuilder; -use reth_provider::{providers::BlockchainProvider, ProviderFactory}; - +//! Example illustrating how to run the ETH JSON RPC API as standalone over a DB file. +//! +//! Run with +//! +//! ```not_rust +//! cargo run -p rpc-db +//! ``` +//! +//! This installs an additional RPC method `myrpcExt_customMethod` that can queried via [cast](https://github.com/foundry-rs/foundry) +//! +//! ```sh +//! cast rpc myrpcExt_customMethod +//! ``` +use reth::{ + primitives::ChainSpecBuilder, + providers::{providers::BlockchainProvider, ProviderFactory}, + utils::db::open_db_read_only, +}; // Bringing up the RPC -use reth_rpc_builder::{ +use reth::rpc::builder::{ RethRpcModule, RpcModuleBuilder, RpcServerConfig, TransportRpcModuleConfig, }; // Code which we'd ideally like to not need to import if you're only spinning up // read-only parts of the API and do not require access to pending state or to // EVM sims -use reth_beacon_consensus::BeaconConsensus; -use reth_blockchain_tree::{ - BlockchainTree, BlockchainTreeConfig, ShareableBlockchainTree, TreeExternals, +use reth::{ + beacon_consensus::BeaconConsensus, + blockchain_tree::{ + BlockchainTree, BlockchainTreeConfig, ShareableBlockchainTree, TreeExternals, + }, + revm::Factory as ExecutionFactory, }; -use reth_revm::Factory as ExecutionFactory; + // Configuring the network parts, ideally also wouldn't ned to think about this. -use reth_network_api::noop::NoopNetwork; -use reth_provider::test_utils::TestCanonStateSubscriptions; -use reth_tasks::TokioTaskExecutor; -use reth_transaction_pool::noop::NoopTransactionPool; +use reth::{providers::test_utils::TestCanonStateSubscriptions, tasks::TokioTaskExecutor}; use std::{path::Path, sync::Arc}; -// Example illustrating how to run the ETH JSON RPC API as standalone over a DB file. -// TODO: Add example showing how to spin up your own custom RPC namespace alongside -// the other default name spaces. +use myrpc_ext::{MyRpcExt, MyRpcExtApiServer}; +// Custom rpc extension +pub mod myrpc_ext; + #[tokio::main] async fn main() -> eyre::Result<()> { // 1. Setup the DB @@ -55,16 +69,20 @@ async fn main() -> eyre::Result<()> { }; let rpc_builder = RpcModuleBuilder::default() - .with_provider(provider) + .with_provider(provider.clone()) // Rest is just noops that do nothing - .with_pool(NoopTransactionPool::default()) - .with_network(NoopNetwork::default()) + .with_noop_pool() + .with_noop_network() .with_executor(TokioTaskExecutor::default()) .with_events(TestCanonStateSubscriptions::default()); // Pick which namespaces to expose. let config = TransportRpcModuleConfig::default().with_http([RethRpcModule::Eth]); - let server = rpc_builder.build(config); + let mut server = rpc_builder.build(config); + + // Add a custom rpc namespace + let custom_rpc = MyRpcExt { provider }; + server.merge_configured(custom_rpc.into_rpc())?; // Start the server & keep it alive let server_args = diff --git a/examples/rpc-db/src/myrpc_ext.rs b/examples/rpc-db/src/myrpc_ext.rs new file mode 100644 index 000000000..d1898b81c --- /dev/null +++ b/examples/rpc-db/src/myrpc_ext.rs @@ -0,0 +1,33 @@ +// Reth block related imports +use reth::{primitives::Block, providers::BlockReaderIdExt}; + +// Rpc related imports +use jsonrpsee::proc_macros::rpc; +use reth::rpc::eth::error::EthResult; + +/// trait interface for a custom rpc namespace: `MyRpc` +/// +/// This defines an additional namespace where all methods are configured as trait functions. +#[rpc(server, namespace = "myrpcExt")] +pub trait MyRpcExtApi { + /// Returns block 0. + #[method(name = "customMethod")] + fn custom_method(&self) -> EthResult>; +} + +/// The type that implements `myRpc` rpc namespace trait +pub struct MyRpcExt { + pub provider: Provider, +} + +impl MyRpcExtApiServer for MyRpcExt +where + Provider: BlockReaderIdExt + 'static, +{ + /// Showcasing how to implement a custom rpc method + /// using the provider. + fn custom_method(&self) -> EthResult> { + let block = self.provider.block_by_number(0)?; + Ok(block) + } +}