Skip to main content

solana_rpc_client/
rpc_client.rs

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