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