Skip to main content

solana_rpc_client/
rpc_client.rs

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