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