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}