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