Skip to content

Commit

Permalink
feat: add rpc namespace (#994)
Browse files Browse the repository at this point in the history
* Implement Rpc namespace

* Review comment

* Dependency fix

---------

Co-authored-by: Mikhail Sozin <[email protected]>
  • Loading branch information
SozinM and Mikhail Sozin authored Jul 10, 2024
1 parent 902d847 commit 617aec5
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 0 deletions.
2 changes: 2 additions & 0 deletions crates/provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ alloy-rpc-types-eth.workspace = true
alloy-rpc-types-trace = { workspace = true, optional = true }
alloy-rpc-types-txpool = { workspace = true, optional = true }
alloy-rpc-types-engine = { workspace = true, optional = true }
alloy-rpc-types = { workspace = true, optional = true }
alloy-transport-http = { workspace = true, optional = true }
alloy-transport-ipc = { workspace = true, optional = true }
alloy-transport-ws = { workspace = true, optional = true }
Expand Down Expand Up @@ -98,4 +99,5 @@ debug-api = ["dep:alloy-rpc-types-trace"]
engine-api = ["dep:alloy-rpc-types-engine"]
net-api = []
trace-api = ["dep:alloy-rpc-types-trace"]
rpc-api = ["dep:alloy-rpc-types"]
txpool-api = ["dep:alloy-rpc-types-txpool"]
5 changes: 5 additions & 0 deletions crates/provider/src/ext/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ mod trace;
#[cfg(feature = "trace-api")]
pub use trace::{TraceApi, TraceCallList};

#[cfg(feature = "rpc-api")]
mod rpc;
#[cfg(feature = "rpc-api")]
pub use rpc::RpcApi;

#[cfg(feature = "txpool-api")]
mod txpool;
#[cfg(feature = "txpool-api")]
Expand Down
27 changes: 27 additions & 0 deletions crates/provider/src/ext/rpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//! This module extends the Ethereum JSON-RPC provider with the Rpc namespace's RPC methods.
use crate::Provider;
use alloy_network::Network;
use alloy_rpc_types::RpcModules;
use alloy_transport::{Transport, TransportResult};

/// The rpc API provides methods to get information about the RPC server itself, such as the enabled
/// namespaces.
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
pub trait RpcApi<N, T>: Send + Sync {
/// Lists the enabled RPC namespaces and the versions of each.
async fn rpc_modules(&self) -> TransportResult<RpcModules>;
}

#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl<N, T, P> RpcApi<N, T> for P
where
N: Network,
T: Transport + Clone,
P: Provider<T, N>,
{
async fn rpc_modules(&self) -> TransportResult<RpcModules> {
self.client().request("rpc_modules", ()).await
}
}
4 changes: 4 additions & 0 deletions crates/rpc-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ alloy-rpc-types-eth = { workspace = true, optional = true }
alloy-rpc-types-mev = { workspace = true, optional = true }
alloy-rpc-types-trace = { workspace = true, optional = true }
alloy-rpc-types-txpool = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive", "std"]}

[dev-dependencies]
serde_json.workspace = true

[features]
default = ["eth"]
Expand Down
3 changes: 3 additions & 0 deletions crates/rpc-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

pub use alloy_serde as serde_helpers;

mod rpc;
pub use rpc::*;

#[cfg(feature = "admin")]
pub use alloy_rpc_types_admin as admin;

Expand Down
42 changes: 42 additions & 0 deletions crates/rpc-types/src/rpc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//! Types for the `rpc` API.
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Represents the `rpc_modules` response, which returns the
/// list of all available modules on that transport and their version
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(transparent)]
pub struct RpcModules {
module_map: HashMap<String, String>,
}

impl RpcModules {
/// Create a new instance of `RPCModules`
pub const fn new(module_map: HashMap<String, String>) -> Self {
Self { module_map }
}

/// Consumes self and returns the inner hashmap mapping module names to their versions
pub fn into_modules(self) -> HashMap<String, String> {
self.module_map
}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_module_versions_roundtrip() {
let s = r#"{"txpool":"1.0","trace":"1.0","eth":"1.0","web3":"1.0","net":"1.0"}"#;
let module_map = HashMap::from([
("txpool".to_owned(), "1.0".to_owned()),
("trace".to_owned(), "1.0".to_owned()),
("eth".to_owned(), "1.0".to_owned()),
("web3".to_owned(), "1.0".to_owned()),
("net".to_owned(), "1.0".to_owned()),
]);
let m = RpcModules::new(module_map);
let de_serialized: RpcModules = serde_json::from_str(s).unwrap();
assert_eq!(de_serialized, m);
}
}

0 comments on commit 617aec5

Please sign in to comment.