diff --git a/crates/alloy/Cargo.toml b/crates/alloy/Cargo.toml index 2add14fb29b..e920d78fb8d 100644 --- a/crates/alloy/Cargo.toml +++ b/crates/alloy/Cargo.toml @@ -81,10 +81,10 @@ full = [ "kzg", "network", "provider-http", # includes `providers` - "provider-ws", # includes `providers` - "provider-ipc", # includes `providers` - "rpc-types", # includes `rpc-types-eth` - "signer-local", # includes `signers` + "provider-ws", # includes `providers` + "provider-ipc", # includes `providers` + "rpc-types", # includes `rpc-types-eth` + "signer-local", # includes `signers` ] # configuration @@ -155,6 +155,7 @@ provider-engine-api = [ "alloy-provider?/engine-api", "rpc-types-engine", ] +provider-net-api = ["providers", "alloy-provider?/net-api"] provider-trace-api = [ "providers", "alloy-provider?/trace-api", diff --git a/crates/provider/Cargo.toml b/crates/provider/Cargo.toml index 7b9c02fe077..fb51899fb39 100644 --- a/crates/provider/Cargo.toml +++ b/crates/provider/Cargo.toml @@ -96,5 +96,6 @@ anvil-node = [ ] debug-api = ["dep:alloy-rpc-types-trace"] engine-api = ["dep:alloy-rpc-types-engine"] +net-api = [] trace-api = ["dep:alloy-rpc-types-trace"] txpool-api = ["dep:alloy-rpc-types-txpool"] diff --git a/crates/provider/src/ext/mod.rs b/crates/provider/src/ext/mod.rs index 9364c8d3b8b..8e06ca3042e 100644 --- a/crates/provider/src/ext/mod.rs +++ b/crates/provider/src/ext/mod.rs @@ -20,6 +20,11 @@ mod debug; #[cfg(feature = "debug-api")] pub use debug::DebugApi; +#[cfg(feature = "net-api")] +mod net; +#[cfg(feature = "net-api")] +pub use net::NetApi; + #[cfg(feature = "trace-api")] mod trace; #[cfg(feature = "trace-api")] diff --git a/crates/provider/src/ext/net.rs b/crates/provider/src/ext/net.rs new file mode 100644 index 00000000000..241dd58ac16 --- /dev/null +++ b/crates/provider/src/ext/net.rs @@ -0,0 +1,75 @@ +//! This module extends the Ethereum JSON-RPC provider with the Net namespace's RPC methods. +use crate::Provider; +use alloy_network::Network; +use alloy_transport::{Transport, TransportResult}; + +/// Net namespace rpc interface that provides access to network information of the node. +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] +pub trait NetApi: Send + Sync { + /// Returns a `bool` indicating whether or not the node is listening for network connections. + async fn net_listening(&self) -> TransportResult; + /// Returns the number of peers connected to the node. + async fn net_peer_count(&self) -> TransportResult; + /// Returns the network ID (e.g. 1 for mainnet). + async fn net_version(&self) -> TransportResult; +} + +#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] +impl NetApi for P +where + N: Network, + T: Transport + Clone, + P: Provider, +{ + async fn net_listening(&self) -> TransportResult { + self.client().request("net_listening", ()).await + } + + async fn net_peer_count(&self) -> TransportResult { + self.client().request("net_peerCount", ()).map_resp(crate::utils::convert_u64).await + } + + async fn net_version(&self) -> TransportResult { + self.client().request("net_version", ()).map_resp(crate::utils::convert_u64).await + } +} + +#[cfg(test)] +mod test { + use crate::ProviderBuilder; + + use super::*; + use alloy_node_bindings::Geth; + + #[tokio::test] + async fn call_net_version() { + let temp_dir = tempfile::TempDir::with_prefix("geth-test-").unwrap(); + let geth = Geth::new().disable_discovery().data_dir(temp_dir.path()).spawn(); + let provider = ProviderBuilder::new().on_http(geth.endpoint_url()); + + let version = provider.net_version().await.expect("net_version call should succeed"); + assert_eq!(version, 1); + } + + #[tokio::test] + async fn call_net_peer_count() { + let temp_dir = tempfile::TempDir::with_prefix("geth-test-").unwrap(); + let geth = Geth::new().disable_discovery().data_dir(temp_dir.path()).spawn(); + let provider = ProviderBuilder::new().on_http(geth.endpoint_url()); + + let count = provider.net_peer_count().await.expect("net_peerCount call should succeed"); + assert_eq!(count, 0); + } + + #[tokio::test] + async fn call_net_listening() { + let temp_dir = tempfile::TempDir::with_prefix("geth-test-").unwrap(); + let geth = Geth::new().disable_discovery().data_dir(temp_dir.path()).spawn(); + let provider = ProviderBuilder::new().on_http(geth.endpoint_url()); + + let listening = provider.net_listening().await.expect("net_listening call should succeed"); + assert!(listening); + } +}