1use std::sync::Arc;
2
3use alloy_primitives::keccak256;
4use alloy_rpc_types_admin::{
5 EthInfo, EthPeerInfo, EthProtocolInfo, NodeInfo, PeerInfo, PeerNetworkInfo, PeerProtocolInfo,
6 Ports, ProtocolInfo,
7};
8use async_trait::async_trait;
9use jsonrpsee::core::RpcResult;
10use reth_chainspec::{EthChainSpec, EthereumHardforks};
11use reth_network_api::{NetworkInfo, Peers};
12use reth_network_peers::{AnyNode, NodeRecord};
13use reth_network_types::PeerKind;
14use reth_rpc_api::AdminApiServer;
15use reth_rpc_server_types::ToRpcResult;
16use reth_transaction_pool::TransactionPool;
17
18pub struct AdminApi<N, ChainSpec, Pool> {
22 network: N,
24 chain_spec: Arc<ChainSpec>,
26 pool: Pool,
28}
29
30impl<N, ChainSpec, Pool> AdminApi<N, ChainSpec, Pool> {
31 pub const fn new(network: N, chain_spec: Arc<ChainSpec>, pool: Pool) -> Self {
33 Self { network, chain_spec, pool }
34 }
35}
36
37#[async_trait]
38impl<N, ChainSpec, Pool> AdminApiServer for AdminApi<N, ChainSpec, Pool>
39where
40 N: NetworkInfo + Peers + 'static,
41 ChainSpec: EthChainSpec + EthereumHardforks + Send + Sync + 'static,
42 Pool: TransactionPool + 'static,
43{
44 fn add_peer(&self, record: NodeRecord) -> RpcResult<bool> {
46 self.network.add_peer_with_udp(record.id, record.tcp_addr(), record.udp_addr());
47 Ok(true)
48 }
49
50 fn remove_peer(&self, record: AnyNode) -> RpcResult<bool> {
52 self.network.remove_peer(record.peer_id(), PeerKind::Basic);
53 Ok(true)
54 }
55
56 fn add_trusted_peer(&self, record: AnyNode) -> RpcResult<bool> {
58 if let Some(trusted) = record.trusted_peer().cloned() {
59 self.network.add_trusted_peer_node(trusted);
60 } else {
61 if let Some(record) = record.node_record() {
62 self.network.add_trusted_peer_with_udp(
63 record.id,
64 record.tcp_addr(),
65 record.udp_addr(),
66 )
67 }
68 self.network.add_trusted_peer_id(record.peer_id());
69 }
70 Ok(true)
71 }
72
73 fn remove_trusted_peer(&self, record: AnyNode) -> RpcResult<bool> {
75 self.network.remove_peer(record.peer_id(), PeerKind::Trusted);
76 Ok(true)
77 }
78
79 fn ban_peer(&self, record: AnyNode) -> RpcResult<bool> {
81 self.network.ban_peer(record.peer_id());
82 Ok(true)
83 }
84
85 fn unban_peer(&self, record: AnyNode) -> RpcResult<bool> {
87 self.network.unban_peer(record.peer_id());
88 Ok(true)
89 }
90
91 async fn peers(&self) -> RpcResult<Vec<PeerInfo>> {
93 let peers = self.network.get_all_peers().await.to_rpc_result()?;
94 let mut infos = Vec::with_capacity(peers.len());
95
96 for peer in peers {
97 infos.push(PeerInfo {
98 id: alloy_primitives::hex::encode(keccak256(peer.remote_id.as_slice())),
99 name: peer.client_version.to_string(),
100 enode: peer.enode,
101 enr: peer.enr,
102 caps: peer.capabilities.capabilities().iter().map(|cap| cap.to_string()).collect(),
103 network: PeerNetworkInfo {
104 remote_address: peer.remote_addr,
105 local_address: peer.local_addr.unwrap_or_else(|| self.network.local_addr()),
106 inbound: peer.direction.is_incoming(),
107 trusted: peer.kind.is_trusted(),
108 static_node: peer.kind.is_static(),
109 },
110 protocols: PeerProtocolInfo {
111 eth: Some(EthPeerInfo::Info(EthInfo { version: peer.status.version as u64 })),
112 snap: None,
113 other: Default::default(),
114 },
115 })
116 }
117
118 Ok(infos)
119 }
120
121 async fn node_info(&self) -> RpcResult<NodeInfo> {
123 let enode = self.network.local_node_record();
124 let status = self.network.network_status().await.to_rpc_result()?;
125 let config = crate::chain_config::chain_config(&*self.chain_spec);
126
127 Ok(NodeInfo {
128 id: alloy_primitives::hex::encode(keccak256(enode.id.as_slice())),
129 name: status.client_version,
130 enode: enode.to_string(),
131 enr: self.network.local_enr().to_string(),
132 ip: enode.address,
133 ports: Ports { discovery: enode.udp_port, listener: enode.tcp_port },
134 listen_addr: enode.tcp_addr(),
135 #[expect(deprecated)]
136 protocols: ProtocolInfo {
137 eth: Some(EthProtocolInfo {
138 network: status.eth_protocol_info.network,
139 genesis: status.eth_protocol_info.genesis,
140 config,
141 head: status.eth_protocol_info.head,
142 difficulty: None,
143 }),
144 snap: None,
145 },
146 })
147 }
148
149 async fn subscribe_peer_events(
151 &self,
152 _pending: jsonrpsee::PendingSubscriptionSink,
153 ) -> jsonrpsee::core::SubscriptionResult {
154 Err("admin_peerEvents is not implemented yet".into())
155 }
156
157 async fn clear_txpool(&self) -> RpcResult<u64> {
159 let all_hashes = self.pool.all_transaction_hashes();
160 let count = all_hashes.len() as u64;
161 let _ = self.pool.remove_transactions(all_hashes);
162 Ok(count)
163 }
164}
165
166impl<N, ChainSpec, Pool> std::fmt::Debug for AdminApi<N, ChainSpec, Pool> {
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 f.debug_struct("AdminApi").finish_non_exhaustive()
169 }
170}