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 /// — 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 /// — 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}