Skip to main content

sol_rpc_router/
lib.rs

1//! Solana RPC Router
2//!
3//! This router splits Solana RPC requests into several RPC providers, taking into account
4//! rate limits of each provider.
5
6use base64::Engine;
7use base64::prelude::BASE64_STANDARD;
8use bincode::serialize;
9use futures::join;
10use log::{debug, info, trace};
11use serde::de::DeserializeOwned;
12use serde_json::{Value, json};
13use solana_account::Account;
14use solana_account_decoder_client_types::UiAccountData;
15use solana_account_decoder_client_types::token::{TokenAccountType, UiTokenAccount};
16use solana_clock::{DEFAULT_MS_PER_SLOT, Epoch, Slot, UnixTimestamp};
17use solana_epoch_info::EpochInfo;
18use solana_epoch_schedule::EpochSchedule;
19use solana_hash::Hash;
20use solana_pubkey::Pubkey;
21use solana_rpc_client::api::client_error::{
22    Error as ClientError, ErrorKind as ClientErrorKind, Result as ClientResult,
23};
24use solana_rpc_client::api::request::RpcRequest;
25pub use solana_rpc_client::rpc_client::{
26    GetConfirmedSignaturesForAddress2Config, SerializableMessage, SerializableTransaction,
27};
28use solana_rpc_client_api::config::{
29    CommitmentConfig, RpcAccountInfoConfig, RpcBlockConfig, RpcBlockProductionConfig,
30    RpcEpochConfig, RpcGetVoteAccountsConfig, RpcLargestAccountsConfig, RpcLeaderScheduleConfig,
31    RpcProgramAccountsConfig, RpcRequestAirdropConfig, RpcSendTransactionConfig,
32    RpcSignaturesForAddressConfig, RpcSimulateTransactionConfig, RpcTokenAccountsFilter,
33    RpcTransactionConfig, UiAccountEncoding, UiTransactionEncoding,
34};
35use solana_rpc_client_api::request::{RpcError, RpcResponseErrorData, TokenAccountsFilter};
36use solana_rpc_client_api::response::transaction::Signature;
37use solana_rpc_client_api::response::{
38    OptionalContext, Response, RpcAccountBalance, RpcBlockProduction, RpcBlockhash,
39    RpcConfirmedTransactionStatusWithSignature, RpcContactInfo, RpcIdentity, RpcInflationGovernor,
40    RpcInflationRate, RpcInflationReward, RpcKeyedAccount, RpcLeaderSchedule, RpcPerfSample,
41    RpcPrioritizationFee, RpcResult, RpcSimulateTransactionResult, RpcSnapshotSlotInfo, RpcSupply,
42    RpcTokenAccountBalance, RpcVersionInfo, RpcVoteAccountStatus, TransactionResult, UiAccount,
43    UiTokenAmount,
44};
45use solana_transaction_status_client_types::{
46    EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus,
47    UiConfirmedBlock,
48};
49use solana_vote_interface::state::MAX_LOCKOUT_HISTORY;
50use tokio::time::sleep;
51
52use std::str::FromStr;
53use std::sync::Arc;
54use std::time::{Duration, Instant};
55use tokio::sync::{Mutex, mpsc, oneshot};
56
57use crate::config::RpcClientConfig;
58use crate::provider::RpcRequestWrapper;
59
60pub mod config;
61pub mod provider;
62
63/// Main RPC client that routes requests to multiple providers.
64#[derive(Debug, Clone)]
65pub struct RpcClient {
66    config: RpcClientConfig,
67    sender: mpsc::Sender<RpcRequestWrapper>,
68}
69
70impl RpcClient {
71    /// Create a new RPC client with the given configuration
72    pub fn new(config: RpcClientConfig) -> Self {
73        let (sender, receiver) = mpsc::channel(10_000);
74        let shared_receiver = Arc::new(Mutex::new(receiver));
75
76        for provider_config in &config.providers {
77            let provider = provider::RpcProvider::new(provider_config.clone());
78            let shared_receiver_clone = Arc::clone(&shared_receiver);
79
80            tokio::spawn(provider.run(shared_receiver_clone));
81        }
82
83        Self { config, sender }
84    }
85
86    pub fn commitment(&self) -> CommitmentConfig {
87        self.config.commitment
88    }
89
90    /// Send a request to one of the providers
91    pub async fn send<T: DeserializeOwned>(
92        &self,
93        request: RpcRequest,
94        params: serde_json::Value,
95    ) -> ClientResult<T> {
96        let (sender, receiver) = oneshot::channel();
97        let request_wrapper = RpcRequestWrapper {
98            request,
99            params,
100            sender,
101        };
102        self.sender.send(request_wrapper).await.map_err(|e| {
103            solana_rpc_client::api::client_error::Error {
104                request: None,
105                kind: Box::new(ClientErrorKind::Custom(e.to_string())),
106            }
107        })?;
108
109        let value = receiver
110            .await
111            .map_err(|e| solana_rpc_client::api::client_error::Error {
112                request: None,
113                kind: Box::new(ClientErrorKind::Custom(e.to_string())),
114            })??;
115
116        Ok(serde_json::from_value(value).map_err(serde_err_to_rpc_err)?)
117    }
118
119    /// Submit a transaction and wait for confirmation.
120    ///
121    /// Once this function returns successfully, the given transaction is
122    /// guaranteed to be processed with the configured [commitment level][cl].
123    ///
124    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
125    ///
126    /// After sending the transaction, this method polls in a loop for the
127    /// status of the transaction until it has ben confirmed.
128    ///
129    /// # Errors
130    ///
131    /// If the transaction is not signed then an error with kind [`RpcError`] is
132    /// returned, containing an [`RpcResponseError`] with `code` set to
133    /// [`JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE`].
134    ///
135    /// If the preflight transaction simulation fails then an error with kind
136    /// [`RpcError`] is returned, containing an [`RpcResponseError`] with `code`
137    /// set to [`JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE`].
138    ///
139    /// If the receiving node is unhealthy, e.g. it is not fully synced to
140    /// the cluster, then an error with kind [`RpcError`] is returned,
141    /// containing an [`RpcResponseError`] with `code` set to
142    /// [`JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY`].
143    ///
144    /// [`RpcResponseError`]: RpcError::RpcResponseError
145    /// [`JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE`]: solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE
146    /// [`JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE`]: solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE
147    /// [`JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY`]: solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY
148    ///
149    /// # RPC Reference
150    ///
151    /// This method is built on the [`sendTransaction`] RPC method, and the
152    /// [`getLatestBlockhash`] RPC method.
153    ///
154    /// [`sendTransaction`]: https://solana.com/docs/rpc/http/sendtransaction
155    /// [`getLatestBlockhash`]: https://solana.com/docs/rpc/http/getlatestblockhash
156    ///
157    /// # Examples
158    ///
159    /// ```ignore
160    /// # use solana_rpc_client_api::client_error::Error;
161    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
162    /// # use solana_keypair::Keypair;
163    /// # use solana_system_transaction as system_transaction;
164    /// # use solana_signature::Signature;
165    /// # use solana_signer::Signer;
166    /// # futures::executor::block_on(async {
167    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
168    /// #     let alice = Keypair::new();
169    /// #     let bob = Keypair::new();
170    /// #     let lamports = 50;
171    /// #     let latest_blockhash = rpc_client.get_latest_blockhash().await?;
172    /// let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
173    /// let signature = rpc_client.send_and_confirm_transaction(&tx).await?;
174    /// #     Ok::<(), Error>(())
175    /// # })?;
176    /// # Ok::<(), Error>(())
177    /// ```
178    pub async fn send_and_confirm_transaction(
179        &self,
180        transaction: &impl SerializableTransaction,
181    ) -> ClientResult<Signature> {
182        const SEND_RETRIES: usize = 1;
183        const GET_STATUS_RETRIES: usize = usize::MAX;
184
185        'sending: for _ in 0..SEND_RETRIES {
186            let (latest_blockhash, signature) = self
187                .send_transaction_and_get_latest_blockhash(transaction, None)
188                .await?;
189
190            for status_retry in 0..GET_STATUS_RETRIES {
191                match self.get_signature_status(&signature).await? {
192                    Some(Ok(_)) => return Ok(signature),
193                    Some(Err(e)) => return Err(e.into()),
194                    None => {
195                        if !self
196                            .is_blockhash_valid(&latest_blockhash, CommitmentConfig::processed())
197                            .await?
198                        {
199                            // Block hash is not found by some reason
200                            break 'sending;
201                        } else if cfg!(not(test))
202                            // Ignore sleep at last step.
203                            && status_retry < GET_STATUS_RETRIES
204                        {
205                            // Retry twice a second
206                            sleep(Duration::from_millis(500)).await;
207                            continue;
208                        }
209                    }
210                }
211            }
212        }
213
214        Err(RpcError::ForUser(
215            "unable to confirm transaction. This can happen in situations such as transaction \
216             expiration and insufficient fee-payer funds"
217                .to_string(),
218        )
219        .into())
220    }
221
222    async fn send_transaction_and_get_latest_blockhash(
223        &self,
224        transaction: &impl SerializableTransaction,
225        config: Option<RpcSendTransactionConfig>,
226    ) -> ClientResult<(Hash, Signature)> {
227        let (latest_blockhash, signature) = join!(
228            async {
229                if transaction.uses_durable_nonce() {
230                    self.get_latest_blockhash_with_commitment(CommitmentConfig::processed())
231                        .await
232                        .map(|v| v.0)
233                } else {
234                    Ok(*transaction.get_recent_blockhash())
235                }
236            },
237            async {
238                if let Some(config) = config {
239                    self.send_transaction_with_config(transaction, config).await
240                } else {
241                    self.send_transaction(transaction).await
242                }
243            },
244        );
245
246        Ok((latest_blockhash?, signature?))
247    }
248
249    /// Submits a signed transaction to the network.
250    ///
251    /// Before a transaction is processed, the receiving node runs a "preflight
252    /// check" which verifies signatures, checks that the node is healthy,
253    /// and simulates the transaction. If the preflight check fails then an
254    /// error is returned immediately. Preflight checks can be disabled by
255    /// calling [`send_transaction_with_config`] and setting the
256    /// [`skip_preflight`] field of [`RpcSendTransactionConfig`] to `true`.
257    ///
258    /// This method does not wait for the transaction to be processed or
259    /// confirmed before returning successfully. To wait for the transaction to
260    /// be processed or confirmed, use the [`send_and_confirm_transaction`]
261    /// method.
262    ///
263    /// [`send_transaction_with_config`]: RpcClient::send_transaction_with_config
264    /// [`skip_preflight`]: solana_rpc_client_api::config::RpcSendTransactionConfig::skip_preflight
265    /// [`RpcSendTransactionConfig`]: solana_rpc_client_api::config::RpcSendTransactionConfig
266    /// [`send_and_confirm_transaction`]: RpcClient::send_and_confirm_transaction
267    ///
268    /// # Errors
269    ///
270    /// If the transaction is not signed then an error with kind [`RpcError`] is
271    /// returned, containing an [`RpcResponseError`] with `code` set to
272    /// [`JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE`].
273    ///
274    /// If the preflight transaction simulation fails then an error with kind
275    /// [`RpcError`] is returned, containing an [`RpcResponseError`] with `code`
276    /// set to [`JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE`].
277    ///
278    /// If the receiving node is unhealthy, e.g. it is not fully synced to
279    /// the cluster, then an error with kind [`RpcError`] is returned,
280    /// containing an [`RpcResponseError`] with `code` set to
281    /// [`JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY`].
282    ///
283    /// [`RpcResponseError`]: RpcError::RpcResponseError
284    /// [`JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE`]: solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE
285    /// [`JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE`]: solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE
286    /// [`JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY`]: solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY
287    ///
288    /// # RPC Reference
289    ///
290    /// This method is built on the [`sendTransaction`] RPC method.
291    ///
292    /// [`sendTransaction`]: https://solana.com/docs/rpc/http/sendtransaction
293    ///
294    /// # Examples
295    ///
296    /// ```ignore
297    /// # use solana_rpc_client_api::client_error::Error;
298    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
299    /// # use solana_hash::Hash;
300    /// # use solana_keypair::Keypair;
301    /// # use solana_system_transaction as system_transaction;
302    /// # use solana_signature::Signature;
303    /// # use solana_signer::Signer;
304    /// # futures::executor::block_on(async {
305    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
306    /// // Transfer lamports from Alice to Bob
307    /// #     let alice = Keypair::new();
308    /// #     let bob = Keypair::new();
309    /// #     let lamports = 50;
310    /// let latest_blockhash = rpc_client.get_latest_blockhash().await?;
311    /// let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
312    /// let signature = rpc_client.send_transaction(&tx).await?;
313    /// #     Ok::<(), Error>(())
314    /// # })?;
315    /// # Ok::<(), Error>(())
316    /// ```
317    pub async fn send_transaction(
318        &self,
319        transaction: &impl SerializableTransaction,
320    ) -> ClientResult<Signature> {
321        self.send_transaction_with_config(
322            transaction,
323            RpcSendTransactionConfig {
324                preflight_commitment: Some(self.commitment().commitment),
325                ..RpcSendTransactionConfig::default()
326            },
327        )
328        .await
329    }
330
331    /// Submits a signed transaction to the network.
332    ///
333    /// Before a transaction is processed, the receiving node runs a "preflight
334    /// check" which verifies signatures, checks that the node is healthy, and
335    /// simulates the transaction. If the preflight check fails then an error is
336    /// returned immediately. Preflight checks can be disabled by setting the
337    /// [`skip_preflight`] field of [`RpcSendTransactionConfig`] to `true`.
338    ///
339    /// This method does not wait for the transaction to be processed or
340    /// confirmed before returning successfully. To wait for the transaction to
341    /// be processed or confirmed, use the [`send_and_confirm_transaction`]
342    /// method.
343    ///
344    /// [`send_transaction_with_config`]: RpcClient::send_transaction_with_config
345    /// [`skip_preflight`]: solana_rpc_client_api::config::RpcSendTransactionConfig::skip_preflight
346    /// [`RpcSendTransactionConfig`]: solana_rpc_client_api::config::RpcSendTransactionConfig
347    /// [`send_and_confirm_transaction`]: RpcClient::send_and_confirm_transaction
348    ///
349    /// # Errors
350    ///
351    /// If preflight checks are enabled, if the transaction is not signed
352    /// then an error with kind [`RpcError`] is returned, containing an
353    /// [`RpcResponseError`] with `code` set to
354    /// [`JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE`].
355    ///
356    /// If preflight checks are enabled, if the preflight transaction simulation
357    /// fails then an error with kind [`RpcError`] is returned, containing an
358    /// [`RpcResponseError`] with `code` set to
359    /// [`JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE`].
360    ///
361    /// If the receiving node is unhealthy, e.g. it is not fully synced to
362    /// the cluster, then an error with kind [`RpcError`] is returned,
363    /// containing an [`RpcResponseError`] with `code` set to
364    /// [`JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY`].
365    ///
366    /// [`RpcResponseError`]: RpcError::RpcResponseError
367    /// [`JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE`]: solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_TRANSACTION_SIGNATURE_VERIFICATION_FAILURE
368    /// [`JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE`]: solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE
369    /// [`JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY`]: solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY
370    ///
371    /// # RPC Reference
372    ///
373    /// This method is built on the [`sendTransaction`] RPC method.
374    ///
375    /// [`sendTransaction`]: https://solana.com/docs/rpc/http/sendtransaction
376    ///
377    /// # Examples
378    ///
379    /// ```ignore
380    /// # use solana_rpc_client_api::{
381    /// #     client_error::Error,
382    /// #     config::RpcSendTransactionConfig,
383    /// # };
384    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
385    /// # use solana_hash::Hash;
386    /// # use solana_keypair::Keypair;
387    /// # use solana_system_transaction as system_transaction;
388    /// # use solana_signature::Signature;
389    /// # use solana_signer::Signer;
390    /// # futures::executor::block_on(async {
391    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
392    /// // Transfer lamports from Alice to Bob
393    /// #     let alice = Keypair::new();
394    /// #     let bob = Keypair::new();
395    /// #     let lamports = 50;
396    /// let latest_blockhash = rpc_client.get_latest_blockhash().await?;
397    /// let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
398    /// let config = RpcSendTransactionConfig {
399    ///     skip_preflight: true,
400    ///     .. RpcSendTransactionConfig::default()
401    /// };
402    /// let signature = rpc_client.send_transaction_with_config(
403    ///     &tx,
404    ///     config,
405    /// ).await?;
406    /// #     Ok::<(), Error>(())
407    /// # })?;
408    /// # Ok::<(), Error>(())
409    /// ```
410    pub async fn send_transaction_with_config(
411        &self,
412        transaction: &impl SerializableTransaction,
413        config: RpcSendTransactionConfig,
414    ) -> ClientResult<Signature> {
415        let encoding = config.encoding.unwrap_or(UiTransactionEncoding::Base64);
416        let preflight_commitment = CommitmentConfig {
417            commitment: config.preflight_commitment.unwrap_or_default(),
418        };
419        let config = RpcSendTransactionConfig {
420            encoding: Some(encoding),
421            preflight_commitment: Some(preflight_commitment.commitment),
422            ..config
423        };
424        let serialized_encoded = serialize_and_encode(transaction, encoding)?;
425        let signature_base58_str: String = match self
426            .send(
427                RpcRequest::SendTransaction,
428                json!([serialized_encoded, config]),
429            )
430            .await
431        {
432            Ok(signature_base58_str) => signature_base58_str,
433            Err(err) => {
434                if let ClientErrorKind::RpcError(RpcError::RpcResponseError {
435                    code,
436                    message,
437                    data,
438                }) = err.kind()
439                {
440                    debug!("{code} {message}");
441                    if let RpcResponseErrorData::SendTransactionPreflightFailure(
442                        RpcSimulateTransactionResult {
443                            logs: Some(logs), ..
444                        },
445                    ) = data
446                    {
447                        for (i, log) in logs.iter().enumerate() {
448                            debug!("{:>3}: {}", i + 1, log);
449                        }
450                        debug!("");
451                    }
452                }
453                return Err(err);
454            }
455        };
456
457        let signature = signature_base58_str
458            .parse::<Signature>()
459            .map_err(|err| Into::<ClientError>::into(RpcError::ParseError(err.to_string())))?;
460        // A mismatching RPC response signature indicates an issue with the RPC node, and
461        // should not be passed along to confirmation methods. The transaction may or may
462        // not have been submitted to the cluster, so callers should verify the success of
463        // the correct transaction signature independently.
464        if signature != *transaction.get_signature() {
465            Err(RpcError::RpcRequestError(format!(
466                "RPC node returned mismatched signature {:?}, expected {:?}",
467                signature,
468                transaction.get_signature()
469            ))
470            .into())
471        } else {
472            Ok(*transaction.get_signature())
473        }
474    }
475
476    /// Check the confirmation status of a transaction.
477    ///
478    /// Returns `true` if the given transaction succeeded and has been committed
479    /// with the configured [commitment level][cl], which can be retrieved with
480    /// the [`commitment`](RpcClient::commitment) method.
481    ///
482    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
483    ///
484    /// Note that this method does not wait for a transaction to be confirmed
485    /// &mdash; it only checks whether a transaction has been confirmed. To
486    /// submit a transaction and wait for it to confirm, use
487    /// [`send_and_confirm_transaction`][RpcClient::send_and_confirm_transaction].
488    ///
489    /// _This method returns `false` if the transaction failed, even if it has
490    /// been confirmed._
491    ///
492    /// # RPC Reference
493    ///
494    /// This method is built on the [`getSignatureStatuses`] RPC method.
495    ///
496    /// [`getSignatureStatuses`]: https://solana.com/docs/rpc/http/getsignaturestatuses
497    ///
498    /// # Examples
499    ///
500    /// ```ignore
501    /// # use solana_rpc_client_api::client_error::Error;
502    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
503    /// # use solana_keypair::Keypair;
504    /// # use solana_system_transaction as system_transaction;
505    /// # use solana_signature::Signature;
506    /// # use solana_signer::Signer;
507    /// # futures::executor::block_on(async {
508    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
509    /// // Transfer lamports from Alice to Bob and wait for confirmation
510    /// #     let alice = Keypair::new();
511    /// #     let bob = Keypair::new();
512    /// #     let lamports = 50;
513    /// let latest_blockhash = rpc_client.get_latest_blockhash().await?;
514    /// let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
515    /// let signature = rpc_client.send_transaction(&tx).await?;
516    ///
517    /// loop {
518    ///     let confirmed = rpc_client.confirm_transaction(&signature).await?;
519    ///     if confirmed {
520    ///         break;
521    ///     }
522    /// }
523    /// #     Ok::<(), Error>(())
524    /// # })?;
525    /// # Ok::<(), Error>(())
526    /// ```
527    pub async fn confirm_transaction(&self, signature: &Signature) -> ClientResult<bool> {
528        Ok(self
529            .confirm_transaction_with_commitment(signature, self.commitment())
530            .await?
531            .value)
532    }
533
534    /// Check the confirmation status of a transaction.
535    ///
536    /// Returns an [`RpcResult`] with value `true` if the given transaction
537    /// succeeded and has been committed with the given [commitment level][cl].
538    ///
539    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
540    ///
541    /// Note that this method does not wait for a transaction to be confirmed
542    /// &mdash; it only checks whether a transaction has been confirmed. To
543    /// submit a transaction and wait for it to confirm, use
544    /// [`send_and_confirm_transaction`][RpcClient::send_and_confirm_transaction].
545    ///
546    /// _This method returns an [`RpcResult`] with value `false` if the
547    /// transaction failed, even if it has been confirmed._
548    ///
549    /// # RPC Reference
550    ///
551    /// This method is built on the [`getSignatureStatuses`] RPC method.
552    ///
553    /// [`getSignatureStatuses`]: https://solana.com/docs/rpc/http/getsignaturestatuses
554    ///
555    /// # Examples
556    ///
557    /// ```ignore
558    /// # use solana_rpc_client_api::client_error::Error;
559    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
560    /// # use solana_commitment_config::CommitmentConfig;
561    /// # use solana_keypair::Keypair;
562    /// # use solana_signature::Signature;
563    /// # use solana_signer::Signer;
564    /// # use solana_system_transaction as system_transaction;
565    /// # use std::time::Duration;
566    /// # futures::executor::block_on(async {
567    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
568    /// // Transfer lamports from Alice to Bob and wait for confirmation
569    /// #     let alice = Keypair::new();
570    /// #     let bob = Keypair::new();
571    /// #     let lamports = 50;
572    /// let latest_blockhash = rpc_client.get_latest_blockhash().await?;
573    /// let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
574    /// let signature = rpc_client.send_transaction(&tx).await?;
575    ///
576    /// loop {
577    ///     let commitment_config = CommitmentConfig::processed();
578    ///     let confirmed = rpc_client.confirm_transaction_with_commitment(&signature, commitment_config).await?;
579    ///     if confirmed.value {
580    ///         break;
581    ///     }
582    /// }
583    /// #     Ok::<(), Error>(())
584    /// # })?;
585    /// # Ok::<(), Error>(())
586    /// ```
587    pub async fn confirm_transaction_with_commitment(
588        &self,
589        signature: &Signature,
590        commitment_config: CommitmentConfig,
591    ) -> RpcResult<bool> {
592        let Response { context, value } = self.get_signature_statuses(&[*signature]).await?;
593
594        Ok(Response {
595            context,
596            value: value[0]
597                .as_ref()
598                .filter(|result| result.satisfies_commitment(commitment_config))
599                .map(|result| result.status.is_ok())
600                .unwrap_or_default(),
601        })
602    }
603
604    /// Simulates sending a transaction.
605    ///
606    /// If the transaction fails, then the [`err`] field of the returned
607    /// [`RpcSimulateTransactionResult`] will be `Some`. Any logs emitted from
608    /// the transaction are returned in the [`logs`] field.
609    ///
610    /// [`err`]: solana_rpc_client_api::response::RpcSimulateTransactionResult::err
611    /// [`logs`]: solana_rpc_client_api::response::RpcSimulateTransactionResult::logs
612    ///
613    /// Simulating a transaction is similar to the ["preflight check"] that is
614    /// run by default when sending a transaction.
615    ///
616    /// ["preflight check"]: https://solana.com/docs/rpc/http/sendtransaction
617    ///
618    /// By default, signatures are not verified during simulation. To verify
619    /// signatures, call the [`simulate_transaction_with_config`] method, with
620    /// the [`sig_verify`] field of [`RpcSimulateTransactionConfig`] set to
621    /// `true`.
622    ///
623    /// [`simulate_transaction_with_config`]: RpcClient::simulate_transaction_with_config
624    /// [`sig_verify`]: solana_rpc_client_api::config::RpcSimulateTransactionConfig::sig_verify
625    ///
626    /// # RPC Reference
627    ///
628    /// This method is built on the [`simulateTransaction`] RPC method.
629    ///
630    /// [`simulateTransaction`]: https://solana.com/docs/rpc/http/simulatetransaction
631    ///
632    /// # Examples
633    ///
634    /// ```ignore
635    /// # use solana_rpc_client_api::{
636    /// #     client_error::Error,
637    /// #     response::RpcSimulateTransactionResult,
638    /// # };
639    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
640    /// # use solana_hash::Hash;
641    /// # use solana_keypair::Keypair;
642    /// # use solana_system_transaction as system_transaction;
643    /// # use solana_signature::Signature;
644    /// # use solana_signer::Signer;
645    /// # futures::executor::block_on(async {
646    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
647    /// // Transfer lamports from Alice to Bob
648    /// #     let alice = Keypair::new();
649    /// #     let bob = Keypair::new();
650    /// #     let lamports = 50;
651    /// let latest_blockhash = rpc_client.get_latest_blockhash().await?;
652    /// let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
653    /// let result = rpc_client.simulate_transaction(&tx).await?;
654    /// assert!(result.value.err.is_none());
655    /// #     Ok::<(), Error>(())
656    /// # })?;
657    /// # Ok::<(), Error>(())
658    /// ```
659    pub async fn simulate_transaction(
660        &self,
661        transaction: &impl SerializableTransaction,
662    ) -> RpcResult<RpcSimulateTransactionResult> {
663        self.simulate_transaction_with_config(
664            transaction,
665            RpcSimulateTransactionConfig {
666                commitment: Some(self.commitment()),
667                ..RpcSimulateTransactionConfig::default()
668            },
669        )
670        .await
671    }
672
673    /// Simulates sending a transaction.
674    ///
675    /// If the transaction fails, then the [`err`] field of the returned
676    /// [`RpcSimulateTransactionResult`] will be `Some`. Any logs emitted from
677    /// the transaction are returned in the [`logs`] field.
678    ///
679    /// [`err`]: solana_rpc_client_api::response::RpcSimulateTransactionResult::err
680    /// [`logs`]: solana_rpc_client_api::response::RpcSimulateTransactionResult::logs
681    ///
682    /// Simulating a transaction is similar to the ["preflight check"] that is
683    /// run by default when sending a transaction.
684    ///
685    /// ["preflight check"]: https://solana.com/docs/rpc/http/sendtransaction
686    ///
687    /// By default, signatures are not verified during simulation. To verify
688    /// signatures, call the [`simulate_transaction_with_config`] method, with
689    /// the [`sig_verify`] field of [`RpcSimulateTransactionConfig`] set to
690    /// `true`.
691    ///
692    /// [`simulate_transaction_with_config`]: RpcClient::simulate_transaction_with_config
693    /// [`sig_verify`]: solana_rpc_client_api::config::RpcSimulateTransactionConfig::sig_verify
694    ///
695    /// This method can additionally query information about accounts by
696    /// including them in the [`accounts`] field of the
697    /// [`RpcSimulateTransactionConfig`] argument, in which case those results
698    /// are reported in the [`accounts`][accounts2] field of the returned
699    /// [`RpcSimulateTransactionResult`].
700    ///
701    /// [`accounts`]: solana_rpc_client_api::config::RpcSimulateTransactionConfig::accounts
702    /// [accounts2]: solana_rpc_client_api::response::RpcSimulateTransactionResult::accounts
703    ///
704    /// # RPC Reference
705    ///
706    /// This method is built on the [`simulateTransaction`] RPC method.
707    ///
708    /// [`simulateTransaction`]: https://solana.com/docs/rpc/http/simulatetransaction
709    ///
710    /// # Examples
711    ///
712    /// ```ignore
713    /// # use solana_hash::Hash;
714    /// # use solana_keypair::Keypair;
715    /// # use solana_rpc_client_api::{
716    /// #     client_error::Error,
717    /// #     config::RpcSimulateTransactionConfig,
718    /// #     response::RpcSimulateTransactionResult,
719    /// # };
720    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
721    /// # use solana_signer::Signer;
722    /// # use solana_system_transaction as system_transaction;
723    /// # futures::executor::block_on(async {
724    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
725    /// // Transfer lamports from Alice to Bob
726    /// #     let alice = Keypair::new();
727    /// #     let bob = Keypair::new();
728    /// #     let lamports = 50;
729    /// let latest_blockhash = rpc_client.get_latest_blockhash().await?;
730    /// let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
731    /// let config = RpcSimulateTransactionConfig {
732    ///     sig_verify: true,
733    ///     .. RpcSimulateTransactionConfig::default()
734    /// };
735    /// let result = rpc_client.simulate_transaction_with_config(
736    ///     &tx,
737    ///     config,
738    /// ).await?;
739    /// assert!(result.value.err.is_none());
740    /// #     Ok::<(), Error>(())
741    /// # })?;
742    /// # Ok::<(), Error>(())
743    /// ```
744    pub async fn simulate_transaction_with_config(
745        &self,
746        transaction: &impl SerializableTransaction,
747        config: RpcSimulateTransactionConfig,
748    ) -> RpcResult<RpcSimulateTransactionResult> {
749        let encoding = config.encoding.unwrap_or(UiTransactionEncoding::Base64);
750        let commitment = config.commitment.unwrap_or_default();
751        let config = RpcSimulateTransactionConfig {
752            encoding: Some(encoding),
753            commitment: Some(commitment),
754            ..config
755        };
756        let serialized_encoded = serialize_and_encode(transaction, encoding)?;
757        self.send(
758            RpcRequest::SimulateTransaction,
759            json!([serialized_encoded, config]),
760        )
761        .await
762    }
763
764    /// Returns the highest slot information that the node has snapshots for.
765    ///
766    /// This will find the highest full snapshot slot, and the highest incremental snapshot slot
767    /// _based on_ the full snapshot slot, if there is one.
768    ///
769    /// # RPC Reference
770    ///
771    /// This method corresponds directly to the [`getHighestSnapshotSlot`] RPC method.
772    ///
773    /// [`getHighestSnapshotSlot`]: https://solana.com/docs/rpc/http/gethighestsnapshotslot
774    ///
775    /// # Examples
776    ///
777    /// ```ignore
778    /// # use solana_rpc_client_api::client_error::Error;
779    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
780    /// # futures::executor::block_on(async {
781    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
782    /// let snapshot_slot_info = rpc_client.get_highest_snapshot_slot().await?;
783    /// #     Ok::<(), Error>(())
784    /// # })?;
785    /// # Ok::<(), Error>(())
786    /// ```
787    pub async fn get_highest_snapshot_slot(&self) -> ClientResult<RpcSnapshotSlotInfo> {
788        self.send(RpcRequest::GetHighestSnapshotSlot, Value::Null)
789            .await
790    }
791
792    /// Check if a transaction has been processed with the default [commitment level][cl].
793    ///
794    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
795    ///
796    /// If the transaction has been processed with the default commitment level,
797    /// then this method returns `Ok` of `Some`. If the transaction has not yet
798    /// been processed with the default commitment level, it returns `Ok` of
799    /// `None`.
800    ///
801    /// If the transaction has been processed with the default commitment level,
802    /// and the transaction succeeded, this method returns `Ok(Some(Ok(())))`.
803    /// If the transaction has been processed with the default commitment level,
804    /// and the transaction failed, this method returns `Ok(Some(Err(_)))`,
805    /// where the interior error is type [`TransactionError`].
806    ///
807    /// [`TransactionError`]: solana_transaction_error::TransactionError
808    ///
809    /// This function only searches a node's recent history, including all
810    /// recent slots, plus up to
811    /// [`MAX_RECENT_BLOCKHASHES`][solana_clock::MAX_RECENT_BLOCKHASHES]
812    /// rooted slots. To search the full transaction history use the
813    /// [`get_signature_status_with_commitment_and_history`][RpcClient::get_signature_status_with_commitment_and_history]
814    /// method.
815    ///
816    /// # RPC Reference
817    ///
818    /// This method is built on the [`getSignatureStatuses`] RPC method.
819    ///
820    /// [`getSignatureStatuses`]: https://solana.com/docs/rpc/http/getsignaturestatuses
821    ///
822    /// # Examples
823    ///
824    /// ```ignore
825    /// # use solana_rpc_client_api::client_error::Error;
826    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
827    /// # use solana_hash::Hash;
828    /// # use solana_keypair::Keypair;
829    /// # use solana_system_transaction as system_transaction;
830    /// # use solana_signature::Signature;
831    /// # use solana_signer::Signer;
832    /// # futures::executor::block_on(async {
833    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
834    /// #     let alice = Keypair::new();
835    /// #     let bob = Keypair::new();
836    /// #     let lamports = 50;
837    /// #     let latest_blockhash = rpc_client.get_latest_blockhash().await?;
838    /// #     let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
839    /// let signature = rpc_client.send_transaction(&tx).await?;
840    /// let status = rpc_client.get_signature_status(&signature).await?;
841    /// #     Ok::<(), Error>(())
842    /// # })?;
843    /// # Ok::<(), Error>(())
844    /// ```
845    pub async fn get_signature_status(
846        &self,
847        signature: &Signature,
848    ) -> ClientResult<Option<TransactionResult<()>>> {
849        self.get_signature_status_with_commitment(signature, self.commitment())
850            .await
851    }
852
853    /// Gets the statuses of a list of transaction signatures.
854    ///
855    /// The returned vector of [`TransactionStatus`] has the same length as the
856    /// input slice.
857    ///
858    /// For any transaction that has not been processed by the network, the
859    /// value of the corresponding entry in the returned vector is `None`. As a
860    /// result, a transaction that has recently been submitted will not have a
861    /// status immediately.
862    ///
863    /// To submit a transaction and wait for it to confirm, use
864    /// [`send_and_confirm_transaction`][RpcClient::send_and_confirm_transaction].
865    ///
866    /// This function ignores the configured confirmation level, and returns the
867    /// transaction status whatever it is. It does not wait for transactions to
868    /// be processed.
869    ///
870    /// This function only searches a node's recent history, including all
871    /// recent slots, plus up to
872    /// [`MAX_RECENT_BLOCKHASHES`][solana_clock::MAX_RECENT_BLOCKHASHES]
873    /// rooted slots. To search the full transaction history use the
874    /// [`get_signature_statuses_with_history`][RpcClient::get_signature_statuses_with_history]
875    /// method.
876    ///
877    /// # Errors
878    ///
879    /// Any individual `TransactionStatus` may have triggered an error during
880    /// processing, in which case its [`err`][`TransactionStatus::err`] field
881    /// will be `Some`.
882    ///
883    /// # RPC Reference
884    ///
885    /// This method corresponds directly to the [`getSignatureStatuses`] RPC method.
886    ///
887    /// [`getSignatureStatuses`]: https://solana.com/docs/rpc/http/getsignaturestatuses
888    ///
889    /// # Examples
890    ///
891    /// ```ignore
892    /// # use solana_rpc_client_api::client_error::Error;
893    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
894    /// # use solana_hash::Hash;
895    /// # use solana_keypair::Keypair;
896    /// # use solana_system_transaction as system_transaction;
897    /// # use solana_signature::Signature;
898    /// # use solana_signer::Signer;
899    /// # use std::time::Duration;
900    /// # futures::executor::block_on(async {
901    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
902    /// #     let alice = Keypair::new();
903    /// // Send lamports from Alice to Bob and wait for the transaction to be processed
904    /// #     let bob = Keypair::new();
905    /// #     let lamports = 50;
906    /// let latest_blockhash = rpc_client.get_latest_blockhash().await?;
907    /// let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
908    /// let signature = rpc_client.send_transaction(&tx).await?;
909    ///
910    /// let status = loop {
911    ///    let statuses = rpc_client.get_signature_statuses(&[signature]).await?.value;
912    ///    if let Some(status) = statuses[0].clone() {
913    ///        break status;
914    ///    }
915    ///    std::thread::sleep(Duration::from_millis(100));
916    /// };
917    ///
918    /// assert!(status.err.is_none());
919    /// #     Ok::<(), Error>(())
920    /// # })?;
921    /// # Ok::<(), Error>(())
922    /// ```
923    pub async fn get_signature_statuses(
924        &self,
925        signatures: &[Signature],
926    ) -> RpcResult<Vec<Option<TransactionStatus>>> {
927        let signatures: Vec<_> = signatures.iter().map(|s| s.to_string()).collect();
928        self.send(RpcRequest::GetSignatureStatuses, json!([signatures]))
929            .await
930    }
931
932    /// Gets the statuses of a list of transaction signatures.
933    ///
934    /// The returned vector of [`TransactionStatus`] has the same length as the
935    /// input slice.
936    ///
937    /// For any transaction that has not been processed by the network, the
938    /// value of the corresponding entry in the returned vector is `None`. As a
939    /// result, a transaction that has recently been submitted will not have a
940    /// status immediately.
941    ///
942    /// To submit a transaction and wait for it to confirm, use
943    /// [`send_and_confirm_transaction`][RpcClient::send_and_confirm_transaction].
944    ///
945    /// This function ignores the configured confirmation level, and returns the
946    /// transaction status whatever it is. It does not wait for transactions to
947    /// be processed.
948    ///
949    /// This function searches a node's full ledger history and (if implemented) long-term storage. To search for
950    /// transactions in recent slots only use the
951    /// [`get_signature_statuses`][RpcClient::get_signature_statuses] method.
952    ///
953    /// # Errors
954    ///
955    /// Any individual `TransactionStatus` may have triggered an error during
956    /// processing, in which case its [`err`][`TransactionStatus::err`] field
957    /// will be `Some`.
958    ///
959    /// # RPC Reference
960    ///
961    /// This method corresponds directly to the [`getSignatureStatuses`] RPC
962    /// method, with the `searchTransactionHistory` configuration option set to
963    /// `true`.
964    ///
965    /// [`getSignatureStatuses`]: https://solana.com/docs/rpc/http/getsignaturestatuses
966    ///
967    /// # Examples
968    ///
969    /// ```ignore
970    /// # use solana_rpc_client_api::client_error::Error;
971    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
972    /// # use solana_hash::Hash;
973    /// # use solana_keypair::Keypair;
974    /// # use solana_system_transaction as system_transaction;
975    /// # use solana_signature::Signature;
976    /// # use solana_signer::Signer;
977    /// # futures::executor::block_on(async {
978    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
979    /// #     let alice = Keypair::new();
980    /// #     fn get_old_transaction_signature() -> Signature { Signature::default() }
981    /// // Check if an old transaction exists
982    /// let signature = get_old_transaction_signature();
983    /// let latest_blockhash = rpc_client.get_latest_blockhash().await?;
984    /// let statuses = rpc_client.get_signature_statuses_with_history(&[signature]).await?.value;
985    /// if statuses[0].is_none() {
986    ///     println!("old transaction does not exist");
987    /// }
988    /// #     Ok::<(), Error>(())
989    /// # })?;
990    /// # Ok::<(), Error>(())
991    /// ```
992    pub async fn get_signature_statuses_with_history(
993        &self,
994        signatures: &[Signature],
995    ) -> RpcResult<Vec<Option<TransactionStatus>>> {
996        let signatures: Vec<_> = signatures.iter().map(|s| s.to_string()).collect();
997        self.send(
998            RpcRequest::GetSignatureStatuses,
999            json!([signatures, {
1000                "searchTransactionHistory": true
1001            }]),
1002        )
1003        .await
1004    }
1005
1006    /// Check if a transaction has been processed with the given [commitment level][cl].
1007    ///
1008    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1009    ///
1010    /// If the transaction has been processed with the given commitment level,
1011    /// then this method returns `Ok` of `Some`. If the transaction has not yet
1012    /// been processed with the given commitment level, it returns `Ok` of
1013    /// `None`.
1014    ///
1015    /// If the transaction has been processed with the given commitment level,
1016    /// and the transaction succeeded, this method returns `Ok(Some(Ok(())))`.
1017    /// If the transaction has been processed with the given commitment level,
1018    /// and the transaction failed, this method returns `Ok(Some(Err(_)))`,
1019    /// where the interior error is type [`TransactionError`].
1020    ///
1021    /// [`TransactionError`]: solana_transaction_error::TransactionError
1022    ///
1023    /// This function only searches a node's recent history, including all
1024    /// recent slots, plus up to
1025    /// [`MAX_RECENT_BLOCKHASHES`][solana_clock::MAX_RECENT_BLOCKHASHES]
1026    /// rooted slots. To search the full transaction history use the
1027    /// [`get_signature_status_with_commitment_and_history`][RpcClient::get_signature_status_with_commitment_and_history]
1028    /// method.
1029    ///
1030    /// # RPC Reference
1031    ///
1032    /// This method is built on the [`getSignatureStatuses`] RPC method.
1033    ///
1034    /// [`getSignatureStatuses`]: https://solana.com/docs/rpc/http/getsignaturestatuses
1035    ///
1036    /// # Examples
1037    ///
1038    /// ```ignore
1039    /// # use solana_rpc_client_api::client_error::Error;
1040    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1041    /// # use solana_commitment_config::CommitmentConfig;
1042    /// # use solana_keypair::Keypair;
1043    /// # use solana_signature::Signature;
1044    /// # use solana_signer::Signer;
1045    /// # use solana_system_transaction as system_transaction;
1046    /// # futures::executor::block_on(async {
1047    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1048    /// #     let alice = Keypair::new();
1049    /// #     let bob = Keypair::new();
1050    /// #     let lamports = 50;
1051    /// #     let latest_blockhash = rpc_client.get_latest_blockhash().await?;
1052    /// #     let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
1053    /// let signature = rpc_client.send_and_confirm_transaction(&tx).await?;
1054    /// let commitment_config = CommitmentConfig::processed();
1055    /// let status = rpc_client.get_signature_status_with_commitment(
1056    ///     &signature,
1057    ///     commitment_config,
1058    /// ).await?;
1059    /// #     Ok::<(), Error>(())
1060    /// # })?;
1061    /// # Ok::<(), Error>(())
1062    /// ```
1063    pub async fn get_signature_status_with_commitment(
1064        &self,
1065        signature: &Signature,
1066        commitment_config: CommitmentConfig,
1067    ) -> ClientResult<Option<TransactionResult<()>>> {
1068        let result: Response<Vec<Option<TransactionStatus>>> = self
1069            .send(
1070                RpcRequest::GetSignatureStatuses,
1071                json!([[signature.to_string()]]),
1072            )
1073            .await?;
1074        Ok(result.value[0]
1075            .clone()
1076            .filter(|result| result.satisfies_commitment(commitment_config))
1077            .map(|status_meta| status_meta.status))
1078    }
1079
1080    /// Check if a transaction has been processed with the given [commitment level][cl].
1081    ///
1082    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1083    ///
1084    /// If the transaction has been processed with the given commitment level,
1085    /// then this method returns `Ok` of `Some`. If the transaction has not yet
1086    /// been processed with the given commitment level, it returns `Ok` of
1087    /// `None`.
1088    ///
1089    /// If the transaction has been processed with the given commitment level,
1090    /// and the transaction succeeded, this method returns `Ok(Some(Ok(())))`.
1091    /// If the transaction has been processed with the given commitment level,
1092    /// and the transaction failed, this method returns `Ok(Some(Err(_)))`,
1093    /// where the interior error is type [`TransactionError`].
1094    ///
1095    /// [`TransactionError`]: solana_transaction_error::TransactionError
1096    ///
1097    /// This method optionally searches a node's full ledger history and (if
1098    /// implemented) long-term storage.
1099    ///
1100    /// # RPC Reference
1101    ///
1102    /// This method is built on the [`getSignatureStatuses`] RPC method.
1103    ///
1104    /// [`getSignatureStatuses`]: https://solana.com/docs/rpc/http/getsignaturestatuses
1105    ///
1106    /// # Examples
1107    ///
1108    /// ```ignore
1109    /// # use solana_rpc_client_api::client_error::Error;
1110    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1111    /// # use solana_commitment_config::CommitmentConfig;
1112    /// # use solana_keypair::Keypair;
1113    /// # use solana_signature::Signature;
1114    /// # use solana_signer::Signer;
1115    /// # use solana_system_transaction as system_transaction;
1116    /// # futures::executor::block_on(async {
1117    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1118    /// #     let alice = Keypair::new();
1119    /// #     let bob = Keypair::new();
1120    /// #     let lamports = 50;
1121    /// #     let latest_blockhash = rpc_client.get_latest_blockhash().await?;
1122    /// #     let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
1123    /// let signature = rpc_client.send_transaction(&tx).await?;
1124    /// let commitment_config = CommitmentConfig::processed();
1125    /// let search_transaction_history = true;
1126    /// let status = rpc_client.get_signature_status_with_commitment_and_history(
1127    ///     &signature,
1128    ///     commitment_config,
1129    ///     search_transaction_history,
1130    /// ).await?;
1131    /// #     Ok::<(), Error>(())
1132    /// # })?;
1133    /// # Ok::<(), Error>(())
1134    /// ```
1135    pub async fn get_signature_status_with_commitment_and_history(
1136        &self,
1137        signature: &Signature,
1138        commitment_config: CommitmentConfig,
1139        search_transaction_history: bool,
1140    ) -> ClientResult<Option<TransactionResult<()>>> {
1141        let result: Response<Vec<Option<TransactionStatus>>> = self
1142            .send(
1143                RpcRequest::GetSignatureStatuses,
1144                json!([[signature.to_string()], {
1145                    "searchTransactionHistory": search_transaction_history
1146                }]),
1147            )
1148            .await?;
1149        Ok(result.value[0]
1150            .clone()
1151            .filter(|result| result.satisfies_commitment(commitment_config))
1152            .map(|status_meta| status_meta.status))
1153    }
1154
1155    /// Returns the slot that has reached the configured [commitment level][cl].
1156    ///
1157    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1158    ///
1159    /// # RPC Reference
1160    ///
1161    /// This method corresponds directly to the [`getSlot`] RPC method.
1162    ///
1163    /// [`getSlot`]: https://solana.com/docs/rpc/http/getslot
1164    ///
1165    /// # Examples
1166    ///
1167    /// ```ignore
1168    /// # use solana_rpc_client_api::client_error::Error;
1169    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1170    /// # futures::executor::block_on(async {
1171    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1172    /// let slot = rpc_client.get_slot().await?;
1173    /// #     Ok::<(), Error>(())
1174    /// # })?;
1175    /// # Ok::<(), Error>(())
1176    /// ```
1177    pub async fn get_slot(&self) -> ClientResult<Slot> {
1178        self.get_slot_with_commitment(self.commitment()).await
1179    }
1180
1181    /// Returns the slot that has reached the given [commitment level][cl].
1182    ///
1183    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1184    ///
1185    /// # RPC Reference
1186    ///
1187    /// This method corresponds directly to the [`getSlot`] RPC method.
1188    ///
1189    /// [`getSlot`]: https://solana.com/docs/rpc/http/getslot
1190    ///
1191    /// # Examples
1192    ///
1193    /// ```ignore
1194    /// # use solana_rpc_client_api::client_error::Error;
1195    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1196    /// # use solana_commitment_config::CommitmentConfig;
1197    /// # futures::executor::block_on(async {
1198    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1199    /// let commitment_config = CommitmentConfig::processed();
1200    /// let slot = rpc_client.get_slot_with_commitment(commitment_config).await?;
1201    /// #     Ok::<(), Error>(())
1202    /// # })?;
1203    /// # Ok::<(), Error>(())
1204    /// ```
1205    pub async fn get_slot_with_commitment(
1206        &self,
1207        commitment_config: CommitmentConfig,
1208    ) -> ClientResult<Slot> {
1209        self.send(RpcRequest::GetSlot, json!([commitment_config]))
1210            .await
1211    }
1212
1213    /// Returns the block height that has reached the configured [commitment level][cl].
1214    ///
1215    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1216    ///
1217    /// # RPC Reference
1218    ///
1219    /// This method is corresponds directly to the [`getBlockHeight`] RPC method.
1220    ///
1221    /// [`getBlockHeight`]: https://solana.com/docs/rpc/http/getblockheight
1222    ///
1223    /// # Examples
1224    ///
1225    /// ```ignore
1226    /// # use solana_rpc_client_api::client_error::Error;
1227    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1228    /// # futures::executor::block_on(async {
1229    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1230    /// let block_height = rpc_client.get_block_height().await?;
1231    /// #     Ok::<(), Error>(())
1232    /// # })?;
1233    /// # Ok::<(), Error>(())
1234    /// ```
1235    pub async fn get_block_height(&self) -> ClientResult<u64> {
1236        self.get_block_height_with_commitment(self.commitment())
1237            .await
1238    }
1239
1240    /// Returns the block height that has reached the given [commitment level][cl].
1241    ///
1242    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1243    ///
1244    /// # RPC Reference
1245    ///
1246    /// This method is corresponds directly to the [`getBlockHeight`] RPC method.
1247    ///
1248    /// [`getBlockHeight`]: https://solana.com/docs/rpc/http/getblockheight
1249    ///
1250    /// # Examples
1251    ///
1252    /// ```ignore
1253    /// # use solana_rpc_client_api::client_error::Error;
1254    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1255    /// # use solana_commitment_config::CommitmentConfig;
1256    /// # futures::executor::block_on(async {
1257    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1258    /// let commitment_config = CommitmentConfig::processed();
1259    /// let block_height = rpc_client.get_block_height_with_commitment(
1260    ///     commitment_config,
1261    /// ).await?;
1262    /// #     Ok::<(), Error>(())
1263    /// # })?;
1264    /// # Ok::<(), Error>(())
1265    /// ```
1266    pub async fn get_block_height_with_commitment(
1267        &self,
1268        commitment_config: CommitmentConfig,
1269    ) -> ClientResult<u64> {
1270        self.send(RpcRequest::GetBlockHeight, json!([commitment_config]))
1271            .await
1272    }
1273
1274    /// Returns the slot leaders for a given slot range.
1275    ///
1276    /// # RPC Reference
1277    ///
1278    /// This method corresponds directly to the [`getSlotLeaders`] RPC method.
1279    ///
1280    /// [`getSlotLeaders`]: https://solana.com/docs/rpc/http/getslotleaders
1281    ///
1282    /// # Examples
1283    ///
1284    /// ```ignore
1285    /// # use solana_rpc_client_api::client_error::Error;
1286    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1287    /// # use solana_clock::Slot;
1288    /// # futures::executor::block_on(async {
1289    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1290    /// let start_slot = 1;
1291    /// let limit = 3;
1292    /// let leaders = rpc_client.get_slot_leaders(start_slot, limit).await?;
1293    /// #     Ok::<(), Error>(())
1294    /// # })?;
1295    /// # Ok::<(), Error>(())
1296    /// ```
1297    pub async fn get_slot_leaders(
1298        &self,
1299        start_slot: Slot,
1300        limit: u64,
1301    ) -> ClientResult<Vec<Pubkey>> {
1302        self.send(RpcRequest::GetSlotLeaders, json!([start_slot, limit]))
1303            .await
1304            .and_then(|slot_leaders: Vec<String>| {
1305                slot_leaders
1306                    .iter()
1307                    .map(|slot_leader| {
1308                        Pubkey::from_str(slot_leader).map_err(|err| {
1309                            ClientErrorKind::Custom(format!("pubkey deserialization failed: {err}"))
1310                                .into()
1311                        })
1312                    })
1313                    .collect()
1314            })
1315    }
1316
1317    /// Get block production for the current epoch.
1318    ///
1319    /// # RPC Reference
1320    ///
1321    /// This method corresponds directly to the [`getBlockProduction`] RPC method.
1322    ///
1323    /// [`getBlockProduction`]: https://solana.com/docs/rpc/http/getblockproduction
1324    ///
1325    /// # Examples
1326    ///
1327    /// ```ignore
1328    /// # use solana_rpc_client_api::client_error::Error;
1329    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1330    /// # futures::executor::block_on(async {
1331    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1332    /// let production = rpc_client.get_block_production().await?;
1333    /// #     Ok::<(), Error>(())
1334    /// # })?;
1335    /// # Ok::<(), Error>(())
1336    /// ```
1337    pub async fn get_block_production(&self) -> RpcResult<RpcBlockProduction> {
1338        self.send(RpcRequest::GetBlockProduction, Value::Null).await
1339    }
1340
1341    /// Get block production for the current or previous epoch.
1342    ///
1343    /// # RPC Reference
1344    ///
1345    /// This method corresponds directly to the [`getBlockProduction`] RPC method.
1346    ///
1347    /// [`getBlockProduction`]: https://solana.com/docs/rpc/http/getblockproduction
1348    ///
1349    /// # Examples
1350    ///
1351    /// ```ignore
1352    /// # use solana_rpc_client_api::{
1353    /// #     client_error::Error,
1354    /// #     config::RpcBlockProductionConfig,
1355    /// #     config::RpcBlockProductionConfigRange,
1356    /// # };
1357    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1358    /// # use solana_commitment_config::CommitmentConfig;
1359    /// # use solana_keypair::Keypair;
1360    /// # use solana_signer::Signer;
1361    /// # futures::executor::block_on(async {
1362    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1363    /// #     let start_slot = 1;
1364    /// #     let limit = 3;
1365    /// let leader = rpc_client.get_slot_leaders(start_slot, limit).await?;
1366    /// let leader = leader[0];
1367    /// let range = RpcBlockProductionConfigRange {
1368    ///     first_slot: start_slot,
1369    ///     last_slot: Some(start_slot + limit),
1370    /// };
1371    /// let config = RpcBlockProductionConfig {
1372    ///     identity: Some(leader.to_string()),
1373    ///     range: Some(range),
1374    ///     commitment: Some(CommitmentConfig::processed()),
1375    /// };
1376    /// let production = rpc_client.get_block_production_with_config(
1377    ///     config
1378    /// ).await?;
1379    /// #     Ok::<(), Error>(())
1380    /// # })?;
1381    /// # Ok::<(), Error>(())
1382    /// ```
1383    pub async fn get_block_production_with_config(
1384        &self,
1385        config: RpcBlockProductionConfig,
1386    ) -> RpcResult<RpcBlockProduction> {
1387        self.send(RpcRequest::GetBlockProduction, json!([config]))
1388            .await
1389    }
1390
1391    /// Returns information about the current supply.
1392    ///
1393    /// This method uses the configured [commitment level][cl].
1394    ///
1395    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1396    ///
1397    /// # RPC Reference
1398    ///
1399    /// This method corresponds directly to the [`getSupply`] RPC method.
1400    ///
1401    /// [`getSupply`]: https://solana.com/docs/rpc/http/getsupply
1402    ///
1403    /// # Examples
1404    ///
1405    /// ```ignore
1406    /// # use solana_rpc_client_api::client_error::Error;
1407    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1408    /// # futures::executor::block_on(async {
1409    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1410    /// let supply = rpc_client.supply().await?;
1411    /// #     Ok::<(), Error>(())
1412    /// # })?;
1413    /// # Ok::<(), Error>(())
1414    /// ```
1415    pub async fn supply(&self) -> RpcResult<RpcSupply> {
1416        self.supply_with_commitment(self.commitment()).await
1417    }
1418
1419    /// Returns information about the current supply.
1420    ///
1421    /// # RPC Reference
1422    ///
1423    /// This method corresponds directly to the [`getSupply`] RPC method.
1424    ///
1425    /// [`getSupply`]: https://solana.com/docs/rpc/http/getsupply
1426    ///
1427    /// # Examples
1428    ///
1429    /// ```ignore
1430    /// # use solana_rpc_client_api::client_error::Error;
1431    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1432    /// # use solana_commitment_config::CommitmentConfig;
1433    /// # futures::executor::block_on(async {
1434    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1435    /// let commitment_config = CommitmentConfig::processed();
1436    /// let supply = rpc_client.supply_with_commitment(
1437    ///     commitment_config,
1438    /// ).await?;
1439    /// #     Ok::<(), Error>(())
1440    /// # })?;
1441    /// # Ok::<(), Error>(())
1442    /// ```
1443    pub async fn supply_with_commitment(
1444        &self,
1445        commitment_config: CommitmentConfig,
1446    ) -> RpcResult<RpcSupply> {
1447        self.send(RpcRequest::GetSupply, json!([commitment_config]))
1448            .await
1449    }
1450
1451    /// Returns the 20 largest accounts, by lamport balance.
1452    ///
1453    /// # RPC Reference
1454    ///
1455    /// This method corresponds directly to the [`getLargestAccounts`] RPC
1456    /// method.
1457    ///
1458    /// [`getLargestAccounts`]: https://solana.com/docs/rpc/http/getlargestaccounts
1459    ///
1460    /// # Examples
1461    ///
1462    /// ```ignore
1463    /// # use solana_rpc_client_api::{
1464    /// #     client_error::Error,
1465    /// #     config::RpcLargestAccountsConfig,
1466    /// #     config::RpcLargestAccountsFilter,
1467    /// # };
1468    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1469    /// # use solana_commitment_config::CommitmentConfig;
1470    /// # futures::executor::block_on(async {
1471    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1472    /// let commitment_config = CommitmentConfig::processed();
1473    /// let config = RpcLargestAccountsConfig {
1474    ///     commitment: Some(commitment_config),
1475    ///     filter: Some(RpcLargestAccountsFilter::Circulating),
1476    ///     sort_results: None,
1477    /// };
1478    /// let accounts = rpc_client.get_largest_accounts_with_config(
1479    ///     config,
1480    /// ).await?;
1481    /// #     Ok::<(), Error>(())
1482    /// # })?;
1483    /// # Ok::<(), Error>(())
1484    /// ```
1485    pub async fn get_largest_accounts_with_config(
1486        &self,
1487        config: RpcLargestAccountsConfig,
1488    ) -> RpcResult<Vec<RpcAccountBalance>> {
1489        let commitment = config.commitment.unwrap_or_default();
1490        let config = RpcLargestAccountsConfig {
1491            commitment: Some(commitment),
1492            ..config
1493        };
1494        self.send(RpcRequest::GetLargestAccounts, json!([config]))
1495            .await
1496    }
1497
1498    /// Returns the account info and associated stake for all the voting accounts
1499    /// that have reached the configured [commitment level][cl].
1500    ///
1501    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1502    ///
1503    /// # RPC Reference
1504    ///
1505    /// This method corresponds directly to the [`getVoteAccounts`]
1506    /// RPC method.
1507    ///
1508    /// [`getVoteAccounts`]: https://solana.com/docs/rpc/http/getvoteaccounts
1509    ///
1510    /// # Examples
1511    ///
1512    /// ```ignore
1513    /// # use solana_rpc_client_api::client_error::Error;
1514    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1515    /// # futures::executor::block_on(async {
1516    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1517    /// let accounts = rpc_client.get_vote_accounts().await?;
1518    /// #     Ok::<(), Error>(())
1519    /// # })?;
1520    /// # Ok::<(), Error>(())
1521    /// ```
1522    pub async fn get_vote_accounts(&self) -> ClientResult<RpcVoteAccountStatus> {
1523        self.get_vote_accounts_with_commitment(self.commitment())
1524            .await
1525    }
1526
1527    /// Returns the account info and associated stake for all the voting accounts
1528    /// that have reached the given [commitment level][cl].
1529    ///
1530    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1531    ///
1532    /// # RPC Reference
1533    ///
1534    /// This method corresponds directly to the [`getVoteAccounts`] RPC method.
1535    ///
1536    /// [`getVoteAccounts`]: https://solana.com/docs/rpc/http/getvoteaccounts
1537    ///
1538    /// # Examples
1539    ///
1540    /// ```ignore
1541    /// # use solana_commitment_config::CommitmentConfig;
1542    /// # use solana_rpc_client_api::client_error::Error;
1543    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1544    /// # futures::executor::block_on(async {
1545    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1546    /// let commitment_config = CommitmentConfig::processed();
1547    /// let accounts = rpc_client.get_vote_accounts_with_commitment(
1548    ///     commitment_config,
1549    /// ).await?;
1550    /// #     Ok::<(), Error>(())
1551    /// # })?;
1552    /// # Ok::<(), Error>(())
1553    /// ```
1554    pub async fn get_vote_accounts_with_commitment(
1555        &self,
1556        commitment_config: CommitmentConfig,
1557    ) -> ClientResult<RpcVoteAccountStatus> {
1558        self.get_vote_accounts_with_config(RpcGetVoteAccountsConfig {
1559            commitment: Some(commitment_config),
1560            ..RpcGetVoteAccountsConfig::default()
1561        })
1562        .await
1563    }
1564
1565    /// Returns the account info and associated stake for all the voting accounts
1566    /// that have reached the given [commitment level][cl].
1567    ///
1568    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1569    ///
1570    /// # RPC Reference
1571    ///
1572    /// This method corresponds directly to the [`getVoteAccounts`] RPC method.
1573    ///
1574    /// [`getVoteAccounts`]: https://solana.com/docs/rpc/http/getvoteaccounts
1575    ///
1576    /// # Examples
1577    ///
1578    /// ```ignore
1579    /// # use solana_rpc_client_api::{
1580    /// #     client_error::Error,
1581    /// #     config::RpcGetVoteAccountsConfig,
1582    /// # };
1583    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1584    /// # use solana_commitment_config::CommitmentConfig;
1585    /// # use solana_keypair::Keypair;
1586    /// # use solana_signer::Signer;
1587    /// # futures::executor::block_on(async {
1588    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1589    /// #     let vote_keypair = Keypair::new();
1590    /// let vote_pubkey = vote_keypair.pubkey();
1591    /// let commitment = CommitmentConfig::processed();
1592    /// let config = RpcGetVoteAccountsConfig {
1593    ///     vote_pubkey: Some(vote_pubkey.to_string()),
1594    ///     commitment: Some(commitment),
1595    ///     keep_unstaked_delinquents: Some(true),
1596    ///     delinquent_slot_distance: Some(10),
1597    /// };
1598    /// let accounts = rpc_client.get_vote_accounts_with_config(
1599    ///     config,
1600    /// ).await?;
1601    /// #     Ok::<(), Error>(())
1602    /// # })?;
1603    /// # Ok::<(), Error>(())
1604    /// ```
1605    pub async fn get_vote_accounts_with_config(
1606        &self,
1607        config: RpcGetVoteAccountsConfig,
1608    ) -> ClientResult<RpcVoteAccountStatus> {
1609        self.send(RpcRequest::GetVoteAccounts, json!([config]))
1610            .await
1611    }
1612
1613    pub async fn wait_for_max_stake(
1614        &self,
1615        commitment: CommitmentConfig,
1616        max_stake_percent: f32,
1617    ) -> ClientResult<()> {
1618        self.wait_for_max_stake_below_threshold_with_timeout_helper(
1619            commitment,
1620            max_stake_percent,
1621            None,
1622        )
1623        .await
1624    }
1625
1626    pub async fn wait_for_max_stake_below_threshold_with_timeout(
1627        &self,
1628        commitment: CommitmentConfig,
1629        max_stake_percent: f32,
1630        timeout: Duration,
1631    ) -> ClientResult<()> {
1632        self.wait_for_max_stake_below_threshold_with_timeout_helper(
1633            commitment,
1634            max_stake_percent,
1635            Some(timeout),
1636        )
1637        .await
1638    }
1639
1640    async fn wait_for_max_stake_below_threshold_with_timeout_helper(
1641        &self,
1642        commitment: CommitmentConfig,
1643        max_stake_percent: f32,
1644        timeout: Option<Duration>,
1645    ) -> ClientResult<()> {
1646        let mut current_percent;
1647        let start = Instant::now();
1648        loop {
1649            let vote_accounts = self.get_vote_accounts_with_commitment(commitment).await?;
1650
1651            let mut max = 0;
1652            let total_active_stake = vote_accounts
1653                .current
1654                .iter()
1655                .chain(vote_accounts.delinquent.iter())
1656                .map(|vote_account| {
1657                    max = std::cmp::max(max, vote_account.activated_stake);
1658                    vote_account.activated_stake
1659                })
1660                .sum::<u64>();
1661            current_percent = 100f32 * max as f32 / total_active_stake as f32;
1662            if current_percent < max_stake_percent {
1663                break;
1664            } else if let Some(timeout) = timeout {
1665                if start.elapsed() > timeout {
1666                    return Err(ClientErrorKind::Custom(
1667                        "timed out waiting for max stake to drop".to_string(),
1668                    )
1669                    .into());
1670                }
1671            }
1672
1673            info!(
1674                "Waiting for stake to drop below {max_stake_percent} current: {current_percent:.1}"
1675            );
1676            sleep(Duration::from_secs(5)).await;
1677        }
1678        Ok(())
1679    }
1680
1681    /// Returns information about all the nodes participating in the cluster.
1682    ///
1683    /// # RPC Reference
1684    ///
1685    /// This method corresponds directly to the [`getClusterNodes`]
1686    /// RPC method.
1687    ///
1688    /// [`getClusterNodes`]: https://solana.com/docs/rpc/http/getclusternodes
1689    ///
1690    /// # Examples
1691    ///
1692    /// ```ignore
1693    /// # use solana_rpc_client_api::client_error::Error;
1694    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1695    /// # futures::executor::block_on(async {
1696    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1697    /// let cluster_nodes = rpc_client.get_cluster_nodes().await?;
1698    /// #     Ok::<(), Error>(())
1699    /// # })?;
1700    /// # Ok::<(), Error>(())
1701    /// ```
1702    pub async fn get_cluster_nodes(&self) -> ClientResult<Vec<RpcContactInfo>> {
1703        self.send(RpcRequest::GetClusterNodes, Value::Null).await
1704    }
1705
1706    /// Returns identity and transaction information about a confirmed block in the ledger.
1707    ///
1708    /// The encodings are returned in [`UiTransactionEncoding::Json`][uite]
1709    /// format. To return transactions in other encodings, use
1710    /// [`get_block_with_encoding`].
1711    ///
1712    /// [`get_block_with_encoding`]: RpcClient::get_block_with_encoding
1713    /// [uite]: UiTransactionEncoding::Json
1714    ///
1715    /// # RPC Reference
1716    ///
1717    /// This method corresponds directly to the [`getBlock`] RPC
1718    /// method.
1719    ///
1720    /// [`getBlock`]: https://solana.com/docs/rpc/http/getblock
1721    ///
1722    /// # Examples
1723    ///
1724    /// ```ignore
1725    /// # use solana_rpc_client_api::client_error::Error;
1726    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1727    /// # futures::executor::block_on(async {
1728    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1729    /// #     let slot = rpc_client.get_slot().await?;
1730    /// let block = rpc_client.get_block(slot).await?;
1731    /// #     Ok::<(), Error>(())
1732    /// # })?;
1733    /// # Ok::<(), Error>(())
1734    /// ```
1735    pub async fn get_block(&self, slot: Slot) -> ClientResult<EncodedConfirmedBlock> {
1736        self.get_block_with_encoding(slot, UiTransactionEncoding::Json)
1737            .await
1738    }
1739
1740    /// Returns identity and transaction information about a confirmed block in the ledger.
1741    ///
1742    /// # RPC Reference
1743    ///
1744    /// This method corresponds directly to the [`getBlock`] RPC method.
1745    ///
1746    /// [`getBlock`]: https://solana.com/docs/rpc/http/getblock
1747    ///
1748    /// # Examples
1749    ///
1750    /// ```ignore
1751    /// # use solana_transaction_status_client_types::UiTransactionEncoding;
1752    /// # use solana_rpc_client_api::client_error::Error;
1753    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1754    /// # futures::executor::block_on(async {
1755    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1756    /// #     let slot = rpc_client.get_slot().await?;
1757    /// let encoding = UiTransactionEncoding::Base58;
1758    /// let block = rpc_client.get_block_with_encoding(
1759    ///     slot,
1760    ///     encoding,
1761    /// ).await?;
1762    /// #     Ok::<(), Error>(())
1763    /// # })?;
1764    /// # Ok::<(), Error>(())
1765    /// ```
1766    pub async fn get_block_with_encoding(
1767        &self,
1768        slot: Slot,
1769        encoding: UiTransactionEncoding,
1770    ) -> ClientResult<EncodedConfirmedBlock> {
1771        self.send(RpcRequest::GetBlock, json!([slot, encoding]))
1772            .await
1773    }
1774
1775    /// Returns identity and transaction information about a confirmed block in the ledger.
1776    ///
1777    /// # RPC Reference
1778    ///
1779    /// This method corresponds directly to the [`getBlock`] RPC method.
1780    ///
1781    /// [`getBlock`]: https://solana.com/docs/rpc/http/getblock
1782    ///
1783    /// # Examples
1784    ///
1785    /// ```ignore
1786    /// # use solana_transaction_status_client_types::{
1787    /// #     TransactionDetails,
1788    /// #     UiTransactionEncoding,
1789    /// # };
1790    /// # use solana_rpc_client_api::{
1791    /// #     config::RpcBlockConfig,
1792    /// #     client_error::Error,
1793    /// # };
1794    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1795    /// # futures::executor::block_on(async {
1796    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1797    /// #     let slot = rpc_client.get_slot().await?;
1798    /// let config = RpcBlockConfig {
1799    ///     encoding: Some(UiTransactionEncoding::Base58),
1800    ///     transaction_details: Some(TransactionDetails::None),
1801    ///     rewards: Some(true),
1802    ///     commitment: None,
1803    ///     max_supported_transaction_version: Some(0),
1804    /// };
1805    /// let block = rpc_client.get_block_with_config(
1806    ///     slot,
1807    ///     config,
1808    /// ).await?;
1809    /// #     Ok::<(), Error>(())
1810    /// # })?;
1811    /// # Ok::<(), Error>(())
1812    /// ```
1813    pub async fn get_block_with_config(
1814        &self,
1815        slot: Slot,
1816        config: RpcBlockConfig,
1817    ) -> ClientResult<UiConfirmedBlock> {
1818        self.send(RpcRequest::GetBlock, json!([slot, config])).await
1819    }
1820
1821    /// Returns a list of finalized blocks between two slots.
1822    ///
1823    /// The range is inclusive, with results including the block for both
1824    /// `start_slot` and `end_slot`.
1825    ///
1826    /// If `end_slot` is not provided, then the end slot is for the latest
1827    /// finalized block.
1828    ///
1829    /// This method may not return blocks for the full range of slots if some
1830    /// slots do not have corresponding blocks. To simply get a specific number
1831    /// of sequential blocks, use the [`get_blocks_with_limit`] method.
1832    ///
1833    /// This method uses the [`Finalized`] [commitment level][cl].
1834    ///
1835    /// [`Finalized`]: CommitmentLevel::Finalized
1836    /// [`get_blocks_with_limit`]: RpcClient::get_blocks_with_limit.
1837    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1838    ///
1839    /// # Errors
1840    ///
1841    /// This method returns an error if the range is greater than 500,000 slots.
1842    ///
1843    /// # RPC Reference
1844    ///
1845    /// This method corresponds directly to the [`getBlocks`] RPC method.
1846    ///
1847    /// [`getBlocks`]: https://solana.com/docs/rpc/http/getblocks
1848    ///
1849    /// # Examples
1850    ///
1851    /// ```ignore
1852    /// # use solana_rpc_client_api::client_error::Error;
1853    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1854    /// # futures::executor::block_on(async {
1855    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1856    /// // Get up to the first 10 blocks
1857    /// let start_slot = 0;
1858    /// let end_slot = 9;
1859    /// let blocks = rpc_client.get_blocks(start_slot, Some(end_slot)).await?;
1860    /// #     Ok::<(), Error>(())
1861    /// # })?;
1862    /// # Ok::<(), Error>(())
1863    /// ```
1864    pub async fn get_blocks(
1865        &self,
1866        start_slot: Slot,
1867        end_slot: Option<Slot>,
1868    ) -> ClientResult<Vec<Slot>> {
1869        self.send(RpcRequest::GetBlocks, json!([start_slot, end_slot]))
1870            .await
1871    }
1872
1873    /// Returns a list of confirmed blocks between two slots.
1874    ///
1875    /// The range is inclusive, with results including the block for both
1876    /// `start_slot` and `end_slot`.
1877    ///
1878    /// If `end_slot` is not provided, then the end slot is for the latest
1879    /// block with the given [commitment level][cl].
1880    ///
1881    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1882    ///
1883    /// This method may not return blocks for the full range of slots if some
1884    /// slots do not have corresponding blocks. To simply get a specific number
1885    /// of sequential blocks, use the [`get_blocks_with_limit_and_commitment`]
1886    /// method.
1887    ///
1888    /// [`get_blocks_with_limit_and_commitment`]: RpcClient::get_blocks_with_limit_and_commitment.
1889    ///
1890    /// # Errors
1891    ///
1892    /// This method returns an error if the range is greater than 500,000 slots.
1893    ///
1894    /// This method returns an error if the given commitment level is below
1895    /// [`Confirmed`].
1896    ///
1897    /// [`Confirmed`]: CommitmentLevel::Confirmed
1898    ///
1899    /// # RPC Reference
1900    ///
1901    /// This method corresponds directly to the [`getBlocks`] RPC method.
1902    ///
1903    /// [`getBlocks`]: https://solana.com/docs/rpc/http/getblocks
1904    ///
1905    /// # Examples
1906    ///
1907    /// ```ignore
1908    /// # use solana_commitment_config::CommitmentConfig;
1909    /// # use solana_rpc_client_api::client_error::Error;
1910    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1911    /// # futures::executor::block_on(async {
1912    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1913    /// // Get up to the first 10 blocks
1914    /// let start_slot = 0;
1915    /// let end_slot = 9;
1916    /// // Method does not support commitment below `confirmed`
1917    /// let commitment_config = CommitmentConfig::confirmed();
1918    /// let blocks = rpc_client.get_blocks_with_commitment(
1919    ///     start_slot,
1920    ///     Some(end_slot),
1921    ///     commitment_config,
1922    /// ).await?;
1923    /// #     Ok::<(), Error>(())
1924    /// # })?;
1925    /// # Ok::<(), Error>(())
1926    /// ```
1927    pub async fn get_blocks_with_commitment(
1928        &self,
1929        start_slot: Slot,
1930        end_slot: Option<Slot>,
1931        commitment_config: CommitmentConfig,
1932    ) -> ClientResult<Vec<Slot>> {
1933        let json = if end_slot.is_some() {
1934            json!([start_slot, end_slot, commitment_config])
1935        } else {
1936            json!([start_slot, commitment_config])
1937        };
1938        self.send(RpcRequest::GetBlocks, json).await
1939    }
1940
1941    /// Returns a list of finalized blocks starting at the given slot.
1942    ///
1943    /// This method uses the [`Finalized`] [commitment level][cl].
1944    ///
1945    /// [`Finalized`]: CommitmentLevel::Finalized.
1946    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1947    ///
1948    /// # Errors
1949    ///
1950    /// This method returns an error if the limit is greater than 500,000 slots.
1951    ///
1952    /// # RPC Reference
1953    ///
1954    /// This method corresponds directly to the [`getBlocksWithLimit`] RPC
1955    /// method.
1956    ///
1957    /// [`getBlocksWithLimit`]: https://solana.com/docs/rpc/http/getblockswithlimit
1958    ///
1959    /// # Examples
1960    ///
1961    /// ```ignore
1962    /// # use solana_rpc_client_api::client_error::Error;
1963    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
1964    /// # futures::executor::block_on(async {
1965    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
1966    /// // Get the first 10 blocks
1967    /// let start_slot = 0;
1968    /// let limit = 10;
1969    /// let blocks = rpc_client.get_blocks_with_limit(start_slot, limit).await?;
1970    /// #     Ok::<(), Error>(())
1971    /// # })?;
1972    /// # Ok::<(), Error>(())
1973    /// ```
1974    pub async fn get_blocks_with_limit(
1975        &self,
1976        start_slot: Slot,
1977        limit: usize,
1978    ) -> ClientResult<Vec<Slot>> {
1979        self.send(RpcRequest::GetBlocksWithLimit, json!([start_slot, limit]))
1980            .await
1981    }
1982
1983    /// Returns a list of confirmed blocks starting at the given slot.
1984    ///
1985    /// # Errors
1986    ///
1987    /// This method returns an error if the limit is greater than 500,000 slots.
1988    ///
1989    /// This method returns an error if the given [commitment level][cl] is below
1990    /// [`Confirmed`].
1991    ///
1992    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
1993    /// [`Confirmed`]: CommitmentLevel::Confirmed
1994    ///
1995    /// # RPC Reference
1996    ///
1997    /// This method corresponds directly to the [`getBlocksWithLimit`] RPC
1998    /// method.
1999    ///
2000    /// [`getBlocksWithLimit`]: https://solana.com/docs/rpc/http/getblockswithlimit
2001    ///
2002    /// # Examples
2003    ///
2004    /// ```ignore
2005    /// # use solana_commitment_config::CommitmentConfig;
2006    /// # use solana_rpc_client_api::client_error::Error;
2007    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2008    /// # futures::executor::block_on(async {
2009    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2010    /// // Get the first 10 blocks
2011    /// let start_slot = 0;
2012    /// let limit = 10;
2013    /// let commitment_config = CommitmentConfig::confirmed();
2014    /// let blocks = rpc_client.get_blocks_with_limit_and_commitment(
2015    ///     start_slot,
2016    ///     limit,
2017    ///     commitment_config,
2018    /// ).await?;
2019    /// #     Ok::<(), Error>(())
2020    /// # })?;
2021    /// # Ok::<(), Error>(())
2022    /// ```
2023    pub async fn get_blocks_with_limit_and_commitment(
2024        &self,
2025        start_slot: Slot,
2026        limit: usize,
2027        commitment_config: CommitmentConfig,
2028    ) -> ClientResult<Vec<Slot>> {
2029        self.send(
2030            RpcRequest::GetBlocksWithLimit,
2031            json!([start_slot, limit, commitment_config]),
2032        )
2033        .await
2034    }
2035
2036    /// Get confirmed signatures for transactions involving an address.
2037    ///
2038    /// Returns up to 1000 signatures, ordered from newest to oldest.
2039    ///
2040    /// This method uses the [`Finalized`] [commitment level][cl].
2041    ///
2042    /// [`Finalized`]: CommitmentLevel::Finalized.
2043    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2044    ///
2045    /// # RPC Reference
2046    ///
2047    /// This method corresponds directly to the [`getSignaturesForAddress`] RPC
2048    /// method.
2049    ///
2050    /// [`getSignaturesForAddress`]: https://solana.com/docs/rpc/http/getsignaturesforaddress
2051    ///
2052    /// # Examples
2053    ///
2054    /// ```ignore
2055    /// # use solana_rpc_client_api::client_error::Error;
2056    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2057    /// # use solana_keypair::Keypair;
2058    /// # use solana_system_transaction as system_transaction;
2059    /// # use solana_signer::Signer;
2060    /// # futures::executor::block_on(async {
2061    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2062    /// #     let alice = Keypair::new();
2063    /// let signatures = rpc_client.get_signatures_for_address(
2064    ///     &alice.pubkey(),
2065    /// ).await?;
2066    /// #     Ok::<(), Error>(())
2067    /// # })?;
2068    /// # Ok::<(), Error>(())
2069    /// ```
2070    pub async fn get_signatures_for_address(
2071        &self,
2072        address: &Pubkey,
2073    ) -> ClientResult<Vec<RpcConfirmedTransactionStatusWithSignature>> {
2074        self.get_signatures_for_address_with_config(
2075            address,
2076            GetConfirmedSignaturesForAddress2Config::default(),
2077        )
2078        .await
2079    }
2080
2081    /// Get confirmed signatures for transactions involving an address.
2082    ///
2083    /// # Errors
2084    ///
2085    /// This method returns an error if the given [commitment level][cl] is below
2086    /// [`Confirmed`].
2087    ///
2088    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2089    /// [`Confirmed`]: CommitmentLevel::Confirmed
2090    ///
2091    /// # RPC Reference
2092    ///
2093    /// This method corresponds directly to the [`getSignaturesForAddress`] RPC
2094    /// method.
2095    ///
2096    /// [`getSignaturesForAddress`]: https://solana.com/docs/rpc/http/getsignaturesforaddress
2097    ///
2098    /// # Examples
2099    ///
2100    /// ```ignore
2101    /// # use solana_rpc_client_api::client_error::Error;
2102    /// # use solana_rpc_client::{
2103    /// #     nonblocking::rpc_client::RpcClient,
2104    /// #     rpc_client::GetConfirmedSignaturesForAddress2Config,
2105    /// # };
2106    /// # use solana_commitment_config::CommitmentConfig;
2107    /// # use solana_keypair::Keypair;
2108    /// # use solana_system_transaction as system_transaction;
2109    /// # use solana_signer::Signer;
2110    /// # futures::executor::block_on(async {
2111    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2112    /// #     let alice = Keypair::new();
2113    /// #     let bob = Keypair::new();
2114    /// #     let lamports = 50;
2115    /// #     let latest_blockhash = rpc_client.get_latest_blockhash().await?;
2116    /// #     let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
2117    /// #     let signature = rpc_client.send_and_confirm_transaction(&tx).await?;
2118    /// let config = GetConfirmedSignaturesForAddress2Config {
2119    ///     before: None,
2120    ///     until: None,
2121    ///     limit: Some(3),
2122    ///     commitment: Some(CommitmentConfig::confirmed()),
2123    /// };
2124    /// let signatures = rpc_client.get_signatures_for_address_with_config(
2125    ///     &alice.pubkey(),
2126    ///     config,
2127    /// ).await?;
2128    /// #     Ok::<(), Error>(())
2129    /// # })?;
2130    /// # Ok::<(), Error>(())
2131    /// ```
2132    pub async fn get_signatures_for_address_with_config(
2133        &self,
2134        address: &Pubkey,
2135        config: GetConfirmedSignaturesForAddress2Config,
2136    ) -> ClientResult<Vec<RpcConfirmedTransactionStatusWithSignature>> {
2137        let config = RpcSignaturesForAddressConfig {
2138            before: config.before.map(|signature| signature.to_string()),
2139            until: config.until.map(|signature| signature.to_string()),
2140            limit: config.limit,
2141            commitment: config.commitment,
2142            min_context_slot: None,
2143        };
2144
2145        let result: Vec<RpcConfirmedTransactionStatusWithSignature> = self
2146            .send(
2147                RpcRequest::GetSignaturesForAddress,
2148                json!([address.to_string(), config]),
2149            )
2150            .await?;
2151
2152        Ok(result)
2153    }
2154
2155    /// Returns transaction details for a confirmed transaction.
2156    ///
2157    /// This method uses the [`Finalized`] [commitment level][cl].
2158    ///
2159    /// [`Finalized`]: CommitmentLevel::Finalized
2160    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2161    ///
2162    /// # RPC Reference
2163    ///
2164    /// This method corresponds directly to the [`getTransaction`] RPC method.
2165    ///
2166    /// [`getTransaction`]: https://solana.com/docs/rpc/http/gettransaction
2167    ///
2168    /// # Examples
2169    ///
2170    /// ```ignore
2171    /// # use solana_rpc_client_api::client_error::Error;
2172    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2173    /// # use solana_keypair::Keypair;
2174    /// # use solana_system_transaction as system_transaction;
2175    /// # use solana_signature::Signature;
2176    /// # use solana_signer::Signer;
2177    /// # use solana_transaction_status_client_types::UiTransactionEncoding;
2178    /// # futures::executor::block_on(async {
2179    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2180    /// #     let alice = Keypair::new();
2181    /// #     let bob = Keypair::new();
2182    /// #     let lamports = 50;
2183    /// #     let latest_blockhash = rpc_client.get_latest_blockhash().await?;
2184    /// #     let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
2185    /// let signature = rpc_client.send_and_confirm_transaction(&tx).await?;
2186    /// let transaction = rpc_client.get_transaction(
2187    ///     &signature,
2188    ///     UiTransactionEncoding::Json,
2189    /// ).await?;
2190    /// #     Ok::<(), Error>(())
2191    /// # })?;
2192    /// # Ok::<(), Error>(())
2193    /// ```
2194    pub async fn get_transaction(
2195        &self,
2196        signature: &Signature,
2197        encoding: UiTransactionEncoding,
2198    ) -> ClientResult<EncodedConfirmedTransactionWithStatusMeta> {
2199        self.send(
2200            RpcRequest::GetTransaction,
2201            json!([signature.to_string(), encoding]),
2202        )
2203        .await
2204    }
2205
2206    /// Returns transaction details for a confirmed transaction.
2207    ///
2208    /// # Errors
2209    ///
2210    /// This method returns an error if the given [commitment level][cl] is below
2211    /// [`Confirmed`].
2212    ///
2213    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2214    /// [`Confirmed`]: CommitmentLevel::Confirmed
2215    ///
2216    /// # RPC Reference
2217    ///
2218    /// This method corresponds directly to the [`getTransaction`] RPC method.
2219    ///
2220    /// [`getTransaction`]: https://solana.com/docs/rpc/http/gettransaction
2221    ///
2222    /// # Examples
2223    ///
2224    /// ```ignore
2225    /// # use solana_rpc_client_api::{
2226    /// #     client_error::Error,
2227    /// #     config::RpcTransactionConfig,
2228    /// # };
2229    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2230    /// # use solana_commitment_config::CommitmentConfig;
2231    /// # use solana_keypair::Keypair;
2232    /// # use solana_system_transaction as system_transaction;
2233    /// # use solana_signature::Signature;
2234    /// # use solana_signer::Signer;
2235    /// # use solana_transaction_status_client_types::UiTransactionEncoding;
2236    /// # futures::executor::block_on(async {
2237    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2238    /// #     let alice = Keypair::new();
2239    /// #     let bob = Keypair::new();
2240    /// #     let lamports = 50;
2241    /// #     let latest_blockhash = rpc_client.get_latest_blockhash().await?;
2242    /// #     let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
2243    /// let signature = rpc_client.send_and_confirm_transaction(&tx).await?;
2244    /// let config = RpcTransactionConfig {
2245    ///     encoding: Some(UiTransactionEncoding::Json),
2246    ///     commitment: Some(CommitmentConfig::confirmed()),
2247    ///     max_supported_transaction_version: Some(0),
2248    /// };
2249    /// let transaction = rpc_client.get_transaction_with_config(
2250    ///     &signature,
2251    ///     config,
2252    /// ).await?;
2253    /// #     Ok::<(), Error>(())
2254    /// # })?;
2255    /// # Ok::<(), Error>(())
2256    /// ```
2257    pub async fn get_transaction_with_config(
2258        &self,
2259        signature: &Signature,
2260        config: RpcTransactionConfig,
2261    ) -> ClientResult<EncodedConfirmedTransactionWithStatusMeta> {
2262        self.send(
2263            RpcRequest::GetTransaction,
2264            json!([signature.to_string(), config]),
2265        )
2266        .await
2267    }
2268
2269    /// Returns the estimated production time of a block.
2270    ///
2271    /// # RPC Reference
2272    ///
2273    /// This method corresponds directly to the [`getBlockTime`] RPC method.
2274    ///
2275    /// [`getBlockTime`]: https://solana.com/docs/rpc/http/getblocktime
2276    ///
2277    /// # Examples
2278    ///
2279    /// ```ignore
2280    /// # use solana_rpc_client_api::client_error::Error;
2281    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2282    /// # futures::executor::block_on(async {
2283    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2284    /// // Get the time of the most recent finalized block
2285    /// let slot = rpc_client.get_slot().await?;
2286    /// let block_time = rpc_client.get_block_time(slot).await?;
2287    /// #     Ok::<(), Error>(())
2288    /// # })?;
2289    /// # Ok::<(), Error>(())
2290    /// ```
2291    pub async fn get_block_time(&self, slot: Slot) -> ClientResult<UnixTimestamp> {
2292        let request = RpcRequest::GetBlockTime;
2293        let response = self.send(request, json!([slot])).await;
2294
2295        response
2296            .map(|result_json: Value| {
2297                if result_json.is_null() {
2298                    return Err(RpcError::ForUser(format!("Block Not Found: slot={slot}")).into());
2299                }
2300                let result = serde_json::from_value(result_json)
2301                    .map_err(|err| ClientError::new_with_request(err.into(), request))?;
2302                trace!("Response block timestamp {slot:?} {result:?}");
2303                Ok(result)
2304            })
2305            .map_err(|err| err.into_with_request(request))?
2306    }
2307
2308    /// Returns information about the current epoch.
2309    ///
2310    /// This method uses the configured default [commitment level][cl].
2311    ///
2312    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2313    ///
2314    /// # RPC Reference
2315    ///
2316    /// This method corresponds directly to the [`getEpochInfo`] RPC method.
2317    ///
2318    /// [`getEpochInfo`]: https://solana.com/docs/rpc/http/getepochinfo
2319    ///
2320    /// # Examples
2321    ///
2322    /// ```ignore
2323    /// # use solana_rpc_client_api::client_error::Error;
2324    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2325    /// # futures::executor::block_on(async {
2326    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2327    /// let epoch_info = rpc_client.get_epoch_info().await?;
2328    /// #     Ok::<(), Error>(())
2329    /// # })?;
2330    /// # Ok::<(), Error>(())
2331    /// ```
2332    pub async fn get_epoch_info(&self) -> ClientResult<EpochInfo> {
2333        self.get_epoch_info_with_commitment(self.commitment()).await
2334    }
2335
2336    /// Returns information about the current epoch.
2337    ///
2338    /// # RPC Reference
2339    ///
2340    /// This method corresponds directly to the [`getEpochInfo`] RPC method.
2341    ///
2342    /// [`getEpochInfo`]: https://solana.com/docs/rpc/http/getepochinfo
2343    ///
2344    /// # Examples
2345    ///
2346    /// ```ignore
2347    /// # use solana_rpc_client_api::client_error::Error;
2348    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2349    /// # use solana_commitment_config::CommitmentConfig;
2350    /// # futures::executor::block_on(async {
2351    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2352    /// let commitment_config = CommitmentConfig::confirmed();
2353    /// let epoch_info = rpc_client.get_epoch_info_with_commitment(
2354    ///     commitment_config,
2355    /// ).await?;
2356    /// #     Ok::<(), Error>(())
2357    /// # })?;
2358    /// # Ok::<(), Error>(())
2359    /// ```
2360    pub async fn get_epoch_info_with_commitment(
2361        &self,
2362        commitment_config: CommitmentConfig,
2363    ) -> ClientResult<EpochInfo> {
2364        self.send(RpcRequest::GetEpochInfo, json!([commitment_config]))
2365            .await
2366    }
2367
2368    /// Returns the leader schedule for an epoch.
2369    ///
2370    /// This method uses the configured default [commitment level][cl].
2371    ///
2372    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2373    ///
2374    /// # RPC Reference
2375    ///
2376    /// This method corresponds directly to the [`getLeaderSchedule`] RPC method.
2377    ///
2378    /// [`getLeaderSchedule`]: https://solana.com/docs/rpc/http/getleaderschedule
2379    ///
2380    /// # Examples
2381    ///
2382    /// ```ignore
2383    /// # use solana_rpc_client_api::client_error::Error;
2384    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2385    /// # use solana_commitment_config::CommitmentConfig;
2386    /// # futures::executor::block_on(async {
2387    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2388    /// #     let slot = rpc_client.get_slot().await?;
2389    /// let leader_schedule = rpc_client.get_leader_schedule(
2390    ///     Some(slot),
2391    /// ).await?;
2392    /// #     Ok::<(), Error>(())
2393    /// # })?;
2394    /// # Ok::<(), Error>(())
2395    /// ```
2396    pub async fn get_leader_schedule(
2397        &self,
2398        slot: Option<Slot>,
2399    ) -> ClientResult<Option<RpcLeaderSchedule>> {
2400        self.get_leader_schedule_with_commitment(slot, self.commitment())
2401            .await
2402    }
2403
2404    /// Returns the leader schedule for an epoch.
2405    ///
2406    /// # RPC Reference
2407    ///
2408    /// This method corresponds directly to the [`getLeaderSchedule`] RPC method.
2409    ///
2410    /// [`getLeaderSchedule`]: https://solana.com/docs/rpc/http/getleaderschedule
2411    ///
2412    /// # Examples
2413    ///
2414    /// ```ignore
2415    /// # use solana_rpc_client_api::client_error::Error;
2416    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2417    /// # use solana_commitment_config::CommitmentConfig;
2418    /// # futures::executor::block_on(async {
2419    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2420    /// #     let slot = rpc_client.get_slot().await?;
2421    /// let commitment_config = CommitmentConfig::processed();
2422    /// let leader_schedule = rpc_client.get_leader_schedule_with_commitment(
2423    ///     Some(slot),
2424    ///     commitment_config,
2425    /// ).await?;
2426    /// #     Ok::<(), Error>(())
2427    /// # })?;
2428    /// # Ok::<(), Error>(())
2429    /// ```
2430    pub async fn get_leader_schedule_with_commitment(
2431        &self,
2432        slot: Option<Slot>,
2433        commitment_config: CommitmentConfig,
2434    ) -> ClientResult<Option<RpcLeaderSchedule>> {
2435        self.get_leader_schedule_with_config(
2436            slot,
2437            RpcLeaderScheduleConfig {
2438                commitment: Some(commitment_config),
2439                ..RpcLeaderScheduleConfig::default()
2440            },
2441        )
2442        .await
2443    }
2444
2445    /// Returns the leader schedule for an epoch.
2446    ///
2447    /// # RPC Reference
2448    ///
2449    /// This method corresponds directly to the [`getLeaderSchedule`] RPC method.
2450    ///
2451    /// [`getLeaderSchedule`]: https://solana.com/docs/rpc/http/getleaderschedule
2452    ///
2453    /// # Examples
2454    ///
2455    /// ```ignore
2456    /// # use solana_rpc_client_api::{
2457    /// #     client_error::Error,
2458    /// #     config::RpcLeaderScheduleConfig,
2459    /// # };
2460    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2461    /// # use solana_commitment_config::CommitmentConfig;
2462    /// # futures::executor::block_on(async {
2463    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2464    /// #     let slot = rpc_client.get_slot().await?;
2465    /// #     let validator_pubkey_str = "7AYmEYBBetok8h5L3Eo3vi3bDWnjNnaFbSXfSNYV5ewB".to_string();
2466    /// let config = RpcLeaderScheduleConfig {
2467    ///     identity: Some(validator_pubkey_str),
2468    ///     commitment: Some(CommitmentConfig::processed()),
2469    /// };
2470    /// let leader_schedule = rpc_client.get_leader_schedule_with_config(
2471    ///     Some(slot),
2472    ///     config,
2473    /// ).await?;
2474    /// #     Ok::<(), Error>(())
2475    /// # })?;
2476    /// # Ok::<(), Error>(())
2477    /// ```
2478    pub async fn get_leader_schedule_with_config(
2479        &self,
2480        slot: Option<Slot>,
2481        config: RpcLeaderScheduleConfig,
2482    ) -> ClientResult<Option<RpcLeaderSchedule>> {
2483        self.send(RpcRequest::GetLeaderSchedule, json!([slot, config]))
2484            .await
2485    }
2486
2487    /// Returns epoch schedule information from this cluster's genesis config.
2488    ///
2489    /// # RPC Reference
2490    ///
2491    /// This method corresponds directly to the [`getEpochSchedule`] RPC method.
2492    ///
2493    /// [`getEpochSchedule`]: https://solana.com/docs/rpc/http/getepochschedule
2494    ///
2495    /// # Examples
2496    ///
2497    /// ```ignore
2498    /// # use solana_rpc_client_api::client_error::Error;
2499    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2500    /// # futures::executor::block_on(async {
2501    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2502    /// let epoch_schedule = rpc_client.get_epoch_schedule().await?;
2503    /// #     Ok::<(), Error>(())
2504    /// # })?;
2505    /// # Ok::<(), Error>(())
2506    /// ```
2507    pub async fn get_epoch_schedule(&self) -> ClientResult<EpochSchedule> {
2508        self.send(RpcRequest::GetEpochSchedule, Value::Null).await
2509    }
2510
2511    /// Returns a list of recent performance samples, in reverse slot order.
2512    ///
2513    /// Performance samples are taken every 60 seconds and include the number of
2514    /// transactions and slots that occur in a given time window.
2515    ///
2516    /// # RPC Reference
2517    ///
2518    /// This method corresponds directly to the [`getRecentPerformanceSamples`] RPC method.
2519    ///
2520    /// [`getRecentPerformanceSamples`]: https://solana.com/docs/rpc/http/getrecentperformancesamples
2521    ///
2522    /// # Examples
2523    ///
2524    /// ```ignore
2525    /// # use solana_rpc_client_api::client_error::Error;
2526    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2527    /// # futures::executor::block_on(async {
2528    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2529    /// let limit = 10;
2530    /// let performance_samples = rpc_client.get_recent_performance_samples(
2531    ///     Some(limit),
2532    /// ).await?;
2533    /// #     Ok::<(), Error>(())
2534    /// # })?;
2535    /// # Ok::<(), Error>(())
2536    /// ```
2537    pub async fn get_recent_performance_samples(
2538        &self,
2539        limit: Option<usize>,
2540    ) -> ClientResult<Vec<RpcPerfSample>> {
2541        self.send(RpcRequest::GetRecentPerformanceSamples, json!([limit]))
2542            .await
2543    }
2544
2545    /// Returns a list of minimum prioritization fees from recent blocks.
2546    /// Takes an optional vector of addresses; if any addresses are provided, the response will
2547    /// reflect the minimum prioritization fee to land a transaction locking all of the provided
2548    /// accounts as writable.
2549    ///
2550    /// Currently, a node's prioritization-fee cache stores data from up to 150 blocks.
2551    ///
2552    /// # RPC Reference
2553    ///
2554    /// This method corresponds directly to the [`getRecentPrioritizationFees`] RPC method.
2555    ///
2556    /// [`getRecentPrioritizationFees`]: https://solana.com/docs/rpc/http/getrecentprioritizationfees
2557    ///
2558    /// # Examples
2559    ///
2560    /// ```ignore
2561    /// # use solana_rpc_client_api::client_error::Error;
2562    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2563    /// # use solana_keypair::Keypair;
2564    /// # use solana_signer::Signer;
2565    /// # futures::executor::block_on(async {
2566    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2567    /// #     let alice = Keypair::new();
2568    /// #     let bob = Keypair::new();
2569    /// let addresses = vec![alice.pubkey(), bob.pubkey()];
2570    /// let prioritization_fees = rpc_client.get_recent_prioritization_fees(
2571    ///     &addresses,
2572    /// ).await?;
2573    /// #     Ok::<(), Error>(())
2574    /// # })?;
2575    /// # Ok::<(), Error>(())
2576    /// ```
2577    pub async fn get_recent_prioritization_fees(
2578        &self,
2579        addresses: &[Pubkey],
2580    ) -> ClientResult<Vec<RpcPrioritizationFee>> {
2581        let addresses: Vec<_> = addresses
2582            .iter()
2583            .map(|address| address.to_string())
2584            .collect();
2585        self.send(RpcRequest::GetRecentPrioritizationFees, json!([addresses]))
2586            .await
2587    }
2588
2589    /// Returns the identity pubkey for the current node.
2590    ///
2591    /// # RPC Reference
2592    ///
2593    /// This method corresponds directly to the [`getIdentity`] RPC method.
2594    ///
2595    /// [`getIdentity`]: https://solana.com/docs/rpc/http/getidentity
2596    ///
2597    /// # Examples
2598    ///
2599    /// ```ignore
2600    /// # use solana_rpc_client_api::client_error::Error;
2601    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2602    /// # futures::executor::block_on(async {
2603    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2604    /// let identity = rpc_client.get_identity().await?;
2605    /// #     Ok::<(), Error>(())
2606    /// # })?;
2607    /// # Ok::<(), Error>(())
2608    /// ```
2609    pub async fn get_identity(&self) -> ClientResult<Pubkey> {
2610        let rpc_identity: RpcIdentity = self.send(RpcRequest::GetIdentity, Value::Null).await?;
2611
2612        rpc_identity.identity.parse::<Pubkey>().map_err(|_| {
2613            ClientError::new_with_request(
2614                RpcError::ParseError("Pubkey".to_string()).into(),
2615                RpcRequest::GetIdentity,
2616            )
2617        })
2618    }
2619
2620    /// Returns the current inflation governor.
2621    ///
2622    /// This method uses the [`Finalized`] [commitment level][cl].
2623    ///
2624    /// [`Finalized`]: CommitmentLevel::Finalized
2625    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2626    ///
2627    /// # RPC Reference
2628    ///
2629    /// This method corresponds directly to the [`getInflationGovernor`] RPC
2630    /// method.
2631    ///
2632    /// [`getInflationGovernor`]: https://solana.com/docs/rpc/http/getinflationgovernor
2633    ///
2634    /// # Examples
2635    ///
2636    /// ```ignore
2637    /// # use solana_rpc_client_api::client_error::Error;
2638    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2639    /// # futures::executor::block_on(async {
2640    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2641    /// let inflation_governor = rpc_client.get_inflation_governor().await?;
2642    /// #     Ok::<(), Error>(())
2643    /// # })?;
2644    /// # Ok::<(), Error>(())
2645    /// ```
2646    pub async fn get_inflation_governor(&self) -> ClientResult<RpcInflationGovernor> {
2647        self.send(RpcRequest::GetInflationGovernor, Value::Null)
2648            .await
2649    }
2650
2651    /// Returns the specific inflation values for the current epoch.
2652    ///
2653    /// # RPC Reference
2654    ///
2655    /// This method corresponds directly to the [`getInflationRate`] RPC method.
2656    ///
2657    /// [`getInflationRate`]: https://solana.com/docs/rpc/http/getinflationrate
2658    ///
2659    /// # Examples
2660    ///
2661    /// ```ignore
2662    /// # use solana_rpc_client_api::client_error::Error;
2663    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2664    /// # futures::executor::block_on(async {
2665    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2666    /// let inflation_rate = rpc_client.get_inflation_rate().await?;
2667    /// #    Ok::<(), Error>(())
2668    /// # })?;
2669    /// # Ok::<(), Error>(())
2670    /// ```
2671    pub async fn get_inflation_rate(&self) -> ClientResult<RpcInflationRate> {
2672        self.send(RpcRequest::GetInflationRate, Value::Null).await
2673    }
2674
2675    /// Returns the inflation reward for a list of addresses for an epoch.
2676    ///
2677    /// This method uses the configured [commitment level][cl].
2678    ///
2679    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2680    ///
2681    /// # RPC Reference
2682    ///
2683    /// This method corresponds directly to the [`getInflationReward`] RPC method.
2684    ///
2685    /// [`getInflationReward`]: https://solana.com/docs/rpc/http/getinflationreward
2686    ///
2687    /// # Examples
2688    ///
2689    /// ```ignore
2690    /// # use solana_rpc_client_api::client_error::Error;
2691    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2692    /// # use solana_keypair::Keypair;
2693    /// # use solana_signer::Signer;
2694    /// # futures::executor::block_on(async {
2695    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2696    /// #     let epoch_info = rpc_client.get_epoch_info().await?;
2697    /// #     let epoch = epoch_info.epoch;
2698    /// #     let alice = Keypair::new();
2699    /// #     let bob = Keypair::new();
2700    /// let addresses = vec![alice.pubkey(), bob.pubkey()];
2701    /// let inflation_reward = rpc_client.get_inflation_reward(
2702    ///     &addresses,
2703    ///     Some(epoch),
2704    /// ).await?;
2705    /// #     Ok::<(), Error>(())
2706    /// # })?;
2707    /// # Ok::<(), Error>(())
2708    /// ```
2709    pub async fn get_inflation_reward(
2710        &self,
2711        addresses: &[Pubkey],
2712        epoch: Option<Epoch>,
2713    ) -> ClientResult<Vec<Option<RpcInflationReward>>> {
2714        let addresses: Vec<_> = addresses
2715            .iter()
2716            .map(|address| address.to_string())
2717            .collect();
2718        self.send(
2719            RpcRequest::GetInflationReward,
2720            json!([
2721                addresses,
2722                RpcEpochConfig {
2723                    epoch,
2724                    commitment: Some(self.commitment()),
2725                    min_context_slot: None,
2726                }
2727            ]),
2728        )
2729        .await
2730    }
2731
2732    /// Returns the current solana version running on the node.
2733    ///
2734    /// # RPC Reference
2735    ///
2736    /// This method corresponds directly to the [`getVersion`] RPC method.
2737    ///
2738    /// [`getVersion`]: https://solana.com/docs/rpc/http/getversion
2739    ///
2740    /// # Examples
2741    ///
2742    /// ```ignore
2743    /// # use solana_rpc_client_api::client_error::Error;
2744    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2745    /// # use solana_keypair::Keypair;
2746    /// # use solana_signer::Signer;
2747    /// # futures::executor::block_on(async {
2748    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2749    /// let expected_version = semver::Version::new(1, 7, 0);
2750    /// let version = rpc_client.get_version().await?;
2751    /// let version = semver::Version::parse(&version.solana_core)?;
2752    /// assert!(version >= expected_version);
2753    /// #     Ok::<(), Box<dyn std::error::Error>>(())
2754    /// # })?;
2755    /// # Ok::<(), Box<dyn std::error::Error>>(())
2756    /// ```
2757    pub async fn get_version(&self) -> ClientResult<RpcVersionInfo> {
2758        self.send(RpcRequest::GetVersion, Value::Null).await
2759    }
2760
2761    /// Returns the lowest slot that the node has information about in its ledger.
2762    ///
2763    /// This value may increase over time if the node is configured to purge
2764    /// older ledger data.
2765    ///
2766    /// # RPC Reference
2767    ///
2768    /// This method corresponds directly to the [`minimumLedgerSlot`] RPC
2769    /// method.
2770    ///
2771    /// [`minimumLedgerSlot`]: https://solana.com/docs/rpc/http/minimumledgerslot
2772    ///
2773    /// # Examples
2774    ///
2775    /// ```ignore
2776    /// # use solana_rpc_client_api::client_error::Error;
2777    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
2778    /// # futures::executor::block_on(async {
2779    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
2780    /// let slot = rpc_client.minimum_ledger_slot().await?;
2781    /// #     Ok::<(), Error>(())
2782    /// # })?;
2783    /// # Ok::<(), Error>(())
2784    /// ```
2785    pub async fn minimum_ledger_slot(&self) -> ClientResult<Slot> {
2786        self.send(RpcRequest::MinimumLedgerSlot, Value::Null).await
2787    }
2788
2789    /// Returns all information associated with the account of the provided pubkey.
2790    ///
2791    /// This method uses the configured [commitment level][cl].
2792    ///
2793    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2794    ///
2795    /// To get multiple accounts at once, use the [`get_multiple_accounts`] method.
2796    ///
2797    /// [`get_multiple_accounts`]: RpcClient::get_multiple_accounts
2798    ///
2799    /// # Errors
2800    ///
2801    /// If the account does not exist, this method returns
2802    /// [`RpcError::ForUser`]. This is unlike [`get_account_with_commitment`],
2803    /// which returns `Ok(None)` if the account does not exist.
2804    ///
2805    /// [`get_account_with_commitment`]: RpcClient::get_account_with_commitment
2806    ///
2807    /// # RPC Reference
2808    ///
2809    /// This method is built on the [`getAccountInfo`] RPC method.
2810    ///
2811    /// [`getAccountInfo`]: https://solana.com/docs/rpc/http/getaccountinfo
2812    ///
2813    /// # Examples
2814    ///
2815    /// ```ignore
2816    /// # use solana_rpc_client_api::client_error::Error;
2817    /// # use solana_rpc_client::nonblocking::rpc_client::{self, RpcClient};
2818    /// # use solana_keypair::Keypair;
2819    /// # use solana_pubkey::Pubkey;
2820    /// # use solana_signer::Signer;
2821    /// # use std::str::FromStr;
2822    /// # futures::executor::block_on(async {
2823    /// #     let mocks = rpc_client::create_rpc_client_mocks();
2824    /// #     let rpc_client = RpcClient::new_mock_with_mocks("succeeds".to_string(), mocks);
2825    /// let alice_pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
2826    /// let account = rpc_client.get_account(&alice_pubkey).await?;
2827    /// #     Ok::<(), Error>(())
2828    /// # })?;
2829    /// # Ok::<(), Error>(())
2830    /// ```
2831    pub async fn get_account(&self, pubkey: &Pubkey) -> ClientResult<Account> {
2832        self.get_account_with_commitment(pubkey, self.commitment())
2833            .await?
2834            .value
2835            .ok_or_else(|| RpcError::ForUser(format!("AccountNotFound: pubkey={pubkey}")).into())
2836    }
2837
2838    /// Returns all information associated with the account of the provided pubkey.
2839    ///
2840    /// If the account does not exist, this method returns `Ok(None)`.
2841    ///
2842    /// To get multiple accounts at once, use the [`get_multiple_accounts_with_commitment`] method.
2843    ///
2844    /// [`get_multiple_accounts_with_commitment`]: RpcClient::get_multiple_accounts_with_commitment
2845    ///
2846    /// # RPC Reference
2847    ///
2848    /// This method is built on the [`getAccountInfo`] RPC method.
2849    ///
2850    /// [`getAccountInfo`]: https://solana.com/docs/rpc/http/getaccountinfo
2851    ///
2852    /// # Examples
2853    ///
2854    /// ```ignore
2855    /// # use solana_rpc_client_api::client_error::Error;
2856    /// # use solana_rpc_client::nonblocking::rpc_client::{self, RpcClient};
2857    /// # use solana_commitment_config::CommitmentConfig;
2858    /// # use solana_keypair::Keypair;
2859    /// # use solana_signer::Signer;
2860    /// # use solana_pubkey::Pubkey;
2861    /// # use std::str::FromStr;
2862    /// # futures::executor::block_on(async {
2863    /// #     let mocks = rpc_client::create_rpc_client_mocks();
2864    /// #     let rpc_client = RpcClient::new_mock_with_mocks("succeeds".to_string(), mocks);
2865    /// let alice_pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
2866    /// let commitment_config = CommitmentConfig::processed();
2867    /// let account = rpc_client.get_account_with_commitment(
2868    ///     &alice_pubkey,
2869    ///     commitment_config,
2870    /// ).await?;
2871    /// assert!(account.value.is_some());
2872    /// #     Ok::<(), Error>(())
2873    /// # })?;
2874    /// # Ok::<(), Error>(())
2875    /// ```
2876    pub async fn get_account_with_commitment(
2877        &self,
2878        pubkey: &Pubkey,
2879        commitment_config: CommitmentConfig,
2880    ) -> RpcResult<Option<Account>> {
2881        let config = RpcAccountInfoConfig {
2882            encoding: Some(UiAccountEncoding::Base64Zstd),
2883            commitment: Some(commitment_config),
2884            data_slice: None,
2885            min_context_slot: None,
2886        };
2887
2888        self.get_ui_account_with_config(pubkey, config)
2889            .await
2890            .map(|response| Response {
2891                context: response.context,
2892                value: response.value.map(|ui_account| {
2893                    ui_account.decode().expect(
2894                        "It should be impossible at this point for the account data not to be \
2895                         decodable. Ensure that the account was fetched using a binary encoding.",
2896                    )
2897                }),
2898            })
2899    }
2900
2901    #[deprecated(
2902        note = "Use `get_ui_account_with_config()` instead. This function will be removed in a \
2903                future version of `solana_rpc_client`."
2904    )]
2905    pub async fn get_account_with_config(
2906        &self,
2907        pubkey: &Pubkey,
2908        config: RpcAccountInfoConfig,
2909    ) -> RpcResult<Option<Account>> {
2910        #[allow(deprecated)]
2911        let response = self
2912            .send(
2913                RpcRequest::GetAccountInfo,
2914                json!([pubkey.to_string(), config]),
2915            )
2916            .await;
2917
2918        response
2919            .map(|result_json: Value| {
2920                if result_json.is_null() {
2921                    return Err(
2922                        RpcError::ForUser(format!("AccountNotFound: pubkey={pubkey}")).into(),
2923                    );
2924                }
2925                let Response {
2926                    context,
2927                    value: rpc_account,
2928                } = serde_json::from_value::<Response<Option<UiAccount>>>(result_json)?;
2929                trace!("Response account {pubkey:?} {rpc_account:?}");
2930                let account = rpc_account.and_then(|rpc_account| rpc_account.decode());
2931
2932                Ok(Response {
2933                    context,
2934                    value: account,
2935                })
2936            })
2937            .map_err(|err| {
2938                Into::<ClientError>::into(RpcError::ForUser(format!(
2939                    "AccountNotFound: pubkey={pubkey}: {err}"
2940                )))
2941            })?
2942    }
2943
2944    /// Returns all information associated with the account of the provided pubkey.
2945    ///
2946    /// If the account does not exist, this method returns `Ok(None)`.
2947    ///
2948    /// To get multiple accounts at once, use the [`get_multiple_ui_accounts_with_config`] method.
2949    ///
2950    /// [`get_multiple_ui_accounts_with_config`]: RpcClient::get_multiple_ui_accounts_with_config
2951    ///
2952    /// # RPC Reference
2953    ///
2954    /// This method is built on the [`getAccountInfo`] RPC method.
2955    ///
2956    /// [`getAccountInfo`]: https://solana.com/docs/rpc/http/getaccountinfo
2957    ///
2958    /// # Examples
2959    ///
2960    /// ```ignore
2961    /// # use solana_rpc_client_api::{
2962    /// #     config::RpcAccountInfoConfig,
2963    /// #     client_error::Error,
2964    /// # };
2965    /// # use solana_rpc_client::nonblocking::rpc_client::{self, RpcClient};
2966    /// # use solana_commitment_config::CommitmentConfig;
2967    /// # use solana_keypair::Keypair;
2968    /// # use solana_signer::Signer;
2969    /// # use solana_pubkey::Pubkey;
2970    /// # use solana_account_decoder_client_types::UiAccountEncoding;
2971    /// # use std::str::FromStr;
2972    /// # futures::executor::block_on(async {
2973    /// #     let mocks = rpc_client::create_rpc_client_mocks();
2974    /// #     let rpc_client = RpcClient::new_mock_with_mocks("succeeds".to_string(), mocks);
2975    /// let alice_pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
2976    /// let commitment_config = CommitmentConfig::processed();
2977    /// let config = RpcAccountInfoConfig {
2978    ///     encoding: Some(UiAccountEncoding::Base64),
2979    ///     commitment: Some(commitment_config),
2980    ///     .. RpcAccountInfoConfig::default()
2981    /// };
2982    /// let ui_account = rpc_client.get_ui_account_with_config(
2983    ///     &alice_pubkey,
2984    ///     config,
2985    /// ).await?;
2986    /// assert!(ui_account.value.is_some());
2987    /// #     Ok::<(), Error>(())
2988    /// # })?;
2989    /// # Ok::<(), Error>(())
2990    /// ```
2991    pub async fn get_ui_account_with_config(
2992        &self,
2993        pubkey: &Pubkey,
2994        config: RpcAccountInfoConfig,
2995    ) -> RpcResult<Option<UiAccount>> {
2996        let response = self
2997            .send(
2998                RpcRequest::GetAccountInfo,
2999                json!([pubkey.to_string(), config]),
3000            )
3001            .await;
3002
3003        response
3004            .map(|result_json: Value| {
3005                if result_json.is_null() {
3006                    return Err(
3007                        RpcError::ForUser(format!("AccountNotFound: pubkey={pubkey}")).into(),
3008                    );
3009                }
3010                let Response {
3011                    context,
3012                    value: ui_account,
3013                } = serde_json::from_value::<Response<Option<UiAccount>>>(result_json)?;
3014                trace!("Response account {pubkey:?} {ui_account:?}");
3015                Ok(Response {
3016                    context,
3017                    value: ui_account,
3018                })
3019            })
3020            .map_err(|err| {
3021                Into::<ClientError>::into(RpcError::ForUser(format!(
3022                    "AccountNotFound: pubkey={pubkey}: {err}"
3023                )))
3024            })?
3025    }
3026
3027    /// Get the max slot seen from retransmit stage.
3028    ///
3029    /// # RPC Reference
3030    ///
3031    /// This method corresponds directly to the [`getMaxRetransmitSlot`] RPC
3032    /// method.
3033    ///
3034    /// [`getMaxRetransmitSlot`]: https://solana.com/docs/rpc/http/getmaxretransmitslot
3035    ///
3036    /// # Examples
3037    ///
3038    /// ```ignore
3039    /// # use solana_rpc_client_api::client_error::Error;
3040    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3041    /// # futures::executor::block_on(async {
3042    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3043    /// let slot = rpc_client.get_max_retransmit_slot().await?;
3044    /// #     Ok::<(), Error>(())
3045    /// # })?;
3046    /// # Ok::<(), Error>(())
3047    pub async fn get_max_retransmit_slot(&self) -> ClientResult<Slot> {
3048        self.send(RpcRequest::GetMaxRetransmitSlot, Value::Null)
3049            .await
3050    }
3051
3052    /// Get the max slot seen from after [shred](https://solana.com/docs/terminology#shred) insert.
3053    ///
3054    /// # RPC Reference
3055    ///
3056    /// This method corresponds directly to the
3057    /// [`getMaxShredInsertSlot`] RPC method.
3058    ///
3059    /// [`getMaxShredInsertSlot`]: https://solana.com/docs/rpc/http/getmaxshredinsertslot
3060    ///
3061    /// # Examples
3062    ///
3063    /// ```ignore
3064    /// # use solana_rpc_client_api::client_error::Error;
3065    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3066    /// # futures::executor::block_on(async {
3067    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3068    /// let slot = rpc_client.get_max_shred_insert_slot().await?;
3069    /// #     Ok::<(), Error>(())
3070    /// # })?;
3071    /// # Ok::<(), Error>(())
3072    pub async fn get_max_shred_insert_slot(&self) -> ClientResult<Slot> {
3073        self.send(RpcRequest::GetMaxShredInsertSlot, Value::Null)
3074            .await
3075    }
3076
3077    /// Returns the account information for a list of pubkeys.
3078    ///
3079    /// This method uses the configured [commitment level][cl].
3080    ///
3081    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
3082    ///
3083    /// # RPC Reference
3084    ///
3085    /// This method is built on the [`getMultipleAccounts`] RPC method.
3086    ///
3087    /// [`getMultipleAccounts`]: https://solana.com/docs/rpc/http/getmultipleaccounts
3088    ///
3089    /// # Examples
3090    ///
3091    /// ```ignore
3092    /// # use solana_rpc_client_api::client_error::Error;
3093    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3094    /// # use solana_keypair::Keypair;
3095    /// # use solana_signer::Signer;
3096    /// # futures::executor::block_on(async {
3097    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3098    /// #     let alice = Keypair::new();
3099    /// #     let bob = Keypair::new();
3100    /// let pubkeys = vec![alice.pubkey(), bob.pubkey()];
3101    /// let accounts = rpc_client.get_multiple_accounts(&pubkeys).await?;
3102    /// #     Ok::<(), Error>(())
3103    /// # })?;
3104    /// # Ok::<(), Error>(())
3105    /// ```
3106    pub async fn get_multiple_accounts(
3107        &self,
3108        pubkeys: &[Pubkey],
3109    ) -> ClientResult<Vec<Option<Account>>> {
3110        Ok(self
3111            .get_multiple_accounts_with_commitment(pubkeys, self.commitment())
3112            .await?
3113            .value)
3114    }
3115
3116    /// Returns the account information for a list of pubkeys.
3117    ///
3118    /// # RPC Reference
3119    ///
3120    /// This method is built on the [`getMultipleAccounts`] RPC method.
3121    ///
3122    /// [`getMultipleAccounts`]: https://solana.com/docs/rpc/http/getmultipleaccounts
3123    ///
3124    /// # Examples
3125    ///
3126    /// ```ignore
3127    /// # use solana_rpc_client_api::client_error::Error;
3128    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3129    /// # use solana_commitment_config::CommitmentConfig;
3130    /// # use solana_keypair::Keypair;
3131    /// # use solana_signer::Signer;
3132    /// # futures::executor::block_on(async {
3133    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3134    /// #     let alice = Keypair::new();
3135    /// #     let bob = Keypair::new();
3136    /// let pubkeys = vec![alice.pubkey(), bob.pubkey()];
3137    /// let commitment_config = CommitmentConfig::processed();
3138    /// let accounts = rpc_client.get_multiple_accounts_with_commitment(
3139    ///     &pubkeys,
3140    ///     commitment_config,
3141    /// ).await?;
3142    /// #     Ok::<(), Error>(())
3143    /// # })?;
3144    /// # Ok::<(), Error>(())
3145    /// ```
3146    pub async fn get_multiple_accounts_with_commitment(
3147        &self,
3148        pubkeys: &[Pubkey],
3149        commitment_config: CommitmentConfig,
3150    ) -> RpcResult<Vec<Option<Account>>> {
3151        self.get_multiple_ui_accounts_with_config(
3152            pubkeys,
3153            RpcAccountInfoConfig {
3154                encoding: Some(UiAccountEncoding::Base64Zstd),
3155                commitment: Some(commitment_config),
3156                data_slice: None,
3157                min_context_slot: None,
3158            },
3159        )
3160        .await
3161        .map(|response| Response {
3162            context: response.context,
3163            value: response
3164                .value
3165                .into_iter()
3166                .map(|ui_account| {
3167                    ui_account.map(|ui_account| {
3168                        ui_account.decode().expect(
3169                            "It should be impossible at this point for the account data not to be \
3170                             decodable. Ensure that the account was fetched using a binary \
3171                             encoding.",
3172                        )
3173                    })
3174                })
3175                .collect(),
3176        })
3177    }
3178
3179    #[deprecated(
3180        note = "Use `get_multiple_ui_accounts_with_config()` instead. This function will be \
3181                removed in a future version of `solana_rpc_client`."
3182    )]
3183    pub async fn get_multiple_accounts_with_config(
3184        &self,
3185        pubkeys: &[Pubkey],
3186        config: RpcAccountInfoConfig,
3187    ) -> RpcResult<Vec<Option<Account>>> {
3188        #[allow(deprecated)]
3189        {
3190            let config = RpcAccountInfoConfig {
3191                commitment: config.commitment.or_else(|| Some(self.commitment())),
3192                ..config
3193            };
3194            let pubkeys: Vec<_> = pubkeys.iter().map(|pubkey| pubkey.to_string()).collect();
3195            let response = self
3196                .send(RpcRequest::GetMultipleAccounts, json!([pubkeys, config]))
3197                .await?;
3198            let Response {
3199                context,
3200                value: accounts,
3201            } = serde_json::from_value::<Response<Vec<Option<UiAccount>>>>(response)?;
3202            let accounts: Vec<Option<Account>> = accounts
3203                .into_iter()
3204                .map(|rpc_account| rpc_account.and_then(|a| a.decode()))
3205                .collect();
3206            Ok(Response {
3207                context,
3208                value: accounts,
3209            })
3210        }
3211    }
3212
3213    /// Returns the account information for a list of pubkeys.
3214    ///
3215    /// # RPC Reference
3216    ///
3217    /// This method is built on the [`getMultipleAccounts`] RPC method.
3218    ///
3219    /// [`getMultipleAccounts`]: https://solana.com/docs/rpc/http/getmultipleaccounts
3220    ///
3221    /// # Examples
3222    ///
3223    /// ```ignore
3224    /// # use solana_rpc_client_api::{
3225    /// #     config::RpcAccountInfoConfig,
3226    /// #     client_error::Error,
3227    /// # };
3228    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3229    /// # use solana_commitment_config::CommitmentConfig;
3230    /// # use solana_keypair::Keypair;
3231    /// # use solana_signer::Signer;
3232    /// # use solana_account_decoder_client_types::UiAccountEncoding;
3233    /// # futures::executor::block_on(async {
3234    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3235    /// #     let alice = Keypair::new();
3236    /// #     let bob = Keypair::new();
3237    /// let pubkeys = vec![alice.pubkey(), bob.pubkey()];
3238    /// let commitment_config = CommitmentConfig::processed();
3239    /// let config = RpcAccountInfoConfig {
3240    ///     encoding: Some(UiAccountEncoding::Base64),
3241    ///     commitment: Some(commitment_config),
3242    ///     .. RpcAccountInfoConfig::default()
3243    /// };
3244    /// let ui_accounts = rpc_client.get_multiple_ui_accounts_with_config(
3245    ///     &pubkeys,
3246    ///     config,
3247    /// ).await?;
3248    /// #     Ok::<(), Error>(())
3249    /// # })?;
3250    /// # Ok::<(), Error>(())
3251    /// ```
3252    pub async fn get_multiple_ui_accounts_with_config(
3253        &self,
3254        pubkeys: &[Pubkey],
3255        config: RpcAccountInfoConfig,
3256    ) -> RpcResult<Vec<Option<UiAccount>>> {
3257        let config = RpcAccountInfoConfig {
3258            commitment: config.commitment.or_else(|| Some(self.commitment())),
3259            ..config
3260        };
3261        let pubkeys: Vec<_> = pubkeys.iter().map(|pubkey| pubkey.to_string()).collect();
3262        let response = self
3263            .send(RpcRequest::GetMultipleAccounts, json!([pubkeys, config]))
3264            .await?;
3265        let Response {
3266            context,
3267            value: ui_accounts,
3268        } = serde_json::from_value::<Response<Vec<Option<UiAccount>>>>(response)?;
3269        Ok(Response {
3270            context,
3271            value: ui_accounts,
3272        })
3273    }
3274
3275    /// Gets the raw data associated with an account.
3276    ///
3277    /// This is equivalent to calling [`get_account`] and then accessing the
3278    /// [`data`] field of the returned [`Account`].
3279    ///
3280    /// [`get_account`]: RpcClient::get_account
3281    /// [`data`]: Account::data
3282    ///
3283    /// # RPC Reference
3284    ///
3285    /// This method is built on the [`getAccountInfo`] RPC method.
3286    ///
3287    /// [`getAccountInfo`]: https://solana.com/docs/rpc/http/getaccountinfo
3288    ///
3289    /// # Examples
3290    ///
3291    /// ```ignore
3292    /// # use solana_rpc_client_api::client_error::Error;
3293    /// # use solana_rpc_client::nonblocking::rpc_client::{self, RpcClient};
3294    /// # use solana_keypair::Keypair;
3295    /// # use solana_pubkey::Pubkey;
3296    /// # use solana_signer::Signer;
3297    /// # use std::str::FromStr;
3298    /// # futures::executor::block_on(async {
3299    /// #     let mocks = rpc_client::create_rpc_client_mocks();
3300    /// #     let rpc_client = RpcClient::new_mock_with_mocks("succeeds".to_string(), mocks);
3301    /// let alice_pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
3302    /// let account_data = rpc_client.get_account_data(&alice_pubkey).await?;
3303    /// #     Ok::<(), Error>(())
3304    /// # })?;
3305    /// # Ok::<(), Error>(())
3306    /// ```
3307    pub async fn get_account_data(&self, pubkey: &Pubkey) -> ClientResult<Vec<u8>> {
3308        Ok(self.get_account(pubkey).await?.data)
3309    }
3310
3311    /// Returns minimum balance required to make an account with specified data length rent exempt.
3312    ///
3313    /// # RPC Reference
3314    ///
3315    /// This method corresponds directly to the
3316    /// [`getMinimumBalanceForRentExemption`] RPC method.
3317    ///
3318    /// [`getMinimumBalanceForRentExemption`]: https://solana.com/docs/rpc/http/getminimumbalanceforrentexemption
3319    ///
3320    /// # Examples
3321    ///
3322    /// ```ignore
3323    /// # use solana_rpc_client_api::client_error::Error;
3324    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3325    /// # futures::executor::block_on(async {
3326    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3327    /// let data_len = 300;
3328    /// let balance = rpc_client.get_minimum_balance_for_rent_exemption(data_len).await?;
3329    /// #     Ok::<(), Error>(())
3330    /// # })?;
3331    /// # Ok::<(), Error>(())
3332    /// ```
3333    pub async fn get_minimum_balance_for_rent_exemption(
3334        &self,
3335        data_len: usize,
3336    ) -> ClientResult<u64> {
3337        let request = RpcRequest::GetMinimumBalanceForRentExemption;
3338        let minimum_balance_json: Value = self
3339            .send(request, json!([data_len]))
3340            .await
3341            .map_err(|err| err.into_with_request(request))?;
3342
3343        let minimum_balance: u64 = serde_json::from_value(minimum_balance_json)
3344            .map_err(|err| ClientError::new_with_request(err.into(), request))?;
3345        trace!("Response minimum balance {data_len:?} {minimum_balance:?}");
3346        Ok(minimum_balance)
3347    }
3348
3349    /// Request the balance of the provided account pubkey.
3350    ///
3351    /// This method uses the configured [commitment level][cl].
3352    ///
3353    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
3354    ///
3355    /// # RPC Reference
3356    ///
3357    /// This method corresponds directly to the [`getBalance`] RPC method.
3358    ///
3359    /// [`getBalance`]: https://solana.com/docs/rpc/http/getbalance
3360    ///
3361    /// # Examples
3362    ///
3363    /// ```ignore
3364    /// # use solana_rpc_client_api::client_error::Error;
3365    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3366    /// # use solana_keypair::Keypair;
3367    /// # use solana_signer::Signer;
3368    /// # futures::executor::block_on(async {
3369    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3370    /// #     let alice = Keypair::new();
3371    /// let balance = rpc_client.get_balance(&alice.pubkey()).await?;
3372    /// #     Ok::<(), Error>(())
3373    /// # })?;
3374    /// # Ok::<(), Error>(())
3375    /// ```
3376    pub async fn get_balance(&self, pubkey: &Pubkey) -> ClientResult<u64> {
3377        Ok(self
3378            .get_balance_with_commitment(pubkey, self.commitment())
3379            .await?
3380            .value)
3381    }
3382
3383    /// Request the balance of the provided account pubkey.
3384    ///
3385    /// # RPC Reference
3386    ///
3387    /// This method corresponds directly to the [`getBalance`] RPC method.
3388    ///
3389    /// [`getBalance`]: https://solana.com/docs/rpc/http/getbalance
3390    ///
3391    /// # Examples
3392    ///
3393    /// ```ignore
3394    /// # use solana_rpc_client_api::client_error::Error;
3395    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3396    /// # use solana_commitment_config::CommitmentConfig;
3397    /// # use solana_keypair::Keypair;
3398    /// # use solana_signer::Signer;
3399    /// # futures::executor::block_on(async {
3400    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3401    /// #     let alice = Keypair::new();
3402    /// let commitment_config = CommitmentConfig::processed();
3403    /// let balance = rpc_client.get_balance_with_commitment(
3404    ///     &alice.pubkey(),
3405    ///     commitment_config,
3406    /// ).await?;
3407    /// #     Ok::<(), Error>(())
3408    /// # })?;
3409    /// # Ok::<(), Error>(())
3410    /// ```
3411    pub async fn get_balance_with_commitment(
3412        &self,
3413        pubkey: &Pubkey,
3414        commitment_config: CommitmentConfig,
3415    ) -> RpcResult<u64> {
3416        self.send(
3417            RpcRequest::GetBalance,
3418            json!([pubkey.to_string(), commitment_config]),
3419        )
3420        .await
3421    }
3422
3423    /// Returns all accounts owned by the provided program pubkey.
3424    ///
3425    /// This method uses the configured [commitment level][cl].
3426    ///
3427    /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
3428    ///
3429    /// # RPC Reference
3430    ///
3431    /// This method corresponds directly to the [`getProgramAccounts`] RPC
3432    /// method.
3433    ///
3434    /// [`getProgramAccounts`]: https://solana.com/docs/rpc/http/getprogramaccounts
3435    ///
3436    /// # Examples
3437    ///
3438    /// ```ignore
3439    /// # use solana_rpc_client_api::client_error::Error;
3440    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3441    /// # use solana_keypair::Keypair;
3442    /// # use solana_signer::Signer;
3443    /// # futures::executor::block_on(async {
3444    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3445    /// #     let alice = Keypair::new();
3446    /// let accounts = rpc_client.get_program_accounts(&alice.pubkey()).await?;
3447    /// #     Ok::<(), Error>(())
3448    /// # })?;
3449    /// # Ok::<(), Error>(())
3450    /// ```
3451    pub async fn get_program_accounts(
3452        &self,
3453        pubkey: &Pubkey,
3454    ) -> ClientResult<Vec<(Pubkey, Account)>> {
3455        self.get_program_ui_accounts_with_config(
3456            pubkey,
3457            RpcProgramAccountsConfig {
3458                account_config: RpcAccountInfoConfig {
3459                    encoding: Some(UiAccountEncoding::Base64Zstd),
3460                    ..RpcAccountInfoConfig::default()
3461                },
3462                ..RpcProgramAccountsConfig::default()
3463            },
3464        )
3465        .await
3466        .map(|response| {
3467            response
3468                .into_iter()
3469                .map(|(pubkey, ui_account)| {
3470                    (
3471                        pubkey,
3472                        ui_account.decode().expect(
3473                            "It should be impossible at this point for the account data not to be \
3474                             decodable. Ensure that the account was fetched using a binary \
3475                             encoding.",
3476                        ),
3477                    )
3478                })
3479                .collect()
3480        })
3481    }
3482
3483    #[deprecated(
3484        note = "Use `get_program_ui_accounts_with_config()` instead. This function will be \
3485                removed in a future version of `solana_rpc_client`."
3486    )]
3487    pub async fn get_program_accounts_with_config(
3488        &self,
3489        pubkey: &Pubkey,
3490        mut config: RpcProgramAccountsConfig,
3491    ) -> ClientResult<Vec<(Pubkey, Account)>> {
3492        #[allow(deprecated)]
3493        {
3494            let commitment = config
3495                .account_config
3496                .commitment
3497                .unwrap_or_else(|| self.commitment());
3498            config.account_config.commitment = Some(commitment);
3499
3500            let accounts = self
3501                .send::<OptionalContext<Vec<RpcKeyedAccount>>>(
3502                    RpcRequest::GetProgramAccounts,
3503                    json!([pubkey.to_string(), config]),
3504                )
3505                .await?
3506                .parse_value();
3507            parse_keyed_accounts(accounts, RpcRequest::GetProgramAccounts)
3508        }
3509    }
3510
3511    /// Returns all accounts owned by the provided program pubkey.
3512    ///
3513    /// # RPC Reference
3514    ///
3515    /// This method is built on the [`getProgramAccounts`] RPC method.
3516    ///
3517    /// [`getProgramAccounts`]: https://solana.com/docs/rpc/http/getprogramaccounts
3518    ///
3519    /// # Examples
3520    ///
3521    /// ```ignore
3522    /// # use solana_rpc_client_api::{
3523    /// #     client_error::Error,
3524    /// #     config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},
3525    /// #     filter::{MemcmpEncodedBytes, RpcFilterType, Memcmp},
3526    /// # };
3527    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3528    /// # use solana_commitment_config::CommitmentConfig;
3529    /// # use solana_keypair::Keypair;
3530    /// # use solana_signer::Signer;
3531    /// # use solana_account_decoder_client_types::{UiDataSliceConfig, UiAccountEncoding};
3532    /// # futures::executor::block_on(async {
3533    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3534    /// #     let alice = Keypair::new();
3535    /// #     let base64_bytes = "\
3536    /// #         AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
3537    /// #         AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
3538    /// #         AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
3539    /// let memcmp = RpcFilterType::Memcmp(Memcmp::new(
3540    ///     0,                                                    // offset
3541    ///     MemcmpEncodedBytes::Base64(base64_bytes.to_string()), // encoded bytes
3542    /// ));
3543    /// let config = RpcProgramAccountsConfig {
3544    ///     filters: Some(vec![
3545    ///         RpcFilterType::DataSize(128),
3546    ///         memcmp,
3547    ///     ]),
3548    ///     account_config: RpcAccountInfoConfig {
3549    ///         encoding: Some(UiAccountEncoding::Base64),
3550    ///         data_slice: Some(UiDataSliceConfig {
3551    ///             offset: 0,
3552    ///             length: 5,
3553    ///         }),
3554    ///         commitment: Some(CommitmentConfig::processed()),
3555    ///         min_context_slot: Some(1234),
3556    ///     },
3557    ///     with_context: Some(false),
3558    ///     sort_results: Some(true),
3559    /// };
3560    /// let ui_accounts = rpc_client.get_program_ui_accounts_with_config(
3561    ///     &alice.pubkey(),
3562    ///     config,
3563    /// ).await?;
3564    /// #     Ok::<(), Error>(())
3565    /// # })?;
3566    /// # Ok::<(), Error>(())
3567    /// ```
3568    pub async fn get_program_ui_accounts_with_config(
3569        &self,
3570        pubkey: &Pubkey,
3571        mut config: RpcProgramAccountsConfig,
3572    ) -> ClientResult<Vec<(Pubkey, UiAccount)>> {
3573        let commitment = config
3574            .account_config
3575            .commitment
3576            .unwrap_or_else(|| self.commitment());
3577        config.account_config.commitment = Some(commitment);
3578
3579        let accounts = self
3580            .send::<OptionalContext<Vec<RpcKeyedAccount>>>(
3581                RpcRequest::GetProgramAccounts,
3582                json!([pubkey.to_string(), config]),
3583            )
3584            .await?
3585            .parse_value();
3586        pubkey_ui_account_client_result_from_keyed_accounts(
3587            accounts,
3588            RpcRequest::GetProgramAccounts,
3589        )
3590    }
3591
3592    /// Returns the stake minimum delegation, in lamports.
3593    ///
3594    /// # RPC Reference
3595    ///
3596    /// This method corresponds directly to the [`getStakeMinimumDelegation`] RPC method.
3597    ///
3598    /// [`getStakeMinimumDelegation`]: https://solana.com/docs/rpc/http/getstakeminimumdelegation
3599    ///
3600    /// # Examples
3601    ///
3602    /// ```ignore
3603    /// # use solana_rpc_client_api::client_error::Error;
3604    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3605    /// # futures::executor::block_on(async {
3606    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3607    /// let stake_minimum_delegation = rpc_client.get_stake_minimum_delegation().await?;
3608    /// #     Ok::<(), Error>(())
3609    /// # })?;
3610    /// # Ok::<(), Error>(())
3611    /// ```
3612    pub async fn get_stake_minimum_delegation(&self) -> ClientResult<u64> {
3613        self.get_stake_minimum_delegation_with_commitment(self.commitment())
3614            .await
3615    }
3616
3617    /// Returns the stake minimum delegation, in lamports, based on the commitment level.
3618    ///
3619    /// # RPC Reference
3620    ///
3621    /// This method corresponds directly to the [`getStakeMinimumDelegation`] RPC method.
3622    ///
3623    /// [`getStakeMinimumDelegation`]: https://solana.com/docs/rpc/http/getstakeminimumdelegation
3624    ///
3625    /// # Examples
3626    ///
3627    /// ```ignore
3628    /// # use solana_rpc_client_api::client_error::Error;
3629    /// # use solana_rpc_client::nonblocking::rpc_client::RpcClient;
3630    /// # use solana_commitment_config::CommitmentConfig;
3631    /// # futures::executor::block_on(async {
3632    /// #     let rpc_client = RpcClient::new_mock("succeeds".to_string());
3633    /// let stake_minimum_delegation = rpc_client.get_stake_minimum_delegation_with_commitment(CommitmentConfig::confirmed()).await?;
3634    /// #     Ok::<(), Error>(())
3635    /// # })?;
3636    /// # Ok::<(), Error>(())
3637    /// ```
3638    pub async fn get_stake_minimum_delegation_with_commitment(
3639        &self,
3640        commitment_config: CommitmentConfig,
3641    ) -> ClientResult<u64> {
3642        Ok(self
3643            .send::<Response<u64>>(
3644                RpcRequest::GetStakeMinimumDelegation,
3645                json!([commitment_config]),
3646            )
3647            .await?
3648            .value)
3649    }
3650
3651    /// Request the transaction count.
3652    pub async fn get_transaction_count(&self) -> ClientResult<u64> {
3653        self.get_transaction_count_with_commitment(self.commitment())
3654            .await
3655    }
3656
3657    pub async fn get_transaction_count_with_commitment(
3658        &self,
3659        commitment_config: CommitmentConfig,
3660    ) -> ClientResult<u64> {
3661        self.send(RpcRequest::GetTransactionCount, json!([commitment_config]))
3662            .await
3663    }
3664
3665    pub async fn get_first_available_block(&self) -> ClientResult<Slot> {
3666        self.send(RpcRequest::GetFirstAvailableBlock, Value::Null)
3667            .await
3668    }
3669
3670    pub async fn get_genesis_hash(&self) -> ClientResult<Hash> {
3671        let hash_str: String = self.send(RpcRequest::GetGenesisHash, Value::Null).await?;
3672        let hash = hash_str.parse().map_err(|_| {
3673            ClientError::new_with_request(
3674                RpcError::ParseError("Hash".to_string()).into(),
3675                RpcRequest::GetGenesisHash,
3676            )
3677        })?;
3678        Ok(hash)
3679    }
3680
3681    pub async fn get_health(&self) -> ClientResult<()> {
3682        self.send::<String>(RpcRequest::GetHealth, Value::Null)
3683            .await
3684            .map(|_| ())
3685    }
3686
3687    pub async fn get_token_account(&self, pubkey: &Pubkey) -> ClientResult<Option<UiTokenAccount>> {
3688        Ok(self
3689            .get_token_account_with_commitment(pubkey, self.commitment())
3690            .await?
3691            .value)
3692    }
3693
3694    pub async fn get_token_account_with_commitment(
3695        &self,
3696        pubkey: &Pubkey,
3697        commitment_config: CommitmentConfig,
3698    ) -> RpcResult<Option<UiTokenAccount>> {
3699        let config = RpcAccountInfoConfig {
3700            encoding: Some(UiAccountEncoding::JsonParsed),
3701            commitment: Some(commitment_config),
3702            data_slice: None,
3703            min_context_slot: None,
3704        };
3705        let response = self
3706            .send(
3707                RpcRequest::GetAccountInfo,
3708                json!([pubkey.to_string(), config]),
3709            )
3710            .await;
3711
3712        response
3713            .map(|result_json: Value| {
3714                if result_json.is_null() {
3715                    return Err(
3716                        RpcError::ForUser(format!("AccountNotFound: pubkey={pubkey}")).into(),
3717                    );
3718                }
3719                let Response {
3720                    context,
3721                    value: rpc_account,
3722                } = serde_json::from_value::<Response<Option<UiAccount>>>(result_json)?;
3723                trace!("Response account {pubkey:?} {rpc_account:?}");
3724                let response = {
3725                    if let Some(rpc_account) = rpc_account {
3726                        if let UiAccountData::Json(account_data) = rpc_account.data {
3727                            let token_account_type: TokenAccountType =
3728                                serde_json::from_value(account_data.parsed)?;
3729                            if let TokenAccountType::Account(token_account) = token_account_type {
3730                                return Ok(Response {
3731                                    context,
3732                                    value: Some(token_account),
3733                                });
3734                            }
3735                        }
3736                    }
3737                    Err(Into::<ClientError>::into(RpcError::ForUser(format!(
3738                        "Account could not be parsed as token account: pubkey={pubkey}"
3739                    ))))
3740                };
3741                response?
3742            })
3743            .map_err(|err| {
3744                Into::<ClientError>::into(RpcError::ForUser(format!(
3745                    "AccountNotFound: pubkey={pubkey}: {err}"
3746                )))
3747            })?
3748    }
3749
3750    pub async fn get_token_account_balance(&self, pubkey: &Pubkey) -> ClientResult<UiTokenAmount> {
3751        Ok(self
3752            .get_token_account_balance_with_commitment(pubkey, self.commitment())
3753            .await?
3754            .value)
3755    }
3756
3757    pub async fn get_token_account_balance_with_commitment(
3758        &self,
3759        pubkey: &Pubkey,
3760        commitment_config: CommitmentConfig,
3761    ) -> RpcResult<UiTokenAmount> {
3762        self.send(
3763            RpcRequest::GetTokenAccountBalance,
3764            json!([pubkey.to_string(), commitment_config]),
3765        )
3766        .await
3767    }
3768
3769    pub async fn get_token_accounts_by_delegate(
3770        &self,
3771        delegate: &Pubkey,
3772        token_account_filter: TokenAccountsFilter,
3773    ) -> ClientResult<Vec<RpcKeyedAccount>> {
3774        Ok(self
3775            .get_token_accounts_by_delegate_with_commitment(
3776                delegate,
3777                token_account_filter,
3778                self.commitment(),
3779            )
3780            .await?
3781            .value)
3782    }
3783
3784    pub async fn get_token_accounts_by_delegate_with_commitment(
3785        &self,
3786        delegate: &Pubkey,
3787        token_account_filter: TokenAccountsFilter,
3788        commitment_config: CommitmentConfig,
3789    ) -> RpcResult<Vec<RpcKeyedAccount>> {
3790        let token_account_filter = match token_account_filter {
3791            TokenAccountsFilter::Mint(mint) => RpcTokenAccountsFilter::Mint(mint.to_string()),
3792            TokenAccountsFilter::ProgramId(program_id) => {
3793                RpcTokenAccountsFilter::ProgramId(program_id.to_string())
3794            }
3795        };
3796
3797        let config = RpcAccountInfoConfig {
3798            encoding: Some(UiAccountEncoding::JsonParsed),
3799            commitment: Some(commitment_config),
3800            data_slice: None,
3801            min_context_slot: None,
3802        };
3803
3804        self.send(
3805            RpcRequest::GetTokenAccountsByOwner,
3806            json!([delegate.to_string(), token_account_filter, config]),
3807        )
3808        .await
3809    }
3810
3811    pub async fn get_token_accounts_by_owner(
3812        &self,
3813        owner: &Pubkey,
3814        token_account_filter: TokenAccountsFilter,
3815    ) -> ClientResult<Vec<RpcKeyedAccount>> {
3816        Ok(self
3817            .get_token_accounts_by_owner_with_commitment(
3818                owner,
3819                token_account_filter,
3820                self.commitment(),
3821            )
3822            .await?
3823            .value)
3824    }
3825
3826    pub async fn get_token_accounts_by_owner_with_commitment(
3827        &self,
3828        owner: &Pubkey,
3829        token_account_filter: TokenAccountsFilter,
3830        commitment_config: CommitmentConfig,
3831    ) -> RpcResult<Vec<RpcKeyedAccount>> {
3832        let token_account_filter = match token_account_filter {
3833            TokenAccountsFilter::Mint(mint) => RpcTokenAccountsFilter::Mint(mint.to_string()),
3834            TokenAccountsFilter::ProgramId(program_id) => {
3835                RpcTokenAccountsFilter::ProgramId(program_id.to_string())
3836            }
3837        };
3838
3839        let config = RpcAccountInfoConfig {
3840            encoding: Some(UiAccountEncoding::JsonParsed),
3841            commitment: Some(commitment_config),
3842            data_slice: None,
3843            min_context_slot: None,
3844        };
3845
3846        self.send(
3847            RpcRequest::GetTokenAccountsByOwner,
3848            json!([owner.to_string(), token_account_filter, config]),
3849        )
3850        .await
3851    }
3852
3853    pub async fn get_token_largest_accounts(
3854        &self,
3855        mint: &Pubkey,
3856    ) -> ClientResult<Vec<RpcTokenAccountBalance>> {
3857        Ok(self
3858            .get_token_largest_accounts_with_commitment(mint, self.commitment())
3859            .await?
3860            .value)
3861    }
3862
3863    pub async fn get_token_largest_accounts_with_commitment(
3864        &self,
3865        mint: &Pubkey,
3866        commitment_config: CommitmentConfig,
3867    ) -> RpcResult<Vec<RpcTokenAccountBalance>> {
3868        self.send(
3869            RpcRequest::GetTokenLargestAccounts,
3870            json!([mint.to_string(), commitment_config]),
3871        )
3872        .await
3873    }
3874
3875    pub async fn get_token_supply(&self, mint: &Pubkey) -> ClientResult<UiTokenAmount> {
3876        Ok(self
3877            .get_token_supply_with_commitment(mint, self.commitment())
3878            .await?
3879            .value)
3880    }
3881
3882    pub async fn get_token_supply_with_commitment(
3883        &self,
3884        mint: &Pubkey,
3885        commitment_config: CommitmentConfig,
3886    ) -> RpcResult<UiTokenAmount> {
3887        self.send(
3888            RpcRequest::GetTokenSupply,
3889            json!([mint.to_string(), commitment_config]),
3890        )
3891        .await
3892    }
3893
3894    pub async fn request_airdrop(&self, pubkey: &Pubkey, lamports: u64) -> ClientResult<Signature> {
3895        self.request_airdrop_with_config(
3896            pubkey,
3897            lamports,
3898            RpcRequestAirdropConfig {
3899                commitment: Some(self.commitment()),
3900                ..RpcRequestAirdropConfig::default()
3901            },
3902        )
3903        .await
3904    }
3905
3906    pub async fn request_airdrop_with_blockhash(
3907        &self,
3908        pubkey: &Pubkey,
3909        lamports: u64,
3910        recent_blockhash: &Hash,
3911    ) -> ClientResult<Signature> {
3912        self.request_airdrop_with_config(
3913            pubkey,
3914            lamports,
3915            RpcRequestAirdropConfig {
3916                commitment: Some(self.commitment()),
3917                recent_blockhash: Some(recent_blockhash.to_string()),
3918            },
3919        )
3920        .await
3921    }
3922
3923    pub async fn request_airdrop_with_config(
3924        &self,
3925        pubkey: &Pubkey,
3926        lamports: u64,
3927        config: RpcRequestAirdropConfig,
3928    ) -> ClientResult<Signature> {
3929        let commitment = config.commitment.unwrap_or_default();
3930        let config = RpcRequestAirdropConfig {
3931            commitment: Some(commitment),
3932            ..config
3933        };
3934        self.send(
3935            RpcRequest::RequestAirdrop,
3936            json!([pubkey.to_string(), lamports, config]),
3937        )
3938        .await
3939        .and_then(|signature: String| {
3940            Signature::from_str(&signature).map_err(|err| {
3941                ClientErrorKind::Custom(format!("signature deserialization failed: {err}")).into()
3942            })
3943        })
3944        .map_err(|_| {
3945            RpcError::ForUser(
3946                "airdrop request failed. This can happen when the rate limit is reached."
3947                    .to_string(),
3948            )
3949            .into()
3950        })
3951    }
3952
3953    pub(crate) async fn poll_balance_with_timeout_and_commitment(
3954        &self,
3955        pubkey: &Pubkey,
3956        polling_frequency: &Duration,
3957        timeout: &Duration,
3958        commitment_config: CommitmentConfig,
3959    ) -> ClientResult<u64> {
3960        let now = Instant::now();
3961        loop {
3962            match self
3963                .get_balance_with_commitment(pubkey, commitment_config)
3964                .await
3965            {
3966                Ok(bal) => {
3967                    return Ok(bal.value);
3968                }
3969                Err(e) => {
3970                    sleep(*polling_frequency).await;
3971                    if now.elapsed() > *timeout {
3972                        return Err(e);
3973                    }
3974                }
3975            };
3976        }
3977    }
3978
3979    pub async fn poll_get_balance_with_commitment(
3980        &self,
3981        pubkey: &Pubkey,
3982        commitment_config: CommitmentConfig,
3983    ) -> ClientResult<u64> {
3984        self.poll_balance_with_timeout_and_commitment(
3985            pubkey,
3986            &Duration::from_millis(100),
3987            &Duration::from_secs(1),
3988            commitment_config,
3989        )
3990        .await
3991    }
3992
3993    pub async fn wait_for_balance_with_commitment(
3994        &self,
3995        pubkey: &Pubkey,
3996        expected_balance: Option<u64>,
3997        commitment_config: CommitmentConfig,
3998    ) -> ClientResult<u64> {
3999        const LAST: usize = 30;
4000        let mut run = 0;
4001        loop {
4002            let balance_result = self
4003                .poll_get_balance_with_commitment(pubkey, commitment_config)
4004                .await;
4005            if expected_balance.is_none() || (balance_result.is_err() && run == LAST) {
4006                return balance_result;
4007            }
4008            trace!(
4009                "wait_for_balance_with_commitment [{run}] {balance_result:?} {expected_balance:?}"
4010            );
4011            if let (Some(expected_balance), Ok(balance_result)) = (expected_balance, balance_result)
4012            {
4013                if expected_balance == balance_result {
4014                    return Ok(balance_result);
4015                }
4016            }
4017            run += 1;
4018        }
4019    }
4020
4021    /// Poll the server to confirm a transaction.
4022    pub async fn poll_for_signature(&self, signature: &Signature) -> ClientResult<()> {
4023        self.poll_for_signature_with_commitment(signature, self.commitment())
4024            .await
4025    }
4026
4027    /// Poll the server to confirm a transaction.
4028    pub async fn poll_for_signature_with_commitment(
4029        &self,
4030        signature: &Signature,
4031        commitment_config: CommitmentConfig,
4032    ) -> ClientResult<()> {
4033        let now = Instant::now();
4034        loop {
4035            if let Ok(Some(_)) = self
4036                .get_signature_status_with_commitment(signature, commitment_config)
4037                .await
4038            {
4039                break;
4040            }
4041            if now.elapsed().as_secs() > 15 {
4042                return Err(RpcError::ForUser(format!(
4043                    "signature not found after {} seconds",
4044                    now.elapsed().as_secs()
4045                ))
4046                .into());
4047            }
4048            sleep(Duration::from_millis(250)).await;
4049        }
4050        Ok(())
4051    }
4052
4053    /// Poll the server to confirm a transaction.
4054    pub async fn poll_for_signature_confirmation(
4055        &self,
4056        signature: &Signature,
4057        min_confirmed_blocks: usize,
4058    ) -> ClientResult<usize> {
4059        let mut now = Instant::now();
4060        let mut confirmed_blocks = 0;
4061        loop {
4062            let response = self
4063                .get_num_blocks_since_signature_confirmation(signature)
4064                .await;
4065            match response {
4066                Ok(count) => {
4067                    if confirmed_blocks != count {
4068                        info!(
4069                            "signature {} confirmed {} out of {} after {} ms",
4070                            signature,
4071                            count,
4072                            min_confirmed_blocks,
4073                            now.elapsed().as_millis()
4074                        );
4075                        now = Instant::now();
4076                        confirmed_blocks = count;
4077                    }
4078                    if count >= min_confirmed_blocks {
4079                        break;
4080                    }
4081                }
4082                Err(err) => {
4083                    debug!("check_confirmations request failed: {err:?}");
4084                }
4085            };
4086            if now.elapsed().as_secs() > 20 {
4087                info!(
4088                    "signature {} confirmed {} out of {} failed after {} ms",
4089                    signature,
4090                    confirmed_blocks,
4091                    min_confirmed_blocks,
4092                    now.elapsed().as_millis()
4093                );
4094                if confirmed_blocks > 0 {
4095                    return Ok(confirmed_blocks);
4096                } else {
4097                    return Err(RpcError::ForUser(format!(
4098                        "signature not found after {} seconds",
4099                        now.elapsed().as_secs()
4100                    ))
4101                    .into());
4102                }
4103            }
4104            sleep(Duration::from_millis(250)).await;
4105        }
4106        Ok(confirmed_blocks)
4107    }
4108
4109    pub async fn get_num_blocks_since_signature_confirmation(
4110        &self,
4111        signature: &Signature,
4112    ) -> ClientResult<usize> {
4113        let result: Response<Vec<Option<TransactionStatus>>> = self
4114            .send(
4115                RpcRequest::GetSignatureStatuses,
4116                json!([[signature.to_string()]]),
4117            )
4118            .await?;
4119
4120        let confirmations = result.value[0]
4121            .clone()
4122            .ok_or_else(|| {
4123                ClientError::new_with_request(
4124                    ClientErrorKind::Custom("signature not found".to_string()),
4125                    RpcRequest::GetSignatureStatuses,
4126                )
4127            })?
4128            .confirmations
4129            .unwrap_or(MAX_LOCKOUT_HISTORY + 1);
4130        Ok(confirmations)
4131    }
4132
4133    pub async fn get_latest_blockhash(&self) -> ClientResult<Hash> {
4134        let (blockhash, _) = self
4135            .get_latest_blockhash_with_commitment(self.commitment())
4136            .await?;
4137        Ok(blockhash)
4138    }
4139
4140    pub async fn get_latest_blockhash_with_commitment(
4141        &self,
4142        commitment: CommitmentConfig,
4143    ) -> ClientResult<(Hash, u64)> {
4144        let RpcBlockhash {
4145            blockhash,
4146            last_valid_block_height,
4147        } = self
4148            .send::<Response<RpcBlockhash>>(RpcRequest::GetLatestBlockhash, json!([commitment]))
4149            .await?
4150            .value;
4151        let blockhash = blockhash.parse().map_err(|_| {
4152            ClientError::new_with_request(
4153                RpcError::ParseError("Hash".to_string()).into(),
4154                RpcRequest::GetLatestBlockhash,
4155            )
4156        })?;
4157        Ok((blockhash, last_valid_block_height))
4158    }
4159
4160    pub async fn is_blockhash_valid(
4161        &self,
4162        blockhash: &Hash,
4163        commitment: CommitmentConfig,
4164    ) -> ClientResult<bool> {
4165        Ok(self
4166            .send::<Response<bool>>(
4167                RpcRequest::IsBlockhashValid,
4168                json!([blockhash.to_string(), commitment,]),
4169            )
4170            .await?
4171            .value)
4172    }
4173
4174    pub async fn get_fee_for_message(
4175        &self,
4176        message: &impl SerializableMessage,
4177    ) -> ClientResult<u64> {
4178        let serialized = message.serialize();
4179        let serialized_encoded = BASE64_STANDARD.encode(serialized);
4180        let result = self
4181            .send::<Response<Option<u64>>>(
4182                RpcRequest::GetFeeForMessage,
4183                json!([serialized_encoded, self.commitment()]),
4184            )
4185            .await?;
4186        result
4187            .value
4188            .ok_or_else(|| ClientErrorKind::Custom("Invalid blockhash".to_string()).into())
4189    }
4190
4191    pub async fn get_new_latest_blockhash(&self, blockhash: &Hash) -> ClientResult<Hash> {
4192        let mut num_retries = 0;
4193        let start = Instant::now();
4194        while start.elapsed().as_secs() < 5 {
4195            if let Ok(new_blockhash) = self.get_latest_blockhash().await {
4196                if new_blockhash != *blockhash {
4197                    return Ok(new_blockhash);
4198                }
4199            }
4200            debug!("Got same blockhash ({blockhash:?}), will retry...");
4201
4202            // Retry ~twice during a slot
4203            sleep(Duration::from_millis(DEFAULT_MS_PER_SLOT / 2)).await;
4204            num_retries += 1;
4205        }
4206        Err(RpcError::ForUser(format!(
4207            "Unable to get new blockhash after {}ms (retried {} times), stuck at {}",
4208            start.elapsed().as_millis(),
4209            num_retries,
4210            blockhash
4211        ))
4212        .into())
4213    }
4214}
4215
4216fn serde_err_to_rpc_err(err: serde_json::Error) -> ClientError {
4217    ClientError::from(ClientErrorKind::from(err))
4218}
4219
4220fn serialize_and_encode<T>(input: &T, encoding: UiTransactionEncoding) -> ClientResult<String>
4221where
4222    T: serde::ser::Serialize,
4223{
4224    let serialized = serialize(input)
4225        .map_err(|e| ClientErrorKind::Custom(format!("Serialization failed: {e}")))?;
4226    let encoded = match encoding {
4227        UiTransactionEncoding::Base58 => bs58::encode(serialized).into_string(),
4228        UiTransactionEncoding::Base64 => BASE64_STANDARD.encode(serialized),
4229        _ => {
4230            return Err(ClientErrorKind::Custom(format!(
4231                "unsupported encoding: {encoding}. Supported encodings: base58, base64"
4232            ))
4233            .into());
4234        }
4235    };
4236    Ok(encoded)
4237}
4238
4239#[deprecated(
4240    note = "Parsing accounts whose data is of type `UiAccountData::Json` will yield `None` when \
4241            it should not. Do not use this function."
4242)]
4243pub(crate) fn parse_keyed_accounts(
4244    accounts: Vec<RpcKeyedAccount>,
4245    request: RpcRequest,
4246) -> ClientResult<Vec<(Pubkey, Account)>> {
4247    let mut pubkey_accounts: Vec<(Pubkey, Account)> = Vec::with_capacity(accounts.len());
4248    for RpcKeyedAccount { pubkey, account } in accounts.into_iter() {
4249        let pubkey = pubkey.parse().map_err(|_| {
4250            ClientError::new_with_request(
4251                RpcError::ParseError("Pubkey".to_string()).into(),
4252                request,
4253            )
4254        })?;
4255        pubkey_accounts.push((
4256            pubkey,
4257            account.decode().ok_or_else(|| {
4258                ClientError::new_with_request(
4259                    RpcError::ParseError("Account from rpc".to_string()).into(),
4260                    request,
4261                )
4262            })?,
4263        ));
4264    }
4265    Ok(pubkey_accounts)
4266}
4267
4268fn pubkey_ui_account_client_result_from_keyed_accounts(
4269    accounts: Vec<RpcKeyedAccount>,
4270    request: RpcRequest,
4271) -> ClientResult<Vec<(Pubkey, UiAccount)>> {
4272    let mut pubkey_ui_accounts: Vec<(Pubkey, UiAccount)> = Vec::with_capacity(accounts.len());
4273    for RpcKeyedAccount { account, pubkey } in accounts.iter() {
4274        let pubkey = pubkey.parse().map_err(|_| {
4275            ClientError::new_with_request(
4276                RpcError::ParseError("Pubkey".to_string()).into(),
4277                request,
4278            )
4279        })?;
4280        pubkey_ui_accounts.push((pubkey, account.clone()));
4281    }
4282    Ok(pubkey_ui_accounts)
4283}