surfpool_core/rpc/
admin.rs

1use std::{
2    collections::HashMap,
3    net::SocketAddr,
4    time::{Duration, SystemTime},
5};
6
7use jsonrpc_core::{BoxFuture, Result};
8use jsonrpc_derive::rpc;
9use solana_client::{rpc_config::RpcAccountIndex, rpc_custom_error::RpcCustomError};
10use solana_pubkey::Pubkey;
11use surfpool_types::SimnetCommand;
12use txtx_addon_network_svm_types::subgraph::PluginConfig;
13use uuid::Uuid;
14
15use super::{not_implemented_err, not_implemented_err_async, RunloopContext};
16use crate::PluginManagerCommand;
17
18#[rpc]
19pub trait AdminRpc {
20    type Metadata;
21
22    /// Immediately shuts down the RPC server.
23    ///
24    /// This administrative endpoint is typically used during controlled shutdowns of the validator
25    /// or service exposing the RPC interface. It allows remote administrators to gracefully terminate
26    /// the process, stopping all RPC activity.
27    ///
28    /// ## Returns
29    /// - [`Result<()>`] — A unit result indicating successful shutdown, or an error if the call fails.
30    ///
31    /// ## Example Request (JSON-RPC)
32    /// ```json
33    /// {
34    ///   "jsonrpc": "2.0",
35    ///   "id": 42,
36    ///   "method": "exit",
37    ///   "params": []
38    /// }
39    /// ```
40    ///
41    /// # Notes
42    /// - This method is privileged and should only be accessible to trusted clients.
43    /// - Use with extreme caution in production environments.
44    /// - If successful, the RPC server process will terminate immediately after processing this call.
45    ///
46    /// # Security
47    /// Access to this method should be tightly restricted. Implement proper authorization mechanisms
48    /// via the RPC metadata to prevent accidental or malicious use.
49    #[rpc(meta, name = "exit")]
50    fn exit(&self, meta: Self::Metadata) -> Result<()>;
51
52    #[rpc(meta, name = "reloadPlugin")]
53    fn reload_plugin(
54        &self,
55        meta: Self::Metadata,
56        name: String,
57        config_file: String,
58    ) -> BoxFuture<Result<()>>;
59
60    /// Reloads a runtime plugin with new configuration.
61    ///
62    /// This administrative endpoint is used to dynamically reload a plugin without restarting
63    /// the entire RPC server or validator. It is useful for applying updated configurations
64    /// to a plugin that supports hot-reloading.
65    ///
66    /// ## Parameters
67    /// - `name`: The identifier of the plugin to reload.
68    /// - `config_file`: Path to the new configuration file to load for the plugin.
69    ///
70    /// ## Returns
71    /// - [`BoxFuture<Result<()>>`] — A future resolving to a unit result on success, or an error if
72    ///   reloading fails.
73    ///
74    /// ## Example Request (JSON-RPC)
75    /// ```json
76    /// {
77    ///   "jsonrpc": "2.0",
78    ///   "id": 101,
79    ///   "method": "reloadPlugin",
80    ///   "params": ["myPlugin", "/etc/plugins/my_plugin_config.toml"]
81    /// }
82    /// ```
83    ///
84    /// # Notes
85    /// - The plugin must support reloading in order for this to succeed.
86    /// - A failed reload will leave the plugin in its previous state.
87    /// - This method is intended for administrators and should be properly secured.
88    ///
89    /// # Security
90    /// Ensure only trusted clients can invoke this method. Use metadata-based access control to limit exposure.
91    #[rpc(meta, name = "unloadPlugin")]
92    fn unload_plugin(&self, meta: Self::Metadata, name: String) -> BoxFuture<Result<()>>;
93
94    /// Dynamically loads a new plugin into the runtime from a configuration file.
95    ///
96    /// This administrative endpoint is used to add a new plugin to the system at runtime,
97    /// based on the configuration provided. It enables extensibility without restarting
98    /// the validator or RPC server.
99    ///
100    /// ## Parameters
101    /// - `config_file`: Path to the plugin's configuration file, which defines its behavior and settings.
102    ///
103    /// ## Returns
104    /// - [`BoxFuture<Result<String>>`] — A future resolving to the name or identifier of the loaded plugin,
105    ///   or an error if the plugin could not be loaded.
106    ///
107    /// ## Example Request (JSON-RPC)
108    /// ```json
109    /// {
110    ///   "jsonrpc": "2.0",
111    ///   "id": 102,
112    ///   "method": "loadPlugin",
113    ///   "params": ["/etc/plugins/my_plugin_config.toml"]
114    /// }
115    /// ```
116    ///
117    /// # Notes
118    /// - The plugin system must be initialized and support runtime loading.
119    /// - The config file should be well-formed and point to a valid plugin implementation.
120    /// - Duplicate plugin names may lead to conflicts or errors.
121    ///
122    /// # Security
123    /// This method should be restricted to administrators only. Validate inputs and use access control.
124    #[rpc(meta, name = "loadPlugin")]
125    fn load_plugin(&self, meta: Self::Metadata, config_file: String) -> BoxFuture<Result<String>>;
126
127    /// Returns a list of all currently loaded plugin names.
128    ///
129    /// This administrative RPC method is used to inspect which plugins have been successfully
130    /// loaded into the runtime. It can be useful for debugging or operational monitoring.
131    ///
132    /// ## Returns
133    /// - `Vec<String>` — A list of plugin names currently active in the system.
134    ///
135    /// ## Example Request (JSON-RPC)
136    /// ```json
137    /// {
138    ///   "jsonrpc": "2.0",
139    ///   "id": 103,
140    ///   "method": "listPlugins",
141    ///   "params": []
142    /// }
143    /// ```
144    ///
145    /// ## Example Response
146    /// ```json
147    /// {
148    ///   "jsonrpc": "2.0",
149    ///   "result": ["tx_filter", "custom_logger"],
150    ///   "id": 103
151    /// }
152    /// ```
153    ///
154    /// # Notes
155    /// - Only plugins that have been successfully loaded will appear in this list.
156    /// - This method is read-only and safe to call frequently.
157    #[rpc(meta, name = "listPlugins")]
158    fn list_plugins(&self, meta: Self::Metadata) -> BoxFuture<Result<Vec<String>>>;
159
160    /// Returns the address of the RPC server.
161    ///
162    /// This RPC method retrieves the network address (IP and port) the RPC server is currently
163    /// listening on. It can be useful for service discovery or monitoring the server’s network status.
164    ///
165    /// ## Returns
166    /// - `Option<SocketAddr>` — The network address of the RPC server, or `None` if no address is available.
167    ///
168    /// ## Example Request (JSON-RPC)
169    /// ```json
170    /// {
171    ///   "jsonrpc": "2.0",
172    ///   "id": 104,
173    ///   "method": "rpcAddress",
174    ///   "params": []
175    /// }
176    /// ```
177    ///
178    /// ## Example Response
179    /// ```json
180    /// {
181    ///   "jsonrpc": "2.0",
182    ///   "result": "127.0.0.1:8080",
183    ///   "id": 104
184    /// }
185    /// ```
186    ///
187    /// # Notes
188    /// - This method is useful for finding the address of a running RPC server, especially in dynamic environments.
189    /// - If the server is not configured or is running without network exposure, the result may be `None`.
190    #[rpc(meta, name = "rpcAddress")]
191    fn rpc_addr(&self, meta: Self::Metadata) -> Result<Option<SocketAddr>>;
192
193    /// Sets a filter for log messages in the system.
194    ///
195    /// This RPC method allows the user to configure the logging level or filters applied to the logs
196    /// generated by the system. It enables fine-grained control over which log messages are captured
197    /// and how they are displayed or stored.
198    ///
199    /// ## Parameters
200    /// - `filter`: A string representing the desired log filter. This could be a log level (e.g., `info`, `debug`, `error`),
201    ///   or a more complex filter expression depending on the system’s logging configuration.
202    ///
203    /// ## Returns
204    /// - `()` — A unit result indicating the operation was successful.
205    ///
206    /// ## Example Request (JSON-RPC)
207    /// ```json
208    /// {
209    ///   "jsonrpc": "2.0",
210    ///   "id": 105,
211    ///   "method": "setLogFilter",
212    ///   "params": ["debug"]
213    /// }
214    /// ```
215    ///
216    /// ## Example Response
217    /// ```json
218    /// {
219    ///   "jsonrpc": "2.0",
220    ///   "result": null,
221    ///   "id": 105
222    /// }
223    /// ```
224    ///
225    /// # Notes
226    /// - The `filter` parameter should be consistent with the logging framework used by the system.
227    /// - Valid filter values might include common log levels such as `trace`, `debug`, `info`, `warn`, `error`, or other custom filters.
228    /// - This method allows dynamic control of the log output, so it should be used cautiously in production environments.
229    #[rpc(name = "setLogFilter")]
230    fn set_log_filter(&self, filter: String) -> Result<()>;
231
232    /// Returns the system start time.
233    ///
234    /// This RPC method retrieves the timestamp of when the system was started, represented as
235    /// a `SystemTime`. It can be useful for measuring uptime or for tracking the system's runtime
236    /// in logs or monitoring systems.
237    ///
238    /// ## Returns
239    /// - `SystemTime` — The timestamp representing when the system was started.
240    ///
241    /// ## Example Request (JSON-RPC)
242    /// ```json
243    /// {
244    ///   "jsonrpc": "2.0",
245    ///   "id": 106,
246    ///   "method": "startTime",
247    ///   "params": []
248    /// }
249    /// ```
250    ///
251    /// ## Example Response
252    /// ```json
253    /// {
254    ///   "jsonrpc": "2.0",
255    ///   "result": "2025-04-24T12:34:56Z",
256    ///   "id": 106
257    /// }
258    /// ```
259    ///
260    /// # Notes
261    /// - The result is a `SystemTime` in UTC, reflecting the moment the system was initialized.
262    /// - This method is useful for monitoring system uptime and verifying system health.
263    #[rpc(meta, name = "startTime")]
264    fn start_time(&self, meta: Self::Metadata) -> Result<SystemTime>;
265
266    // #[rpc(meta, name = "startProgress")]
267    // fn start_progress(&self, meta: Self::Metadata) -> Result<ValidatorStartProgress>;
268
269    /// Adds an authorized voter to the system.
270    ///
271    /// This RPC method allows an authorized user to add a new voter to the list of authorized
272    /// voters. A voter is typically an entity that can participate in governance actions, such as
273    /// voting on proposals or other decision-making processes.
274    ///
275    /// ## Parameters
276    /// - `keypair_file`: A string representing the path to the file containing the keypair of the new voter.
277    ///   The keypair is used to authenticate and authorize the voter to participate in governance.
278    ///
279    /// ## Returns
280    /// - `()` — A unit result indicating that the operation was successful.
281    ///
282    /// ## Example Request (JSON-RPC)
283    /// ```json
284    /// {
285    ///   "jsonrpc": "2.0",
286    ///   "id": 107,
287    ///   "method": "addAuthorizedVoter",
288    ///   "params": ["path/to/voter_keypair.json"]
289    /// }
290    /// ```
291    ///
292    /// ## Example Response
293    /// ```json
294    /// {
295    ///   "jsonrpc": "2.0",
296    ///   "result": null,
297    ///   "id": 107
298    /// }
299    /// ```
300    ///
301    /// # Notes
302    /// - This method typically requires administrative or elevated permissions to execute.
303    /// - The `keypair_file` should contain a valid keypair for the new voter, formatted according to the system's expectations.
304    /// - Once added, the new voter will be able to participate in governance actions.
305    #[rpc(meta, name = "addAuthorizedVoter")]
306    fn add_authorized_voter(&self, meta: Self::Metadata, keypair_file: String) -> Result<()>;
307
308    /// Adds an authorized voter to the system using a byte-encoded keypair.
309    ///
310    /// This RPC method allows an authorized user to add a new voter by directly providing the
311    /// keypair in the form of a byte vector (`Vec<u8>`). This can be useful for systems where keypairs
312    /// are serialized or passed in a non-file-based format.
313    ///
314    /// ## Parameters
315    /// - `keypair`: A vector of bytes representing the keypair of the new voter. This keypair will be used to
316    ///   authenticate and authorize the voter to participate in governance actions.
317    ///
318    /// ## Returns
319    /// - `()` — A unit result indicating the operation was successful.
320    ///
321    /// ## Example Request (JSON-RPC)
322    /// ```json
323    /// {
324    ///   "jsonrpc": "2.0",
325    ///   "id": 108,
326    ///   "method": "addAuthorizedVoterFromBytes",
327    ///   "params": ["<base64-encoded-keypair>"]
328    /// }
329    /// ```
330    ///
331    /// ## Example Response
332    /// ```json
333    /// {
334    ///   "jsonrpc": "2.0",
335    ///   "result": null,
336    ///   "id": 108
337    /// }
338    /// ```
339    ///
340    /// # Notes
341    /// - This method allows for adding a voter directly from a byte-encoded keypair, which may be useful for
342    ///   systems that store keypairs in non-traditional formats (e.g., databases, serialized data).
343    /// - The `keypair` should be provided in the correct format expected by the system (typically a base64 or raw binary format).
344    /// - This method typically requires administrative or elevated permissions to execute.
345    /// - Once added, the new voter will be able to participate in governance actions.
346    #[rpc(meta, name = "addAuthorizedVoterFromBytes")]
347    fn add_authorized_voter_from_bytes(&self, meta: Self::Metadata, keypair: Vec<u8>)
348        -> Result<()>;
349
350    /// Removes all authorized voters from the system.
351    ///
352    /// This RPC method removes all voters from the list of authorized voters. This action
353    /// is typically an administrative function and may be used to reset or clean up the list of
354    /// voters in the system.
355    ///
356    /// ## Parameters
357    /// - None.
358    ///
359    /// ## Returns
360    /// - `()` — A unit result indicating that the operation was successful.
361    ///
362    /// ## Example Request (JSON-RPC)
363    /// ```json
364    /// {
365    ///   "jsonrpc": "2.0",
366    ///   "id": 109,
367    ///   "method": "removeAllAuthorizedVoters",
368    ///   "params": []
369    /// }
370    /// ```
371    ///
372    /// ## Example Response
373    /// ```json
374    /// {
375    ///   "jsonrpc": "2.0",
376    ///   "result": null,
377    ///   "id": 109
378    /// }
379    /// ```
380    ///
381    /// # Notes
382    /// - This method will remove all voters and may not be reversible. It is a critical operation that
383    ///   typically requires elevated administrative permissions.
384    /// - Use this method with caution as it will prevent any previously authorized voter from participating
385    ///   in governance actions until they are re-added.
386    #[rpc(meta, name = "removeAllAuthorizedVoters")]
387    fn remove_all_authorized_voters(&self, meta: Self::Metadata) -> Result<()>;
388
389    /// Sets the identity for the system using the provided keypair.
390    ///
391    /// This RPC method allows you to set the system's identity by specifying a keypair file.
392    /// The identity set here is typically used to authenticate the system and validate its
393    /// actions in governance or other sensitive operations. The `require_tower` flag ensures
394    /// that a specific security feature, called "tower," is enabled for the identity.
395    ///
396    /// ## Parameters
397    /// - `keypair_file`: The file path to the keypair that will be used to set the system's identity.
398    /// - `require_tower`: A boolean flag indicating whether the tower security feature should be enforced
399    ///   for this identity.
400    ///
401    /// ## Returns
402    /// - `()` — A unit result indicating that the operation was successful.
403    ///
404    /// ## Example Request (JSON-RPC)
405    /// ```json
406    /// {
407    ///   "jsonrpc": "2.0",
408    ///   "id": 110,
409    ///   "method": "setIdentity",
410    ///   "params": ["/path/to/keypair.json", true]
411    /// }
412    /// ```
413    ///
414    /// ## Example Response
415    /// ```json
416    /// {
417    ///   "jsonrpc": "2.0",
418    ///   "result": null,
419    ///   "id": 110
420    /// }
421    /// ```
422    ///
423    /// # Notes
424    /// - This method allows for setting the identity of the system, which could have security and governance
425    ///   implications. It is typically used when initializing or reconfiguring the system's identity.
426    /// - The `require_tower` flag is optional but can be used to add an extra layer of security for the identity.
427    /// - The method usually requires administrative permissions and a valid keypair to execute.
428    #[rpc(meta, name = "setIdentity")]
429    fn set_identity(
430        &self,
431        meta: Self::Metadata,
432        keypair_file: String,
433        require_tower: bool,
434    ) -> Result<()>;
435
436    /// Sets the identity for the system using a keypair provided as a byte array.
437    ///
438    /// This RPC method allows you to set the system's identity by directly providing a byte array
439    /// representing the keypair. The `require_tower` flag is used to enforce the "tower" security feature
440    /// for this identity, if needed.
441    ///
442    /// ## Parameters
443    /// - `identity_keypair`: A byte array representing the keypair to set the system's identity.
444    /// - `require_tower`: A boolean flag indicating whether the tower security feature should be enforced
445    ///   for this identity.
446    ///
447    /// ## Returns
448    /// - `()` — A unit result indicating that the operation was successful.
449    ///
450    /// ## Example Request (JSON-RPC)
451    /// ```json
452    /// {
453    ///   "jsonrpc": "2.0",
454    ///   "id": 111,
455    ///   "method": "setIdentityFromBytes",
456    ///   "params": [[72, 101, 108, 108, 111], true]
457    /// }
458    /// ```
459    ///
460    /// ## Example Response
461    /// ```json
462    /// {
463    ///   "jsonrpc": "2.0",
464    ///   "result": null,
465    ///   "id": 111
466    /// }
467    /// ```
468    ///
469    /// # Notes
470    /// - This method is useful for scenarios where the keypair is not stored in a file but is instead available
471    ///   as a byte array (e.g., for programmatically generated keypairs).
472    /// - The `require_tower` flag, when set to `true`, enforces additional security for the identity.
473    /// - The method typically requires administrative permissions to execute.
474    #[rpc(meta, name = "setIdentityFromBytes")]
475    fn set_identity_from_bytes(
476        &self,
477        meta: Self::Metadata,
478        identity_keypair: Vec<u8>,
479        require_tower: bool,
480    ) -> Result<()>;
481
482    /// Sets the overrides for staked nodes using a specified path.
483    ///
484    /// This RPC method allows you to configure overrides for staked nodes by specifying the path
485    /// to a configuration file. This is typically used for adjusting the parameters or behavior
486    /// of the staked nodes in the system, such as custom settings for node management or staking
487    /// operations.
488    ///
489    /// ## Parameters
490    /// - `path`: The file path to the configuration file that contains the staked node overrides.
491    ///   This file should define the necessary settings for overriding the default staked node configuration.
492    ///
493    /// ## Returns
494    /// - `()` — A unit result indicating that the operation was successful.
495    ///
496    /// ## Example Request (JSON-RPC)
497    /// ```json
498    /// {
499    ///   "jsonrpc": "2.0",
500    ///   "id": 112,
501    ///   "method": "setStakedNodesOverrides",
502    ///   "params": ["/path/to/overrides.json"]
503    /// }
504    /// ```
505    ///
506    /// ## Example Response
507    /// ```json
508    /// {
509    ///   "jsonrpc": "2.0",
510    ///   "result": null,
511    ///   "id": 112
512    /// }
513    /// ```
514    ///
515    /// # Notes
516    /// - This method is used for overriding the configuration of staked nodes in the system.
517    ///   The `path` parameter should point to a file that contains the necessary overrides.
518    /// - It may require administrative permissions to modify the staked node configurations.
519    /// - The path file should be in a format understood by the system (e.g., JSON, YAML).
520    #[rpc(meta, name = "setStakedNodesOverrides")]
521    fn set_staked_nodes_overrides(&self, meta: Self::Metadata, path: String) -> Result<()>;
522
523    /// Repairs a shred from a peer node in the network.
524    ///
525    /// This RPC method triggers the repair of a specific shred from a peer node, using the given
526    /// `pubkey` (if provided), `slot`, and `shred_index`. This is typically used in cases where
527    /// a shred is missing or corrupted and needs to be retrieved from another node in the network.
528    ///
529    /// ## Parameters
530    /// - `pubkey` (Optional): The public key of the node from which to request the shred. If `None`,
531    ///   the system may choose any peer to attempt the repair from.
532    /// - `slot`: The slot number where the shred is located.
533    /// - `shred_index`: The index of the specific shred within the given slot that needs repair.
534    ///
535    /// ## Returns
536    /// - `()` — A unit result indicating that the operation was successful.
537    ///
538    /// ## Example Request (JSON-RPC)
539    /// ```json
540    /// {
541    ///   "jsonrpc": "2.0",
542    ///   "id": 113,
543    ///   "method": "repairShredFromPeer",
544    ///   "params": ["PubkeyHere", 12345, 6789]
545    /// }
546    /// ```
547    ///
548    /// ## Example Response
549    /// ```json
550    /// {
551    ///   "jsonrpc": "2.0",
552    ///   "result": null,
553    ///   "id": 113
554    /// }
555    /// ```
556    ///
557    /// # Notes
558    /// - The method may require specific network configurations or permissions to allow for the repair of the shred.
559    /// - If the `pubkey` is provided, the system will attempt to retrieve the shred from the specified peer node. Otherwise,
560    ///   it will attempt the repair from any available node in the network.
561    #[rpc(meta, name = "repairShredFromPeer")]
562    fn repair_shred_from_peer(
563        &self,
564        meta: Self::Metadata,
565        pubkey: Option<Pubkey>,
566        slot: u64,
567        shred_index: u64,
568    ) -> Result<()>;
569
570    /// Sets the whitelist of nodes allowed to repair shreds.
571    ///
572    /// This RPC method sets a list of nodes (identified by their public keys) that are permitted
573    /// to repair shreds in the network. The whitelist controls which nodes have the authority to
574    /// perform repairs. Any node not included in the whitelist will be restricted from initiating
575    /// shred repair operations.
576    ///
577    /// ## Parameters
578    /// - `whitelist`: A vector of `Pubkey` values representing the public keys of the nodes
579    ///   that are authorized to repair shreds.
580    ///
581    /// ## Returns
582    /// - `()` — A unit result indicating that the operation was successful.
583    ///
584    /// ## Example Request (JSON-RPC)
585    /// ```json
586    /// {
587    ///   "jsonrpc": "2.0",
588    ///   "id": 114,
589    ///   "method": "setRepairWhitelist",
590    ///   "params": [["Pubkey1", "Pubkey2", "Pubkey3"]]
591    /// }
592    /// ```
593    ///
594    /// ## Example Response
595    /// ```json
596    /// {
597    ///   "jsonrpc": "2.0",
598    ///   "result": null,
599    ///   "id": 114
600    /// }
601    /// ```
602    ///
603    /// # Notes
604    /// - This method is generally used by network administrators to control which nodes are trusted
605    ///   to perform repairs on the network.
606    /// - The whitelist ensures that only authorized nodes can engage in potentially sensitive network repair actions.
607    #[rpc(meta, name = "setRepairWhitelist")]
608    fn set_repair_whitelist(&self, meta: Self::Metadata, whitelist: Vec<Pubkey>) -> Result<()>;
609
610    /// Retrieves the size of the secondary index key for a given account.
611    ///
612    /// This RPC method returns the size of the secondary index key associated with a specific
613    /// account, identified by its public key. The secondary index key is used in the indexing
614    /// mechanism to quickly access account-related data.
615    ///
616    /// ## Parameters
617    /// - `pubkey_str`: A string representing the public key of the account for which the
618    ///   secondary index key size is being queried.
619    ///
620    /// ## Returns
621    /// - `HashMap<RpcAccountIndex, usize>`: A mapping of account indices to their respective key sizes.
622    ///
623    /// ## Example Request (JSON-RPC)
624    /// ```json
625    /// {
626    ///   "jsonrpc": "2.0",
627    ///   "id": 115,
628    ///   "method": "getSecondaryIndexKeySize",
629    ///   "params": ["PubkeyString"]
630    /// }
631    /// ```
632    ///
633    /// ## Example Response
634    /// ```json
635    /// {
636    ///   "jsonrpc": "2.0",
637    ///   "result": {
638    ///     "programId": 128,
639    ///     "splTokenMint": 256,
640    ///     "splTokenOwner": 192
641    ///   },
642    ///   "id": 115
643    /// }
644    /// ```
645    ///
646    /// # Notes
647    /// - The returned `HashMap` will contain index types as keys, and the size of each key
648    #[rpc(meta, name = "getSecondaryIndexKeySize")]
649    fn get_secondary_index_key_size(
650        &self,
651        meta: Self::Metadata,
652        pubkey_str: String,
653    ) -> Result<HashMap<RpcAccountIndex, usize>>;
654
655    /// Sets the public TPU (Transaction Processing Unit) address.
656    ///
657    /// This RPC method is used to configure the public TPU address of the node. The TPU address
658    /// is used for communication between the validator and the network, allowing the node to
659    /// send and receive transactions.
660    ///
661    /// ## Parameters
662    /// - `public_tpu_addr`: A `SocketAddr` representing the public TPU address to be set.
663    ///
664    /// ## Returns
665    /// - `Result<()>`: Returns `Ok(())` if the operation was successful, or an error if
666    ///   there was an issue setting the TPU address.
667    ///
668    /// ## Example Request (JSON-RPC)
669    /// ```json
670    /// {
671    ///   "jsonrpc": "2.0",
672    ///   "id": 118,
673    ///   "method": "setPublicTpuAddress",
674    ///   "params": ["127.0.0.1:8000"]
675    /// }
676    /// ```
677    ///
678    /// ## Example Response
679    /// ```json
680    /// {
681    ///   "jsonrpc": "2.0",
682    ///   "result": null,
683    ///   "id": 118
684    /// }
685    /// ```
686    ///
687    /// # Notes
688    /// - The TPU address is important for a validator node to participate in transaction
689    ///   processing and communication with the rest of the Solana network.
690    /// - This method is typically used to configure the node's external-facing address, allowing
691    ///   it to communicate with clients or other validators.
692    ///
693    /// ## Errors
694    /// - If the provided address is invalid or there is a failure when setting the address,
695    ///   an error will be returned.
696    #[rpc(meta, name = "setPublicTpuAddress")]
697    fn set_public_tpu_address(
698        &self,
699        meta: Self::Metadata,
700        public_tpu_addr: SocketAddr,
701    ) -> Result<()>;
702
703    /// Sets the public TPU forwards address.
704    ///
705    /// This RPC method configures the public address for TPU forwarding. It is used to specify
706    /// a separate address for forwarding transactions to a different destination, often used
707    /// for specialized network configurations or load balancing.
708    ///
709    /// ## Parameters
710    /// - `public_tpu_forwards_addr`: A `SocketAddr` representing the public TPU forwards
711    ///   address to be set.
712    ///
713    /// ## Returns
714    /// - `Result<()>`: Returns `Ok(())` if the operation was successful, or an error if
715    ///   there was an issue setting the TPU forwards address.
716    ///
717    /// ## Example Request (JSON-RPC)
718    /// ```json
719    /// {
720    ///   "jsonrpc": "2.0",
721    ///   "id": 118,
722    ///   "method": "setPublicTpuForwardsAddress",
723    ///   "params": ["127.0.0.1:9000"]
724    /// }
725    /// ```
726    ///
727    /// ## Example Response
728    /// ```json
729    /// {
730    ///   "jsonrpc": "2.0",
731    ///   "result": null,
732    ///   "id": 118
733    /// }
734    /// ```
735    ///
736    /// # Notes
737    /// - This method is typically used for advanced network configurations, where a node might
738    ///   want to forward its transaction processing requests to another address.
739    /// - The provided `SocketAddr` should be valid and reachable.
740    ///
741    /// ## Errors
742    /// - If the provided address is invalid or there is a failure when setting the address,
743    ///   an error will be returned.
744    #[rpc(meta, name = "setPublicTpuForwardsAddress")]
745    fn set_public_tpu_forwards_address(
746        &self,
747        meta: Self::Metadata,
748        public_tpu_forwards_addr: SocketAddr,
749    ) -> Result<()>;
750}
751
752pub struct SurfpoolAdminRpc;
753impl AdminRpc for SurfpoolAdminRpc {
754    type Metadata = Option<RunloopContext>;
755
756    fn exit(&self, meta: Self::Metadata) -> Result<()> {
757        let Some(ctx) = meta else {
758            return Err(RpcCustomError::NodeUnhealthy {
759                num_slots_behind: None,
760            }
761            .into());
762        };
763
764        let _ = ctx
765            .simnet_commands_tx
766            .send(SimnetCommand::Terminate(ctx.id));
767
768        Ok(())
769    }
770
771    fn reload_plugin(
772        &self,
773        _meta: Self::Metadata,
774        _name: String,
775        _config_file: String,
776    ) -> BoxFuture<Result<()>> {
777        not_implemented_err_async("reload_plugin")
778    }
779
780    fn unload_plugin(&self, _meta: Self::Metadata, _name: String) -> BoxFuture<Result<()>> {
781        not_implemented_err_async("unload_plugin")
782    }
783
784    fn load_plugin(&self, meta: Self::Metadata, config_file: String) -> BoxFuture<Result<String>> {
785        let config = match serde_json::from_str::<PluginConfig>(&config_file)
786            .map_err(|e| format!("failed to deserialize plugin config: {e}"))
787        {
788            Ok(config) => config,
789            Err(e) => return Box::pin(async move { Err(jsonrpc_core::Error::invalid_params(&e)) }),
790        };
791        let ctx = meta.unwrap();
792        let uuid = Uuid::new_v4();
793        let (tx, rx) = crossbeam_channel::bounded(1);
794        let _ = ctx
795            .plugin_manager_commands_tx
796            .send(PluginManagerCommand::LoadConfig(uuid, config, tx));
797
798        let Ok(endpoint_url) = rx.recv_timeout(Duration::from_secs(10)) else {
799            return Box::pin(async move { Err(jsonrpc_core::Error::internal_error()) });
800        };
801        Box::pin(async move { Ok(endpoint_url) })
802    }
803
804    fn list_plugins(&self, _meta: Self::Metadata) -> BoxFuture<Result<Vec<String>>> {
805        not_implemented_err_async("list_plugins")
806    }
807
808    fn rpc_addr(&self, _meta: Self::Metadata) -> Result<Option<SocketAddr>> {
809        not_implemented_err("rpc_addr")
810    }
811
812    fn set_log_filter(&self, _filter: String) -> Result<()> {
813        not_implemented_err("set_log_filter")
814    }
815
816    fn start_time(&self, _meta: Self::Metadata) -> Result<SystemTime> {
817        not_implemented_err("start_time")
818    }
819
820    fn add_authorized_voter(&self, _meta: Self::Metadata, _keypair_file: String) -> Result<()> {
821        not_implemented_err("add_authorized_voter")
822    }
823
824    fn add_authorized_voter_from_bytes(
825        &self,
826        _meta: Self::Metadata,
827        _keypair: Vec<u8>,
828    ) -> Result<()> {
829        not_implemented_err("add_authorized_voter_from_bytes")
830    }
831
832    fn remove_all_authorized_voters(&self, _meta: Self::Metadata) -> Result<()> {
833        not_implemented_err("remove_all_authorized_voters")
834    }
835
836    fn set_identity(
837        &self,
838        _meta: Self::Metadata,
839        _keypair_file: String,
840        _require_tower: bool,
841    ) -> Result<()> {
842        not_implemented_err("set_identity")
843    }
844
845    fn set_identity_from_bytes(
846        &self,
847        _meta: Self::Metadata,
848        _identity_keypair: Vec<u8>,
849        _require_tower: bool,
850    ) -> Result<()> {
851        not_implemented_err("set_identity_from_bytes")
852    }
853
854    fn set_staked_nodes_overrides(&self, _meta: Self::Metadata, _path: String) -> Result<()> {
855        not_implemented_err("set_staked_nodes_overrides")
856    }
857
858    fn repair_shred_from_peer(
859        &self,
860        _meta: Self::Metadata,
861        _pubkey: Option<Pubkey>,
862        _slot: u64,
863        _shred_index: u64,
864    ) -> Result<()> {
865        not_implemented_err("repair_shred_from_peer")
866    }
867
868    fn set_repair_whitelist(&self, _meta: Self::Metadata, _whitelist: Vec<Pubkey>) -> Result<()> {
869        not_implemented_err("set_repair_whitelist")
870    }
871
872    fn get_secondary_index_key_size(
873        &self,
874        _meta: Self::Metadata,
875        _pubkey_str: String,
876    ) -> Result<HashMap<RpcAccountIndex, usize>> {
877        not_implemented_err("get_secondary_index_key_size")
878    }
879
880    fn set_public_tpu_address(
881        &self,
882        _meta: Self::Metadata,
883        _public_tpu_addr: SocketAddr,
884    ) -> Result<()> {
885        not_implemented_err("set_public_tpu_address")
886    }
887
888    fn set_public_tpu_forwards_address(
889        &self,
890        _meta: Self::Metadata,
891        _public_tpu_forwards_addr: SocketAddr,
892    ) -> Result<()> {
893        not_implemented_err("set_public_tpu_forwards_address")
894    }
895}