surfpool_core/rpc/
bank_data.rs

1use jsonrpc_core::Result;
2use jsonrpc_derive::rpc;
3use solana_client::{
4    rpc_config::{RpcBlockProductionConfig, RpcContextConfig},
5    rpc_response::{RpcBlockProduction, RpcInflationGovernor, RpcInflationRate},
6};
7use solana_clock::Slot;
8use solana_commitment_config::CommitmentConfig;
9use solana_epoch_schedule::EpochSchedule;
10use solana_rpc_client_api::response::Response as RpcResponse;
11
12use super::{not_implemented_err, RunloopContext, State};
13
14#[rpc]
15pub trait BankData {
16    type Metadata;
17
18    /// Returns the minimum balance required for rent exemption based on the given data length.
19    ///
20    /// This RPC method calculates the minimum balance required for an account to be exempt from
21    /// rent charges. It uses the data length of the account to determine the balance. The result
22    /// can help users manage their accounts by ensuring they have enough balance to cover rent
23    /// exemption, preventing accounts from being purged by the system.
24    ///
25    /// ## Parameters
26    /// - `data_len`: The length (in bytes) of the account data. This is used to determine the
27    ///   minimum balance required for rent exemption.
28    /// - `commitment`: (Optional) A `CommitmentConfig` that allows specifying the level of
29    ///   commitment for querying. If not provided, the default commitment level will be used.
30    ///
31    /// ## Returns
32    /// - `Result<u64>`: The method returns the minimum balance required for rent exemption
33    ///   as a `u64`. If successful, it will be wrapped in `Ok`, otherwise an error will be
34    ///   returned.
35    ///
36    /// ## Example Request (JSON-RPC)
37    /// ```json
38    /// {
39    ///   "jsonrpc": "2.0",
40    ///   "id": 1,
41    ///   "method": "getMinimumBalanceForRentExemption",
42    ///   "params": [128]
43    /// }
44    /// ```
45    ///
46    /// ## Example Response
47    /// ```json
48    /// {
49    ///   "jsonrpc": "2.0",
50    ///   "result": 2039280,
51    ///   "id": 1
52    /// }
53    /// ```
54    ///
55    /// # Notes
56    /// - This method is commonly used to determine the required balance when creating new accounts
57    ///   or performing account setup operations that need rent exemption.
58    /// - The `commitment` parameter allows users to specify the level of assurance they want
59    ///   regarding the state of the ledger. For example, using `Confirmed` or `Finalized` ensures
60    ///   that the state is more reliable.
61    ///
62    /// ## Errors
63    /// - If there is an issue with the `data_len` or `commitment` parameter (e.g., invalid data),
64    ///   an error will be returned.
65    #[rpc(meta, name = "getMinimumBalanceForRentExemption")]
66    fn get_minimum_balance_for_rent_exemption(
67        &self,
68        meta: Self::Metadata,
69        data_len: usize,
70        commitment: Option<CommitmentConfig>,
71    ) -> Result<u64>;
72
73    /// Retrieves the inflation governor settings for the network.
74    ///
75    /// This RPC method returns the current inflation governor configuration, which controls the
76    /// inflation rate of the network. The inflation governor is responsible for adjusting the
77    /// inflation rate over time, with parameters like the initial and terminal inflation rates,
78    /// the taper rate, the foundation amount, and the foundation term.
79    ///
80    /// ## Parameters
81    /// - `commitment`: (Optional) A `CommitmentConfig` that specifies the commitment level for
82    ///   querying the inflation governor settings. If not provided, the default commitment level
83    ///   is used. Valid commitment levels include `Processed`, `Confirmed`, or `Finalized`.
84    ///
85    /// ## Returns
86    /// - `Result<RpcInflationGovernor>`: The method returns an `RpcInflationGovernor` struct that
87    ///   contains the inflation parameters if successful. Otherwise, an error will be returned.
88    ///
89    /// ## Example Request (JSON-RPC)
90    /// ```json
91    /// {
92    ///   "jsonrpc": "2.0",
93    ///   "id": 1,
94    ///   "method": "getInflationGovernor",
95    ///   "params": []
96    /// }
97    /// ```
98    ///
99    /// ## Example Response
100    /// ```json
101    /// {
102    ///   "jsonrpc": "2.0",
103    ///   "result": {
104    ///     "initial": 0.15,
105    ///     "terminal": 0.05,
106    ///     "taper": 0.9,
107    ///     "foundation": 0.02,
108    ///     "foundation_term": 5.0
109    ///   },
110    ///   "id": 1
111    /// }
112    /// ```
113    ///
114    /// # Notes
115    /// - The inflation governor defines how inflation changes over time, ensuring the network's
116    ///   growth remains stable and sustainable.
117    /// - The `commitment` parameter allows users to define how strongly they want to ensure the
118    ///   inflation data is confirmed or finalized when queried. For example, using `Confirmed` or
119    ///   `Finalized` ensures a more reliable inflation state.
120    ///
121    /// ## Errors
122    /// - If there is an issue with the `commitment` parameter or an internal error occurs,
123    ///   an error will be returned.
124    #[rpc(meta, name = "getInflationGovernor")]
125    fn get_inflation_governor(
126        &self,
127        meta: Self::Metadata,
128        commitment: Option<CommitmentConfig>,
129    ) -> Result<RpcInflationGovernor>;
130
131    /// Retrieves the current inflation rate for the network.
132    ///
133    /// This RPC method returns the current inflation rate, including the breakdown of inflation
134    /// allocated to different entities such as validators and the foundation, along with the current
135    /// epoch during which the rate applies.
136    ///
137    /// ## Parameters
138    /// - No parameters are required for this method.
139    ///
140    /// ## Returns
141    /// - `Result<RpcInflationRate>`: The method returns an `RpcInflationRate` struct that contains
142    ///   the total inflation rate, the validator portion, the foundation portion, and the epoch
143    ///   during which this inflation rate applies.
144    ///
145    /// ## Example Request (JSON-RPC)
146    /// ```json
147    /// {
148    ///   "jsonrpc": "2.0",
149    ///   "id": 1,
150    ///   "method": "getInflationRate",
151    ///   "params": []
152    /// }
153    /// ```
154    ///
155    /// ## Example Response
156    /// ```json
157    /// {
158    ///   "jsonrpc": "2.0",
159    ///   "result": {
160    ///     "total": 0.10,
161    ///     "validator": 0.07,
162    ///     "foundation": 0.03,
163    ///     "epoch": 1500
164    ///   },
165    ///   "id": 1
166    /// }
167    /// ```
168    ///
169    /// # Notes
170    /// - The total inflation rate is distributed among validators and the foundation based on
171    ///   the configuration defined in the inflation governor.
172    /// - The epoch field indicates the current epoch number during which this inflation rate applies.
173    ///   An epoch is a period during which the network operates under certain parameters.
174    /// - Inflation rates can change over time depending on network conditions and governance decisions.
175    ///
176    /// ## Errors
177    /// - If there is an internal error, or if the RPC request is malformed, an error will be returned.
178    #[rpc(meta, name = "getInflationRate")]
179    fn get_inflation_rate(&self, meta: Self::Metadata) -> Result<RpcInflationRate>;
180
181    /// Retrieves the epoch schedule for the network.
182    ///
183    /// This RPC method returns the configuration for the network's epoch schedule, including
184    /// details on the number of slots per epoch, leader schedule offsets, and epoch warmup.
185    ///
186    /// ## Parameters
187    /// - No parameters are required for this method.
188    ///
189    /// ## Returns
190    /// - `Result<EpochSchedule>`: The method returns an `EpochSchedule` struct, which contains
191    ///   information about the slots per epoch, leader schedule offsets, warmup state, and the
192    ///   first epoch after the warmup period.
193    ///
194    /// ## Example Request (JSON-RPC)
195    /// ```json
196    /// {
197    ///   "jsonrpc": "2.0",
198    ///   "id": 1,
199    ///   "method": "getEpochSchedule",
200    ///   "params": []
201    /// }
202    /// ```
203    ///
204    /// ## Example Response
205    /// ```json
206    /// {
207    ///   "jsonrpc": "2.0",
208    ///   "result": {
209    ///     "slotsPerEpoch": 432000,
210    ///     "leaderScheduleSlotOffset": 500,
211    ///     "warmup": true,
212    ///     "firstNormalEpoch": 8,
213    ///     "firstNormalSlot": 1073741824
214    ///   },
215    ///   "id": 1
216    /// }
217    /// ```
218    ///
219    /// # Notes
220    /// - The `slots_per_epoch` defines the maximum number of slots in each epoch, which determines
221    ///   the number of time slots available for network validators to produce blocks.
222    /// - The `leader_schedule_slot_offset` specifies how many slots before an epoch’s start the leader
223    ///   schedule calculation begins for that epoch.
224    /// - The `warmup` field indicates whether the epochs start short and grow over time.
225    /// - The `first_normal_epoch` marks the first epoch after the warmup period.
226    /// - The `first_normal_slot` gives the first slot after the warmup period in terms of the number of slots
227    ///   from the start of the network.
228    ///
229    /// ## Errors
230    /// - If the RPC request is malformed, or if there is an internal error, an error will be returned.
231    #[rpc(meta, name = "getEpochSchedule")]
232    fn get_epoch_schedule(&self, meta: Self::Metadata) -> Result<EpochSchedule>;
233
234    /// Retrieves the leader of the current slot.
235    ///
236    /// This RPC method returns the leader for the current slot in the Solana network. The leader is responsible
237    /// for producing blocks for the current slot. The leader is selected based on the Solana consensus mechanism.
238    ///
239    /// ## Parameters
240    /// - `config`: An optional configuration for the request, which can include:
241    ///     - `commitment`: A commitment level that defines how "final" the data must be.
242    ///     - `min_context_slot`: An optional parameter to specify a minimum slot for the request.
243    ///
244    /// ## Returns
245    /// - `Result<String>`: The method returns a `String` representing the public key of the leader for the current slot.
246    ///
247    /// ## Example Request (JSON-RPC)
248    /// ```json
249    /// {
250    ///   "jsonrpc": "2.0",
251    ///   "id": 1,
252    ///   "method": "getSlotLeader",
253    ///   "params": []
254    /// }
255    /// ```
256    ///
257    /// ## Example Response
258    /// ```json
259    /// {
260    ///   "jsonrpc": "2.0",
261    ///   "result": "3HgA9r8H9z5Pb2L6Pt5Yq1QoFwgr6YwdKKUh9n2ANp5U"
262    /// }
263    /// ```
264    ///
265    /// # Notes
266    /// - The leader for a given slot is selected based on the Solana network's consensus mechanism, and this method
267    ///   allows you to query the current leader.
268    #[rpc(meta, name = "getSlotLeader")]
269    fn get_slot_leader(
270        &self,
271        meta: Self::Metadata,
272        config: Option<RpcContextConfig>,
273    ) -> Result<String>;
274
275    /// Retrieves the leaders for a specified range of slots.
276    ///
277    /// This RPC method returns the leaders for a specified range of slots in the Solana network. You can
278    /// specify the `start_slot` from which the leaders should be queried and limit the number of results
279    /// with the `limit` parameter. The leaders are responsible for producing blocks in the respective slots.
280    ///
281    /// ## Parameters
282    /// - `start_slot`: The starting slot number for which the leaders should be queried.
283    /// - `limit`: The number of slots (starting from `start_slot`) for which the leaders should be retrieved.
284    ///
285    /// ## Returns
286    /// - `Result<Vec<String>>`: A vector of `String` values representing the public keys of the leaders for
287    ///   the specified slot range.
288    ///
289    /// ## Example Request (JSON-RPC)
290    /// ```json
291    /// {
292    ///   "jsonrpc": "2.0",
293    ///   "id": 1,
294    ///   "method": "getSlotLeaders",
295    ///   "params": [1000, 5]
296    /// }
297    /// ```
298    ///
299    /// ## Example Response
300    /// ```json
301    /// {
302    ///   "jsonrpc": "2.0",
303    ///   "result": [
304    ///     "3HgA9r8H9z5Pb2L6Pt5Yq1QoFwgr6YwdKKUh9n2ANp5U",
305    ///     "BBh1FwXts8EZY6rPZ5kS2ygq99wYjFd5K5daRjc7eF9X",
306    ///     "4XYo7yP5J2J8sLNSW3wGYPk3mdS1rbZUy4oFCp7wH1DN",
307    ///     "8v1Cp6sHZh8XfGWS7sHZczH3v9NxdgMbo3g91Sh88dcJ",
308    ///     "N6bPqwEoD9StS4AnzE27rHyz47tPcsZQjvW9w8p2NhF7"
309    ///   ]
310    /// }
311    /// ```
312    ///
313    /// # Notes
314    /// - The leaders are returned in the order corresponding to the slots queried, starting from `start_slot`
315    ///   and continuing for `limit` slots.
316    /// - This method provides an efficient way to get multiple leaders for a range of slots, useful for tracking
317    ///   leaders over time or for scheduling purposes in decentralized applications.
318    #[rpc(meta, name = "getSlotLeaders")]
319    fn get_slot_leaders(
320        &self,
321        meta: Self::Metadata,
322        start_slot: Slot,
323        limit: u64,
324    ) -> Result<Vec<String>>;
325
326    /// Retrieves block production information for the specified validator identity or range of slots.
327    ///
328    /// This RPC method returns block production details for a given validator identity or a range of slots
329    /// within a certain epoch. If no `identity` is provided, the method returns block production data for all
330    /// validators. If a `range` is provided, it will return block production information for the slots within
331    /// the specified range.
332    ///
333    /// ## Parameters
334    /// - `config`: An optional configuration object that can include:
335    ///     - `identity`: The base-58 encoded public key of a validator to query for block production data. If `None`, results for all validators will be returned.
336    ///     - `range`: A range of slots for which block production information is needed. The range will default to the current epoch if `None`.
337    ///     - `commitment`: The commitment level (optional) to use when querying for the block production data.
338    ///
339    /// ## Returns
340    /// - `Result<RpcResponse<RpcBlockProduction>>`: The result contains a response object with block production data, including the number of leader slots and blocks produced by each validator.
341    ///
342    /// ## Example Request (JSON-RPC)
343    /// ```json
344    /// {
345    ///   "jsonrpc": "2.0",
346    ///   "id": 1,
347    ///   "method": "getBlockProduction",
348    ///   "params": [{
349    ///     "identity": "3HgA9r8H9z5Pb2L6Pt5Yq1QoFwgr6YwdKKUh9n2ANp5U",
350    ///     "range": {
351    ///       "firstSlot": 1000,
352    ///       "lastSlot": 1050
353    ///     }
354    ///   }]
355    /// }
356    /// ```
357    ///
358    /// ## Example Response
359    /// ```json
360    /// {
361    ///   "jsonrpc": "2.0",
362    ///   "result": {
363    ///     "byIdentity": {
364    ///       "3HgA9r8H9z5Pb2L6Pt5Yq1QoFwgr6YwdKKUh9n2ANp5U": [10, 8],
365    ///       "BBh1FwXts8EZY6rPZ5kS2ygq99wYjFd5K5daRjc7eF9X": [5, 4]
366    ///     },
367    ///     "range": {
368    ///       "firstSlot": 1000,
369    ///       "lastSlot": 1050
370    ///     }
371    ///   }
372    /// }
373    /// ```
374    ///
375    /// # Notes
376    /// - The response contains a map of validator identities to a tuple of two values:
377    ///     - The first value is the number of leader slots.
378    ///     - The second value is the number of blocks produced by that validator in the queried range.
379    /// - The `range` object specifies the range of slots that the block production information applies to, with `first_slot` being the starting slot and `last_slot` being the optional ending slot.
380    ///
381    /// ## Example Response Interpretation
382    /// - In the example response, the identity `3HgA9r8H9z5Pb2L6Pt5Yq1QoFwgr6YwdKKUh9n2ANp5U` produced 10 leader slots and 8 blocks between slots 1000 and 1050.
383    /// - Similarly, `BBh1FwXts8EZY6rPZ5kS2ygq99wYjFd5K5daRjc7eF9X` produced 5 leader slots and 4 blocks in the same slot range.
384    #[rpc(meta, name = "getBlockProduction")]
385    fn get_block_production(
386        &self,
387        meta: Self::Metadata,
388        config: Option<RpcBlockProductionConfig>,
389    ) -> Result<RpcResponse<RpcBlockProduction>>;
390}
391
392#[derive(Clone)]
393pub struct SurfpoolBankDataRpc;
394impl BankData for SurfpoolBankDataRpc {
395    type Metadata = Option<RunloopContext>;
396
397    fn get_minimum_balance_for_rent_exemption(
398        &self,
399        meta: Self::Metadata,
400        data_len: usize,
401        _commitment: Option<CommitmentConfig>,
402    ) -> Result<u64> {
403        meta.with_svm_reader(move |svm_reader| {
404            svm_reader
405                .inner
406                .minimum_balance_for_rent_exemption(data_len)
407        })
408        .map_err(Into::into)
409    }
410
411    fn get_inflation_governor(
412        &self,
413        _meta: Self::Metadata,
414        _commitment: Option<CommitmentConfig>,
415    ) -> Result<RpcInflationGovernor> {
416        not_implemented_err("get_inflation_governor")
417    }
418
419    fn get_inflation_rate(&self, _meta: Self::Metadata) -> Result<RpcInflationRate> {
420        not_implemented_err("get_inflation_rate")
421    }
422
423    fn get_epoch_schedule(&self, meta: Self::Metadata) -> Result<EpochSchedule> {
424        meta.with_svm_reader(move |svm_reader| svm_reader.inner.get_sysvar::<EpochSchedule>())
425            .map_err(Into::into)
426    }
427
428    fn get_slot_leader(
429        &self,
430        _meta: Self::Metadata,
431        _config: Option<RpcContextConfig>,
432    ) -> Result<String> {
433        not_implemented_err("get_slot_leader")
434    }
435
436    fn get_slot_leaders(
437        &self,
438        _meta: Self::Metadata,
439        _start_slot: Slot,
440        _limit: u64,
441    ) -> Result<Vec<String>> {
442        not_implemented_err("get_slot_leaders")
443    }
444
445    fn get_block_production(
446        &self,
447        _meta: Self::Metadata,
448        _config: Option<RpcBlockProductionConfig>,
449    ) -> Result<RpcResponse<RpcBlockProduction>> {
450        not_implemented_err("get_block_production")
451    }
452}
453
454#[cfg(test)]
455mod tests {
456    use super::*;
457    use crate::tests::helpers::TestSetup;
458
459    #[tokio::test(flavor = "multi_thread")]
460    async fn test_get_epoch_schedule() {
461        let setup = TestSetup::new(SurfpoolBankDataRpc);
462        let res = setup.rpc.get_epoch_schedule(Some(setup.context)).unwrap();
463
464        assert_eq!(res, EpochSchedule::default());
465    }
466}