solana_rpc_client/nonblocking/
rpc_client.rs

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