solana_rpc_client/
rpc_client.rs

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