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