alloy_provider/ext/
admin.rsuse crate::Provider;
use alloy_network::Network;
use alloy_rpc_types_admin::{NodeInfo, PeerInfo};
use alloy_transport::{Transport, TransportResult};
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
pub trait AdminApi<N, T>: Send + Sync {
async fn add_peer(&self, record: &str) -> TransportResult<bool>;
async fn add_trusted_peer(&self, record: &str) -> TransportResult<bool>;
async fn remove_peer(&self, record: &str) -> TransportResult<bool>;
async fn remove_trusted_peer(&self, record: &str) -> TransportResult<bool>;
async fn peers(&self) -> TransportResult<Vec<PeerInfo>>;
async fn node_info(&self) -> TransportResult<NodeInfo>;
#[cfg(feature = "pubsub")]
async fn subscribe_peer_events(
&self,
) -> TransportResult<alloy_pubsub::Subscription<alloy_rpc_types_admin::PeerEvent>>;
}
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl<N, T, P> AdminApi<N, T> for P
where
N: Network,
T: Transport + Clone,
P: Provider<T, N>,
{
async fn add_peer(&self, record: &str) -> TransportResult<bool> {
self.client().request("admin_addPeer", (record,)).await
}
async fn add_trusted_peer(&self, record: &str) -> TransportResult<bool> {
self.client().request("admin_addTrustedPeer", (record,)).await
}
async fn remove_peer(&self, record: &str) -> TransportResult<bool> {
self.client().request("admin_removePeer", (record,)).await
}
async fn remove_trusted_peer(&self, record: &str) -> TransportResult<bool> {
self.client().request("admin_removeTrustedPeer", (record,)).await
}
async fn peers(&self) -> TransportResult<Vec<PeerInfo>> {
self.client().request_noparams("admin_peers").await
}
async fn node_info(&self) -> TransportResult<NodeInfo> {
self.client().request_noparams("admin_nodeInfo").await
}
#[cfg(feature = "pubsub")]
async fn subscribe_peer_events(
&self,
) -> TransportResult<alloy_pubsub::Subscription<alloy_rpc_types_admin::PeerEvent>> {
self.root().pubsub_frontend()?;
let mut call = self.client().request_noparams("admin_peerEvents_subscribe");
call.set_is_subscription();
let id = call.await?;
self.root().get_subscription(id).await
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{ext::test::async_ci_only, ProviderBuilder};
use alloy_node_bindings::{utils::run_with_tempdir, Geth};
#[tokio::test]
async fn node_info() {
async_ci_only(|| async move {
run_with_tempdir("geth-test-", |temp_dir| async move {
let geth = Geth::new().disable_discovery().data_dir(temp_dir).spawn();
let provider = ProviderBuilder::new().on_http(geth.endpoint_url());
let node_info = provider.node_info().await.unwrap();
assert!(node_info.enode.starts_with("enode://"));
})
.await;
})
.await;
}
#[tokio::test]
async fn admin_peers() {
async_ci_only(|| async move {
run_with_tempdir("geth-test-1", |temp_dir_1| async move {
run_with_tempdir("geth-test-2", |temp_dir_2| async move {
let geth1 = Geth::new().disable_discovery().data_dir(&temp_dir_1).spawn();
let mut geth2 =
Geth::new().disable_discovery().port(0u16).data_dir(&temp_dir_2).spawn();
let provider1 = ProviderBuilder::new().on_http(geth1.endpoint_url());
let provider2 = ProviderBuilder::new().on_http(geth2.endpoint_url());
let node1_info = provider1.node_info().await.unwrap();
let node1_id = node1_info.id;
let node1_enode = node1_info.enode;
let added = provider2.add_peer(&node1_enode).await.unwrap();
assert!(added);
geth2.wait_to_add_peer(&node1_id).unwrap();
let peers = provider2.peers().await.unwrap();
assert_eq!(peers[0].enode, node1_enode);
})
.await;
})
.await;
})
.await;
}
}