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