surfpool_core/rpc/minimal.rs
1use super::{not_implemented_err, RunloopContext};
2use crate::{
3 rpc::{utils::verify_pubkey, State},
4 surfnet::GetAccountStrategy,
5};
6use jsonrpc_core::{futures::future, BoxFuture, Result};
7use jsonrpc_derive::rpc;
8use solana_client::{
9 rpc_config::{
10 RpcContextConfig, RpcGetVoteAccountsConfig, RpcLeaderScheduleConfig,
11 RpcLeaderScheduleConfigWrapper,
12 },
13 rpc_response::{
14 RpcIdentity, RpcLeaderSchedule, RpcResponseContext, RpcSnapshotSlotInfo,
15 RpcVoteAccountStatus,
16 },
17};
18use solana_clock::Slot;
19use solana_epoch_info::EpochInfo;
20use solana_rpc_client_api::response::Response as RpcResponse;
21const SURFPOOL_VERSION: &str = env!("CARGO_PKG_VERSION");
22
23#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
24#[serde(rename_all = "kebab-case")]
25pub struct SurfpoolRpcVersionInfo {
26 /// The current version of surfpool
27 pub surfpool_version: String,
28 /// The current version of solana-core
29 pub solana_core: String,
30 /// first 4 bytes of the FeatureSet identifier
31 pub feature_set: Option<u32>,
32}
33
34#[rpc]
35pub trait Minimal {
36 type Metadata;
37
38 /// Returns the balance (in lamports) of the account at the provided public key.
39 ///
40 /// This endpoint queries the current or historical balance of an account, depending on the optional commitment level provided in the config.
41 ///
42 /// ## Parameters
43 /// - `pubkey_str`: The base-58 encoded public key of the account to query.
44 /// - `_config` *(optional)*: [`RpcContextConfig`] specifying commitment level and/or minimum context slot.
45 ///
46 /// ## Returns
47 /// An [`RpcResponse<u64>`] where the value is the balance in lamports.
48 ///
49 /// ## Example Request
50 /// ```json
51 /// {
52 /// "jsonrpc": "2.0",
53 /// "id": 1,
54 /// "method": "getBalance",
55 /// "params": [
56 /// "4Nd1mXUmh23rQk8VN7wM9hEnfxqrrB1yrn11eW9gMoVr"
57 /// ]
58 /// }
59 /// ```
60 ///
61 /// ## Example Response
62 /// ```json
63 /// {
64 /// "jsonrpc": "2.0",
65 /// "result": {
66 /// "context": {
67 /// "slot": 1085597
68 /// },
69 /// "value": 20392800
70 /// },
71 /// "id": 1
72 /// }
73 /// ```
74 ///
75 /// # Notes
76 /// - 1 SOL = 1,000,000,000 lamports.
77 /// - Use commitment level in the config to specify whether the balance should be fetched from processed, confirmed, or finalized state.
78 ///
79 /// # See Also
80 /// - `getAccountInfo`, `getTokenAccountBalance`
81 #[rpc(meta, name = "getBalance")]
82 fn get_balance(
83 &self,
84 meta: Self::Metadata,
85 pubkey_str: String,
86 _config: Option<RpcContextConfig>,
87 ) -> BoxFuture<Result<RpcResponse<u64>>>;
88
89 /// Returns information about the current epoch.
90 ///
91 /// This endpoint provides epoch-related data such as the current epoch number, the total number of slots in the epoch,
92 /// the current slot index within the epoch, and the absolute slot number.
93 ///
94 /// ## Parameters
95 /// - `config` *(optional)*: [`RpcContextConfig`] for specifying commitment level and/or minimum context slot.
96 ///
97 /// ## Returns
98 /// An [`EpochInfo`] struct containing information about the current epoch.
99 ///
100 /// ## Example Request
101 /// ```json
102 /// {
103 /// "jsonrpc": "2.0",
104 /// "id": 1,
105 /// "method": "getEpochInfo"
106 /// }
107 /// ```
108 ///
109 /// ## Example Response
110 /// ```json
111 /// {
112 /// "jsonrpc": "2.0",
113 /// "result": {
114 /// "epoch": 278,
115 /// "slotIndex": 423,
116 /// "slotsInEpoch": 432000,
117 /// "absoluteSlot": 124390823,
118 /// "blockHeight": 18962432,
119 /// "transactionCount": 981234523
120 /// },
121 /// "id": 1
122 /// }
123 /// ```
124 ///
125 /// # Notes
126 /// - The `slotIndex` is the current slot's position within the epoch.
127 /// - `slotsInEpoch` may vary due to network adjustments (e.g., warm-up periods).
128 /// - The `commitment` field in the config can influence how recent the returned data is.
129 ///
130 /// # See Also
131 /// - `getEpochSchedule`, `getSlot`, `getBlockHeight`
132 #[rpc(meta, name = "getEpochInfo")]
133 fn get_epoch_info(
134 &self,
135 meta: Self::Metadata,
136 config: Option<RpcContextConfig>,
137 ) -> Result<EpochInfo>;
138
139 /// Returns the genesis hash of the blockchain.
140 ///
141 /// The genesis hash is a unique identifier that represents the state of the blockchain at the genesis block (the very first block).
142 /// This can be used to validate the integrity of the blockchain and ensure that a node is operating with the correct blockchain data.
143 ///
144 /// ## Parameters
145 /// - None.
146 ///
147 /// ## Returns
148 /// A `String` containing the base-58 encoded genesis hash.
149 ///
150 /// ## Example Request
151 /// ```json
152 /// {
153 /// "jsonrpc": "2.0",
154 /// "id": 1,
155 /// "method": "getGenesisHash"
156 /// }
157 /// ```
158 ///
159 /// ## Example Response
160 /// ```json
161 /// {
162 /// "jsonrpc": "2.0",
163 /// "result": "5eymX3jrWXcKqD1tsB2BzAB6gX9LP2pLrpVG6KwBSoZJ"
164 /// "id": 1
165 /// }
166 /// ```
167 ///
168 /// # Notes
169 /// - The genesis hash is a critical identifier for validating the blockchain’s origin and initial state.
170 /// - This endpoint does not require any parameters and provides a quick way to verify the genesis hash for blockchain verification or initial setup.
171 ///
172 /// # See Also
173 /// - `getEpochInfo`, `getBlock`, `getClusterNodes`
174 #[rpc(meta, name = "getGenesisHash")]
175 fn get_genesis_hash(&self, meta: Self::Metadata) -> Result<String>;
176
177 /// Returns the health status of the blockchain node.
178 ///
179 /// This method checks the health of the node and returns a status indicating whether the node is in a healthy state
180 /// or if it is experiencing any issues such as being out of sync with the network or encountering any failures.
181 ///
182 /// ## Parameters
183 /// - None.
184 ///
185 /// ## Returns
186 /// A `String` indicating the health status of the node:
187 /// - `"ok"`: The node is healthy and synchronized with the network.
188 /// - `"failed"`: The node is not healthy or is experiencing issues.
189 ///
190 /// ## Example Request
191 /// ```json
192 /// {
193 /// "jsonrpc": "2.0",
194 /// "id": 1,
195 /// "method": "getHealth"
196 /// }
197 /// ```
198 ///
199 /// ## Example Response
200 /// ```json
201 /// {
202 /// "jsonrpc": "2.0",
203 /// "result": "ok",
204 /// "id": 1
205 /// }
206 /// ```
207 ///
208 /// # Notes
209 /// - The `"ok"` response means that the node is fully operational and synchronized with the blockchain.
210 /// - The `"failed"` response indicates that the node is either out of sync, has encountered an error, or is not functioning properly.
211 /// - This is typically used to monitor the health of the node in production environments.
212 ///
213 /// # See Also
214 /// - `getGenesisHash`, `getEpochInfo`, `getBlock`
215 #[rpc(meta, name = "getHealth")]
216 fn get_health(&self, meta: Self::Metadata) -> Result<String>;
217
218 /// Returns the identity (public key) of the node.
219 ///
220 /// This method retrieves the current identity of the node, which is represented by a public key.
221 /// The identity is used to uniquely identify the node on the network.
222 ///
223 /// ## Parameters
224 /// - None.
225 ///
226 /// ## Returns
227 /// A `RpcIdentity` object containing the identity of the node:
228 /// - `identity`: The base-58 encoded public key of the node's identity.
229 ///
230 /// ## Example Request
231 /// ```json
232 /// {
233 /// "jsonrpc": "2.0",
234 /// "id": 1,
235 /// "method": "getIdentity"
236 /// }
237 /// ```
238 ///
239 /// ## Example Response
240 /// ```json
241 /// {
242 /// "jsonrpc": "2.0",
243 /// "result": {
244 /// "identity": "Base58EncodedPublicKeyHere"
245 /// },
246 /// "id": 1
247 /// }
248 /// ```
249 ///
250 /// # Notes
251 /// - The identity returned is a base-58 encoded public key representing the current node.
252 /// - This identity is often used for network identification and security.
253 ///
254 /// # See Also
255 /// - `getGenesisHash`, `getHealth`, `getBlock`
256 #[rpc(meta, name = "getIdentity")]
257 fn get_identity(&self, meta: Self::Metadata) -> Result<RpcIdentity>;
258
259 /// Returns the current slot of the ledger.
260 ///
261 /// This method retrieves the current slot number in the blockchain, which represents a point in the ledger's history.
262 /// Slots are used to organize and validate the timing of transactions in the network.
263 ///
264 /// ## Parameters
265 /// - `config` (optional): Configuration options for the request, such as commitment level or context slot. Defaults to `None`.
266 ///
267 /// ## Returns
268 /// A `Slot` value representing the current slot of the ledger.
269 ///
270 /// ## Example Request
271 /// ```json
272 /// {
273 /// "jsonrpc": "2.0",
274 /// "id": 1,
275 /// "method": "getSlot"
276 /// }
277 /// ```
278 ///
279 /// ## Example Response
280 /// ```json
281 /// {
282 /// "jsonrpc": "2.0",
283 /// "result": 12345678,
284 /// "id": 1
285 /// }
286 /// ```
287 ///
288 /// # Notes
289 /// - The slot represents the position in the ledger. It increments over time as new blocks are produced.
290 ///
291 /// # See Also
292 /// - `getBlock`, `getEpochInfo`, `getGenesisHash`
293 #[rpc(meta, name = "getSlot")]
294 fn get_slot(&self, meta: Self::Metadata, config: Option<RpcContextConfig>) -> Result<Slot>;
295
296 /// Returns the current block height.
297 ///
298 /// This method retrieves the height of the most recent block in the ledger, which is an indicator of how many blocks have been added to the blockchain. The block height is the number of blocks that have been produced since the genesis block.
299 ///
300 /// ## Parameters
301 /// - `config` (optional): Configuration options for the request, such as commitment level or context slot. Defaults to `None`.
302 ///
303 /// ## Returns
304 /// A `u64` representing the current block height of the ledger.
305 ///
306 /// ## Example Request
307 /// ```json
308 /// {
309 /// "jsonrpc": "2.0",
310 /// "id": 1,
311 /// "method": "getBlockHeight"
312 /// }
313 /// ```
314 ///
315 /// ## Example Response
316 /// ```json
317 /// {
318 /// "jsonrpc": "2.0",
319 /// "result": 12345678,
320 /// "id": 1
321 /// }
322 /// ```
323 ///
324 /// # Notes
325 /// - The block height reflects the number of blocks produced in the ledger, starting from the genesis block. It is incremented each time a new block is added.
326 ///
327 /// # See Also
328 /// - `getSlot`, `getEpochInfo`, `getGenesisHash`
329 #[rpc(meta, name = "getBlockHeight")]
330 fn get_block_height(
331 &self,
332 meta: Self::Metadata,
333 config: Option<RpcContextConfig>,
334 ) -> Result<u64>;
335
336 /// Returns information about the highest snapshot slot.
337 ///
338 /// This method retrieves information about the most recent snapshot slot, which refers to the slot in the blockchain where the most recent snapshot has been taken. A snapshot is a point-in-time capture of the state of the ledger, allowing for quicker validation of the state without processing every transaction.
339 ///
340 /// ## Parameters
341 /// - `meta`: Metadata passed with the request, such as the client’s request context.
342 ///
343 /// ## Returns
344 /// A `RpcSnapshotSlotInfo` containing information about the highest snapshot slot.
345 ///
346 /// ## Example Request
347 /// ```json
348 /// {
349 /// "jsonrpc": "2.0",
350 /// "id": 1,
351 /// "method": "getHighestSnapshotSlot"
352 /// }
353 /// ```
354 ///
355 /// ## Example Response
356 /// ```json
357 /// {
358 /// "jsonrpc": "2.0",
359 /// "result": {
360 /// "slot": 987654,
361 /// "root": "A9B7F1A4D1D55D0635B905E5AB6341C5D9F7F4D2A1160C53B5647B1E3259BB24"
362 /// },
363 /// "id": 1
364 /// }
365 /// ```
366 ///
367 /// # Notes
368 /// - The snapshot slot represents the most recent snapshot in the blockchain and is used for more efficient state validation and recovery.
369 /// - The result also includes the root, which is the blockhash at the snapshot point.
370 ///
371 /// # See Also
372 /// - `getBlock`, `getSnapshotInfo`
373 #[rpc(meta, name = "getHighestSnapshotSlot")]
374 fn get_highest_snapshot_slot(&self, meta: Self::Metadata) -> Result<RpcSnapshotSlotInfo>;
375
376 /// Returns the total number of transactions processed by the blockchain.
377 ///
378 /// This method retrieves the number of transactions that have been processed in the blockchain up to the current point. It provides a snapshot of the transaction throughput and can be useful for monitoring and performance analysis.
379 ///
380 /// ## Parameters
381 /// - `meta`: Metadata passed with the request, such as the client’s request context.
382 /// - `config`: Optional configuration for the request, such as commitment settings or minimum context slot.
383 ///
384 /// ## Returns
385 /// A `u64` representing the total transaction count.
386 ///
387 /// ## Example Request
388 /// ```json
389 /// {
390 /// "jsonrpc": "2.0",
391 /// "id": 1,
392 /// "method": "getTransactionCount"
393 /// }
394 /// ```
395 ///
396 /// ## Example Response
397 /// ```json
398 /// {
399 /// "jsonrpc": "2.0",
400 /// "result": 1234567890,
401 /// "id": 1
402 /// }
403 /// ```
404 ///
405 /// # Notes
406 /// - This method gives a cumulative count of all transactions in the blockchain from the start of the network.
407 ///
408 /// # See Also
409 /// - `getBlockHeight`, `getEpochInfo`
410 #[rpc(meta, name = "getTransactionCount")]
411 fn get_transaction_count(
412 &self,
413 meta: Self::Metadata,
414 config: Option<RpcContextConfig>,
415 ) -> Result<u64>;
416
417 /// Returns the current version of the server or application.
418 ///
419 /// This method retrieves the version information for the server or application. It provides details such as the version number and additional metadata that can help with compatibility checks or updates.
420 ///
421 /// ## Parameters
422 /// - `meta`: Metadata passed with the request, such as the client’s request context.
423 ///
424 /// ## Returns
425 /// A `SurfpoolRpcVersionInfo` object containing the version details.
426 ///
427 /// ## Example Request
428 /// ```json
429 /// {
430 /// "jsonrpc": "2.0",
431 /// "id": 1,
432 /// "method": "getVersion"
433 /// }
434 /// ```
435 ///
436 /// ## Example Response
437 /// ```json
438 /// {
439 /// "jsonrpc": "2.0",
440 /// "result": {
441 /// "surfpool_version": "1.2.3",
442 /// "solana_core": "1.9.0",
443 /// "feature_set": 12345
444 /// },
445 /// "id": 1
446 /// }
447 /// ```
448 ///
449 /// # Notes
450 /// - The version information typically includes the version number of `surfpool`, the version of `solana-core`, and a `feature_set` identifier (first 4 bytes).
451 /// - The `feature_set` field may not always be present, depending on whether a feature set identifier is available.
452 ///
453 /// # See Also
454 /// - `getHealth`, `getIdentity`
455 #[rpc(meta, name = "getVersion")]
456 fn get_version(&self, meta: Self::Metadata) -> Result<SurfpoolRpcVersionInfo>;
457
458 /// Returns vote account information.
459 ///
460 /// This method retrieves the current status of vote accounts, including information about the validator’s vote account and whether it is delinquent. The response includes vote account details such as the stake, commission, vote history, and more.
461 ///
462 /// ## Parameters
463 /// - `meta`: Metadata passed with the request, such as the client’s request context.
464 /// - `config`: Optional configuration parameters, such as specific vote account addresses or commitment settings.
465 ///
466 /// ## Returns
467 /// A `RpcVoteAccountStatus` object containing details about the current and delinquent vote accounts.
468 ///
469 /// ## Example Request
470 /// ```json
471 /// {
472 /// "jsonrpc": "2.0",
473 /// "id": 1,
474 /// "method": "getVoteAccounts",
475 /// "params": [{}]
476 /// }
477 /// ```
478 ///
479 /// ## Example Response
480 /// ```json
481 /// {
482 /// "jsonrpc": "2.0",
483 /// "result": {
484 /// "current": [
485 /// {
486 /// "votePubkey": "votePubkeyBase58",
487 /// "nodePubkey": "nodePubkeyBase58",
488 /// "activatedStake": 1000000,
489 /// "commission": 5,
490 /// "epochVoteAccount": true,
491 /// "epochCredits": [[1, 1000, 900], [2, 1100, 1000]],
492 /// "lastVote": 1000,
493 /// "rootSlot": 1200
494 /// }
495 /// ],
496 /// "delinquent": [
497 /// {
498 /// "votePubkey": "delinquentVotePubkeyBase58",
499 /// "nodePubkey": "delinquentNodePubkeyBase58",
500 /// "activatedStake": 0,
501 /// "commission": 10,
502 /// "epochVoteAccount": false,
503 /// "epochCredits": [[1, 500, 400]],
504 /// "lastVote": 0,
505 /// "rootSlot": 0
506 /// }
507 /// ]
508 /// },
509 /// "id": 1
510 /// }
511 /// ```
512 ///
513 /// # Notes
514 /// - The `current` field contains details about vote accounts that are active and have current stake.
515 /// - The `delinquent` field contains details about vote accounts that have become delinquent due to inactivity or other issues.
516 /// - The `epochCredits` field contains historical voting data.
517 ///
518 /// # See Also
519 /// - `getHealth`, `getIdentity`, `getVersion`
520 #[rpc(meta, name = "getVoteAccounts")]
521 fn get_vote_accounts(
522 &self,
523 meta: Self::Metadata,
524 config: Option<RpcGetVoteAccountsConfig>,
525 ) -> Result<RpcVoteAccountStatus>;
526
527 /// Returns the leader schedule for the given configuration or slot.
528 ///
529 /// This method retrieves the leader schedule for the given slot or configuration, providing a map of validator identities to slot indices within a given range.
530 ///
531 /// ## Parameters
532 /// - `meta`: Metadata passed with the request, such as the client’s request context.
533 /// - `options`: Optional configuration wrapper, which can either be a specific slot or a full configuration.
534 /// - `config`: Optional configuration containing the validator identity and commitment level.
535 ///
536 /// ## Returns
537 /// An `Option<RpcLeaderSchedule>` containing a map of leader identities (base-58 encoded pubkeys) to slot indices, relative to the first epoch slot.
538 ///
539 /// ## Example Request
540 /// ```json
541 /// {
542 /// "jsonrpc": "2.0",
543 /// "id": 1,
544 /// "method": "getLeaderSchedule",
545 /// "params": [{}]
546 /// }
547 /// ```
548 ///
549 /// ## Example Response
550 /// ```json
551 /// {
552 /// "jsonrpc": "2.0",
553 /// "result": {
554 /// "votePubkey1": [0, 2, 4],
555 /// "votePubkey2": [1, 3, 5]
556 /// },
557 /// "id": 1
558 /// }
559 /// ```
560 ///
561 /// # Notes
562 /// - The returned map contains validator identities as keys (base-58 encoded strings), with slot indices as values.
563 ///
564 /// # See Also
565 /// - `getSlot`, `getBlockHeight`, `getEpochInfo`
566 #[rpc(meta, name = "getLeaderSchedule")]
567 fn get_leader_schedule(
568 &self,
569 meta: Self::Metadata,
570 options: Option<RpcLeaderScheduleConfigWrapper>,
571 config: Option<RpcLeaderScheduleConfig>,
572 ) -> Result<Option<RpcLeaderSchedule>>;
573}
574
575#[derive(Clone)]
576pub struct SurfpoolMinimalRpc;
577impl Minimal for SurfpoolMinimalRpc {
578 type Metadata = Option<RunloopContext>;
579
580 fn get_balance(
581 &self,
582 meta: Self::Metadata,
583 pubkey_str: String,
584 _config: Option<RpcContextConfig>, // TODO: use config
585 ) -> BoxFuture<Result<RpcResponse<u64>>> {
586 let pubkey = match verify_pubkey(&pubkey_str) {
587 Ok(res) => res,
588 Err(e) => return e.into(),
589 };
590
591 let svm_locker = match meta.get_svm_locker() {
592 Ok(res) => res,
593 Err(e) => return Box::pin(future::err(e.into())),
594 };
595
596 Box::pin(async move {
597 let mut svm_writer = svm_locker.write().await;
598 let res = svm_writer
599 .get_account_mut(
600 &pubkey,
601 GetAccountStrategy::LocalThenConnectionOrDefault(None),
602 )
603 .await?;
604 let balance = match res {
605 Some(account) => account.lamports,
606 None => 0,
607 };
608
609 Ok(RpcResponse {
610 context: RpcResponseContext::new(svm_writer.get_latest_absolute_slot()),
611 value: balance,
612 })
613 })
614 }
615
616 fn get_epoch_info(
617 &self,
618 meta: Self::Metadata,
619 _config: Option<RpcContextConfig>,
620 ) -> Result<EpochInfo> {
621 meta.with_svm_reader(|svm_reader| svm_reader.latest_epoch_info.clone())
622 .map_err(Into::into)
623 }
624
625 fn get_genesis_hash(&self, _meta: Self::Metadata) -> Result<String> {
626 not_implemented_err()
627 }
628
629 fn get_health(&self, _meta: Self::Metadata) -> Result<String> {
630 // todo: we could check the time from the state clock and compare
631 Ok("ok".to_string())
632 }
633
634 fn get_identity(&self, _meta: Self::Metadata) -> Result<RpcIdentity> {
635 not_implemented_err()
636 }
637
638 fn get_slot(&self, meta: Self::Metadata, _config: Option<RpcContextConfig>) -> Result<Slot> {
639 meta.with_svm_reader(|svm_reader| svm_reader.get_latest_absolute_slot().into())
640 .map_err(Into::into)
641 }
642
643 fn get_block_height(
644 &self,
645 meta: Self::Metadata,
646 _config: Option<RpcContextConfig>,
647 ) -> Result<u64> {
648 meta.with_svm_reader(|svm_reader| svm_reader.latest_epoch_info.block_height)
649 .map_err(Into::into)
650 }
651
652 fn get_highest_snapshot_slot(&self, _meta: Self::Metadata) -> Result<RpcSnapshotSlotInfo> {
653 not_implemented_err()
654 }
655
656 fn get_transaction_count(
657 &self,
658 meta: Self::Metadata,
659 _config: Option<RpcContextConfig>,
660 ) -> Result<u64> {
661 meta.with_svm_reader(|svm_reader| svm_reader.transactions_processed as u64)
662 .map_err(Into::into)
663 }
664
665 fn get_version(&self, _: Self::Metadata) -> Result<SurfpoolRpcVersionInfo> {
666 let version = solana_version::Version::default();
667
668 Ok(SurfpoolRpcVersionInfo {
669 surfpool_version: format!("surfpool_v{}", SURFPOOL_VERSION),
670 solana_core: version.to_string(),
671 feature_set: Some(version.feature_set),
672 })
673 }
674
675 // TODO: Refactor `agave-validator wait-for-restart-window` to not require this method, so
676 // it can be removed from rpc_minimal
677 fn get_vote_accounts(
678 &self,
679 _meta: Self::Metadata,
680 _config: Option<RpcGetVoteAccountsConfig>,
681 ) -> Result<RpcVoteAccountStatus> {
682 Ok(RpcVoteAccountStatus {
683 current: vec![],
684 delinquent: vec![],
685 })
686 }
687
688 // TODO: Refactor `agave-validator wait-for-restart-window` to not require this method, so
689 // it can be removed from rpc_minimal
690 fn get_leader_schedule(
691 &self,
692 _meta: Self::Metadata,
693 _options: Option<RpcLeaderScheduleConfigWrapper>,
694 _config: Option<RpcLeaderScheduleConfig>,
695 ) -> Result<Option<RpcLeaderSchedule>> {
696 // let (slot, maybe_config) = options.map(|options| options.unzip()).unwrap_or_default();
697 // let config = maybe_config.or(config).unwrap_or_default();
698
699 // if let Some(ref identity) = config.identity {
700 // let _ = verify_pubkey(identity)?;
701 // }
702
703 // let bank = meta.bank(config.commitment);
704 // let slot = slot.unwrap_or_else(|| bank.slot());
705 // let epoch = bank.epoch_schedule().get_epoch(slot);
706
707 // println!("get_leader_schedule rpc request received: {:?}", slot);
708
709 // Ok(meta
710 // .leader_schedule_cache
711 // .get_epoch_leader_schedule(epoch)
712 // .map(|leader_schedule| {
713 // let mut schedule_by_identity =
714 // solana_ledger::leader_schedule_utils::leader_schedule_by_identity(
715 // leader_schedule.get_slot_leaders().iter().enumerate(),
716 // );
717 // if let Some(identity) = config.identity {
718 // schedule_by_identity.retain(|k, _| *k == identity);
719 // }
720 // schedule_by_identity
721 // }))
722 not_implemented_err()
723 }
724}
725
726#[cfg(test)]
727mod tests {
728 use super::*;
729 use crate::tests::helpers::TestSetup;
730
731 #[test]
732 fn test_get_health() {
733 let setup = TestSetup::new(SurfpoolMinimalRpc);
734 let result = setup.rpc.get_health(Some(setup.context));
735 assert_eq!(result.unwrap(), "ok");
736 }
737
738 #[test]
739 fn test_get_transaction_count() {
740 let setup = TestSetup::new(SurfpoolMinimalRpc);
741 let transactions_processed = setup
742 .context
743 .surfnet_svm
744 .blocking_read()
745 .transactions_processed;
746 let result = setup.rpc.get_transaction_count(Some(setup.context), None);
747 assert_eq!(result.unwrap(), transactions_processed);
748 }
749
750 #[test]
751 fn test_get_epoch_info() {
752 let info = EpochInfo {
753 epoch: 1,
754 slot_index: 1,
755 slots_in_epoch: 1,
756 absolute_slot: 1,
757 block_height: 1,
758 transaction_count: Some(1),
759 };
760 let setup = TestSetup::new_with_epoch_info(SurfpoolMinimalRpc, info.clone());
761 let result = setup.rpc.get_epoch_info(Some(setup.context), None).unwrap();
762 assert_eq!(result, info);
763 }
764
765 #[test]
766 fn test_get_slot() {
767 let setup = TestSetup::new(SurfpoolMinimalRpc);
768 let result = setup.rpc.get_slot(Some(setup.context), None).unwrap();
769 assert_eq!(result, 123);
770 }
771
772 #[test]
773 fn test_get_version() {
774 let setup = TestSetup::new(SurfpoolMinimalRpc);
775 let result = setup.rpc.get_version(Some(setup.context)).unwrap();
776 assert!(!result.solana_core.is_empty());
777 assert!(result.feature_set.is_some());
778 assert_eq!(
779 result.surfpool_version,
780 format!("surfpool_v{}", SURFPOOL_VERSION)
781 );
782 }
783
784 #[test]
785 fn test_get_vote_accounts() {
786 let setup = TestSetup::new(SurfpoolMinimalRpc);
787 let result = setup
788 .rpc
789 .get_vote_accounts(Some(setup.context), None)
790 .unwrap();
791 assert!(result.current.is_empty());
792 assert!(result.delinquent.is_empty());
793 }
794}