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