solana_rpc_client/rpc_client.rs
1//! Communication with a Solana node over RPC.
2//!
3//! Software that interacts with the Solana blockchain, whether querying its
4//! state or submitting transactions, communicates with a Solana node over
5//! [JSON-RPC], using the [`RpcClient`] type.
6//!
7//! [JSON-RPC]: https://www.jsonrpc.org/specification
8//!
9//! This is a blocking API. For a non-blocking API use the asynchronous client
10//! in [`crate::nonblocking::rpc_client`].
11
12pub use crate::mock_sender::Mocks;
13use {
14 crate::{
15 http_sender::HttpSender,
16 mock_sender::{MockSender, MocksMap, mock_encoded_account},
17 nonblocking::{self, rpc_client::get_rpc_request_str},
18 rpc_sender::*,
19 },
20 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::{Message as LegacyMessage, v0},
32 solana_pubkey::Pubkey,
33 solana_rpc_client_api::{
34 client_error::{Error as ClientError, ErrorKind, Result as ClientResult},
35 config::{RpcAccountInfoConfig, *},
36 request::{RpcRequest, TokenAccountsFilter},
37 response::*,
38 },
39 solana_signature::Signature,
40 solana_transaction::{Transaction, uses_durable_nonce, versioned::VersionedTransaction},
41 solana_transaction_error::TransactionResult,
42 solana_transaction_status_client_types::{
43 EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus,
44 UiConfirmedBlock, UiTransactionEncoding,
45 },
46 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 been 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 /// Returns information about all the nodes participating in the cluster.
1975 ///
1976 /// # RPC Reference
1977 ///
1978 /// This method corresponds directly to the [`getClusterNodes`]
1979 /// RPC method.
1980 ///
1981 /// [`getClusterNodes`]: https://solana.com/docs/rpc/http/getclusternodes
1982 ///
1983 /// # Examples
1984 ///
1985 /// ```
1986 /// # use solana_rpc_client_api::client_error::Error;
1987 /// # use solana_rpc_client::rpc_client::RpcClient;
1988 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
1989 /// let cluster_nodes = rpc_client.get_cluster_nodes()?;
1990 /// # Ok::<(), Error>(())
1991 /// ```
1992 pub fn get_cluster_nodes(&self) -> ClientResult<Vec<RpcContactInfo>> {
1993 self.invoke((self.rpc_client.as_ref()).get_cluster_nodes())
1994 }
1995
1996 /// Returns identity and transaction information about a confirmed block in the ledger.
1997 ///
1998 /// The encodings are returned in [`UiTransactionEncoding::Json`][uite]
1999 /// format. To return transactions in other encodings, use
2000 /// [`get_block_with_encoding`].
2001 ///
2002 /// [`get_block_with_encoding`]: RpcClient::get_block_with_encoding
2003 /// [uite]: UiTransactionEncoding::Json
2004 ///
2005 /// # RPC Reference
2006 ///
2007 /// This method corresponds directly to the [`getBlock`] RPC
2008 /// method.
2009 ///
2010 /// [`getBlock`]: https://solana.com/docs/rpc/http/getblock
2011 ///
2012 /// # Examples
2013 ///
2014 /// ```
2015 /// # use solana_rpc_client_api::client_error::Error;
2016 /// # use solana_rpc_client::rpc_client::RpcClient;
2017 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2018 /// # let slot = rpc_client.get_slot()?;
2019 /// let block = rpc_client.get_block(slot)?;
2020 /// # Ok::<(), Error>(())
2021 /// ```
2022 pub fn get_block(&self, slot: Slot) -> ClientResult<EncodedConfirmedBlock> {
2023 self.invoke((self.rpc_client.as_ref()).get_block(slot))
2024 }
2025
2026 /// Returns identity and transaction information about a confirmed block in the ledger.
2027 ///
2028 /// # RPC Reference
2029 ///
2030 /// This method corresponds directly to the [`getBlock`] RPC method.
2031 ///
2032 /// [`getBlock`]: https://solana.com/docs/rpc/http/getblock
2033 ///
2034 /// # Examples
2035 ///
2036 /// ```
2037 /// # use solana_rpc_client_api::client_error::Error;
2038 /// # use solana_rpc_client::rpc_client::RpcClient;
2039 /// # use solana_transaction_status_client_types::UiTransactionEncoding;
2040 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2041 /// # let slot = rpc_client.get_slot()?;
2042 /// let encoding = UiTransactionEncoding::Base58;
2043 /// let block = rpc_client.get_block_with_encoding(
2044 /// slot,
2045 /// encoding,
2046 /// )?;
2047 /// # Ok::<(), Error>(())
2048 /// ```
2049 pub fn get_block_with_encoding(
2050 &self,
2051 slot: Slot,
2052 encoding: UiTransactionEncoding,
2053 ) -> ClientResult<EncodedConfirmedBlock> {
2054 self.invoke((self.rpc_client.as_ref()).get_block_with_encoding(slot, encoding))
2055 }
2056
2057 /// Returns identity and transaction information about a confirmed block in the ledger.
2058 ///
2059 /// # RPC Reference
2060 ///
2061 /// This method corresponds directly to the [`getBlock`] RPC method.
2062 ///
2063 /// [`getBlock`]: https://solana.com/docs/rpc/http/getblock
2064 ///
2065 /// # Examples
2066 ///
2067 /// ```
2068 /// # use solana_rpc_client_api::{
2069 /// # config::RpcBlockConfig,
2070 /// # client_error::Error,
2071 /// # };
2072 /// # use solana_rpc_client::rpc_client::RpcClient;
2073 /// # use solana_transaction_status_client_types::{
2074 /// # TransactionDetails,
2075 /// # UiTransactionEncoding,
2076 /// # };
2077 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2078 /// # let slot = rpc_client.get_slot()?;
2079 /// let config = RpcBlockConfig {
2080 /// encoding: Some(UiTransactionEncoding::Base58),
2081 /// transaction_details: Some(TransactionDetails::None),
2082 /// rewards: Some(true),
2083 /// commitment: None,
2084 /// max_supported_transaction_version: Some(0),
2085 /// };
2086 /// let block = rpc_client.get_block_with_config(
2087 /// slot,
2088 /// config,
2089 /// )?;
2090 /// # Ok::<(), Error>(())
2091 /// ```
2092 pub fn get_block_with_config(
2093 &self,
2094 slot: Slot,
2095 config: RpcBlockConfig,
2096 ) -> ClientResult<UiConfirmedBlock> {
2097 self.invoke((self.rpc_client.as_ref()).get_block_with_config(slot, config))
2098 }
2099
2100 /// Returns a list of finalized blocks between two slots.
2101 ///
2102 /// The range is inclusive, with results including the block for both
2103 /// `start_slot` and `end_slot`.
2104 ///
2105 /// If `end_slot` is not provided, then the end slot is for the latest
2106 /// finalized block.
2107 ///
2108 /// This method may not return blocks for the full range of slots if some
2109 /// slots do not have corresponding blocks. To simply get a specific number
2110 /// of sequential blocks, use the [`get_blocks_with_limit`] method.
2111 ///
2112 /// This method uses the [`Finalized`] [commitment level][cl].
2113 ///
2114 /// [`Finalized`]: solana_commitment_config::CommitmentLevel::Finalized
2115 /// [`get_blocks_with_limit`]: RpcClient::get_blocks_with_limit.
2116 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2117 ///
2118 /// # Errors
2119 ///
2120 /// This method returns an error if the range is greater than 500,000 slots.
2121 ///
2122 /// # RPC Reference
2123 ///
2124 /// This method corresponds directly to the [`getBlocks`] RPC method.
2125 ///
2126 /// [`getBlocks`]: https://solana.com/docs/rpc/http/getblocks
2127 ///
2128 /// # Examples
2129 ///
2130 /// ```
2131 /// # use solana_rpc_client_api::client_error::Error;
2132 /// # use solana_rpc_client::rpc_client::RpcClient;
2133 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2134 /// // Get up to the first 10 blocks
2135 /// let start_slot = 0;
2136 /// let end_slot = 9;
2137 /// let blocks = rpc_client.get_blocks(start_slot, Some(end_slot))?;
2138 /// # Ok::<(), Error>(())
2139 /// ```
2140 pub fn get_blocks(&self, start_slot: Slot, end_slot: Option<Slot>) -> ClientResult<Vec<Slot>> {
2141 self.invoke((self.rpc_client.as_ref()).get_blocks(start_slot, end_slot))
2142 }
2143
2144 /// Returns a list of confirmed blocks between two slots.
2145 ///
2146 /// The range is inclusive, with results including the block for both
2147 /// `start_slot` and `end_slot`.
2148 ///
2149 /// If `end_slot` is not provided, then the end slot is for the latest
2150 /// block with the given [commitment level][cl].
2151 ///
2152 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2153 ///
2154 /// This method may not return blocks for the full range of slots if some
2155 /// slots do not have corresponding blocks. To simply get a specific number
2156 /// of sequential blocks, use the [`get_blocks_with_limit_and_commitment`]
2157 /// method.
2158 ///
2159 /// [`get_blocks_with_limit_and_commitment`]: RpcClient::get_blocks_with_limit_and_commitment.
2160 ///
2161 /// # Errors
2162 ///
2163 /// This method returns an error if the range is greater than 500,000 slots.
2164 ///
2165 /// This method returns an error if the given commitment level is below
2166 /// [`Confirmed`].
2167 ///
2168 /// [`Confirmed`]: solana_commitment_config::CommitmentLevel::Confirmed
2169 ///
2170 /// # RPC Reference
2171 ///
2172 /// This method corresponds directly to the [`getBlocks`] RPC method.
2173 ///
2174 /// [`getBlocks`]: https://solana.com/docs/rpc/http/getblocks
2175 ///
2176 /// # Examples
2177 ///
2178 /// ```
2179 /// # use solana_rpc_client_api::client_error::Error;
2180 /// # use solana_rpc_client::rpc_client::RpcClient;
2181 /// # use solana_commitment_config::CommitmentConfig;
2182 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2183 /// // Get up to the first 10 blocks
2184 /// let start_slot = 0;
2185 /// let end_slot = 9;
2186 /// // Method does not support commitment below `confirmed`
2187 /// let commitment_config = CommitmentConfig::confirmed();
2188 /// let blocks = rpc_client.get_blocks_with_commitment(
2189 /// start_slot,
2190 /// Some(end_slot),
2191 /// commitment_config,
2192 /// )?;
2193 /// # Ok::<(), Error>(())
2194 /// ```
2195 pub fn get_blocks_with_commitment(
2196 &self,
2197 start_slot: Slot,
2198 end_slot: Option<Slot>,
2199 commitment_config: CommitmentConfig,
2200 ) -> ClientResult<Vec<Slot>> {
2201 self.invoke((self.rpc_client.as_ref()).get_blocks_with_commitment(
2202 start_slot,
2203 end_slot,
2204 commitment_config,
2205 ))
2206 }
2207
2208 /// Returns a list of finalized blocks starting at the given slot.
2209 ///
2210 /// This method uses the [`Finalized`] [commitment level][cl].
2211 ///
2212 /// [`Finalized`]: CommitmentLevel::Finalized.
2213 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2214 ///
2215 /// # Errors
2216 ///
2217 /// This method returns an error if the limit is greater than 500,000 slots.
2218 ///
2219 /// # RPC Reference
2220 ///
2221 /// This method corresponds directly to the [`getBlocksWithLimit`] RPC
2222 /// method.
2223 ///
2224 /// [`getBlocksWithLimit`]: https://solana.com/docs/rpc/http/getblockswithlimit
2225 ///
2226 /// # Examples
2227 ///
2228 /// ```
2229 /// # use solana_rpc_client_api::client_error::Error;
2230 /// # use solana_rpc_client::rpc_client::RpcClient;
2231 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2232 /// // Get the first 10 blocks
2233 /// let start_slot = 0;
2234 /// let limit = 10;
2235 /// let blocks = rpc_client.get_blocks_with_limit(start_slot, limit)?;
2236 /// # Ok::<(), Error>(())
2237 /// ```
2238 pub fn get_blocks_with_limit(&self, start_slot: Slot, limit: usize) -> ClientResult<Vec<Slot>> {
2239 self.invoke((self.rpc_client.as_ref()).get_blocks_with_limit(start_slot, limit))
2240 }
2241
2242 /// Returns a list of confirmed blocks starting at the given slot.
2243 ///
2244 /// # Errors
2245 ///
2246 /// This method returns an error if the limit is greater than 500,000 slots.
2247 ///
2248 /// This method returns an error if the given [commitment level][cl] is below
2249 /// [`Confirmed`].
2250 ///
2251 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2252 /// [`Confirmed`]: solana_commitment_config::CommitmentLevel::Confirmed
2253 ///
2254 /// # RPC Reference
2255 ///
2256 /// This method corresponds directly to the [`getBlocksWithLimit`] RPC
2257 /// method.
2258 ///
2259 /// [`getBlocksWithLimit`]: https://solana.com/docs/rpc/http/getblockswithlimit
2260 ///
2261 /// # Examples
2262 ///
2263 /// ```
2264 /// # use solana_rpc_client_api::client_error::Error;
2265 /// # use solana_rpc_client::rpc_client::RpcClient;
2266 /// # use solana_commitment_config::CommitmentConfig;
2267 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2268 /// // Get the first 10 blocks
2269 /// let start_slot = 0;
2270 /// let limit = 10;
2271 /// let commitment_config = CommitmentConfig::confirmed();
2272 /// let blocks = rpc_client.get_blocks_with_limit_and_commitment(
2273 /// start_slot,
2274 /// limit,
2275 /// commitment_config,
2276 /// )?;
2277 /// # Ok::<(), Error>(())
2278 /// ```
2279 pub fn get_blocks_with_limit_and_commitment(
2280 &self,
2281 start_slot: Slot,
2282 limit: usize,
2283 commitment_config: CommitmentConfig,
2284 ) -> ClientResult<Vec<Slot>> {
2285 self.invoke(
2286 (self.rpc_client.as_ref()).get_blocks_with_limit_and_commitment(
2287 start_slot,
2288 limit,
2289 commitment_config,
2290 ),
2291 )
2292 }
2293
2294 /// Get confirmed signatures for transactions involving an address.
2295 ///
2296 /// Returns up to 1000 signatures, ordered from newest to oldest.
2297 ///
2298 /// This method uses the [`Finalized`] [commitment level][cl].
2299 ///
2300 /// [`Finalized`]: CommitmentLevel::Finalized.
2301 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2302 ///
2303 /// # RPC Reference
2304 ///
2305 /// This method corresponds directly to the [`getSignaturesForAddress`] RPC
2306 /// method.
2307 ///
2308 /// [`getSignaturesForAddress`]: https://solana.com/docs/rpc/http/getsignaturesforaddress
2309 ///
2310 /// # Examples
2311 ///
2312 /// ```
2313 /// # use solana_rpc_client_api::client_error::Error;
2314 /// # use solana_rpc_client::rpc_client::RpcClient;
2315 /// # use solana_keypair::Keypair;
2316 /// # use solana_system_transaction as system_transaction;
2317 /// # use solana_signer::Signer;
2318 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2319 /// # let alice = Keypair::new();
2320 /// let signatures = rpc_client.get_signatures_for_address(
2321 /// &alice.pubkey(),
2322 /// )?;
2323 /// # Ok::<(), Error>(())
2324 /// ```
2325 pub fn get_signatures_for_address(
2326 &self,
2327 address: &Pubkey,
2328 ) -> ClientResult<Vec<RpcConfirmedTransactionStatusWithSignature>> {
2329 self.invoke((self.rpc_client.as_ref()).get_signatures_for_address(address))
2330 }
2331
2332 /// Get confirmed signatures for transactions involving an address.
2333 ///
2334 /// # Errors
2335 ///
2336 /// This method returns an error if the given [commitment level][cl] is below
2337 /// [`Confirmed`].
2338 ///
2339 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2340 /// [`Confirmed`]: solana_commitment_config::CommitmentLevel::Confirmed
2341 ///
2342 /// # RPC Reference
2343 ///
2344 /// This method corresponds directly to the [`getSignaturesForAddress`] RPC
2345 /// method.
2346 ///
2347 /// [`getSignaturesForAddress`]: https://solana.com/docs/rpc/http/getsignaturesforaddress
2348 ///
2349 /// # Examples
2350 ///
2351 /// ```
2352 /// # use solana_rpc_client_api::client_error::Error;
2353 /// # use solana_rpc_client::rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient};
2354 /// # use solana_commitment_config::CommitmentConfig;
2355 /// # use solana_keypair::Keypair;
2356 /// # use solana_system_transaction as system_transaction;
2357 /// # use solana_signer::Signer;
2358 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2359 /// # let alice = Keypair::new();
2360 /// # let bob = Keypair::new();
2361 /// # let lamports = 50;
2362 /// # let latest_blockhash = rpc_client.get_latest_blockhash()?;
2363 /// # let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
2364 /// # let signature = rpc_client.send_and_confirm_transaction(&tx)?;
2365 /// let config = GetConfirmedSignaturesForAddress2Config {
2366 /// before: None,
2367 /// until: None,
2368 /// limit: Some(3),
2369 /// commitment: Some(CommitmentConfig::confirmed()),
2370 /// };
2371 /// let signatures = rpc_client.get_signatures_for_address_with_config(
2372 /// &alice.pubkey(),
2373 /// config,
2374 /// )?;
2375 /// # Ok::<(), Error>(())
2376 /// ```
2377 pub fn get_signatures_for_address_with_config(
2378 &self,
2379 address: &Pubkey,
2380 config: GetConfirmedSignaturesForAddress2Config,
2381 ) -> ClientResult<Vec<RpcConfirmedTransactionStatusWithSignature>> {
2382 self.invoke(
2383 (self.rpc_client.as_ref()).get_signatures_for_address_with_config(address, config),
2384 )
2385 }
2386
2387 /// Returns transaction details for a confirmed transaction.
2388 ///
2389 /// This method uses the [`Finalized`] [commitment level][cl].
2390 ///
2391 /// [`Finalized`]: solana_commitment_config::CommitmentLevel::Finalized
2392 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2393 ///
2394 /// # RPC Reference
2395 ///
2396 /// This method corresponds directly to the [`getTransaction`] RPC method.
2397 ///
2398 /// [`getTransaction`]: https://solana.com/docs/rpc/http/gettransaction
2399 ///
2400 /// # Examples
2401 ///
2402 /// ```
2403 /// # use solana_rpc_client_api::client_error::Error;
2404 /// # use solana_rpc_client::rpc_client::RpcClient;
2405 /// # use solana_keypair::Keypair;
2406 /// # use solana_system_transaction as system_transaction;
2407 /// # use solana_signature::Signature;
2408 /// # use solana_signer::Signer;
2409 /// # use solana_transaction_status_client_types::UiTransactionEncoding;
2410 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2411 /// # let alice = Keypair::new();
2412 /// # let bob = Keypair::new();
2413 /// # let lamports = 50;
2414 /// # let latest_blockhash = rpc_client.get_latest_blockhash()?;
2415 /// # let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
2416 /// let signature = rpc_client.send_and_confirm_transaction(&tx)?;
2417 /// let transaction = rpc_client.get_transaction(
2418 /// &signature,
2419 /// UiTransactionEncoding::Json,
2420 /// )?;
2421 /// # Ok::<(), Error>(())
2422 /// ```
2423 pub fn get_transaction(
2424 &self,
2425 signature: &Signature,
2426 encoding: UiTransactionEncoding,
2427 ) -> ClientResult<EncodedConfirmedTransactionWithStatusMeta> {
2428 self.invoke((self.rpc_client.as_ref()).get_transaction(signature, encoding))
2429 }
2430
2431 /// Returns transaction details for a confirmed transaction.
2432 ///
2433 /// # Errors
2434 ///
2435 /// This method returns an error if the given [commitment level][cl] is below
2436 /// [`Confirmed`].
2437 ///
2438 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2439 /// [`Confirmed`]: solana_commitment_config::CommitmentLevel::Confirmed
2440 ///
2441 /// # RPC Reference
2442 ///
2443 /// This method corresponds directly to the [`getTransaction`] RPC method.
2444 ///
2445 /// [`getTransaction`]: https://solana.com/docs/rpc/http/gettransaction
2446 ///
2447 /// # Examples
2448 ///
2449 /// ```
2450 /// # use solana_rpc_client_api::{
2451 /// # client_error::Error,
2452 /// # config::RpcTransactionConfig,
2453 /// # };
2454 /// # use solana_rpc_client::rpc_client::RpcClient;
2455 /// # use solana_commitment_config::CommitmentConfig;
2456 /// # use solana_keypair::Keypair;
2457 /// # use solana_system_transaction as system_transaction;
2458 /// # use solana_signature::Signature;
2459 /// # use solana_signer::Signer;
2460 /// # use solana_transaction_status_client_types::UiTransactionEncoding;
2461 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2462 /// # let alice = Keypair::new();
2463 /// # let bob = Keypair::new();
2464 /// # let lamports = 50;
2465 /// # let latest_blockhash = rpc_client.get_latest_blockhash()?;
2466 /// # let tx = system_transaction::transfer(&alice, &bob.pubkey(), lamports, latest_blockhash);
2467 /// let signature = rpc_client.send_and_confirm_transaction(&tx)?;
2468 /// let config = RpcTransactionConfig {
2469 /// encoding: Some(UiTransactionEncoding::Json),
2470 /// commitment: Some(CommitmentConfig::confirmed()),
2471 /// max_supported_transaction_version: Some(0),
2472 /// };
2473 /// let transaction = rpc_client.get_transaction_with_config(
2474 /// &signature,
2475 /// config,
2476 /// )?;
2477 /// # Ok::<(), Error>(())
2478 /// ```
2479 pub fn get_transaction_with_config(
2480 &self,
2481 signature: &Signature,
2482 config: RpcTransactionConfig,
2483 ) -> ClientResult<EncodedConfirmedTransactionWithStatusMeta> {
2484 self.invoke((self.rpc_client.as_ref()).get_transaction_with_config(signature, config))
2485 }
2486
2487 /// Returns the estimated production time of a block.
2488 ///
2489 /// # RPC Reference
2490 ///
2491 /// This method corresponds directly to the [`getBlockTime`] RPC method.
2492 ///
2493 /// [`getBlockTime`]: https://solana.com/docs/rpc/http/getblocktime
2494 ///
2495 /// # Examples
2496 ///
2497 /// ```
2498 /// # use solana_rpc_client_api::client_error::Error;
2499 /// # use solana_rpc_client::rpc_client::RpcClient;
2500 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2501 /// // Get the time of the most recent finalized block
2502 /// let slot = rpc_client.get_slot()?;
2503 /// let block_time = rpc_client.get_block_time(slot)?;
2504 /// # Ok::<(), Error>(())
2505 /// ```
2506 pub fn get_block_time(&self, slot: Slot) -> ClientResult<UnixTimestamp> {
2507 self.invoke((self.rpc_client.as_ref()).get_block_time(slot))
2508 }
2509
2510 /// Returns information about the current epoch.
2511 ///
2512 /// This method uses the configured default [commitment level][cl].
2513 ///
2514 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2515 ///
2516 /// # RPC Reference
2517 ///
2518 /// This method corresponds directly to the [`getEpochInfo`] RPC method.
2519 ///
2520 /// [`getEpochInfo`]: https://solana.com/docs/rpc/http/getepochinfo
2521 ///
2522 /// # Examples
2523 ///
2524 /// ```
2525 /// # use solana_rpc_client_api::client_error::Error;
2526 /// # use solana_rpc_client::rpc_client::RpcClient;
2527 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2528 /// let epoch_info = rpc_client.get_epoch_info()?;
2529 /// # Ok::<(), Error>(())
2530 /// ```
2531 pub fn get_epoch_info(&self) -> ClientResult<EpochInfo> {
2532 self.invoke((self.rpc_client.as_ref()).get_epoch_info())
2533 }
2534
2535 /// Returns information about the current epoch.
2536 ///
2537 /// # RPC Reference
2538 ///
2539 /// This method corresponds directly to the [`getEpochInfo`] RPC method.
2540 ///
2541 /// [`getEpochInfo`]: https://solana.com/docs/rpc/http/getepochinfo
2542 ///
2543 /// # Examples
2544 ///
2545 /// ```
2546 /// # use solana_rpc_client_api::client_error::Error;
2547 /// # use solana_rpc_client::rpc_client::RpcClient;
2548 /// # use solana_commitment_config::CommitmentConfig;
2549 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2550 /// let commitment_config = CommitmentConfig::confirmed();
2551 /// let epoch_info = rpc_client.get_epoch_info_with_commitment(
2552 /// commitment_config,
2553 /// )?;
2554 /// # Ok::<(), Error>(())
2555 /// ```
2556 pub fn get_epoch_info_with_commitment(
2557 &self,
2558 commitment_config: CommitmentConfig,
2559 ) -> ClientResult<EpochInfo> {
2560 self.invoke((self.rpc_client.as_ref()).get_epoch_info_with_commitment(commitment_config))
2561 }
2562
2563 /// Returns the leader schedule for an epoch.
2564 ///
2565 /// This method uses the configured default [commitment level][cl].
2566 ///
2567 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2568 ///
2569 /// # RPC Reference
2570 ///
2571 /// This method corresponds directly to the [`getLeaderSchedule`] RPC method.
2572 ///
2573 /// [`getLeaderSchedule`]: https://solana.com/docs/rpc/http/getleaderschedule
2574 ///
2575 /// # Examples
2576 ///
2577 /// ```
2578 /// # use solana_rpc_client_api::client_error::Error;
2579 /// # use solana_rpc_client::rpc_client::RpcClient;
2580 /// # use solana_commitment_config::CommitmentConfig;
2581 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2582 /// # let slot = rpc_client.get_slot()?;
2583 /// let leader_schedule = rpc_client.get_leader_schedule(
2584 /// Some(slot),
2585 /// )?;
2586 /// # Ok::<(), Error>(())
2587 /// ```
2588 pub fn get_leader_schedule(
2589 &self,
2590 slot: Option<Slot>,
2591 ) -> ClientResult<Option<RpcLeaderSchedule>> {
2592 self.invoke((self.rpc_client.as_ref()).get_leader_schedule(slot))
2593 }
2594
2595 /// Returns the leader schedule for an epoch.
2596 ///
2597 /// # RPC Reference
2598 ///
2599 /// This method corresponds directly to the [`getLeaderSchedule`] RPC method.
2600 ///
2601 /// [`getLeaderSchedule`]: https://solana.com/docs/rpc/http/getleaderschedule
2602 ///
2603 /// # Examples
2604 ///
2605 /// ```
2606 /// # use solana_rpc_client_api::client_error::Error;
2607 /// # use solana_rpc_client::rpc_client::RpcClient;
2608 /// # use solana_commitment_config::CommitmentConfig;
2609 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2610 /// # let slot = rpc_client.get_slot()?;
2611 /// let commitment_config = CommitmentConfig::processed();
2612 /// let leader_schedule = rpc_client.get_leader_schedule_with_commitment(
2613 /// Some(slot),
2614 /// commitment_config,
2615 /// )?;
2616 /// # Ok::<(), Error>(())
2617 /// ```
2618 pub fn get_leader_schedule_with_commitment(
2619 &self,
2620 slot: Option<Slot>,
2621 commitment_config: CommitmentConfig,
2622 ) -> ClientResult<Option<RpcLeaderSchedule>> {
2623 self.invoke(
2624 (self.rpc_client.as_ref()).get_leader_schedule_with_commitment(slot, commitment_config),
2625 )
2626 }
2627
2628 /// Returns the leader schedule for an epoch.
2629 ///
2630 /// # RPC Reference
2631 ///
2632 /// This method corresponds directly to the [`getLeaderSchedule`] RPC method.
2633 ///
2634 /// [`getLeaderSchedule`]: https://solana.com/docs/rpc/http/getleaderschedule
2635 ///
2636 /// # Examples
2637 ///
2638 /// ```
2639 /// # use solana_rpc_client_api::{
2640 /// # client_error::Error,
2641 /// # config::RpcLeaderScheduleConfig,
2642 /// # };
2643 /// # use solana_rpc_client::rpc_client::RpcClient;
2644 /// # use solana_commitment_config::CommitmentConfig;
2645 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2646 /// # let slot = rpc_client.get_slot()?;
2647 /// # let validator_pubkey_str = "7AYmEYBBetok8h5L3Eo3vi3bDWnjNnaFbSXfSNYV5ewB".to_string();
2648 /// let config = RpcLeaderScheduleConfig {
2649 /// identity: Some(validator_pubkey_str),
2650 /// commitment: Some(CommitmentConfig::processed()),
2651 /// };
2652 /// let leader_schedule = rpc_client.get_leader_schedule_with_config(
2653 /// Some(slot),
2654 /// config,
2655 /// )?;
2656 /// # Ok::<(), Error>(())
2657 /// ```
2658 pub fn get_leader_schedule_with_config(
2659 &self,
2660 slot: Option<Slot>,
2661 config: RpcLeaderScheduleConfig,
2662 ) -> ClientResult<Option<RpcLeaderSchedule>> {
2663 self.invoke((self.rpc_client.as_ref()).get_leader_schedule_with_config(slot, config))
2664 }
2665
2666 /// Returns epoch schedule information from this cluster's genesis config.
2667 ///
2668 /// # RPC Reference
2669 ///
2670 /// This method corresponds directly to the [`getEpochSchedule`] RPC method.
2671 ///
2672 /// [`getEpochSchedule`]: https://solana.com/docs/rpc/http/getepochschedule
2673 ///
2674 /// # Examples
2675 ///
2676 /// ```
2677 /// # use solana_rpc_client_api::client_error::Error;
2678 /// # use solana_rpc_client::rpc_client::RpcClient;
2679 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2680 /// let epoch_schedule = rpc_client.get_epoch_schedule()?;
2681 /// # Ok::<(), Error>(())
2682 /// ```
2683 pub fn get_epoch_schedule(&self) -> ClientResult<EpochSchedule> {
2684 self.invoke((self.rpc_client.as_ref()).get_epoch_schedule())
2685 }
2686
2687 /// Returns a list of recent performance samples, in reverse slot order.
2688 ///
2689 /// Performance samples are taken every 60 seconds and include the number of
2690 /// transactions and slots that occur in a given time window.
2691 ///
2692 /// # RPC Reference
2693 ///
2694 /// This method corresponds directly to the [`getRecentPerformanceSamples`] RPC method.
2695 ///
2696 /// [`getRecentPerformanceSamples`]: https://solana.com/docs/rpc/http/getrecentperformancesamples
2697 ///
2698 /// # Examples
2699 ///
2700 /// ```
2701 /// # use solana_rpc_client_api::client_error::Error;
2702 /// # use solana_rpc_client::rpc_client::RpcClient;
2703 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2704 /// let limit = 10;
2705 /// let performance_samples = rpc_client.get_recent_performance_samples(
2706 /// Some(limit),
2707 /// )?;
2708 /// # Ok::<(), Error>(())
2709 /// ```
2710 pub fn get_recent_performance_samples(
2711 &self,
2712 limit: Option<usize>,
2713 ) -> ClientResult<Vec<RpcPerfSample>> {
2714 self.invoke((self.rpc_client.as_ref()).get_recent_performance_samples(limit))
2715 }
2716
2717 /// Returns a list of minimum prioritization fees from recent blocks.
2718 /// Takes an optional vector of addresses; if any addresses are provided, the response will
2719 /// reflect the minimum prioritization fee to land a transaction locking all of the provided
2720 /// accounts as writable.
2721 ///
2722 /// Currently, a node's prioritization-fee cache stores data from up to 150 blocks.
2723 ///
2724 /// # RPC Reference
2725 ///
2726 /// This method corresponds directly to the [`getRecentPrioritizationFees`] RPC method.
2727 ///
2728 /// [`getRecentPrioritizationFees`]: https://solana.com/docs/rpc/http/getrecentprioritizationfees
2729 ///
2730 /// # Examples
2731 ///
2732 /// ```
2733 /// # use solana_rpc_client_api::client_error::Error;
2734 /// # use solana_rpc_client::rpc_client::RpcClient;
2735 /// # use solana_keypair::Keypair;
2736 /// # use solana_signer::Signer;
2737 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2738 /// # let alice = Keypair::new();
2739 /// # let bob = Keypair::new();
2740 /// let addresses = vec![alice.pubkey(), bob.pubkey()];
2741 /// let prioritization_fees = rpc_client.get_recent_prioritization_fees(
2742 /// &addresses,
2743 /// )?;
2744 /// # Ok::<(), Error>(())
2745 /// ```
2746 pub fn get_recent_prioritization_fees(
2747 &self,
2748 addresses: &[Pubkey],
2749 ) -> ClientResult<Vec<RpcPrioritizationFee>> {
2750 self.invoke((self.rpc_client.as_ref()).get_recent_prioritization_fees(addresses))
2751 }
2752
2753 /// Returns the identity pubkey for the current node.
2754 ///
2755 /// # RPC Reference
2756 ///
2757 /// This method corresponds directly to the [`getIdentity`] RPC method.
2758 ///
2759 /// [`getIdentity`]: https://solana.com/docs/rpc/http/getidentity
2760 ///
2761 /// # Examples
2762 ///
2763 /// ```
2764 /// # use solana_rpc_client_api::client_error::Error;
2765 /// # use solana_rpc_client::rpc_client::RpcClient;
2766 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2767 /// let identity = rpc_client.get_identity()?;
2768 /// # Ok::<(), Error>(())
2769 /// ```
2770 pub fn get_identity(&self) -> ClientResult<Pubkey> {
2771 self.invoke((self.rpc_client.as_ref()).get_identity())
2772 }
2773
2774 /// Returns the current inflation governor.
2775 ///
2776 /// This method uses the [`Finalized`] [commitment level][cl].
2777 ///
2778 /// [`Finalized`]: solana_commitment_config::CommitmentLevel::Finalized
2779 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2780 ///
2781 /// # RPC Reference
2782 ///
2783 /// This method corresponds directly to the [`getInflationGovernor`] RPC
2784 /// method.
2785 ///
2786 /// [`getInflationGovernor`]: https://solana.com/docs/rpc/http/getinflationgovernor
2787 ///
2788 /// # Examples
2789 ///
2790 /// ```
2791 /// # use solana_rpc_client_api::client_error::Error;
2792 /// # use solana_rpc_client::rpc_client::RpcClient;
2793 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2794 /// let inflation_governor = rpc_client.get_inflation_governor()?;
2795 /// # Ok::<(), Error>(())
2796 /// ```
2797 pub fn get_inflation_governor(&self) -> ClientResult<RpcInflationGovernor> {
2798 self.invoke((self.rpc_client.as_ref()).get_inflation_governor())
2799 }
2800
2801 /// Returns the specific inflation values for the current epoch.
2802 ///
2803 /// # RPC Reference
2804 ///
2805 /// This method corresponds directly to the [`getInflationRate`] RPC method.
2806 ///
2807 /// [`getInflationRate`]: https://solana.com/docs/rpc/http/getinflationrate
2808 ///
2809 /// # Examples
2810 ///
2811 /// ```
2812 /// # use solana_rpc_client_api::client_error::Error;
2813 /// # use solana_rpc_client::rpc_client::RpcClient;
2814 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2815 /// let inflation_rate = rpc_client.get_inflation_rate()?;
2816 /// # Ok::<(), Error>(())
2817 /// ```
2818 pub fn get_inflation_rate(&self) -> ClientResult<RpcInflationRate> {
2819 self.invoke((self.rpc_client.as_ref()).get_inflation_rate())
2820 }
2821
2822 /// Returns the inflation reward for a list of addresses for an epoch.
2823 ///
2824 /// This method uses the configured [commitment level][cl].
2825 ///
2826 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2827 ///
2828 /// # RPC Reference
2829 ///
2830 /// This method corresponds directly to the [`getInflationReward`] RPC method.
2831 ///
2832 /// [`getInflationReward`]: https://solana.com/docs/rpc/http/getinflationreward
2833 ///
2834 /// # Examples
2835 ///
2836 /// ```
2837 /// # use solana_rpc_client_api::client_error::Error;
2838 /// # use solana_rpc_client::rpc_client::RpcClient;
2839 /// # use solana_keypair::Keypair;
2840 /// # use solana_signer::Signer;
2841 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2842 /// # let epoch_info = rpc_client.get_epoch_info()?;
2843 /// # let epoch = epoch_info.epoch;
2844 /// # let alice = Keypair::new();
2845 /// # let bob = Keypair::new();
2846 /// let addresses = vec![alice.pubkey(), bob.pubkey()];
2847 /// let inflation_reward = rpc_client.get_inflation_reward(
2848 /// &addresses,
2849 /// Some(epoch),
2850 /// )?;
2851 /// # Ok::<(), Error>(())
2852 /// ```
2853 pub fn get_inflation_reward(
2854 &self,
2855 addresses: &[Pubkey],
2856 epoch: Option<Epoch>,
2857 ) -> ClientResult<Vec<Option<RpcInflationReward>>> {
2858 self.invoke((self.rpc_client.as_ref()).get_inflation_reward(addresses, epoch))
2859 }
2860
2861 /// Returns the current solana version running on the node.
2862 ///
2863 /// # RPC Reference
2864 ///
2865 /// This method corresponds directly to the [`getVersion`] RPC method.
2866 ///
2867 /// [`getVersion`]: https://solana.com/docs/rpc/http/getversion
2868 ///
2869 /// # Examples
2870 ///
2871 /// ```
2872 /// # use solana_rpc_client_api::client_error::Error;
2873 /// # use solana_rpc_client::rpc_client::RpcClient;
2874 /// # use solana_keypair::Keypair;
2875 /// # use solana_signer::Signer;
2876 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2877 /// let expected_version = semver::Version::new(1, 7, 0);
2878 /// let version = rpc_client.get_version()?;
2879 /// let version = semver::Version::parse(&version.solana_core)?;
2880 /// assert!(version >= expected_version);
2881 /// # Ok::<(), Box<dyn std::error::Error>>(())
2882 /// ```
2883 pub fn get_version(&self) -> ClientResult<RpcVersionInfo> {
2884 self.invoke((self.rpc_client.as_ref()).get_version())
2885 }
2886
2887 /// Returns the lowest slot that the node has information about in its ledger.
2888 ///
2889 /// This value may increase over time if the node is configured to purge
2890 /// older ledger data.
2891 ///
2892 /// # RPC Reference
2893 ///
2894 /// This method corresponds directly to the [`minimumLedgerSlot`] RPC
2895 /// method.
2896 ///
2897 /// [`minimumLedgerSlot`]: https://solana.com/docs/rpc/http/minimumledgerslot
2898 ///
2899 /// # Examples
2900 ///
2901 /// ```
2902 /// # use solana_rpc_client_api::client_error::Error;
2903 /// # use solana_rpc_client::rpc_client::RpcClient;
2904 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
2905 /// let slot = rpc_client.minimum_ledger_slot()?;
2906 /// # Ok::<(), Error>(())
2907 /// ```
2908 pub fn minimum_ledger_slot(&self) -> ClientResult<Slot> {
2909 self.invoke((self.rpc_client.as_ref()).minimum_ledger_slot())
2910 }
2911
2912 /// Returns all information associated with the account of the provided pubkey.
2913 ///
2914 /// This method uses the configured [commitment level][cl].
2915 ///
2916 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
2917 ///
2918 /// To get multiple accounts at once, use the [`get_multiple_accounts`] method.
2919 ///
2920 /// [`get_multiple_accounts`]: RpcClient::get_multiple_accounts
2921 ///
2922 /// # Errors
2923 ///
2924 /// If the account does not exist, this method returns
2925 /// [`RpcError::ForUser`]. This is unlike [`get_account_with_commitment`],
2926 /// which returns `Ok(None)` if the account does not exist.
2927 ///
2928 /// [`RpcError::ForUser`]: solana_rpc_client_api::request::RpcError::ForUser
2929 /// [`get_account_with_commitment`]: RpcClient::get_account_with_commitment
2930 ///
2931 /// # RPC Reference
2932 ///
2933 /// This method is built on the [`getAccountInfo`] RPC method.
2934 ///
2935 /// [`getAccountInfo`]: https://solana.com/docs/rpc/http/getaccountinfo
2936 ///
2937 /// # Examples
2938 ///
2939 /// ```
2940 /// # use solana_rpc_client_api::client_error::Error;
2941 /// # use solana_rpc_client::rpc_client::{self, RpcClient};
2942 /// # use solana_keypair::Keypair;
2943 /// # use solana_pubkey::Pubkey;
2944 /// # use solana_signer::Signer;
2945 /// # use std::str::FromStr;
2946 /// # let mocks = rpc_client::create_rpc_client_mocks();
2947 /// # let rpc_client = RpcClient::new_mock_with_mocks("succeeds".to_string(), mocks);
2948 /// let alice_pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
2949 /// let account = rpc_client.get_account(&alice_pubkey)?;
2950 /// # Ok::<(), Error>(())
2951 /// ```
2952 pub fn get_account(&self, pubkey: &Pubkey) -> ClientResult<Account> {
2953 self.invoke((self.rpc_client.as_ref()).get_account(pubkey))
2954 }
2955
2956 /// Returns all information associated with the account of the provided pubkey.
2957 ///
2958 /// If the account does not exist, this method returns `Ok(None)`.
2959 ///
2960 /// To get multiple accounts at once, use the [`get_multiple_accounts_with_commitment`] method.
2961 ///
2962 /// [`get_multiple_accounts_with_commitment`]: RpcClient::get_multiple_accounts_with_commitment
2963 ///
2964 /// # RPC Reference
2965 ///
2966 /// This method is built on the [`getAccountInfo`] RPC method.
2967 ///
2968 /// [`getAccountInfo`]: https://solana.com/docs/rpc/http/getaccountinfo
2969 ///
2970 /// # Examples
2971 ///
2972 /// ```
2973 /// # use solana_rpc_client_api::client_error::Error;
2974 /// # use solana_rpc_client::rpc_client::{self, RpcClient};
2975 /// # use solana_commitment_config::CommitmentConfig;
2976 /// # use solana_keypair::Keypair;
2977 /// # use solana_signer::Signer;
2978 /// # use solana_pubkey::Pubkey;
2979 /// # use std::str::FromStr;
2980 /// # let mocks = rpc_client::create_rpc_client_mocks();
2981 /// # let rpc_client = RpcClient::new_mock_with_mocks("succeeds".to_string(), mocks);
2982 /// let alice_pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
2983 /// let commitment_config = CommitmentConfig::processed();
2984 /// let account = rpc_client.get_account_with_commitment(
2985 /// &alice_pubkey,
2986 /// commitment_config,
2987 /// )?;
2988 /// assert!(account.value.is_some());
2989 /// # Ok::<(), Error>(())
2990 /// ```
2991 pub fn get_account_with_commitment(
2992 &self,
2993 pubkey: &Pubkey,
2994 commitment_config: CommitmentConfig,
2995 ) -> RpcResult<Option<Account>> {
2996 self.invoke(
2997 (self.rpc_client.as_ref()).get_account_with_commitment(pubkey, commitment_config),
2998 )
2999 }
3000
3001 /// Returns all information associated with the account of the provided pubkey.
3002 ///
3003 /// If the account does not exist, this method returns `Ok(None)`.
3004 ///
3005 /// To get multiple accounts at once, use the [`get_multiple_ui_accounts_with_config`] method.
3006 ///
3007 /// [`get_multiple_ui_accounts_with_config`]: RpcClient::get_multiple_ui_accounts_with_config
3008 ///
3009 /// # RPC Reference
3010 ///
3011 /// This method is built on the [`getAccountInfo`] RPC method.
3012 ///
3013 /// [`getAccountInfo`]: https://solana.com/docs/rpc/http/getaccountinfo
3014 ///
3015 /// # Examples
3016 ///
3017 /// ```
3018 /// # use solana_rpc_client_api::{
3019 /// # config::RpcAccountInfoConfig,
3020 /// # client_error::Error,
3021 /// # };
3022 /// # use solana_rpc_client::rpc_client::{self, RpcClient};
3023 /// # use solana_commitment_config::CommitmentConfig;
3024 /// # use solana_keypair::Keypair;
3025 /// # use solana_signer::Signer;
3026 /// # use solana_pubkey::Pubkey;
3027 /// # use solana_account_decoder_client_types::UiAccountEncoding;
3028 /// # use std::str::FromStr;
3029 /// # let mocks = rpc_client::create_rpc_client_mocks();
3030 /// # let rpc_client = RpcClient::new_mock_with_mocks("succeeds".to_string(), mocks);
3031 /// let alice_pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
3032 /// let commitment_config = CommitmentConfig::processed();
3033 /// let config = RpcAccountInfoConfig {
3034 /// encoding: Some(UiAccountEncoding::Base64),
3035 /// commitment: Some(commitment_config),
3036 /// .. RpcAccountInfoConfig::default()
3037 /// };
3038 /// let ui_account = rpc_client.get_ui_account_with_config(
3039 /// &alice_pubkey,
3040 /// config,
3041 /// )?;
3042 /// assert!(ui_account.value.is_some());
3043 /// # Ok::<(), Error>(())
3044 /// ```
3045 pub fn get_ui_account_with_config(
3046 &self,
3047 pubkey: &Pubkey,
3048 config: RpcAccountInfoConfig,
3049 ) -> RpcResult<Option<UiAccount>> {
3050 self.invoke((self.rpc_client.as_ref()).get_ui_account_with_config(pubkey, config))
3051 }
3052
3053 /// Get the max slot seen from retransmit stage.
3054 ///
3055 /// # RPC Reference
3056 ///
3057 /// This method corresponds directly to the [`getMaxRetransmitSlot`] RPC
3058 /// method.
3059 ///
3060 /// [`getMaxRetransmitSlot`]: https://solana.com/docs/rpc/http/getmaxretransmitslot
3061 ///
3062 /// # Examples
3063 ///
3064 /// ```
3065 /// # use solana_rpc_client_api::client_error::Error;
3066 /// # use solana_rpc_client::rpc_client::RpcClient;
3067 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3068 /// let slot = rpc_client.get_max_retransmit_slot()?;
3069 /// # Ok::<(), Error>(())
3070 pub fn get_max_retransmit_slot(&self) -> ClientResult<Slot> {
3071 self.invoke((self.rpc_client.as_ref()).get_max_retransmit_slot())
3072 }
3073
3074 /// Get the max slot seen from after [shred](https://solana.com/docs/terminology#shred) insert.
3075 ///
3076 /// # RPC Reference
3077 ///
3078 /// This method corresponds directly to the
3079 /// [`getMaxShredInsertSlot`] RPC method.
3080 ///
3081 /// [`getMaxShredInsertSlot`]: https://solana.com/docs/rpc/http/getmaxshredinsertslot
3082 ///
3083 /// # Examples
3084 ///
3085 /// ```
3086 /// # use solana_rpc_client_api::client_error::Error;
3087 /// # use solana_rpc_client::rpc_client::RpcClient;
3088 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3089 /// let slot = rpc_client.get_max_shred_insert_slot()?;
3090 /// # Ok::<(), Error>(())
3091 pub fn get_max_shred_insert_slot(&self) -> ClientResult<Slot> {
3092 self.invoke((self.rpc_client.as_ref()).get_max_shred_insert_slot())
3093 }
3094
3095 /// Returns the account information for a list of pubkeys.
3096 ///
3097 /// This method uses the configured [commitment level][cl].
3098 ///
3099 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
3100 ///
3101 /// # RPC Reference
3102 ///
3103 /// This method is built on the [`getMultipleAccounts`] RPC method.
3104 ///
3105 /// [`getMultipleAccounts`]: https://solana.com/docs/rpc/http/getmultipleaccounts
3106 ///
3107 /// # Examples
3108 ///
3109 /// ```
3110 /// # use solana_rpc_client_api::client_error::Error;
3111 /// # use solana_rpc_client::rpc_client::RpcClient;
3112 /// # use solana_keypair::Keypair;
3113 /// # use solana_signer::Signer;
3114 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3115 /// # let alice = Keypair::new();
3116 /// # let bob = Keypair::new();
3117 /// let pubkeys = vec![alice.pubkey(), bob.pubkey()];
3118 /// let accounts = rpc_client.get_multiple_accounts(&pubkeys)?;
3119 /// # Ok::<(), Error>(())
3120 /// ```
3121 pub fn get_multiple_accounts(&self, pubkeys: &[Pubkey]) -> ClientResult<Vec<Option<Account>>> {
3122 self.invoke((self.rpc_client.as_ref()).get_multiple_accounts(pubkeys))
3123 }
3124
3125 /// Returns the account information for a list of pubkeys.
3126 ///
3127 /// # RPC Reference
3128 ///
3129 /// This method is built on the [`getMultipleAccounts`] RPC method.
3130 ///
3131 /// [`getMultipleAccounts`]: https://solana.com/docs/rpc/http/getmultipleaccounts
3132 ///
3133 /// # Examples
3134 ///
3135 /// ```
3136 /// # use solana_rpc_client_api::client_error::Error;
3137 /// # use solana_rpc_client::rpc_client::RpcClient;
3138 /// # use solana_commitment_config::CommitmentConfig;
3139 /// # use solana_keypair::Keypair;
3140 /// # use solana_signer::Signer;
3141 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3142 /// # let alice = Keypair::new();
3143 /// # let bob = Keypair::new();
3144 /// let pubkeys = vec![alice.pubkey(), bob.pubkey()];
3145 /// let commitment_config = CommitmentConfig::processed();
3146 /// let accounts = rpc_client.get_multiple_accounts_with_commitment(
3147 /// &pubkeys,
3148 /// commitment_config,
3149 /// )?;
3150 /// # Ok::<(), Error>(())
3151 /// ```
3152 pub fn get_multiple_accounts_with_commitment(
3153 &self,
3154 pubkeys: &[Pubkey],
3155 commitment_config: CommitmentConfig,
3156 ) -> RpcResult<Vec<Option<Account>>> {
3157 self.invoke(
3158 (self.rpc_client.as_ref())
3159 .get_multiple_accounts_with_commitment(pubkeys, commitment_config),
3160 )
3161 }
3162
3163 /// Returns the account information for a list of pubkeys.
3164 ///
3165 /// # RPC Reference
3166 ///
3167 /// This method is built on the [`getMultipleAccounts`] RPC method.
3168 ///
3169 /// [`getMultipleAccounts`]: https://solana.com/docs/rpc/http/getmultipleaccounts
3170 ///
3171 /// # Examples
3172 ///
3173 /// ```
3174 /// # use solana_rpc_client_api::{
3175 /// # config::RpcAccountInfoConfig,
3176 /// # client_error::Error,
3177 /// # };
3178 /// # use solana_rpc_client::rpc_client::RpcClient;
3179 /// # use solana_commitment_config::CommitmentConfig;
3180 /// # use solana_keypair::Keypair;
3181 /// # use solana_signer::Signer;
3182 /// # use solana_account_decoder_client_types::UiAccountEncoding;
3183 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3184 /// # let alice = Keypair::new();
3185 /// # let bob = Keypair::new();
3186 /// let pubkeys = vec![alice.pubkey(), bob.pubkey()];
3187 /// let commitment_config = CommitmentConfig::processed();
3188 /// let config = RpcAccountInfoConfig {
3189 /// encoding: Some(UiAccountEncoding::Base64),
3190 /// commitment: Some(commitment_config),
3191 /// .. RpcAccountInfoConfig::default()
3192 /// };
3193 /// let ui_accounts = rpc_client.get_multiple_ui_accounts_with_config(
3194 /// &pubkeys,
3195 /// config,
3196 /// )?;
3197 /// # Ok::<(), Error>(())
3198 /// ```
3199 pub fn get_multiple_ui_accounts_with_config(
3200 &self,
3201 pubkeys: &[Pubkey],
3202 config: RpcAccountInfoConfig,
3203 ) -> RpcResult<Vec<Option<UiAccount>>> {
3204 self.invoke(
3205 (self.rpc_client.as_ref()).get_multiple_ui_accounts_with_config(pubkeys, config),
3206 )
3207 }
3208
3209 /// Gets the raw data associated with an account.
3210 ///
3211 /// This is equivalent to calling [`get_account`] and then accessing the
3212 /// [`data`] field of the returned [`Account`].
3213 ///
3214 /// [`get_account`]: RpcClient::get_account
3215 /// [`data`]: Account::data
3216 ///
3217 /// # RPC Reference
3218 ///
3219 /// This method is built on the [`getAccountInfo`] RPC method.
3220 ///
3221 /// [`getAccountInfo`]: https://solana.com/docs/rpc/http/getaccountinfo
3222 ///
3223 /// # Examples
3224 ///
3225 /// ```
3226 /// # use solana_rpc_client_api::client_error::Error;
3227 /// # use solana_rpc_client::rpc_client::{self, RpcClient};
3228 /// # use solana_keypair::Keypair;
3229 /// # use solana_pubkey::Pubkey;
3230 /// # use solana_signer::Signer;
3231 /// # use std::str::FromStr;
3232 /// # let mocks = rpc_client::create_rpc_client_mocks();
3233 /// # let rpc_client = RpcClient::new_mock_with_mocks("succeeds".to_string(), mocks);
3234 /// let alice_pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
3235 /// let account_data = rpc_client.get_account_data(&alice_pubkey)?;
3236 /// # Ok::<(), Error>(())
3237 /// ```
3238 pub fn get_account_data(&self, pubkey: &Pubkey) -> ClientResult<Vec<u8>> {
3239 self.invoke((self.rpc_client.as_ref()).get_account_data(pubkey))
3240 }
3241
3242 /// Returns minimum balance required to make an account with specified data length rent exempt.
3243 ///
3244 /// # RPC Reference
3245 ///
3246 /// This method corresponds directly to the
3247 /// [`getMinimumBalanceForRentExemption`] RPC method.
3248 ///
3249 /// [`getMinimumBalanceForRentExemption`]: https://solana.com/docs/rpc/http/getminimumbalanceforrentexemption
3250 ///
3251 /// # Examples
3252 ///
3253 /// ```
3254 /// # use solana_rpc_client_api::client_error::Error;
3255 /// # use solana_rpc_client::rpc_client::RpcClient;
3256 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3257 /// let data_len = 300;
3258 /// let balance = rpc_client.get_minimum_balance_for_rent_exemption(data_len)?;
3259 /// # Ok::<(), Error>(())
3260 /// ```
3261 pub fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> ClientResult<u64> {
3262 self.invoke((self.rpc_client.as_ref()).get_minimum_balance_for_rent_exemption(data_len))
3263 }
3264
3265 /// Request the balance of the provided account pubkey.
3266 ///
3267 /// This method uses the configured [commitment level][cl].
3268 ///
3269 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
3270 ///
3271 /// # RPC Reference
3272 ///
3273 /// This method corresponds directly to the [`getBalance`] RPC method.
3274 ///
3275 /// [`getBalance`]: https://solana.com/docs/rpc/http/getbalance
3276 ///
3277 /// # Examples
3278 ///
3279 /// ```
3280 /// # use solana_rpc_client_api::client_error::Error;
3281 /// # use solana_rpc_client::rpc_client::RpcClient;
3282 /// # use solana_keypair::Keypair;
3283 /// # use solana_signer::Signer;
3284 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3285 /// # let alice = Keypair::new();
3286 /// let balance = rpc_client.get_balance(&alice.pubkey())?;
3287 /// # Ok::<(), Error>(())
3288 /// ```
3289 pub fn get_balance(&self, pubkey: &Pubkey) -> ClientResult<u64> {
3290 self.invoke((self.rpc_client.as_ref()).get_balance(pubkey))
3291 }
3292
3293 /// Request the balance of the provided account pubkey.
3294 ///
3295 /// # RPC Reference
3296 ///
3297 /// This method corresponds directly to the [`getBalance`] RPC method.
3298 ///
3299 /// [`getBalance`]: https://solana.com/docs/rpc/http/getbalance
3300 ///
3301 /// # Examples
3302 ///
3303 /// ```
3304 /// # use solana_rpc_client_api::client_error::Error;
3305 /// # use solana_rpc_client::rpc_client::RpcClient;
3306 /// # use solana_commitment_config::CommitmentConfig;
3307 /// # use solana_keypair::Keypair;
3308 /// # use solana_signer::Signer;
3309 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3310 /// # let alice = Keypair::new();
3311 /// let commitment_config = CommitmentConfig::processed();
3312 /// let balance = rpc_client.get_balance_with_commitment(
3313 /// &alice.pubkey(),
3314 /// commitment_config,
3315 /// )?;
3316 /// # Ok::<(), Error>(())
3317 /// ```
3318 pub fn get_balance_with_commitment(
3319 &self,
3320 pubkey: &Pubkey,
3321 commitment_config: CommitmentConfig,
3322 ) -> RpcResult<u64> {
3323 self.invoke(
3324 (self.rpc_client.as_ref()).get_balance_with_commitment(pubkey, commitment_config),
3325 )
3326 }
3327
3328 /// Returns all accounts owned by the provided program pubkey.
3329 ///
3330 /// This method uses the configured [commitment level][cl].
3331 ///
3332 /// [cl]: https://solana.com/docs/rpc#configuring-state-commitment
3333 ///
3334 /// # RPC Reference
3335 ///
3336 /// This method corresponds directly to the [`getProgramAccounts`] RPC
3337 /// method.
3338 ///
3339 /// [`getProgramAccounts`]: https://solana.com/docs/rpc/http/getprogramaccounts
3340 ///
3341 /// # Examples
3342 ///
3343 /// ```
3344 /// # use solana_rpc_client_api::client_error::Error;
3345 /// # use solana_rpc_client::rpc_client::RpcClient;
3346 /// # use solana_keypair::Keypair;
3347 /// # use solana_signer::Signer;
3348 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3349 /// # let alice = Keypair::new();
3350 /// let accounts = rpc_client.get_program_accounts(&alice.pubkey())?;
3351 /// # Ok::<(), Error>(())
3352 /// ```
3353 pub fn get_program_accounts(&self, pubkey: &Pubkey) -> ClientResult<Vec<(Pubkey, Account)>> {
3354 self.invoke((self.rpc_client.as_ref()).get_program_accounts(pubkey))
3355 }
3356
3357 /// Returns all accounts owned by the provided program pubkey.
3358 ///
3359 /// # RPC Reference
3360 ///
3361 /// This method is built on the [`getProgramAccounts`] RPC method.
3362 ///
3363 /// [`getProgramAccounts`]: https://solana.com/docs/rpc/http/getprogramaccounts
3364 ///
3365 /// # Examples
3366 ///
3367 /// ```
3368 /// # use solana_rpc_client_api::{
3369 /// # client_error::Error,
3370 /// # config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},
3371 /// # filter::{MemcmpEncodedBytes, RpcFilterType, Memcmp},
3372 /// # };
3373 /// # use solana_rpc_client::rpc_client::RpcClient;
3374 /// # use solana_commitment_config::CommitmentConfig;
3375 /// # use solana_keypair::Keypair;
3376 /// # use solana_signer::Signer;
3377 /// # use solana_account_decoder_client_types::{UiDataSliceConfig, UiAccountEncoding};
3378 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3379 /// # let alice = Keypair::new();
3380 /// # let base64_bytes = "\
3381 /// # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
3382 /// # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
3383 /// # AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
3384 /// let memcmp = RpcFilterType::Memcmp(Memcmp::new(
3385 /// 0, // offset
3386 /// MemcmpEncodedBytes::Base64(base64_bytes.to_string()), // encoded bytes
3387 /// ));
3388 /// let config = RpcProgramAccountsConfig {
3389 /// filters: Some(vec![
3390 /// RpcFilterType::DataSize(128),
3391 /// memcmp,
3392 /// ]),
3393 /// account_config: RpcAccountInfoConfig {
3394 /// encoding: Some(UiAccountEncoding::Base64),
3395 /// data_slice: Some(UiDataSliceConfig {
3396 /// offset: 0,
3397 /// length: 5,
3398 /// }),
3399 /// commitment: Some(CommitmentConfig::processed()),
3400 /// min_context_slot: Some(1234),
3401 /// },
3402 /// with_context: Some(false),
3403 /// sort_results: Some(true),
3404 /// };
3405 /// let ui_accounts = rpc_client.get_program_ui_accounts_with_config(
3406 /// &alice.pubkey(),
3407 /// config,
3408 /// )?;
3409 /// # Ok::<(), Error>(())
3410 /// ```
3411 pub fn get_program_ui_accounts_with_config(
3412 &self,
3413 pubkey: &Pubkey,
3414 config: RpcProgramAccountsConfig,
3415 ) -> ClientResult<Vec<(Pubkey, UiAccount)>> {
3416 self.invoke((self.rpc_client.as_ref()).get_program_ui_accounts_with_config(pubkey, config))
3417 }
3418
3419 /// Returns the stake minimum delegation, in lamports.
3420 ///
3421 /// # RPC Reference
3422 ///
3423 /// This method corresponds directly to the [`getStakeMinimumDelegation`] RPC method.
3424 ///
3425 /// [`getStakeMinimumDelegation`]: https://solana.com/docs/rpc/http/getstakeminimumdelegation
3426 ///
3427 /// # Examples
3428 ///
3429 /// ```
3430 /// # use solana_rpc_client_api::client_error::Error;
3431 /// # use solana_rpc_client::rpc_client::RpcClient;
3432 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3433 /// let stake_minimum_delegation = rpc_client.get_stake_minimum_delegation()?;
3434 /// # Ok::<(), Error>(())
3435 /// ```
3436 pub fn get_stake_minimum_delegation(&self) -> ClientResult<u64> {
3437 self.invoke((self.rpc_client.as_ref()).get_stake_minimum_delegation())
3438 }
3439
3440 /// Returns the stake minimum delegation, in lamports, based on the commitment level.
3441 ///
3442 /// # RPC Reference
3443 ///
3444 /// This method corresponds directly to the [`getStakeMinimumDelegation`] RPC method.
3445 ///
3446 /// [`getStakeMinimumDelegation`]: https://solana.com/docs/rpc/http/getstakeminimumdelegation
3447 ///
3448 /// # Examples
3449 ///
3450 /// ```
3451 /// # use solana_rpc_client_api::client_error::Error;
3452 /// # use solana_rpc_client::rpc_client::RpcClient;
3453 /// # use solana_commitment_config::CommitmentConfig;
3454 /// # let rpc_client = RpcClient::new_mock("succeeds".to_string());
3455 /// let stake_minimum_delegation =
3456 /// rpc_client.get_stake_minimum_delegation_with_commitment(CommitmentConfig::confirmed())?;
3457 /// # Ok::<(), Error>(())
3458 /// ```
3459 pub fn get_stake_minimum_delegation_with_commitment(
3460 &self,
3461 commitment_config: CommitmentConfig,
3462 ) -> ClientResult<u64> {
3463 self.invoke(
3464 self.rpc_client
3465 .get_stake_minimum_delegation_with_commitment(commitment_config),
3466 )
3467 }
3468
3469 /// Request the transaction count.
3470 pub fn get_transaction_count(&self) -> ClientResult<u64> {
3471 self.invoke((self.rpc_client.as_ref()).get_transaction_count())
3472 }
3473
3474 pub fn get_transaction_count_with_commitment(
3475 &self,
3476 commitment_config: CommitmentConfig,
3477 ) -> ClientResult<u64> {
3478 self.invoke(
3479 (self.rpc_client.as_ref()).get_transaction_count_with_commitment(commitment_config),
3480 )
3481 }
3482
3483 pub fn get_first_available_block(&self) -> ClientResult<Slot> {
3484 self.invoke((self.rpc_client.as_ref()).get_first_available_block())
3485 }
3486
3487 pub fn get_genesis_hash(&self) -> ClientResult<Hash> {
3488 self.invoke((self.rpc_client.as_ref()).get_genesis_hash())
3489 }
3490
3491 pub fn get_health(&self) -> ClientResult<()> {
3492 self.invoke((self.rpc_client.as_ref()).get_health())
3493 }
3494
3495 pub fn get_token_account(&self, pubkey: &Pubkey) -> ClientResult<Option<UiTokenAccount>> {
3496 self.invoke((self.rpc_client.as_ref()).get_token_account(pubkey))
3497 }
3498
3499 pub fn get_token_account_with_commitment(
3500 &self,
3501 pubkey: &Pubkey,
3502 commitment_config: CommitmentConfig,
3503 ) -> RpcResult<Option<UiTokenAccount>> {
3504 self.invoke(
3505 (self.rpc_client.as_ref()).get_token_account_with_commitment(pubkey, commitment_config),
3506 )
3507 }
3508
3509 pub fn get_token_account_balance(&self, pubkey: &Pubkey) -> ClientResult<UiTokenAmount> {
3510 self.invoke((self.rpc_client.as_ref()).get_token_account_balance(pubkey))
3511 }
3512
3513 pub fn get_token_account_balance_with_commitment(
3514 &self,
3515 pubkey: &Pubkey,
3516 commitment_config: CommitmentConfig,
3517 ) -> RpcResult<UiTokenAmount> {
3518 self.invoke(
3519 (self.rpc_client.as_ref())
3520 .get_token_account_balance_with_commitment(pubkey, commitment_config),
3521 )
3522 }
3523
3524 pub fn get_token_accounts_by_delegate(
3525 &self,
3526 delegate: &Pubkey,
3527 token_account_filter: TokenAccountsFilter,
3528 ) -> ClientResult<Vec<RpcKeyedAccount>> {
3529 self.invoke(
3530 (self.rpc_client.as_ref())
3531 .get_token_accounts_by_delegate(delegate, token_account_filter),
3532 )
3533 }
3534
3535 pub fn get_token_accounts_by_delegate_with_commitment(
3536 &self,
3537 delegate: &Pubkey,
3538 token_account_filter: TokenAccountsFilter,
3539 commitment_config: CommitmentConfig,
3540 ) -> RpcResult<Vec<RpcKeyedAccount>> {
3541 self.invoke(
3542 (self.rpc_client.as_ref()).get_token_accounts_by_delegate_with_commitment(
3543 delegate,
3544 token_account_filter,
3545 commitment_config,
3546 ),
3547 )
3548 }
3549
3550 pub fn get_token_accounts_by_owner(
3551 &self,
3552 owner: &Pubkey,
3553 token_account_filter: TokenAccountsFilter,
3554 ) -> ClientResult<Vec<RpcKeyedAccount>> {
3555 self.invoke(
3556 (self.rpc_client.as_ref()).get_token_accounts_by_owner(owner, token_account_filter),
3557 )
3558 }
3559
3560 pub fn get_token_accounts_by_owner_with_commitment(
3561 &self,
3562 owner: &Pubkey,
3563 token_account_filter: TokenAccountsFilter,
3564 commitment_config: CommitmentConfig,
3565 ) -> RpcResult<Vec<RpcKeyedAccount>> {
3566 self.invoke(
3567 (self.rpc_client.as_ref()).get_token_accounts_by_owner_with_commitment(
3568 owner,
3569 token_account_filter,
3570 commitment_config,
3571 ),
3572 )
3573 }
3574
3575 pub fn get_token_largest_accounts(
3576 &self,
3577 mint: &Pubkey,
3578 ) -> ClientResult<Vec<RpcTokenAccountBalance>> {
3579 self.invoke((self.rpc_client.as_ref()).get_token_largest_accounts(mint))
3580 }
3581
3582 pub fn get_token_largest_accounts_with_commitment(
3583 &self,
3584 mint: &Pubkey,
3585 commitment_config: CommitmentConfig,
3586 ) -> RpcResult<Vec<RpcTokenAccountBalance>> {
3587 self.invoke(
3588 (self.rpc_client.as_ref())
3589 .get_token_largest_accounts_with_commitment(mint, commitment_config),
3590 )
3591 }
3592
3593 pub fn get_token_supply(&self, mint: &Pubkey) -> ClientResult<UiTokenAmount> {
3594 self.invoke((self.rpc_client.as_ref()).get_token_supply(mint))
3595 }
3596
3597 pub fn get_token_supply_with_commitment(
3598 &self,
3599 mint: &Pubkey,
3600 commitment_config: CommitmentConfig,
3601 ) -> RpcResult<UiTokenAmount> {
3602 self.invoke(
3603 (self.rpc_client.as_ref()).get_token_supply_with_commitment(mint, commitment_config),
3604 )
3605 }
3606
3607 pub fn request_airdrop(&self, pubkey: &Pubkey, lamports: u64) -> ClientResult<Signature> {
3608 self.invoke((self.rpc_client.as_ref()).request_airdrop(pubkey, lamports))
3609 }
3610
3611 pub fn request_airdrop_with_blockhash(
3612 &self,
3613 pubkey: &Pubkey,
3614 lamports: u64,
3615 recent_blockhash: &Hash,
3616 ) -> ClientResult<Signature> {
3617 self.invoke((self.rpc_client.as_ref()).request_airdrop_with_blockhash(
3618 pubkey,
3619 lamports,
3620 recent_blockhash,
3621 ))
3622 }
3623
3624 pub fn request_airdrop_with_config(
3625 &self,
3626 pubkey: &Pubkey,
3627 lamports: u64,
3628 config: RpcRequestAirdropConfig,
3629 ) -> ClientResult<Signature> {
3630 self.invoke(
3631 (self.rpc_client.as_ref()).request_airdrop_with_config(pubkey, lamports, config),
3632 )
3633 }
3634
3635 pub fn poll_get_balance_with_commitment(
3636 &self,
3637 pubkey: &Pubkey,
3638 commitment_config: CommitmentConfig,
3639 ) -> ClientResult<u64> {
3640 self.invoke(
3641 (self.rpc_client.as_ref()).poll_get_balance_with_commitment(pubkey, commitment_config),
3642 )
3643 }
3644
3645 pub fn wait_for_balance_with_commitment(
3646 &self,
3647 pubkey: &Pubkey,
3648 expected_balance: Option<u64>,
3649 commitment_config: CommitmentConfig,
3650 ) -> Option<u64> {
3651 self.invoke((self.rpc_client.as_ref()).wait_for_balance_with_commitment(
3652 pubkey,
3653 expected_balance,
3654 commitment_config,
3655 ))
3656 .ok()
3657 }
3658
3659 /// Poll the server to confirm a transaction.
3660 pub fn poll_for_signature(&self, signature: &Signature) -> ClientResult<()> {
3661 self.invoke((self.rpc_client.as_ref()).poll_for_signature(signature))
3662 }
3663
3664 /// Poll the server to confirm a transaction.
3665 pub fn poll_for_signature_with_commitment(
3666 &self,
3667 signature: &Signature,
3668 commitment_config: CommitmentConfig,
3669 ) -> ClientResult<()> {
3670 self.invoke(
3671 (self.rpc_client.as_ref())
3672 .poll_for_signature_with_commitment(signature, commitment_config),
3673 )
3674 }
3675
3676 /// Poll the server to confirm a transaction.
3677 pub fn poll_for_signature_confirmation(
3678 &self,
3679 signature: &Signature,
3680 min_confirmed_blocks: usize,
3681 ) -> ClientResult<usize> {
3682 self.invoke(
3683 (self.rpc_client.as_ref())
3684 .poll_for_signature_confirmation(signature, min_confirmed_blocks),
3685 )
3686 }
3687
3688 pub fn get_num_blocks_since_signature_confirmation(
3689 &self,
3690 signature: &Signature,
3691 ) -> ClientResult<usize> {
3692 self.invoke(
3693 (self.rpc_client.as_ref()).get_num_blocks_since_signature_confirmation(signature),
3694 )
3695 }
3696
3697 pub fn get_latest_blockhash(&self) -> ClientResult<Hash> {
3698 self.invoke((self.rpc_client.as_ref()).get_latest_blockhash())
3699 }
3700
3701 pub fn get_latest_blockhash_with_commitment(
3702 &self,
3703 commitment: CommitmentConfig,
3704 ) -> ClientResult<(Hash, u64)> {
3705 self.invoke((self.rpc_client.as_ref()).get_latest_blockhash_with_commitment(commitment))
3706 }
3707
3708 pub fn is_blockhash_valid(
3709 &self,
3710 blockhash: &Hash,
3711 commitment: CommitmentConfig,
3712 ) -> ClientResult<bool> {
3713 self.invoke((self.rpc_client.as_ref()).is_blockhash_valid(blockhash, commitment))
3714 }
3715
3716 pub fn get_fee_for_message(&self, message: &impl SerializableMessage) -> ClientResult<u64> {
3717 self.invoke((self.rpc_client.as_ref()).get_fee_for_message(message))
3718 }
3719
3720 pub fn get_new_latest_blockhash(&self, blockhash: &Hash) -> ClientResult<Hash> {
3721 self.invoke((self.rpc_client.as_ref()).get_new_latest_blockhash(blockhash))
3722 }
3723
3724 pub fn get_transport_stats(&self) -> RpcTransportStats {
3725 (self.rpc_client.as_ref()).get_transport_stats()
3726 }
3727
3728 pub fn get_feature_activation_slot(&self, feature_id: &Pubkey) -> ClientResult<Option<Slot>> {
3729 self.get_account_with_commitment(feature_id, self.commitment())
3730 .and_then(|maybe_feature_account| {
3731 maybe_feature_account
3732 .value
3733 .map(|feature_account| {
3734 bincode::deserialize(feature_account.data()).map_err(|_| {
3735 ClientError::from(ErrorKind::Custom(
3736 "Failed to deserialize feature account".to_string(),
3737 ))
3738 })
3739 })
3740 .transpose()
3741 })
3742 .map(|maybe_feature: Option<Feature>| {
3743 maybe_feature.and_then(|feature| feature.activated_at)
3744 })
3745 }
3746
3747 fn invoke<T, F: std::future::Future<Output = ClientResult<T>>>(&self, f: F) -> ClientResult<T> {
3748 // `block_on()` panics if called within an asynchronous execution context. Whereas
3749 // `block_in_place()` only panics if called from a current_thread runtime, which is the
3750 // lesser evil.
3751 tokio::task::block_in_place(move || self.runtime.as_ref().expect("runtime").block_on(f))
3752 }
3753
3754 pub fn get_inner_client(&self) -> &Arc<nonblocking::rpc_client::RpcClient> {
3755 &self.rpc_client
3756 }
3757
3758 pub fn runtime(&self) -> &tokio::runtime::Runtime {
3759 self.runtime.as_ref().expect("runtime")
3760 }
3761}
3762
3763/// Mocks for documentation examples
3764#[doc(hidden)]
3765pub fn create_rpc_client_mocks() -> crate::mock_sender::Mocks {
3766 let mut mocks = std::collections::HashMap::new();
3767
3768 let get_account_request = RpcRequest::GetAccountInfo;
3769 let get_account_response = serde_json::to_value(Response {
3770 context: RpcResponseContext {
3771 slot: 1,
3772 api_version: None,
3773 },
3774 value: {
3775 let pubkey = Pubkey::from_str("BgvYtJEfmZYdVKiptmMjxGzv8iQoo4MWjsP3QsTkhhxa").unwrap();
3776 mock_encoded_account(&pubkey)
3777 },
3778 })
3779 .unwrap();
3780 mocks.insert(get_account_request, get_account_response);
3781 mocks
3782}
3783
3784#[cfg(test)]
3785mod tests {
3786 use {
3787 super::*,
3788 crate::mock_sender::PUBKEY,
3789 assert_matches::assert_matches,
3790 base64::{Engine, prelude::BASE64_STANDARD},
3791 crossbeam_channel::unbounded,
3792 jsonrpc_core::{Error, IoHandler, Params, futures::prelude::*},
3793 jsonrpc_http_server::{AccessControlAllowOrigin, DomainsValidation, ServerBuilder},
3794 serde_json::{Number, json},
3795 solana_account_decoder::{UiAccountData, encode_ui_account},
3796 solana_account_decoder_client_types::UiAccountEncoding,
3797 solana_hash::Hash,
3798 solana_instruction::error::InstructionError,
3799 solana_keypair::Keypair,
3800 solana_message::{MessageHeader, compiled_instruction::CompiledInstruction},
3801 solana_rpc_client_api::client_error::ErrorKind,
3802 solana_signer::Signer,
3803 solana_system_transaction as system_transaction,
3804 solana_transaction_error::TransactionError,
3805 std::{io, thread},
3806 test_case::test_case,
3807 };
3808
3809 #[test]
3810 fn test_send() {
3811 _test_send();
3812 }
3813
3814 #[tokio::test(flavor = "current_thread")]
3815 #[should_panic(expected = "can call blocking only when running on the multi-threaded runtime")]
3816 async fn test_send_async_current_thread() {
3817 _test_send();
3818 }
3819
3820 #[tokio::test(flavor = "multi_thread")]
3821 async fn test_send_async_multi_thread() {
3822 _test_send();
3823 }
3824
3825 fn _test_send() {
3826 let (sender, receiver) = unbounded();
3827 thread::spawn(move || {
3828 let rpc_addr = "0.0.0.0:0".parse().unwrap();
3829 let mut io = IoHandler::default();
3830 // Successful request
3831 io.add_method("getBalance", |_params: Params| {
3832 future::ok(Value::Number(Number::from(50)))
3833 });
3834 // Failed request
3835 io.add_method("getLatestBlockhash", |params: Params| {
3836 if params != Params::None {
3837 future::err(Error::invalid_request())
3838 } else {
3839 future::ok(Value::String(
3840 "deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx".to_string(),
3841 ))
3842 }
3843 });
3844
3845 let server = ServerBuilder::new(io)
3846 .threads(1)
3847 .cors(DomainsValidation::AllowOnly(vec![
3848 AccessControlAllowOrigin::Any,
3849 ]))
3850 .start_http(&rpc_addr)
3851 .expect("Unable to start RPC server");
3852 sender.send(*server.address()).unwrap();
3853 server.wait();
3854 });
3855
3856 let rpc_addr = receiver.recv().unwrap();
3857 let rpc_client = RpcClient::new_socket(rpc_addr);
3858
3859 let balance: u64 = rpc_client
3860 .send(
3861 RpcRequest::GetBalance,
3862 json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"]),
3863 )
3864 .unwrap();
3865 assert_eq!(balance, 50);
3866
3867 let blockhash: String = rpc_client
3868 .send(RpcRequest::GetLatestBlockhash, Value::Null)
3869 .unwrap();
3870 assert_eq!(blockhash, "deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
3871
3872 // Send erroneous parameter
3873 let blockhash: ClientResult<String> =
3874 rpc_client.send(RpcRequest::GetLatestBlockhash, json!(["parameter"]));
3875 assert!(blockhash.is_err());
3876 }
3877
3878 #[test]
3879 fn test_send_transaction() {
3880 let rpc_client = RpcClient::new_mock("succeeds".to_string());
3881
3882 let key = Keypair::new();
3883 let to = solana_pubkey::new_rand();
3884 let blockhash = Hash::default();
3885 let tx = system_transaction::transfer(&key, &to, 50, blockhash);
3886
3887 let signature = rpc_client.send_transaction(&tx);
3888 assert_eq!(signature.unwrap(), tx.signatures[0]);
3889
3890 let rpc_client = RpcClient::new_mock("fails".to_string());
3891
3892 let signature = rpc_client.send_transaction(&tx);
3893 assert!(signature.is_err());
3894
3895 // Test bad signature returned from rpc node
3896 let rpc_client = RpcClient::new_mock("malicious".to_string());
3897 let signature = rpc_client.send_transaction(&tx);
3898 assert!(signature.is_err());
3899 }
3900
3901 #[test]
3902 fn test_custom_request() {
3903 let rpc_client = RpcClient::new_mock("succeeds".to_string());
3904
3905 let slot = rpc_client.get_slot().unwrap();
3906 assert_eq!(slot, 0);
3907
3908 let custom_slot = rpc_client
3909 .send::<Slot>(RpcRequest::Custom { method: "getSlot" }, Value::Null)
3910 .unwrap();
3911
3912 assert_eq!(slot, custom_slot);
3913 }
3914
3915 #[test]
3916 fn test_get_signature_status() {
3917 let signature = Signature::default();
3918
3919 let rpc_client = RpcClient::new_mock("succeeds".to_string());
3920 let status = rpc_client.get_signature_status(&signature).unwrap();
3921 assert_eq!(status, Some(Ok(())));
3922
3923 let rpc_client = RpcClient::new_mock("sig_not_found".to_string());
3924 let status = rpc_client.get_signature_status(&signature).unwrap();
3925 assert_eq!(status, None);
3926
3927 let rpc_client = RpcClient::new_mock("account_in_use".to_string());
3928 let status = rpc_client.get_signature_status(&signature).unwrap();
3929 assert_eq!(status, Some(Err(TransactionError::AccountInUse)));
3930 }
3931
3932 #[test]
3933 fn test_send_and_confirm_transaction() {
3934 let rpc_client = RpcClient::new_mock("succeeds".to_string());
3935
3936 let key = Keypair::new();
3937 let to = solana_pubkey::new_rand();
3938 let blockhash = Hash::default();
3939 let tx = system_transaction::transfer(&key, &to, 50, blockhash);
3940 let result = rpc_client.send_and_confirm_transaction(&tx);
3941 result.unwrap();
3942
3943 let rpc_client = RpcClient::new_mock("account_in_use".to_string());
3944 let result = rpc_client.send_and_confirm_transaction(&tx);
3945 assert!(result.is_err());
3946
3947 let rpc_client = RpcClient::new_mock("instruction_error".to_string());
3948 let result = rpc_client.send_and_confirm_transaction(&tx);
3949 assert_matches!(
3950 result.unwrap_err().kind(),
3951 ErrorKind::TransactionError(TransactionError::InstructionError(
3952 0,
3953 InstructionError::UninitializedAccount
3954 ))
3955 );
3956
3957 let rpc_client = RpcClient::new_mock("sig_not_found".to_string());
3958 let result = rpc_client.send_and_confirm_transaction(&tx);
3959 if let ErrorKind::Io(err) = result.unwrap_err().kind() {
3960 assert_eq!(err.kind(), io::ErrorKind::Other);
3961 }
3962 }
3963
3964 #[test]
3965 fn test_rpc_client_thread() {
3966 let rpc_client = RpcClient::new_mock("succeeds".to_string());
3967 thread::spawn(move || rpc_client);
3968 }
3969
3970 // Regression test that the get_block_production_with_config
3971 // method internally creates the json params array correctly.
3972 #[test]
3973 fn get_block_production_with_config_no_error() -> ClientResult<()> {
3974 let rpc_client = RpcClient::new_mock("succeeds".to_string());
3975
3976 let config = RpcBlockProductionConfig {
3977 identity: Some(Keypair::new().pubkey().to_string()),
3978 range: None,
3979 commitment: None,
3980 };
3981
3982 let prod = rpc_client.get_block_production_with_config(config)?.value;
3983
3984 assert!(!prod.by_identity.is_empty());
3985
3986 Ok(())
3987 }
3988
3989 #[test]
3990 fn test_get_latest_blockhash() {
3991 let rpc_client = RpcClient::new_mock("succeeds".to_string());
3992
3993 let expected_blockhash: Hash = PUBKEY.parse().unwrap();
3994
3995 let blockhash = rpc_client.get_latest_blockhash().expect("blockhash ok");
3996 assert_eq!(blockhash, expected_blockhash);
3997
3998 let rpc_client = RpcClient::new_mock("fails".to_string());
3999
4000 let is_err = rpc_client.get_latest_blockhash().is_err();
4001 assert!(is_err);
4002 }
4003
4004 #[test]
4005 fn test_get_stake_minimum_delegation() {
4006 let expected_minimum_delegation: u64 = 123_456_789;
4007 let rpc_client = RpcClient::new_mock("succeeds".to_string());
4008
4009 // Test: without commitment
4010 {
4011 let actual_minimum_delegation = rpc_client.get_stake_minimum_delegation().unwrap();
4012 assert_eq!(expected_minimum_delegation, actual_minimum_delegation);
4013 }
4014
4015 // Test: with commitment
4016 {
4017 let actual_minimum_delegation = rpc_client
4018 .get_stake_minimum_delegation_with_commitment(CommitmentConfig::confirmed())
4019 .unwrap();
4020 assert_eq!(expected_minimum_delegation, actual_minimum_delegation);
4021 }
4022 }
4023
4024 #[test]
4025 fn test_get_program_accounts_with_config() {
4026 let program_id = Pubkey::new_unique();
4027 let pubkey = Pubkey::new_unique();
4028 let account = Account {
4029 lamports: 1_000_000,
4030 data: vec![],
4031 owner: program_id,
4032 executable: false,
4033 rent_epoch: 0,
4034 };
4035 let keyed_account = RpcKeyedAccount {
4036 pubkey: pubkey.to_string(),
4037 account: encode_ui_account(&pubkey, &account, UiAccountEncoding::Base64, None, None),
4038 };
4039 let expected_result = vec![(pubkey, keyed_account.account.clone())];
4040 // Test: without context
4041 {
4042 let mocks: Mocks = [(
4043 RpcRequest::GetProgramAccounts,
4044 serde_json::to_value(OptionalContext::NoContext(vec![keyed_account.clone()]))
4045 .unwrap(),
4046 )]
4047 .into_iter()
4048 .collect();
4049 let rpc_client = RpcClient::new_mock_with_mocks("mock_client".to_string(), mocks);
4050 let result = rpc_client
4051 .get_program_ui_accounts_with_config(
4052 &program_id,
4053 RpcProgramAccountsConfig {
4054 filters: None,
4055 account_config: RpcAccountInfoConfig {
4056 encoding: Some(UiAccountEncoding::Base64),
4057 data_slice: None,
4058 commitment: None,
4059 min_context_slot: None,
4060 },
4061 with_context: None,
4062 sort_results: None,
4063 },
4064 )
4065 .unwrap();
4066 assert_eq!(expected_result, result);
4067 }
4068
4069 // Test: with context
4070 {
4071 let mocks: Mocks = [(
4072 RpcRequest::GetProgramAccounts,
4073 serde_json::to_value(OptionalContext::Context(Response {
4074 context: RpcResponseContext {
4075 slot: 1,
4076 api_version: None,
4077 },
4078 value: vec![keyed_account.clone()],
4079 }))
4080 .unwrap(),
4081 )]
4082 .into_iter()
4083 .collect();
4084 let rpc_client = RpcClient::new_mock_with_mocks("mock_client".to_string(), mocks);
4085 let result = rpc_client
4086 .get_program_ui_accounts_with_config(
4087 &program_id,
4088 RpcProgramAccountsConfig {
4089 filters: None,
4090 account_config: RpcAccountInfoConfig {
4091 encoding: Some(UiAccountEncoding::Base64),
4092 data_slice: None,
4093 commitment: None,
4094 min_context_slot: None,
4095 },
4096 with_context: Some(true),
4097 sort_results: None,
4098 },
4099 )
4100 .unwrap();
4101 assert_eq!(expected_result, result);
4102 }
4103
4104 // Test: Mock with duplicate requests
4105 {
4106 let expected_result = vec![
4107 (pubkey, keyed_account.account.clone()),
4108 (pubkey, keyed_account.account.clone()),
4109 (pubkey, keyed_account.account.clone()),
4110 (pubkey, keyed_account.account.clone()),
4111 (pubkey, keyed_account.account.clone()),
4112 ];
4113
4114 let mut mocks: MocksMap = [
4115 (
4116 RpcRequest::GetProgramAccounts,
4117 serde_json::to_value(OptionalContext::Context(Response {
4118 context: RpcResponseContext {
4119 slot: 1,
4120 api_version: None,
4121 },
4122 value: vec![keyed_account.clone()],
4123 }))
4124 .unwrap(),
4125 ),
4126 (
4127 RpcRequest::GetProgramAccounts,
4128 serde_json::to_value(OptionalContext::Context(Response {
4129 context: RpcResponseContext {
4130 slot: 1,
4131 api_version: None,
4132 },
4133 value: vec![keyed_account.clone()],
4134 }))
4135 .unwrap(),
4136 ),
4137 ]
4138 .into_iter()
4139 .collect();
4140
4141 mocks.insert(
4142 RpcRequest::GetProgramAccounts,
4143 serde_json::to_value(OptionalContext::Context(Response {
4144 context: RpcResponseContext {
4145 slot: 1,
4146 api_version: None,
4147 },
4148 value: vec![
4149 keyed_account.clone(),
4150 keyed_account.clone(),
4151 keyed_account.clone(),
4152 ],
4153 }))
4154 .unwrap(),
4155 );
4156
4157 mocks.insert(
4158 RpcRequest::GetProgramAccounts,
4159 serde_json::to_value(OptionalContext::Context(Response {
4160 context: RpcResponseContext {
4161 slot: 1,
4162 api_version: None,
4163 },
4164 value: Vec::<RpcKeyedAccount>::new(),
4165 }))
4166 .unwrap(),
4167 );
4168
4169 let rpc_client = RpcClient::new_mock_with_mocks_map("mock_client".to_string(), mocks);
4170 let mut result1 = rpc_client
4171 .get_program_ui_accounts_with_config(
4172 &program_id,
4173 RpcProgramAccountsConfig {
4174 filters: None,
4175 account_config: RpcAccountInfoConfig {
4176 encoding: Some(UiAccountEncoding::Base64),
4177 data_slice: None,
4178 commitment: None,
4179 min_context_slot: None,
4180 },
4181 with_context: Some(true),
4182 sort_results: None,
4183 },
4184 )
4185 .unwrap();
4186
4187 assert_eq!(result1.len(), 1);
4188
4189 let result2 = rpc_client
4190 .get_program_ui_accounts_with_config(
4191 &program_id,
4192 RpcProgramAccountsConfig {
4193 filters: None,
4194 account_config: RpcAccountInfoConfig {
4195 encoding: Some(UiAccountEncoding::Base64),
4196 data_slice: None,
4197 commitment: None,
4198 min_context_slot: None,
4199 },
4200 with_context: Some(true),
4201 sort_results: None,
4202 },
4203 )
4204 .unwrap();
4205
4206 assert_eq!(result2.len(), 1);
4207
4208 let result_3 = rpc_client
4209 .get_program_ui_accounts_with_config(
4210 &program_id,
4211 RpcProgramAccountsConfig {
4212 filters: None,
4213 account_config: RpcAccountInfoConfig {
4214 encoding: Some(UiAccountEncoding::Base64),
4215 data_slice: None,
4216 commitment: None,
4217 min_context_slot: None,
4218 },
4219 with_context: Some(true),
4220 sort_results: None,
4221 },
4222 )
4223 .unwrap();
4224
4225 assert_eq!(result_3.len(), 3);
4226
4227 let result_4 = rpc_client
4228 .get_program_ui_accounts_with_config(
4229 &program_id,
4230 RpcProgramAccountsConfig {
4231 filters: None,
4232 account_config: RpcAccountInfoConfig {
4233 encoding: Some(UiAccountEncoding::Base64),
4234 data_slice: None,
4235 commitment: None,
4236 min_context_slot: None,
4237 },
4238 with_context: Some(true),
4239 sort_results: None,
4240 },
4241 )
4242 .unwrap();
4243
4244 assert_eq!(result_4.len(), 0);
4245
4246 result1.extend(result2);
4247 result1.extend(result_3);
4248 assert_eq!(expected_result, result1);
4249 }
4250 }
4251
4252 #[test]
4253 fn test_get_program_ui_accounts_with_config() {
4254 let program_id = Pubkey::new_unique();
4255 let pubkey = Pubkey::new_unique();
4256 let account = UiAccount {
4257 lamports: 1_000_000,
4258 data: UiAccountData::Binary("".to_string(), UiAccountEncoding::Base64),
4259 owner: program_id.to_string(),
4260 executable: false,
4261 rent_epoch: 0,
4262 space: Some(0),
4263 };
4264 let keyed_account = RpcKeyedAccount {
4265 account: account.clone(),
4266 pubkey: pubkey.to_string(),
4267 };
4268 let expected_result = vec![(pubkey, account.clone())];
4269 // Test: without context
4270 {
4271 let mocks: Mocks = [(
4272 RpcRequest::GetProgramAccounts,
4273 serde_json::to_value(OptionalContext::NoContext(vec![keyed_account.clone()]))
4274 .unwrap(),
4275 )]
4276 .into_iter()
4277 .collect();
4278 let rpc_client = RpcClient::new_mock_with_mocks("mock_client".to_string(), mocks);
4279 let result = rpc_client
4280 .get_program_ui_accounts_with_config(
4281 &program_id,
4282 RpcProgramAccountsConfig {
4283 filters: None,
4284 account_config: RpcAccountInfoConfig {
4285 encoding: Some(UiAccountEncoding::Base64),
4286 data_slice: None,
4287 commitment: None,
4288 min_context_slot: None,
4289 },
4290 with_context: None,
4291 sort_results: None,
4292 },
4293 )
4294 .unwrap();
4295 assert_eq!(expected_result, result);
4296 }
4297
4298 // Test: with context
4299 {
4300 let mocks: Mocks = [(
4301 RpcRequest::GetProgramAccounts,
4302 serde_json::to_value(OptionalContext::Context(Response {
4303 context: RpcResponseContext {
4304 slot: 1,
4305 api_version: None,
4306 },
4307 value: vec![keyed_account.clone()],
4308 }))
4309 .unwrap(),
4310 )]
4311 .into_iter()
4312 .collect();
4313 let rpc_client = RpcClient::new_mock_with_mocks("mock_client".to_string(), mocks);
4314 let result = rpc_client
4315 .get_program_ui_accounts_with_config(
4316 &program_id,
4317 RpcProgramAccountsConfig {
4318 filters: None,
4319 account_config: RpcAccountInfoConfig {
4320 encoding: Some(UiAccountEncoding::Base64),
4321 data_slice: None,
4322 commitment: None,
4323 min_context_slot: None,
4324 },
4325 with_context: Some(true),
4326 sort_results: None,
4327 },
4328 )
4329 .unwrap();
4330 assert_eq!(expected_result, result);
4331 }
4332
4333 // Test: Mock with duplicate requests
4334 {
4335 let expected_result = vec![
4336 (pubkey, account.clone()),
4337 (pubkey, account.clone()),
4338 (pubkey, account.clone()),
4339 (pubkey, account.clone()),
4340 (pubkey, account.clone()),
4341 ];
4342
4343 let mut mocks: MocksMap = [
4344 (
4345 RpcRequest::GetProgramAccounts,
4346 serde_json::to_value(OptionalContext::Context(Response {
4347 context: RpcResponseContext {
4348 slot: 1,
4349 api_version: None,
4350 },
4351 value: vec![keyed_account.clone()],
4352 }))
4353 .unwrap(),
4354 ),
4355 (
4356 RpcRequest::GetProgramAccounts,
4357 serde_json::to_value(OptionalContext::Context(Response {
4358 context: RpcResponseContext {
4359 slot: 1,
4360 api_version: None,
4361 },
4362 value: vec![keyed_account.clone()],
4363 }))
4364 .unwrap(),
4365 ),
4366 ]
4367 .into_iter()
4368 .collect();
4369
4370 mocks.insert(
4371 RpcRequest::GetProgramAccounts,
4372 serde_json::to_value(OptionalContext::Context(Response {
4373 context: RpcResponseContext {
4374 slot: 1,
4375 api_version: None,
4376 },
4377 value: vec![
4378 keyed_account.clone(),
4379 keyed_account.clone(),
4380 keyed_account.clone(),
4381 ],
4382 }))
4383 .unwrap(),
4384 );
4385
4386 mocks.insert(
4387 RpcRequest::GetProgramAccounts,
4388 serde_json::to_value(OptionalContext::Context(Response {
4389 context: RpcResponseContext {
4390 slot: 1,
4391 api_version: None,
4392 },
4393 value: Vec::<RpcKeyedAccount>::new(),
4394 }))
4395 .unwrap(),
4396 );
4397
4398 let rpc_client = RpcClient::new_mock_with_mocks_map("mock_client".to_string(), mocks);
4399 let mut result1 = rpc_client
4400 .get_program_ui_accounts_with_config(
4401 &program_id,
4402 RpcProgramAccountsConfig {
4403 filters: None,
4404 account_config: RpcAccountInfoConfig {
4405 encoding: Some(UiAccountEncoding::Base64),
4406 data_slice: None,
4407 commitment: None,
4408 min_context_slot: None,
4409 },
4410 with_context: Some(true),
4411 sort_results: None,
4412 },
4413 )
4414 .unwrap();
4415
4416 assert_eq!(result1.len(), 1);
4417
4418 let result2 = rpc_client
4419 .get_program_ui_accounts_with_config(
4420 &program_id,
4421 RpcProgramAccountsConfig {
4422 filters: None,
4423 account_config: RpcAccountInfoConfig {
4424 encoding: Some(UiAccountEncoding::Base64),
4425 data_slice: None,
4426 commitment: None,
4427 min_context_slot: None,
4428 },
4429 with_context: Some(true),
4430 sort_results: None,
4431 },
4432 )
4433 .unwrap();
4434
4435 assert_eq!(result2.len(), 1);
4436
4437 let result_3 = rpc_client
4438 .get_program_ui_accounts_with_config(
4439 &program_id,
4440 RpcProgramAccountsConfig {
4441 filters: None,
4442 account_config: RpcAccountInfoConfig {
4443 encoding: Some(UiAccountEncoding::Base64),
4444 data_slice: None,
4445 commitment: None,
4446 min_context_slot: None,
4447 },
4448 with_context: Some(true),
4449 sort_results: None,
4450 },
4451 )
4452 .unwrap();
4453
4454 assert_eq!(result_3.len(), 3);
4455
4456 let result_4 = rpc_client
4457 .get_program_ui_accounts_with_config(
4458 &program_id,
4459 RpcProgramAccountsConfig {
4460 filters: None,
4461 account_config: RpcAccountInfoConfig {
4462 encoding: Some(UiAccountEncoding::Base64),
4463 data_slice: None,
4464 commitment: None,
4465 min_context_slot: None,
4466 },
4467 with_context: Some(true),
4468 sort_results: None,
4469 },
4470 )
4471 .unwrap();
4472
4473 assert_eq!(result_4.len(), 0);
4474
4475 result1.extend(result2);
4476 result1.extend(result_3);
4477 assert_eq!(expected_result, result1);
4478 }
4479 }
4480
4481 #[test_case(LegacyMessage {
4482 header: MessageHeader {
4483 num_required_signatures: 1,
4484 num_readonly_signed_accounts: 0,
4485 num_readonly_unsigned_accounts: 1,
4486 },
4487 account_keys: vec![Pubkey::new_unique()],
4488 recent_blockhash: Hash::new_unique(),
4489 instructions: vec![CompiledInstruction {
4490 program_id_index: 1,
4491 accounts: vec![0],
4492 data: vec![],
4493 }],
4494 }; "legacy message")]
4495 #[test_case(v0::Message {
4496 header: MessageHeader {
4497 num_required_signatures: 1,
4498 num_readonly_signed_accounts: 0,
4499 num_readonly_unsigned_accounts: 0,
4500 },
4501 account_keys: vec![Pubkey::new_unique()],
4502 recent_blockhash: Hash::new_unique(),
4503 instructions: vec![CompiledInstruction {
4504 program_id_index: 0,
4505 accounts: vec![],
4506 data: vec![],
4507 }],
4508 address_table_lookups: vec![],
4509 }; "v0 message")]
4510 fn test_get_fee_for_message_sends_properly_serialized_v0_transaction<M>(message: M)
4511 where
4512 M: SerializableMessage,
4513 {
4514 let serialized_message = message.serialize();
4515 let serialized_message_base64 = BASE64_STANDARD.encode(serialized_message);
4516
4517 let (sender, receiver) = unbounded();
4518 thread::spawn(move || {
4519 let rpc_addr = "0.0.0.0:0".parse().unwrap();
4520 let mut io = IoHandler::default();
4521 // Successful request
4522 io.add_method("getFeeForMessage", move |params: Params| match params {
4523 Params::Array(p) => {
4524 let first_element = p.first().unwrap();
4525 if let Value::String(actual_serialized_message) = first_element {
4526 assert_eq!(actual_serialized_message, &serialized_message_base64);
4527 return future::ok(json!(Response {
4528 context: RpcResponseContext {
4529 api_version: None,
4530 slot: 1,
4531 },
4532 value: json!(42),
4533 }));
4534 }
4535 future::err(Error::invalid_params(
4536 "Expected the serialized message to be the first element of the params",
4537 ))
4538 }
4539 _ => {
4540 panic!("Expected an array of params to be forwarded to `getFeeForMessage");
4541 }
4542 });
4543
4544 let server = ServerBuilder::new(io)
4545 .threads(1)
4546 .cors(DomainsValidation::AllowOnly(vec![
4547 AccessControlAllowOrigin::Any,
4548 ]))
4549 .start_http(&rpc_addr)
4550 .expect("Unable to start RPC server");
4551 sender.send(*server.address()).unwrap();
4552 server.wait();
4553 });
4554
4555 let rpc_addr = receiver.recv().unwrap();
4556 let rpc_client = RpcClient::new_socket(rpc_addr);
4557
4558 let fee: u64 = rpc_client.get_fee_for_message(&message).unwrap();
4559 assert_eq!(fee, 42);
4560 }
4561}