1#[cfg(feature = "dev-context-only-utils")]
3use solana_runtime::installed_scheduler_pool::BankWithScheduler;
4use {
5 crate::{
6 filter::filter_allows, max_slots::MaxSlots,
7 optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank,
8 parsed_token_accounts::*, rpc_cache::LargestAccountsCache, rpc_health::*,
9 },
10 agave_snapshots::{paths as snapshot_paths, snapshot_config::SnapshotConfig},
11 base64::{prelude::BASE64_STANDARD, Engine},
12 bincode::{config::Options, serialize},
13 crossbeam_channel::{unbounded, Receiver, Sender},
14 jsonrpc_core::{
15 futures::future::{self, FutureExt, OptionFuture},
16 types::error,
17 BoxFuture, Error, Metadata, Result,
18 },
19 jsonrpc_derive::rpc,
20 solana_account::{AccountSharedData, ReadableAccount},
21 solana_account_decoder::{
22 encode_ui_account,
23 parse_account_data::SplTokenAdditionalDataV2,
24 parse_token::{is_known_spl_token_id, token_amount_to_ui_amount_v3, UiTokenAmount},
25 UiAccount, UiAccountEncoding, UiDataSliceConfig, MAX_BASE58_BYTES,
26 },
27 solana_accounts_db::{
28 accounts::AccountAddressFilter,
29 accounts_index::{
30 AccountIndex, AccountSecondaryIndexes, IndexKey, ScanConfig, ScanOrder, ScanResult,
31 },
32 },
33 solana_client::connection_cache::Protocol,
34 solana_clock::{Slot, UnixTimestamp, MAX_PROCESSING_AGE},
35 solana_commitment_config::{CommitmentConfig, CommitmentLevel},
36 solana_entry::entry::Entry,
37 solana_epoch_info::EpochInfo,
38 solana_epoch_rewards_hasher::EpochRewardsHasher,
39 solana_epoch_schedule::EpochSchedule,
40 solana_faucet::faucet::request_airdrop_transaction,
41 solana_gossip::cluster_info::ClusterInfo,
42 solana_hash::Hash,
43 solana_keypair::Keypair,
44 solana_ledger::{
45 blockstore::{Blockstore, BlockstoreError, SignatureInfosForAddress},
46 blockstore_meta::{PerfSample, PerfSampleV1, PerfSampleV2},
47 leader_schedule_cache::LeaderScheduleCache,
48 },
49 solana_message::{AddressLoader, SanitizedMessage},
50 solana_metrics::inc_new_counter_info,
51 solana_perf::packet::PACKET_DATA_SIZE,
52 solana_program_pack::Pack,
53 solana_pubkey::{Pubkey, PUBKEY_BYTES},
54 solana_rpc_client_api::{
55 config::*,
56 custom_error::RpcCustomError,
57 filter::{Memcmp, RpcFilterType},
58 request::{
59 TokenAccountsFilter, DELINQUENT_VALIDATOR_SLOT_DISTANCE,
60 MAX_GET_CONFIRMED_BLOCKS_RANGE, MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT,
61 MAX_GET_PROGRAM_ACCOUNT_FILTERS, MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS,
62 MAX_GET_SLOT_LEADERS, MAX_MULTIPLE_ACCOUNTS,
63 MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY, NUM_LARGEST_ACCOUNTS,
64 },
65 response::{Response as RpcResponse, *},
66 },
67 solana_runtime::{
68 bank::{Bank, TransactionSimulationResult},
69 bank_forks::BankForks,
70 commitment::{BlockCommitmentArray, BlockCommitmentCache},
71 non_circulating_supply::{calculate_non_circulating_supply, NonCirculatingSupply},
72 prioritization_fee_cache::PrioritizationFeeCache,
73 stake_utils,
74 },
75 solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
76 solana_send_transaction_service::send_transaction_service::TransactionInfo,
77 solana_signature::Signature,
78 solana_signer::Signer,
79 solana_storage_bigtable::Error as StorageError,
80 solana_transaction::{
81 sanitized::{MessageHash, SanitizedTransaction, MAX_TX_ACCOUNT_LOCKS},
82 versioned::VersionedTransaction,
83 },
84 solana_transaction_context::transaction_accounts::KeyedAccountSharedData,
85 solana_transaction_error::TransactionError,
86 solana_transaction_status::{
87 map_inner_instructions, BlockEncodingOptions, ConfirmedBlock,
88 ConfirmedTransactionStatusWithSignature, ConfirmedTransactionWithStatusMeta,
89 EncodedConfirmedTransactionWithStatusMeta, Reward, RewardType, Rewards,
90 TransactionBinaryEncoding, TransactionConfirmationStatus, TransactionStatus,
91 UiConfirmedBlock, UiTransactionEncoding,
92 },
93 solana_validator_exit::Exit,
94 solana_vote_program::vote_state::MAX_LOCKOUT_HISTORY,
95 spl_generic_token::{
96 token::{SPL_TOKEN_ACCOUNT_MINT_OFFSET, SPL_TOKEN_ACCOUNT_OWNER_OFFSET},
97 token_2022::{self, ACCOUNTTYPE_ACCOUNT},
98 },
99 spl_token_2022_interface::{
100 extension::{
101 interest_bearing_mint::InterestBearingConfig, scaled_ui_amount::ScaledUiAmountConfig,
102 BaseStateWithExtensions, StateWithExtensions,
103 },
104 state::{Account as TokenAccount, Mint},
105 },
106 std::{
107 any::type_name,
108 cmp::{max, min, Reverse},
109 collections::{BinaryHeap, HashMap, HashSet},
110 convert::TryFrom,
111 net::SocketAddr,
112 str::FromStr,
113 sync::{
114 atomic::{AtomicBool, AtomicU64, Ordering},
115 Arc, RwLock,
116 },
117 time::Duration,
118 },
119 tokio::runtime::Runtime,
120};
121#[cfg(test)]
122use {
123 solana_gossip::contact_info::ContactInfo,
124 solana_ledger::get_tmp_ledger_path,
125 solana_runtime::commitment::CommitmentSlots,
126 solana_send_transaction_service::{
127 send_transaction_service::Config as SendTransactionServiceConfig,
128 send_transaction_service::SendTransactionService, test_utils::ClientWithCreator,
129 },
130 solana_streamer::socket::SocketAddrSpace,
131};
132
133mod transaction {
134 pub use solana_transaction_error::TransactionResult as Result;
135}
136
137pub mod account_resolver;
138
139type RpcCustomResult<T> = std::result::Result<T, RpcCustomError>;
140
141pub const MAX_REQUEST_BODY_SIZE: usize = 50 * (1 << 10); pub const PERFORMANCE_SAMPLES_LIMIT: usize = 720;
143
144fn new_response<T>(bank: &Bank, value: T) -> RpcResponse<T> {
145 RpcResponse {
146 context: RpcResponseContext::new(bank.slot()),
147 value,
148 }
149}
150
151fn is_finalized(
152 block_commitment_cache: &BlockCommitmentCache,
153 bank: &Bank,
154 blockstore: &Blockstore,
155 slot: Slot,
156) -> bool {
157 slot <= block_commitment_cache.highest_super_majority_root()
158 && (blockstore.is_root(slot) || bank.status_cache_ancestors().contains(&slot))
159}
160
161#[derive(Debug, Clone, PartialEq)]
162pub struct JsonRpcConfig {
163 pub enable_rpc_transaction_history: bool,
164 pub enable_extended_tx_metadata_storage: bool,
165 pub faucet_addr: Option<SocketAddr>,
166 pub health_check_slot_distance: u64,
167 pub skip_preflight_health_check: bool,
168 pub rpc_bigtable_config: Option<RpcBigtableConfig>,
169 pub max_multiple_accounts: Option<usize>,
170 pub account_indexes: AccountSecondaryIndexes,
171 pub rpc_threads: usize,
172 pub rpc_blocking_threads: usize,
173 pub rpc_niceness_adj: i8,
174 pub full_api: bool,
175 pub rpc_scan_and_fix_roots: bool,
176 pub max_request_body_size: Option<usize>,
177 pub disable_health_check: bool,
179}
180
181impl Default for JsonRpcConfig {
182 fn default() -> Self {
183 Self {
184 enable_rpc_transaction_history: Default::default(),
185 enable_extended_tx_metadata_storage: Default::default(),
186 faucet_addr: Option::default(),
187 health_check_slot_distance: Default::default(),
188 skip_preflight_health_check: bool::default(),
189 rpc_bigtable_config: Option::default(),
190 max_multiple_accounts: Option::default(),
191 account_indexes: AccountSecondaryIndexes::default(),
192 rpc_threads: 1,
193 rpc_blocking_threads: 1,
194 rpc_niceness_adj: Default::default(),
195 full_api: Default::default(),
196 rpc_scan_and_fix_roots: Default::default(),
197 max_request_body_size: Option::default(),
198 disable_health_check: Default::default(),
199 }
200 }
201}
202
203impl JsonRpcConfig {
204 pub fn default_for_test() -> Self {
205 Self {
206 full_api: true,
207 disable_health_check: true,
208 ..Self::default()
209 }
210 }
211}
212
213#[derive(Debug, Clone, PartialEq)]
214pub struct RpcBigtableConfig {
215 pub enable_bigtable_ledger_upload: bool,
216 pub bigtable_instance_name: String,
217 pub bigtable_app_profile_id: String,
218 pub timeout: Option<Duration>,
219 pub max_message_size: usize,
220}
221
222impl Default for RpcBigtableConfig {
223 fn default() -> Self {
224 let bigtable_instance_name = solana_storage_bigtable::DEFAULT_INSTANCE_NAME.to_string();
225 let bigtable_app_profile_id = solana_storage_bigtable::DEFAULT_APP_PROFILE_ID.to_string();
226 Self {
227 enable_bigtable_ledger_upload: false,
228 bigtable_instance_name,
229 bigtable_app_profile_id,
230 timeout: None,
231 max_message_size: solana_storage_bigtable::DEFAULT_MAX_MESSAGE_SIZE,
232 }
233 }
234}
235
236#[derive(Clone)]
237pub struct JsonRpcRequestProcessor {
238 bank_forks: Arc<RwLock<BankForks>>,
239 block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
240 blockstore: Arc<Blockstore>,
241 config: JsonRpcConfig,
242 snapshot_config: Option<SnapshotConfig>,
243 #[allow(dead_code)]
244 validator_exit: Arc<RwLock<Exit>>,
245 health: Arc<RpcHealth>,
246 cluster_info: Arc<ClusterInfo>,
247 genesis_hash: Hash,
248 transaction_sender: Sender<TransactionInfo>,
249 bigtable_ledger_storage: Option<solana_storage_bigtable::LedgerStorage>,
250 optimistically_confirmed_bank: Arc<RwLock<OptimisticallyConfirmedBank>>,
251 largest_accounts_cache: Arc<RwLock<LargestAccountsCache>>,
252 max_slots: Arc<MaxSlots>,
253 leader_schedule_cache: Arc<LeaderScheduleCache>,
254 max_complete_transaction_status_slot: Arc<AtomicU64>,
255 prioritization_fee_cache: Arc<PrioritizationFeeCache>,
256 runtime: Arc<Runtime>,
257}
258impl Metadata for JsonRpcRequestProcessor {}
259
260impl JsonRpcRequestProcessor {
261 pub fn clone_without_bigtable(&self) -> JsonRpcRequestProcessor {
262 Self {
263 bigtable_ledger_storage: None, ..self.clone()
265 }
266 }
267}
268
269impl JsonRpcRequestProcessor {
270 fn get_bank_with_config(&self, config: RpcContextConfig) -> Result<Arc<Bank>> {
271 let RpcContextConfig {
272 commitment,
273 min_context_slot,
274 } = config;
275 let bank = self.bank(commitment);
276 if let Some(min_context_slot) = min_context_slot {
277 if bank.slot() < min_context_slot {
278 return Err(RpcCustomError::MinContextSlotNotReached {
279 context_slot: bank.slot(),
280 }
281 .into());
282 }
283 }
284 Ok(bank)
285 }
286
287 fn check_if_transaction_history_enabled(&self) -> Result<()> {
288 if !self.config.enable_rpc_transaction_history {
289 return Err(RpcCustomError::TransactionHistoryNotAvailable.into());
290 }
291 Ok(())
292 }
293
294 async fn calculate_non_circulating_supply(
295 &self,
296 bank: &Arc<Bank>,
297 ) -> ScanResult<NonCirculatingSupply> {
298 let bank = Arc::clone(bank);
299 self.runtime
300 .spawn_blocking(move || calculate_non_circulating_supply(&bank))
301 .await
302 .expect("Failed to spawn blocking task")
303 }
304
305 pub async fn get_filtered_indexed_accounts(
306 &self,
307 bank: &Arc<Bank>,
308 index_key: &IndexKey,
309 program_id: &Pubkey,
310 filters: Vec<RpcFilterType>,
311 sort_results: bool,
312 ) -> ScanResult<Vec<KeyedAccountSharedData>> {
313 let scan_order = if sort_results {
314 ScanOrder::Sorted
315 } else {
316 ScanOrder::Unsorted
317 };
318 let bank = Arc::clone(bank);
319 let index_key = index_key.to_owned();
320 let program_id = program_id.to_owned();
321 self.runtime
322 .spawn_blocking(move || {
323 bank.get_filtered_indexed_accounts(
324 &index_key,
325 |account| {
326 account.owner().eq(&program_id)
332 && filters
333 .iter()
334 .all(|filter_type| filter_allows(filter_type, account))
335 },
336 &ScanConfig::new(scan_order),
337 bank.byte_limit_for_scans(),
338 )
339 })
340 .await
341 .expect("Failed to spawn blocking task")
342 }
343
344 #[allow(deprecated)]
345 fn bank(&self, commitment: Option<CommitmentConfig>) -> Arc<Bank> {
346 debug!("RPC commitment_config: {commitment:?}");
347
348 let commitment = commitment.unwrap_or_default();
349 if commitment.is_confirmed() {
350 let bank = self
351 .optimistically_confirmed_bank
352 .read()
353 .unwrap()
354 .bank
355 .clone();
356 debug!("RPC using optimistically confirmed slot: {:?}", bank.slot());
357 return bank;
358 }
359
360 let slot = self
361 .block_commitment_cache
362 .read()
363 .unwrap()
364 .slot_with_commitment(commitment.commitment);
365
366 match commitment.commitment {
367 CommitmentLevel::Processed => {
368 debug!("RPC using the heaviest slot: {slot:?}");
369 }
370 CommitmentLevel::Finalized => {
371 debug!("RPC using block: {slot:?}");
372 }
373 CommitmentLevel::Confirmed => unreachable!(), };
375
376 let r_bank_forks = self.bank_forks.read().unwrap();
377 r_bank_forks.get(slot).unwrap_or_else(|| {
378 warn!(
390 "Bank with {:?} not found at slot: {:?}",
391 commitment.commitment, slot
392 );
393 r_bank_forks.root_bank()
394 })
395 }
396
397 fn genesis_creation_time(&self) -> UnixTimestamp {
398 self.bank(None).genesis_creation_time()
399 }
400
401 #[allow(clippy::too_many_arguments)]
402 pub fn new(
403 config: JsonRpcConfig,
404 snapshot_config: Option<SnapshotConfig>,
405 bank_forks: Arc<RwLock<BankForks>>,
406 block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
407 blockstore: Arc<Blockstore>,
408 validator_exit: Arc<RwLock<Exit>>,
409 health: Arc<RpcHealth>,
410 cluster_info: Arc<ClusterInfo>,
411 genesis_hash: Hash,
412 bigtable_ledger_storage: Option<solana_storage_bigtable::LedgerStorage>,
413 optimistically_confirmed_bank: Arc<RwLock<OptimisticallyConfirmedBank>>,
414 largest_accounts_cache: Arc<RwLock<LargestAccountsCache>>,
415 max_slots: Arc<MaxSlots>,
416 leader_schedule_cache: Arc<LeaderScheduleCache>,
417 max_complete_transaction_status_slot: Arc<AtomicU64>,
418 prioritization_fee_cache: Arc<PrioritizationFeeCache>,
419 runtime: Arc<Runtime>,
420 ) -> (Self, Receiver<TransactionInfo>) {
421 let (transaction_sender, transaction_receiver) = unbounded();
422 (
423 Self {
424 config,
425 snapshot_config,
426 bank_forks,
427 block_commitment_cache,
428 blockstore,
429 validator_exit,
430 health,
431 cluster_info,
432 genesis_hash,
433 transaction_sender,
434 bigtable_ledger_storage,
435 optimistically_confirmed_bank,
436 largest_accounts_cache,
437 max_slots,
438 leader_schedule_cache,
439 max_complete_transaction_status_slot,
440 prioritization_fee_cache,
441 runtime,
442 },
443 transaction_receiver,
444 )
445 }
446
447 #[cfg(test)]
448 pub fn new_from_bank<Client: ClientWithCreator>(
449 bank: Bank,
450 socket_addr_space: SocketAddrSpace,
451 ) -> Self {
452 use crate::rpc_service::service_runtime;
453
454 let genesis_hash = bank.hash();
455 let bank_forks = BankForks::new_rw_arc(bank);
456 let bank = bank_forks.read().unwrap().root_bank();
457 let blockstore = Arc::new(Blockstore::open(&get_tmp_ledger_path!()).unwrap());
458 let exit = Arc::new(AtomicBool::new(false));
459 let cluster_info = Arc::new({
460 let keypair = Arc::new(Keypair::new());
461 let contact_info = ContactInfo::new_localhost(
462 &keypair.pubkey(),
463 solana_time_utils::timestamp(), );
465 ClusterInfo::new(contact_info, keypair, socket_addr_space)
466 });
467 let my_tpu_address = cluster_info.my_contact_info().tpu(Protocol::QUIC).unwrap();
471 let (transaction_sender, transaction_receiver) = unbounded();
472
473 let config = JsonRpcConfig::default();
474 let JsonRpcConfig {
475 rpc_threads,
476 rpc_blocking_threads,
477 rpc_niceness_adj,
478 ..
479 } = config;
480 let runtime = service_runtime(rpc_threads, rpc_blocking_threads, rpc_niceness_adj);
481 let client = Client::create_client(Some(runtime.handle().clone()), my_tpu_address, None, 1);
482
483 SendTransactionService::new_with_client(
484 &bank_forks,
485 transaction_receiver,
486 client,
487 SendTransactionServiceConfig {
488 retry_rate_ms: 1_000,
489 leader_forward_count: 1,
490 ..SendTransactionServiceConfig::default()
491 },
492 exit.clone(),
493 );
494
495 let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
496 let slot = bank.slot();
497 let optimistically_confirmed_bank =
498 Arc::new(RwLock::new(OptimisticallyConfirmedBank { bank }));
499 Self {
500 config,
501 snapshot_config: None,
502 bank_forks,
503 block_commitment_cache: Arc::new(RwLock::new(BlockCommitmentCache::new(
504 HashMap::new(),
505 0,
506 CommitmentSlots::new_from_slot(slot),
507 ))),
508 blockstore: Arc::clone(&blockstore),
509 validator_exit: create_validator_exit(exit.clone()),
510 health: Arc::new(RpcHealth::new(
511 Arc::clone(&optimistically_confirmed_bank),
512 blockstore,
513 0,
514 exit,
515 )),
516 cluster_info,
517 genesis_hash,
518 transaction_sender,
519 bigtable_ledger_storage: None,
520 optimistically_confirmed_bank,
521 largest_accounts_cache: Arc::new(RwLock::new(LargestAccountsCache::new(30))),
522 max_slots: Arc::new(MaxSlots::default()),
523 leader_schedule_cache,
524 max_complete_transaction_status_slot: Arc::new(AtomicU64::default()),
525 prioritization_fee_cache: Arc::new(PrioritizationFeeCache::default()),
526 runtime,
527 }
528 }
529
530 pub async fn get_account_info(
531 &self,
532 pubkey: Pubkey,
533 config: Option<RpcAccountInfoConfig>,
534 ) -> Result<RpcResponse<Option<UiAccount>>> {
535 let RpcAccountInfoConfig {
536 encoding,
537 data_slice,
538 commitment,
539 min_context_slot,
540 } = config.unwrap_or_default();
541 let bank = self.get_bank_with_config(RpcContextConfig {
542 commitment,
543 min_context_slot,
544 })?;
545 let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
546
547 let response = self
548 .runtime
549 .spawn_blocking({
550 let bank = Arc::clone(&bank);
551 move || get_encoded_account(&bank, &pubkey, encoding, data_slice, None)
552 })
553 .await
554 .expect("rpc: get_encoded_account panicked")?;
555 Ok(new_response(&bank, response))
556 }
557
558 pub async fn get_multiple_accounts(
559 &self,
560 pubkeys: Vec<Pubkey>,
561 config: Option<RpcAccountInfoConfig>,
562 ) -> Result<RpcResponse<Vec<Option<UiAccount>>>> {
563 let RpcAccountInfoConfig {
564 encoding,
565 data_slice,
566 commitment,
567 min_context_slot,
568 } = config.unwrap_or_default();
569 let bank = self.get_bank_with_config(RpcContextConfig {
570 commitment,
571 min_context_slot,
572 })?;
573 let encoding = encoding.unwrap_or(UiAccountEncoding::Base64);
574
575 let mut accounts = Vec::with_capacity(pubkeys.len());
576 for pubkey in pubkeys {
577 let bank = Arc::clone(&bank);
578 accounts.push(
579 self.runtime
580 .spawn_blocking(move || {
581 get_encoded_account(&bank, &pubkey, encoding, data_slice, None)
582 })
583 .await
584 .expect("rpc: get_encoded_account panicked")?,
585 );
586 }
587 Ok(new_response(&bank, accounts))
588 }
589
590 pub fn get_minimum_balance_for_rent_exemption(
591 &self,
592 data_len: usize,
593 commitment: Option<CommitmentConfig>,
594 ) -> u64 {
595 self.bank(commitment)
596 .get_minimum_balance_for_rent_exemption(data_len)
597 }
598
599 pub async fn get_program_accounts(
600 &self,
601 program_id: Pubkey,
602 config: Option<RpcAccountInfoConfig>,
603 mut filters: Vec<RpcFilterType>,
604 with_context: bool,
605 sort_results: bool,
606 ) -> Result<OptionalContext<Vec<RpcKeyedAccount>>> {
607 let RpcAccountInfoConfig {
608 encoding,
609 data_slice: data_slice_config,
610 commitment,
611 min_context_slot,
612 } = config.unwrap_or_default();
613 let bank = self.get_bank_with_config(RpcContextConfig {
614 commitment,
615 min_context_slot,
616 })?;
617 let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
618 optimize_filters(&mut filters);
619 let keyed_accounts = {
620 if let Some(owner) = get_spl_token_owner_filter(&program_id, &filters)? {
621 self.get_filtered_spl_token_accounts_by_owner(
622 Arc::clone(&bank),
623 program_id,
624 owner,
625 filters,
626 sort_results,
627 )
628 .await?
629 } else if let Some(mint) = get_spl_token_mint_filter(&program_id, &filters)? {
630 self.get_filtered_spl_token_accounts_by_mint(
631 Arc::clone(&bank),
632 program_id,
633 mint,
634 filters,
635 sort_results,
636 )
637 .await?
638 } else {
639 self.get_filtered_program_accounts(
640 Arc::clone(&bank),
641 program_id,
642 filters,
643 sort_results,
644 )
645 .await?
646 }
647 };
648 let accounts = if is_known_spl_token_id(&program_id)
649 && encoding == UiAccountEncoding::JsonParsed
650 {
651 get_parsed_token_accounts(Arc::clone(&bank), keyed_accounts.into_iter()).collect()
652 } else {
653 keyed_accounts
654 .into_iter()
655 .map(|(pubkey, account)| {
656 Ok(RpcKeyedAccount {
657 pubkey: pubkey.to_string(),
658 account: encode_account(&account, &pubkey, encoding, data_slice_config)?,
659 })
660 })
661 .collect::<Result<Vec<_>>>()?
662 };
663 Ok(match with_context {
664 true => OptionalContext::Context(new_response(&bank, accounts)),
665 false => OptionalContext::NoContext(accounts),
666 })
667 }
668
669 fn filter_map_rewards<'a, F>(
670 rewards: Option<Rewards>,
671 slot: Slot,
672 addresses: &'a [String],
673 reward_type_filter: &'a F,
674 ) -> impl Iterator<Item = (String, (Reward, Slot))> + use<'a, F>
675 where
676 F: Fn(RewardType) -> bool,
677 {
678 Self::filter_rewards(rewards, reward_type_filter)
679 .filter(|reward| addresses.contains(&reward.pubkey))
680 .map(move |reward| (reward.pubkey.clone(), (reward, slot)))
681 }
682
683 fn filter_rewards<F>(
684 rewards: Option<Rewards>,
685 reward_type_filter: &F,
686 ) -> impl Iterator<Item = Reward> + use<'_, F>
687 where
688 F: Fn(RewardType) -> bool,
689 {
690 rewards
691 .into_iter()
692 .flatten()
693 .filter(move |reward| reward.reward_type.is_some_and(reward_type_filter))
694 }
695
696 pub async fn get_inflation_reward(
697 &self,
698 addresses: Vec<Pubkey>,
699 config: Option<RpcEpochConfig>,
700 ) -> Result<Vec<Option<RpcInflationReward>>> {
701 let config = config.unwrap_or_default();
702 let epoch_schedule = self.get_epoch_schedule();
703 let first_available_block = self.get_first_available_block().await;
704 let context_config = RpcContextConfig {
705 commitment: config.commitment,
706 min_context_slot: config.min_context_slot,
707 };
708 let epoch = match config.epoch {
709 Some(epoch) => epoch,
710 None => epoch_schedule
711 .get_epoch(self.get_slot(context_config)?)
712 .saturating_sub(1),
713 };
714
715 let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch.saturating_add(1));
717 if first_slot_in_epoch < first_available_block {
718 if self.bigtable_ledger_storage.is_some() {
719 return Err(RpcCustomError::LongTermStorageSlotSkipped {
720 slot: first_slot_in_epoch,
721 }
722 .into());
723 } else {
724 return Err(RpcCustomError::BlockCleanedUp {
725 slot: first_slot_in_epoch,
726 first_available_block,
727 }
728 .into());
729 }
730 }
731
732 let first_confirmed_block_in_epoch = *self
733 .get_blocks_with_limit(first_slot_in_epoch, 1, Some(context_config))
734 .await?
735 .first()
736 .ok_or(RpcCustomError::BlockNotAvailable {
737 slot: first_slot_in_epoch,
738 })?;
739
740 let bank = self.get_bank_with_config(context_config)?;
743
744 let Ok(Some(epoch_boundary_block)) = self
746 .get_block(
747 first_confirmed_block_in_epoch,
748 Some(RpcBlockConfig::rewards_with_commitment(config.commitment).into()),
749 )
750 .await
751 else {
752 return Err(RpcCustomError::BlockNotAvailable {
753 slot: first_confirmed_block_in_epoch,
754 }
755 .into());
756 };
757
758 if epoch_boundary_block.parent_slot >= first_slot_in_epoch {
766 return Err(RpcCustomError::SlotNotEpochBoundary {
767 slot: first_confirmed_block_in_epoch,
768 }
769 .into());
770 }
771
772 let epoch_has_partitioned_rewards = epoch_boundary_block.num_reward_partitions.is_some();
773
774 let mut reward_map: HashMap<String, (Reward, Slot)> = {
777 let addresses: Vec<String> =
778 addresses.iter().map(|pubkey| pubkey.to_string()).collect();
779 Self::filter_map_rewards(
780 epoch_boundary_block.rewards,
781 first_confirmed_block_in_epoch,
782 &addresses,
783 &|reward_type| -> bool {
784 reward_type == RewardType::Voting
785 || (!epoch_has_partitioned_rewards && reward_type == RewardType::Staking)
786 },
787 )
788 .collect()
789 };
790
791 if epoch_has_partitioned_rewards {
794 let num_partitions = epoch_boundary_block.num_reward_partitions.expect(
795 "epoch-boundary block should have num_reward_partitions for epochs with \
796 partitioned rewards enabled",
797 );
798
799 let num_partitions = usize::try_from(num_partitions)
800 .expect("num_partitions should never exceed usize::MAX");
801 let hasher = EpochRewardsHasher::new(
802 num_partitions,
803 &Hash::from_str(&epoch_boundary_block.previous_blockhash)
804 .expect("UiConfirmedBlock::previous_blockhash should be properly formed"),
805 );
806 let mut partition_index_addresses: HashMap<usize, Vec<String>> = HashMap::new();
807 for address in addresses.iter() {
808 let address_string = address.to_string();
809 if !reward_map.contains_key(&address_string) {
812 let partition_index = hasher.clone().hash_address_to_partition(address);
813 partition_index_addresses
814 .entry(partition_index)
815 .and_modify(|list| list.push(address_string.clone()))
816 .or_insert(vec![address_string]);
817 }
818 }
819
820 let block_list = self
821 .get_blocks_with_limit(
822 first_confirmed_block_in_epoch + 1,
823 num_partitions,
824 Some(context_config),
825 )
826 .await?;
827
828 for (partition_index, addresses) in partition_index_addresses.iter() {
829 let slot = *block_list.get(*partition_index).ok_or_else(|| {
830 let rewards_complete_block_height = epoch_boundary_block
834 .block_height
835 .map(|block_height| {
836 block_height
837 .saturating_add(num_partitions as u64)
838 .saturating_add(1)
839 })
840 .expect(
841 "every block after partitioned_epoch_reward_enabled should have a \
842 populated block_height",
843 );
844 RpcCustomError::EpochRewardsPeriodActive {
845 slot: bank.slot(),
846 current_block_height: bank.block_height(),
847 rewards_complete_block_height,
848 }
849 })?;
850
851 let Ok(Some(block)) = self
852 .get_block(
853 slot,
854 Some(RpcBlockConfig::rewards_with_commitment(config.commitment).into()),
855 )
856 .await
857 else {
858 return Err(RpcCustomError::BlockNotAvailable { slot }.into());
859 };
860
861 let index_reward_map = Self::filter_map_rewards(
862 block.rewards,
863 slot,
864 addresses,
865 &|reward_type| -> bool { reward_type == RewardType::Staking },
866 );
867 reward_map.extend(index_reward_map);
868 }
869 }
870
871 let rewards = addresses
872 .iter()
873 .map(|address| {
874 if let Some((reward, slot)) = reward_map.get(&address.to_string()) {
875 return Some(RpcInflationReward {
876 epoch,
877 effective_slot: *slot,
878 amount: reward.lamports.unsigned_abs(),
879 post_balance: reward.post_balance,
880 commission: reward.commission,
881 });
882 }
883 None
884 })
885 .collect();
886
887 Ok(rewards)
888 }
889
890 pub fn get_inflation_governor(
891 &self,
892 commitment: Option<CommitmentConfig>,
893 ) -> RpcInflationGovernor {
894 self.bank(commitment).inflation().into()
895 }
896
897 pub fn get_inflation_rate(&self) -> RpcInflationRate {
898 let bank = self.bank(None);
899 let epoch = bank.epoch();
900 let inflation = bank.inflation();
901 let slot_in_year = bank.slot_in_year_for_inflation();
902
903 RpcInflationRate {
904 total: inflation.total(slot_in_year),
905 validator: inflation.validator(slot_in_year),
906 foundation: inflation.foundation(slot_in_year),
907 epoch,
908 }
909 }
910
911 pub fn get_epoch_schedule(&self) -> EpochSchedule {
912 let bank = self.bank(Some(CommitmentConfig::finalized()));
915 bank.epoch_schedule().clone()
916 }
917
918 pub fn get_balance(
919 &self,
920 pubkey: &Pubkey,
921 config: RpcContextConfig,
922 ) -> Result<RpcResponse<u64>> {
923 let bank = self.get_bank_with_config(config)?;
924 Ok(new_response(&bank, bank.get_balance(pubkey)))
925 }
926
927 pub fn confirm_transaction(
928 &self,
929 signature: &Signature,
930 commitment: Option<CommitmentConfig>,
931 ) -> Result<RpcResponse<bool>> {
932 let bank = self.bank(commitment);
933 let status = bank.get_signature_status(signature);
934 match status {
935 Some(status) => Ok(new_response(&bank, status.is_ok())),
936 None => Ok(new_response(&bank, false)),
937 }
938 }
939
940 fn get_block_commitment(&self, block: Slot) -> RpcBlockCommitment<BlockCommitmentArray> {
941 let r_block_commitment = self.block_commitment_cache.read().unwrap();
942 RpcBlockCommitment {
943 commitment: r_block_commitment
944 .get_block_commitment(block)
945 .map(|block_commitment| block_commitment.commitment),
946 total_stake: r_block_commitment.total_stake(),
947 }
948 }
949
950 fn get_slot(&self, config: RpcContextConfig) -> Result<Slot> {
951 let bank = self.get_bank_with_config(config)?;
952 Ok(bank.slot())
953 }
954
955 fn get_block_height(&self, config: RpcContextConfig) -> Result<u64> {
956 let bank = self.get_bank_with_config(config)?;
957 Ok(bank.block_height())
958 }
959
960 fn get_max_retransmit_slot(&self) -> Slot {
961 self.max_slots.retransmit.load(Ordering::Relaxed)
962 }
963
964 fn get_max_shred_insert_slot(&self) -> Slot {
965 self.max_slots.shred_insert.load(Ordering::Relaxed)
966 }
967
968 fn get_slot_leader(&self, config: RpcContextConfig) -> Result<String> {
969 let bank = self.get_bank_with_config(config)?;
970 Ok(bank.collector_id().to_string())
971 }
972
973 fn get_slot_leaders(
974 &self,
975 commitment: Option<CommitmentConfig>,
976 start_slot: Slot,
977 limit: usize,
978 ) -> Result<Vec<Pubkey>> {
979 let bank = self.bank(commitment);
980
981 let (mut epoch, mut slot_index) =
982 bank.epoch_schedule().get_epoch_and_slot_index(start_slot);
983
984 let mut slot_leaders = Vec::with_capacity(limit);
985 while slot_leaders.len() < limit {
986 if let Some(leader_schedule) =
987 self.leader_schedule_cache.get_epoch_leader_schedule(epoch)
988 {
989 slot_leaders.extend(
990 leader_schedule
991 .get_slot_leaders()
992 .iter()
993 .skip(slot_index as usize)
994 .take(limit.saturating_sub(slot_leaders.len())),
995 );
996 } else {
997 return Err(Error::invalid_params(format!(
998 "Invalid slot range: leader schedule for epoch {epoch} is unavailable"
999 )));
1000 }
1001
1002 epoch += 1;
1003 slot_index = 0;
1004 }
1005
1006 Ok(slot_leaders)
1007 }
1008
1009 fn minimum_ledger_slot(&self) -> Result<Slot> {
1010 match self.blockstore.slot_meta_iterator(0) {
1011 Ok(mut metas) => match metas.next() {
1012 Some((slot, _meta)) => Ok(slot),
1013 None => Err(Error::invalid_request()),
1014 },
1015 Err(err) => {
1016 warn!("slot_meta_iterator failed: {err:?}");
1017 Err(Error::invalid_request())
1018 }
1019 }
1020 }
1021
1022 fn get_transaction_count(&self, config: RpcContextConfig) -> Result<u64> {
1023 let bank = self.get_bank_with_config(config)?;
1024 Ok(bank.transaction_count())
1025 }
1026
1027 fn get_cached_largest_accounts(
1028 &self,
1029 filter: &Option<RpcLargestAccountsFilter>,
1030 ) -> Option<(u64, Vec<RpcAccountBalance>)> {
1031 let largest_accounts_cache = self.largest_accounts_cache.read().unwrap();
1032 largest_accounts_cache.get_largest_accounts(filter)
1033 }
1034
1035 fn set_cached_largest_accounts(
1036 &self,
1037 filter: &Option<RpcLargestAccountsFilter>,
1038 slot: u64,
1039 accounts: &[RpcAccountBalance],
1040 ) {
1041 let mut largest_accounts_cache = self.largest_accounts_cache.write().unwrap();
1042 largest_accounts_cache.set_largest_accounts(filter, slot, accounts)
1043 }
1044
1045 async fn get_largest_accounts(
1046 &self,
1047 config: Option<RpcLargestAccountsConfig>,
1048 ) -> RpcCustomResult<RpcResponse<Vec<RpcAccountBalance>>> {
1049 let config = config.unwrap_or_default();
1050 let bank = self.bank(config.commitment);
1051 let sort_results = config.sort_results.unwrap_or(true);
1052
1053 if let Some((slot, accounts)) = self.get_cached_largest_accounts(&config.filter) {
1054 Ok(RpcResponse {
1055 context: RpcResponseContext::new(slot),
1056 value: accounts,
1057 })
1058 } else {
1059 let (addresses, address_filter) = if let Some(filter) = config.clone().filter {
1060 let non_circulating_supply = self
1061 .calculate_non_circulating_supply(&bank)
1062 .await
1063 .map_err(|e| RpcCustomError::ScanError {
1064 message: e.to_string(),
1065 })?;
1066 let addresses = non_circulating_supply.accounts.into_iter().collect();
1067 let address_filter = match filter {
1068 RpcLargestAccountsFilter::Circulating => AccountAddressFilter::Exclude,
1069 RpcLargestAccountsFilter::NonCirculating => AccountAddressFilter::Include,
1070 };
1071 (addresses, address_filter)
1072 } else {
1073 (HashSet::new(), AccountAddressFilter::Exclude)
1074 };
1075 let accounts = self
1076 .runtime
1077 .spawn_blocking({
1078 let bank = Arc::clone(&bank);
1079 move || {
1080 bank.get_largest_accounts(
1081 NUM_LARGEST_ACCOUNTS,
1082 &addresses,
1083 address_filter,
1084 sort_results,
1085 )
1086 }
1087 })
1088 .await
1089 .expect("Failed to spawn blocking task")
1090 .map_err(|e| RpcCustomError::ScanError {
1091 message: e.to_string(),
1092 })?
1093 .into_iter()
1094 .map(|(address, lamports)| RpcAccountBalance {
1095 address: address.to_string(),
1096 lamports,
1097 })
1098 .collect::<Vec<RpcAccountBalance>>();
1099
1100 self.set_cached_largest_accounts(&config.filter, bank.slot(), &accounts);
1101 Ok(new_response(&bank, accounts))
1102 }
1103 }
1104
1105 async fn get_supply(
1106 &self,
1107 config: Option<RpcSupplyConfig>,
1108 ) -> RpcCustomResult<RpcResponse<RpcSupply>> {
1109 let config = config.unwrap_or_default();
1110 let bank = self.bank(config.commitment);
1111 let non_circulating_supply =
1112 self.calculate_non_circulating_supply(&bank)
1113 .await
1114 .map_err(|e| RpcCustomError::ScanError {
1115 message: e.to_string(),
1116 })?;
1117 let total_supply = bank.capitalization();
1118 let non_circulating_accounts = if config.exclude_non_circulating_accounts_list {
1119 vec![]
1120 } else {
1121 non_circulating_supply
1122 .accounts
1123 .iter()
1124 .map(|pubkey| pubkey.to_string())
1125 .collect()
1126 };
1127
1128 Ok(new_response(
1129 &bank,
1130 RpcSupply {
1131 total: total_supply,
1132 circulating: total_supply - non_circulating_supply.lamports,
1133 non_circulating: non_circulating_supply.lamports,
1134 non_circulating_accounts,
1135 },
1136 ))
1137 }
1138
1139 fn get_vote_accounts(
1140 &self,
1141 config: Option<RpcGetVoteAccountsConfig>,
1142 ) -> Result<RpcVoteAccountStatus> {
1143 let config = config.unwrap_or_default();
1144
1145 let filter_by_vote_pubkey = if let Some(ref vote_pubkey) = config.vote_pubkey {
1146 Some(verify_pubkey(vote_pubkey)?)
1147 } else {
1148 None
1149 };
1150
1151 let bank = self.bank(config.commitment);
1152 let vote_accounts = bank.vote_accounts();
1153 let epoch_vote_accounts = bank
1154 .epoch_vote_accounts(bank.get_epoch_and_slot_index(bank.slot()).0)
1155 .ok_or_else(Error::invalid_request)?;
1156 let delinquent_validator_slot_distance = config
1157 .delinquent_slot_distance
1158 .unwrap_or(DELINQUENT_VALIDATOR_SLOT_DISTANCE);
1159 let (current_vote_accounts, delinquent_vote_accounts): (
1160 Vec<RpcVoteAccountInfo>,
1161 Vec<RpcVoteAccountInfo>,
1162 ) = vote_accounts
1163 .iter()
1164 .filter_map(|(vote_pubkey, (activated_stake, account))| {
1165 if let Some(filter_by_vote_pubkey) = filter_by_vote_pubkey {
1166 if *vote_pubkey != filter_by_vote_pubkey {
1167 return None;
1168 }
1169 }
1170
1171 let vote_state_view = account.vote_state_view();
1172 let last_vote = vote_state_view.last_voted_slot().unwrap_or(0);
1173 let num_epoch_credits = vote_state_view.num_epoch_credits();
1174 let epoch_credits = vote_state_view
1175 .epoch_credits_iter()
1176 .skip(
1177 num_epoch_credits
1178 .saturating_sub(MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY),
1179 )
1180 .map(Into::into)
1181 .collect();
1182
1183 Some(RpcVoteAccountInfo {
1184 vote_pubkey: vote_pubkey.to_string(),
1185 node_pubkey: vote_state_view.node_pubkey().to_string(),
1186 activated_stake: *activated_stake,
1187 commission: vote_state_view.commission(),
1188 root_slot: vote_state_view.root_slot().unwrap_or(0),
1189 epoch_credits,
1190 epoch_vote_account: epoch_vote_accounts.contains_key(vote_pubkey),
1191 last_vote,
1192 })
1193 })
1194 .partition(|vote_account_info| {
1195 if bank.slot() >= delinquent_validator_slot_distance {
1196 vote_account_info.last_vote > bank.slot() - delinquent_validator_slot_distance
1197 } else {
1198 vote_account_info.last_vote > 0
1199 }
1200 });
1201
1202 let keep_unstaked_delinquents = config.keep_unstaked_delinquents.unwrap_or_default();
1203 let delinquent_vote_accounts = if !keep_unstaked_delinquents {
1204 delinquent_vote_accounts
1205 .into_iter()
1206 .filter(|vote_account_info| vote_account_info.activated_stake > 0)
1207 .collect::<Vec<_>>()
1208 } else {
1209 delinquent_vote_accounts
1210 };
1211
1212 Ok(RpcVoteAccountStatus {
1213 current: current_vote_accounts,
1214 delinquent: delinquent_vote_accounts,
1215 })
1216 }
1217
1218 fn check_blockstore_root<T>(
1219 &self,
1220 result: &std::result::Result<T, BlockstoreError>,
1221 slot: Slot,
1222 ) -> Result<()> {
1223 if let Err(err) = result {
1224 debug!(
1225 "check_blockstore_root, slot: {:?}, max root: {:?}, err: {:?}",
1226 slot,
1227 self.blockstore.max_root(),
1228 err
1229 );
1230 if slot >= self.blockstore.max_root() {
1231 return Err(RpcCustomError::BlockNotAvailable { slot }.into());
1232 }
1233 if self.blockstore.is_skipped(slot) {
1234 return Err(RpcCustomError::SlotSkipped { slot }.into());
1235 }
1236 }
1237 Ok(())
1238 }
1239
1240 fn check_slot_cleaned_up<T>(
1241 &self,
1242 result: &std::result::Result<T, BlockstoreError>,
1243 slot: Slot,
1244 ) -> Result<()> {
1245 let first_available_block = self
1246 .blockstore
1247 .get_first_available_block()
1248 .unwrap_or_default();
1249 let err: Error = RpcCustomError::BlockCleanedUp {
1250 slot,
1251 first_available_block,
1252 }
1253 .into();
1254 if let Err(BlockstoreError::SlotCleanedUp) = result {
1255 return Err(err);
1256 }
1257 if slot < first_available_block {
1258 return Err(err);
1259 }
1260 Ok(())
1261 }
1262
1263 fn check_bigtable_result<T>(
1264 &self,
1265 result: &std::result::Result<T, solana_storage_bigtable::Error>,
1266 ) -> Result<()> {
1267 if let Err(solana_storage_bigtable::Error::BlockNotFound(slot)) = result {
1268 return Err(RpcCustomError::LongTermStorageSlotSkipped { slot: *slot }.into());
1269 }
1270 Ok(())
1271 }
1272
1273 fn check_blockstore_writes_complete(&self, slot: Slot) -> Result<()> {
1274 if slot
1275 > self
1276 .max_complete_transaction_status_slot
1277 .load(Ordering::SeqCst)
1278 {
1279 Err(RpcCustomError::BlockStatusNotAvailableYet { slot }.into())
1280 } else {
1281 Ok(())
1282 }
1283 }
1284
1285 pub async fn get_block(
1286 &self,
1287 slot: Slot,
1288 config: Option<RpcEncodingConfigWrapper<RpcBlockConfig>>,
1289 ) -> Result<Option<UiConfirmedBlock>> {
1290 self.check_if_transaction_history_enabled()?;
1291
1292 let config = config
1293 .map(|config| config.convert_to_current())
1294 .unwrap_or_default();
1295 let encoding = config.encoding.unwrap_or(UiTransactionEncoding::Json);
1296 let encoding_options = BlockEncodingOptions {
1297 transaction_details: config.transaction_details.unwrap_or_default(),
1298 show_rewards: config.rewards.unwrap_or(true),
1299 max_supported_transaction_version: config.max_supported_transaction_version,
1300 };
1301 let commitment = config.commitment.unwrap_or_default();
1302 check_is_at_least_confirmed(commitment)?;
1303
1304 if slot
1306 <= self
1307 .block_commitment_cache
1308 .read()
1309 .unwrap()
1310 .highest_super_majority_root()
1311 {
1312 self.check_blockstore_writes_complete(slot)?;
1313 let result = self
1314 .runtime
1315 .spawn_blocking({
1316 let blockstore = Arc::clone(&self.blockstore);
1317 move || blockstore.get_rooted_block(slot, true)
1318 })
1319 .await
1320 .expect("Failed to spawn blocking task");
1321 self.check_blockstore_root(&result, slot)?;
1322 let encode_block = |confirmed_block: ConfirmedBlock| async move {
1323 let mut encoded_block = self
1324 .runtime
1325 .spawn_blocking(move || {
1326 confirmed_block
1327 .encode_with_options(encoding, encoding_options)
1328 .map_err(RpcCustomError::from)
1329 })
1330 .await
1331 .expect("Failed to spawn blocking task")?;
1332 if slot == 0 {
1333 encoded_block.block_time = Some(self.genesis_creation_time());
1334 encoded_block.block_height = Some(0);
1335 }
1336 Ok::<UiConfirmedBlock, Error>(encoded_block)
1337 };
1338 if result.is_err() {
1339 if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
1340 let bigtable_result = bigtable_ledger_storage.get_confirmed_block(slot).await;
1341 self.check_bigtable_result(&bigtable_result)?;
1342 let encoded_block_future: OptionFuture<_> =
1343 bigtable_result.ok().map(encode_block).into();
1344 return encoded_block_future.await.transpose();
1345 }
1346 }
1347 self.check_slot_cleaned_up(&result, slot)?;
1348 let encoded_block_future: OptionFuture<_> = result
1349 .ok()
1350 .map(ConfirmedBlock::from)
1351 .map(encode_block)
1352 .into();
1353 return encoded_block_future.await.transpose();
1354 } else if commitment.is_confirmed() {
1355 let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
1357 if confirmed_bank.status_cache_ancestors().contains(&slot) {
1358 self.check_blockstore_writes_complete(slot)?;
1359 let result = self
1360 .runtime
1361 .spawn_blocking({
1362 let blockstore = Arc::clone(&self.blockstore);
1363 move || blockstore.get_complete_block(slot, true)
1364 })
1365 .await
1366 .expect("Failed to spawn blocking task");
1367 let encoded_block_future: OptionFuture<_> = result
1368 .ok()
1369 .map(ConfirmedBlock::from)
1370 .map(|mut confirmed_block| async move {
1371 if confirmed_block.block_time.is_none()
1372 || confirmed_block.block_height.is_none()
1373 {
1374 let r_bank_forks = self.bank_forks.read().unwrap();
1375 if let Some(bank) = r_bank_forks.get(slot) {
1376 if confirmed_block.block_time.is_none() {
1377 confirmed_block.block_time = Some(bank.clock().unix_timestamp);
1378 }
1379 if confirmed_block.block_height.is_none() {
1380 confirmed_block.block_height = Some(bank.block_height());
1381 }
1382 }
1383 }
1384 let encoded_block = self
1385 .runtime
1386 .spawn_blocking(move || {
1387 confirmed_block
1388 .encode_with_options(encoding, encoding_options)
1389 .map_err(RpcCustomError::from)
1390 })
1391 .await
1392 .expect("Failed to spawn blocking task")?;
1393
1394 Ok(encoded_block)
1395 })
1396 .into();
1397 return encoded_block_future.await.transpose();
1398 }
1399 }
1400
1401 Err(RpcCustomError::BlockNotAvailable { slot }.into())
1402 }
1403
1404 pub async fn get_blocks(
1405 &self,
1406 start_slot: Slot,
1407 end_slot: Option<Slot>,
1408 config: Option<RpcContextConfig>,
1409 ) -> Result<Vec<Slot>> {
1410 let config = config.unwrap_or_default();
1411 let commitment = config.commitment.unwrap_or_default();
1412 check_is_at_least_confirmed(commitment)?;
1413
1414 let highest_super_majority_root = self
1415 .block_commitment_cache
1416 .read()
1417 .unwrap()
1418 .highest_super_majority_root();
1419
1420 let min_context_slot = config.min_context_slot.unwrap_or_default();
1421 if commitment.is_finalized() && highest_super_majority_root < min_context_slot {
1422 return Err(RpcCustomError::MinContextSlotNotReached {
1423 context_slot: highest_super_majority_root,
1424 }
1425 .into());
1426 }
1427
1428 let end_slot = min(
1429 end_slot.unwrap_or_else(|| start_slot.saturating_add(MAX_GET_CONFIRMED_BLOCKS_RANGE)),
1430 if commitment.is_finalized() {
1431 highest_super_majority_root
1432 } else {
1433 self.get_bank_with_config(config)?.slot()
1434 },
1435 );
1436 if end_slot < start_slot {
1437 return Ok(vec![]);
1438 }
1439 if end_slot - start_slot > MAX_GET_CONFIRMED_BLOCKS_RANGE {
1440 return Err(Error::invalid_params(format!(
1441 "Slot range too large; max {MAX_GET_CONFIRMED_BLOCKS_RANGE}"
1442 )));
1443 }
1444
1445 let lowest_blockstore_slot = self
1446 .blockstore
1447 .get_first_available_block()
1448 .unwrap_or_default();
1449 if start_slot < lowest_blockstore_slot {
1450 if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
1454 return bigtable_ledger_storage
1455 .get_confirmed_blocks(start_slot, (end_slot - start_slot) as usize + 1) .await
1457 .map(|mut bigtable_blocks| {
1458 bigtable_blocks.retain(|&slot| slot <= end_slot);
1459 bigtable_blocks
1460 })
1461 .map_err(|_| {
1462 Error::invalid_params(
1463 "BigTable query failed (maybe timeout due to too large range?)"
1464 .to_string(),
1465 )
1466 });
1467 }
1468 }
1469
1470 let mut blocks: Vec<_> = self
1472 .blockstore
1473 .rooted_slot_iterator(max(start_slot, lowest_blockstore_slot))
1474 .map_err(|_| Error::internal_error())?
1475 .filter(|&slot| slot <= end_slot && slot <= highest_super_majority_root)
1476 .collect();
1477 let last_element = blocks
1478 .last()
1479 .cloned()
1480 .unwrap_or_else(|| start_slot.saturating_sub(1));
1481
1482 if commitment.is_confirmed() {
1484 let confirmed_bank = self.get_bank_with_config(config)?;
1485 if last_element < end_slot {
1486 let mut confirmed_blocks = confirmed_bank
1487 .status_cache_ancestors()
1488 .into_iter()
1489 .filter(|&slot| slot <= end_slot && slot > last_element)
1490 .collect();
1491 blocks.append(&mut confirmed_blocks);
1492 }
1493 }
1494
1495 Ok(blocks)
1496 }
1497
1498 pub async fn get_blocks_with_limit(
1499 &self,
1500 start_slot: Slot,
1501 limit: usize,
1502 config: Option<RpcContextConfig>,
1503 ) -> Result<Vec<Slot>> {
1504 let config = config.unwrap_or_default();
1505 let commitment = config.commitment.unwrap_or_default();
1506 check_is_at_least_confirmed(commitment)?;
1507
1508 if limit > MAX_GET_CONFIRMED_BLOCKS_RANGE as usize {
1509 return Err(Error::invalid_params(format!(
1510 "Limit too large; max {MAX_GET_CONFIRMED_BLOCKS_RANGE}"
1511 )));
1512 }
1513
1514 let lowest_blockstore_slot = self
1515 .blockstore
1516 .get_first_available_block()
1517 .unwrap_or_default();
1518
1519 if start_slot < lowest_blockstore_slot {
1520 if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
1524 return Ok(bigtable_ledger_storage
1525 .get_confirmed_blocks(start_slot, limit)
1526 .await
1527 .unwrap_or_default());
1528 }
1529 }
1530
1531 let highest_super_majority_root = self
1532 .block_commitment_cache
1533 .read()
1534 .unwrap()
1535 .highest_super_majority_root();
1536
1537 if commitment.is_finalized() {
1538 let min_context_slot = config.min_context_slot.unwrap_or_default();
1539 if highest_super_majority_root < min_context_slot {
1540 return Err(RpcCustomError::MinContextSlotNotReached {
1541 context_slot: highest_super_majority_root,
1542 }
1543 .into());
1544 }
1545 }
1546
1547 let mut blocks: Vec<_> = self
1549 .blockstore
1550 .rooted_slot_iterator(max(start_slot, lowest_blockstore_slot))
1551 .map_err(|_| Error::internal_error())?
1552 .take(limit)
1553 .filter(|&slot| slot <= highest_super_majority_root)
1554 .collect();
1555
1556 if commitment.is_confirmed() {
1558 let confirmed_bank = self.get_bank_with_config(config)?;
1559 if blocks.len() < limit {
1560 let last_element = blocks
1561 .last()
1562 .cloned()
1563 .unwrap_or_else(|| start_slot.saturating_sub(1));
1564 let mut confirmed_blocks = confirmed_bank
1565 .status_cache_ancestors()
1566 .into_iter()
1567 .filter(|&slot| slot > last_element)
1568 .collect();
1569 blocks.append(&mut confirmed_blocks);
1570 blocks.truncate(limit);
1571 }
1572 }
1573
1574 Ok(blocks)
1575 }
1576
1577 pub async fn get_block_time(&self, slot: Slot) -> Result<Option<UnixTimestamp>> {
1578 if slot == 0 {
1579 return Ok(Some(self.genesis_creation_time()));
1580 }
1581 if slot
1582 <= self
1583 .block_commitment_cache
1584 .read()
1585 .unwrap()
1586 .highest_super_majority_root()
1587 {
1588 let result = self.blockstore.get_rooted_block_time(slot);
1589 self.check_blockstore_root(&result, slot)?;
1590 if result.is_err() {
1591 if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
1592 let bigtable_result = bigtable_ledger_storage.get_confirmed_block(slot).await;
1593 self.check_bigtable_result(&bigtable_result)?;
1594 return Ok(bigtable_result
1595 .ok()
1596 .and_then(|confirmed_block| confirmed_block.block_time));
1597 }
1598 }
1599 self.check_slot_cleaned_up(&result, slot)?;
1600 Ok(result.ok())
1601 } else {
1602 let r_bank_forks = self.bank_forks.read().unwrap();
1603 if let Some(bank) = r_bank_forks.get(slot) {
1604 Ok(Some(bank.clock().unix_timestamp))
1605 } else {
1606 Err(RpcCustomError::BlockNotAvailable { slot }.into())
1607 }
1608 }
1609 }
1610
1611 pub fn get_signature_confirmation_status(
1612 &self,
1613 signature: Signature,
1614 commitment: Option<CommitmentConfig>,
1615 ) -> Result<Option<RpcSignatureConfirmation>> {
1616 let bank = self.bank(commitment);
1617 Ok(self
1618 .get_transaction_status(signature, &bank)
1619 .map(|transaction_status| {
1620 let confirmations = transaction_status
1621 .confirmations
1622 .unwrap_or(MAX_LOCKOUT_HISTORY + 1);
1623 RpcSignatureConfirmation {
1624 confirmations,
1625 status: transaction_status.status,
1626 }
1627 }))
1628 }
1629
1630 pub fn get_signature_status(
1631 &self,
1632 signature: Signature,
1633 commitment: Option<CommitmentConfig>,
1634 ) -> Result<Option<transaction::Result<()>>> {
1635 let bank = self.bank(commitment);
1636 Ok(bank
1637 .get_signature_status_slot(&signature)
1638 .map(|(_, status)| status))
1639 }
1640
1641 pub async fn get_signature_statuses(
1642 &self,
1643 signatures: Vec<Signature>,
1644 config: Option<RpcSignatureStatusConfig>,
1645 ) -> Result<RpcResponse<Vec<Option<TransactionStatus>>>> {
1646 let search_transaction_history = config
1647 .map(|x| x.search_transaction_history)
1648 .unwrap_or(false);
1649 if search_transaction_history {
1650 self.check_if_transaction_history_enabled()?;
1651 }
1652
1653 let bank = self.bank(Some(CommitmentConfig::processed()));
1654 let mut statuses: Vec<Option<TransactionStatus>> = vec![];
1655
1656 for signature in signatures {
1657 let status = if let Some(status) = self.get_transaction_status(signature, &bank) {
1658 Some(status)
1659 } else if search_transaction_history {
1660 if let Some(status) = self
1661 .blockstore
1662 .get_rooted_transaction_status(signature)
1663 .map_err(|_| Error::internal_error())?
1664 .filter(|(slot, _status_meta)| {
1665 slot <= &self
1666 .block_commitment_cache
1667 .read()
1668 .unwrap()
1669 .highest_super_majority_root()
1670 })
1671 .map(|(slot, status_meta)| {
1672 let err = status_meta.status.clone().err();
1673 TransactionStatus {
1674 slot,
1675 status: status_meta.status,
1676 confirmations: None,
1677 err,
1678 confirmation_status: Some(TransactionConfirmationStatus::Finalized),
1679 }
1680 })
1681 {
1682 Some(status)
1683 } else if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
1684 bigtable_ledger_storage
1685 .get_signature_status(&signature)
1686 .await
1687 .map(Some)
1688 .unwrap_or(None)
1689 } else {
1690 None
1691 }
1692 } else {
1693 None
1694 };
1695 statuses.push(status);
1696 }
1697 Ok(new_response(&bank, statuses))
1698 }
1699
1700 fn get_transaction_status(
1701 &self,
1702 signature: Signature,
1703 bank: &Bank,
1704 ) -> Option<TransactionStatus> {
1705 let (slot, status) = bank.get_signature_status_slot(&signature)?;
1706
1707 let optimistically_confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
1708 let optimistically_confirmed =
1709 optimistically_confirmed_bank.get_signature_status_slot(&signature);
1710
1711 let r_block_commitment_cache = self.block_commitment_cache.read().unwrap();
1712 let confirmations = if r_block_commitment_cache.root() >= slot
1713 && is_finalized(&r_block_commitment_cache, bank, &self.blockstore, slot)
1714 {
1715 None
1716 } else {
1717 r_block_commitment_cache
1718 .get_confirmation_count(slot)
1719 .or(Some(0))
1720 };
1721 let err = status.clone().err();
1722 Some(TransactionStatus {
1723 slot,
1724 status,
1725 confirmations,
1726 err,
1727 confirmation_status: if confirmations.is_none() {
1728 Some(TransactionConfirmationStatus::Finalized)
1729 } else if optimistically_confirmed.is_some() {
1730 Some(TransactionConfirmationStatus::Confirmed)
1731 } else {
1732 Some(TransactionConfirmationStatus::Processed)
1733 },
1734 })
1735 }
1736
1737 pub async fn get_transaction(
1738 &self,
1739 signature: Signature,
1740 config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>,
1741 ) -> Result<Option<EncodedConfirmedTransactionWithStatusMeta>> {
1742 self.check_if_transaction_history_enabled()?;
1743
1744 let config = config
1745 .map(|config| config.convert_to_current())
1746 .unwrap_or_default();
1747 let encoding = config.encoding.unwrap_or(UiTransactionEncoding::Json);
1748 let max_supported_transaction_version = config.max_supported_transaction_version;
1749 let commitment = config.commitment.unwrap_or_default();
1750 check_is_at_least_confirmed(commitment)?;
1751
1752 let confirmed_bank = self.bank(Some(CommitmentConfig::confirmed()));
1753 let confirmed_transaction = self
1754 .runtime
1755 .spawn_blocking({
1756 let blockstore = Arc::clone(&self.blockstore);
1757 let confirmed_bank = Arc::clone(&confirmed_bank);
1758 move || {
1759 if commitment.is_confirmed() {
1760 let highest_confirmed_slot = confirmed_bank.slot();
1761 blockstore.get_complete_transaction(signature, highest_confirmed_slot)
1762 } else {
1763 blockstore.get_rooted_transaction(signature)
1764 }
1765 }
1766 })
1767 .await
1768 .expect("Failed to spawn blocking task");
1769
1770 let encode_transaction =
1771 |confirmed_tx_with_meta: ConfirmedTransactionWithStatusMeta| -> Result<EncodedConfirmedTransactionWithStatusMeta> {
1772 Ok(confirmed_tx_with_meta.encode(encoding, max_supported_transaction_version).map_err(RpcCustomError::from)?)
1773 };
1774
1775 match confirmed_transaction.unwrap_or(None) {
1776 Some(mut confirmed_transaction) => {
1777 if commitment.is_confirmed()
1778 && confirmed_bank .status_cache_ancestors()
1780 .contains(&confirmed_transaction.slot)
1781 {
1782 if confirmed_transaction.block_time.is_none() {
1783 let r_bank_forks = self.bank_forks.read().unwrap();
1784 confirmed_transaction.block_time = r_bank_forks
1785 .get(confirmed_transaction.slot)
1786 .map(|bank| bank.clock().unix_timestamp);
1787 }
1788 return Ok(Some(encode_transaction(confirmed_transaction)?));
1789 }
1790
1791 if confirmed_transaction.slot
1792 <= self
1793 .block_commitment_cache
1794 .read()
1795 .unwrap()
1796 .highest_super_majority_root()
1797 {
1798 return Ok(Some(encode_transaction(confirmed_transaction)?));
1799 }
1800 }
1801 None => {
1802 if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
1803 return bigtable_ledger_storage
1804 .get_confirmed_transaction(&signature)
1805 .await
1806 .unwrap_or(None)
1807 .map(encode_transaction)
1808 .transpose();
1809 }
1810 }
1811 }
1812
1813 Ok(None)
1814 }
1815
1816 pub async fn get_signatures_for_address(
1817 &self,
1818 address: Pubkey,
1819 before: Option<Signature>,
1820 until: Option<Signature>,
1821 mut limit: usize,
1822 config: RpcContextConfig,
1823 ) -> Result<Vec<RpcConfirmedTransactionStatusWithSignature>> {
1824 self.check_if_transaction_history_enabled()?;
1825
1826 let commitment = config.commitment.unwrap_or_default();
1827 check_is_at_least_confirmed(commitment)?;
1828
1829 let highest_super_majority_root = self
1830 .block_commitment_cache
1831 .read()
1832 .unwrap()
1833 .highest_super_majority_root();
1834 let highest_slot = if commitment.is_confirmed() {
1835 let confirmed_bank = self.get_bank_with_config(config)?;
1836 confirmed_bank.slot()
1837 } else {
1838 let min_context_slot = config.min_context_slot.unwrap_or_default();
1839 if highest_super_majority_root < min_context_slot {
1840 return Err(RpcCustomError::MinContextSlotNotReached {
1841 context_slot: highest_super_majority_root,
1842 }
1843 .into());
1844 }
1845 highest_super_majority_root
1846 };
1847
1848 let SignatureInfosForAddress {
1849 infos: mut results,
1850 found_before,
1851 } = self
1852 .blockstore
1853 .get_confirmed_signatures_for_address2(address, highest_slot, before, until, limit)
1854 .map_err(|err| Error::invalid_params(format!("{err}")))?;
1855
1856 let map_results = |results: Vec<ConfirmedTransactionStatusWithSignature>| {
1857 results
1858 .into_iter()
1859 .map(|x| {
1860 let mut item: RpcConfirmedTransactionStatusWithSignature = x.into();
1861 if item.slot <= highest_super_majority_root {
1862 item.confirmation_status = Some(TransactionConfirmationStatus::Finalized);
1863 } else {
1864 item.confirmation_status = Some(TransactionConfirmationStatus::Confirmed);
1865 if item.block_time.is_none() {
1866 let r_bank_forks = self.bank_forks.read().unwrap();
1867 item.block_time = r_bank_forks
1868 .get(item.slot)
1869 .map(|bank| bank.clock().unix_timestamp);
1870 }
1871 }
1872 item
1873 })
1874 .collect()
1875 };
1876
1877 if results.len() < limit {
1878 if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
1879 let mut bigtable_before = before;
1880 if !results.is_empty() {
1881 limit -= results.len();
1882 bigtable_before = results.last().map(|x| x.signature);
1883 }
1884
1885 if found_before && bigtable_before.is_some() {
1889 match bigtable_ledger_storage
1890 .get_signature_status(&bigtable_before.unwrap())
1891 .await
1892 {
1893 Err(StorageError::SignatureNotFound) => {
1894 bigtable_before = None;
1895 }
1896 Err(err) => {
1897 warn!("Failed to query Bigtable: {err:?}");
1898 return Err(RpcCustomError::LongTermStorageUnreachable.into());
1899 }
1900 Ok(_) => {}
1901 }
1902 }
1903
1904 let bigtable_results = bigtable_ledger_storage
1905 .get_confirmed_signatures_for_address(
1906 &address,
1907 bigtable_before.as_ref(),
1908 until.as_ref(),
1909 limit,
1910 )
1911 .await;
1912 match bigtable_results {
1913 Ok(bigtable_results) => {
1914 let results_set: HashSet<_> =
1915 results.iter().map(|result| result.signature).collect();
1916 for (bigtable_result, _) in bigtable_results {
1917 if before != Some(bigtable_result.signature)
1920 && !results_set.contains(&bigtable_result.signature)
1922 {
1923 results.push(bigtable_result);
1924 }
1925 }
1926 }
1927 Err(StorageError::SignatureNotFound) => {}
1928 Err(err) => {
1929 warn!("Failed to query Bigtable: {err:?}");
1930 return Err(RpcCustomError::LongTermStorageUnreachable.into());
1931 }
1932 }
1933 }
1934 }
1935
1936 Ok(map_results(results))
1937 }
1938
1939 pub async fn get_first_available_block(&self) -> Slot {
1940 let slot = self
1941 .blockstore
1942 .get_first_available_block()
1943 .unwrap_or_default();
1944
1945 if let Some(bigtable_ledger_storage) = &self.bigtable_ledger_storage {
1946 let bigtable_slot = bigtable_ledger_storage
1947 .get_first_available_block()
1948 .await
1949 .unwrap_or(None)
1950 .unwrap_or(slot);
1951
1952 if bigtable_slot < slot {
1953 return bigtable_slot;
1954 }
1955 }
1956 slot
1957 }
1958
1959 pub fn get_token_account_balance(
1960 &self,
1961 pubkey: &Pubkey,
1962 commitment: Option<CommitmentConfig>,
1963 ) -> Result<RpcResponse<UiTokenAmount>> {
1964 let bank = self.bank(commitment);
1965 let account = bank.get_account(pubkey).ok_or_else(|| {
1966 Error::invalid_params("Invalid param: could not find account".to_string())
1967 })?;
1968
1969 if !is_known_spl_token_id(account.owner()) {
1970 return Err(Error::invalid_params(
1971 "Invalid param: not a Token account".to_string(),
1972 ));
1973 }
1974 let token_account = StateWithExtensions::<TokenAccount>::unpack(account.data())
1975 .map_err(|_| Error::invalid_params("Invalid param: not a Token account".to_string()))?;
1976 let mint = &Pubkey::from_str(&token_account.base.mint.to_string())
1977 .expect("Token account mint should be convertible to Pubkey");
1978 let (_, data) = get_mint_owner_and_additional_data(&bank, mint)?;
1979 let balance = token_amount_to_ui_amount_v3(token_account.base.amount, &data);
1980 Ok(new_response(&bank, balance))
1981 }
1982
1983 pub fn get_token_supply(
1984 &self,
1985 mint: &Pubkey,
1986 commitment: Option<CommitmentConfig>,
1987 ) -> Result<RpcResponse<UiTokenAmount>> {
1988 let bank = self.bank(commitment);
1989 let mint_account = bank.get_account(mint).ok_or_else(|| {
1990 Error::invalid_params("Invalid param: could not find account".to_string())
1991 })?;
1992 if !is_known_spl_token_id(mint_account.owner()) {
1993 return Err(Error::invalid_params(
1994 "Invalid param: not a Token mint".to_string(),
1995 ));
1996 }
1997 let mint = StateWithExtensions::<Mint>::unpack(mint_account.data()).map_err(|_| {
1998 Error::invalid_params("Invalid param: mint could not be unpacked".to_string())
1999 })?;
2000
2001 let interest_bearing_config = mint
2002 .get_extension::<InterestBearingConfig>()
2003 .map(|x| (*x, bank.clock().unix_timestamp))
2004 .ok();
2005
2006 let scaled_ui_amount_config = mint
2007 .get_extension::<ScaledUiAmountConfig>()
2008 .map(|x| (*x, bank.clock().unix_timestamp))
2009 .ok();
2010
2011 let supply = token_amount_to_ui_amount_v3(
2012 mint.base.supply,
2013 &SplTokenAdditionalDataV2 {
2014 decimals: mint.base.decimals,
2015 interest_bearing_config,
2016 scaled_ui_amount_config,
2017 },
2018 );
2019 Ok(new_response(&bank, supply))
2020 }
2021
2022 pub async fn get_token_largest_accounts(
2023 &self,
2024 mint: Pubkey,
2025 commitment: Option<CommitmentConfig>,
2026 ) -> Result<RpcResponse<Vec<RpcTokenAccountBalance>>> {
2027 let bank = self.bank(commitment);
2028 let (mint_owner, data) = get_mint_owner_and_additional_data(&bank, &mint)?;
2029 if !is_known_spl_token_id(&mint_owner) {
2030 return Err(Error::invalid_params(
2031 "Invalid param: not a Token mint".to_string(),
2032 ));
2033 }
2034
2035 let mut token_balances =
2036 BinaryHeap::<Reverse<(u64, Pubkey)>>::with_capacity(NUM_LARGEST_ACCOUNTS);
2037 for (address, account) in self
2038 .get_filtered_spl_token_accounts_by_mint(
2039 Arc::clone(&bank),
2040 mint_owner,
2041 mint,
2042 vec![],
2043 true,
2044 )
2045 .await?
2046 {
2047 let amount = StateWithExtensions::<TokenAccount>::unpack(account.data())
2048 .map(|account| account.base.amount)
2049 .unwrap_or(0);
2050
2051 let new_entry = (amount, address);
2052 if token_balances.len() >= NUM_LARGEST_ACCOUNTS {
2053 let Reverse(entry) = token_balances
2054 .peek()
2055 .expect("BinaryHeap::peek should succeed when len > 0");
2056 if *entry >= new_entry {
2057 continue;
2058 }
2059 token_balances.pop();
2060 }
2061 token_balances.push(Reverse(new_entry));
2062 }
2063
2064 let token_balances = token_balances
2065 .into_sorted_vec()
2066 .into_iter()
2067 .map(|Reverse((amount, address))| {
2068 Ok(RpcTokenAccountBalance {
2069 address: address.to_string(),
2070 amount: token_amount_to_ui_amount_v3(amount, &data),
2071 })
2072 })
2073 .collect::<Result<Vec<_>>>()?;
2074
2075 Ok(new_response(&bank, token_balances))
2076 }
2077
2078 pub async fn get_token_accounts_by_owner(
2079 &self,
2080 owner: Pubkey,
2081 token_account_filter: TokenAccountsFilter,
2082 config: Option<RpcAccountInfoConfig>,
2083 sort_results: bool,
2084 ) -> Result<RpcResponse<Vec<RpcKeyedAccount>>> {
2085 let RpcAccountInfoConfig {
2086 encoding,
2087 data_slice: data_slice_config,
2088 commitment,
2089 min_context_slot,
2090 } = config.unwrap_or_default();
2091 let bank = self.get_bank_with_config(RpcContextConfig {
2092 commitment,
2093 min_context_slot,
2094 })?;
2095 let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
2096 let (token_program_id, mint) = get_token_program_id_and_mint(&bank, token_account_filter)?;
2097
2098 let mut filters = vec![];
2099 if let Some(mint) = mint {
2100 filters.push(RpcFilterType::Memcmp(Memcmp::new_raw_bytes(
2102 0,
2103 mint.to_bytes().into(),
2104 )));
2105 }
2106
2107 let keyed_accounts = self
2108 .get_filtered_spl_token_accounts_by_owner(
2109 Arc::clone(&bank),
2110 token_program_id,
2111 owner,
2112 filters,
2113 sort_results,
2114 )
2115 .await?;
2116 let accounts = if encoding == UiAccountEncoding::JsonParsed {
2117 get_parsed_token_accounts(bank.clone(), keyed_accounts.into_iter()).collect()
2118 } else {
2119 keyed_accounts
2120 .into_iter()
2121 .map(|(pubkey, account)| {
2122 Ok(RpcKeyedAccount {
2123 pubkey: pubkey.to_string(),
2124 account: encode_account(&account, &pubkey, encoding, data_slice_config)?,
2125 })
2126 })
2127 .collect::<Result<Vec<_>>>()?
2128 };
2129 Ok(new_response(&bank, accounts))
2130 }
2131
2132 pub async fn get_token_accounts_by_delegate(
2133 &self,
2134 delegate: Pubkey,
2135 token_account_filter: TokenAccountsFilter,
2136 config: Option<RpcAccountInfoConfig>,
2137 sort_results: bool,
2138 ) -> Result<RpcResponse<Vec<RpcKeyedAccount>>> {
2139 let RpcAccountInfoConfig {
2140 encoding,
2141 data_slice: data_slice_config,
2142 commitment,
2143 min_context_slot,
2144 } = config.unwrap_or_default();
2145 let bank = self.get_bank_with_config(RpcContextConfig {
2146 commitment,
2147 min_context_slot,
2148 })?;
2149 let encoding = encoding.unwrap_or(UiAccountEncoding::Binary);
2150 let (token_program_id, mint) = get_token_program_id_and_mint(&bank, token_account_filter)?;
2151
2152 let mut filters = vec![
2153 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(
2155 72,
2156 bincode::serialize(&1u32).unwrap(),
2157 )),
2158 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(76, delegate.to_bytes().into())),
2160 ];
2161 let keyed_accounts = if let Some(mint) = mint {
2163 self.get_filtered_spl_token_accounts_by_mint(
2164 Arc::clone(&bank),
2165 token_program_id,
2166 mint,
2167 filters,
2168 sort_results,
2169 )
2170 .await?
2171 } else {
2172 filters.push(RpcFilterType::TokenAccountState);
2174 self.get_filtered_program_accounts(
2175 Arc::clone(&bank),
2176 token_program_id,
2177 filters,
2178 sort_results,
2179 )
2180 .await?
2181 };
2182 let accounts = if encoding == UiAccountEncoding::JsonParsed {
2183 get_parsed_token_accounts(bank.clone(), keyed_accounts.into_iter()).collect()
2184 } else {
2185 keyed_accounts
2186 .into_iter()
2187 .map(|(pubkey, account)| {
2188 Ok(RpcKeyedAccount {
2189 pubkey: pubkey.to_string(),
2190 account: encode_account(&account, &pubkey, encoding, data_slice_config)?,
2191 })
2192 })
2193 .collect::<Result<Vec<_>>>()?
2194 };
2195 Ok(new_response(&bank, accounts))
2196 }
2197
2198 async fn get_filtered_program_accounts(
2200 &self,
2201 bank: Arc<Bank>,
2202 program_id: Pubkey,
2203 mut filters: Vec<RpcFilterType>,
2204 sort_results: bool,
2205 ) -> RpcCustomResult<Vec<(Pubkey, AccountSharedData)>> {
2206 optimize_filters(&mut filters);
2207 if self
2208 .config
2209 .account_indexes
2210 .contains(&AccountIndex::ProgramId)
2211 {
2212 if !self.config.account_indexes.include_key(&program_id) {
2213 return Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
2214 index_key: program_id.to_string(),
2215 });
2216 }
2217 self.get_filtered_indexed_accounts(
2218 &bank,
2219 &IndexKey::ProgramId(program_id),
2220 &program_id,
2221 filters,
2222 sort_results,
2223 )
2224 .await
2225 .map_err(|e| RpcCustomError::ScanError {
2226 message: e.to_string(),
2227 })
2228 } else {
2229 let scan_order = if sort_results {
2231 ScanOrder::Sorted
2232 } else {
2233 ScanOrder::Unsorted
2234 };
2235 self.runtime
2236 .spawn_blocking(move || {
2237 bank.get_filtered_program_accounts(
2238 &program_id,
2239 |account: &AccountSharedData| {
2240 filters
2241 .iter()
2242 .all(|filter_type| filter_allows(filter_type, account))
2243 },
2244 &ScanConfig::new(scan_order),
2245 )
2246 .map_err(|e| RpcCustomError::ScanError {
2247 message: e.to_string(),
2248 })
2249 })
2250 .await
2251 .expect("Failed to spawn blocking task")
2252 }
2253 }
2254
2255 async fn get_filtered_spl_token_accounts_by_owner(
2257 &self,
2258 bank: Arc<Bank>,
2259 program_id: Pubkey,
2260 owner_key: Pubkey,
2261 mut filters: Vec<RpcFilterType>,
2262 sort_results: bool,
2263 ) -> RpcCustomResult<Vec<(Pubkey, AccountSharedData)>> {
2264 filters.push(RpcFilterType::TokenAccountState);
2271 filters.push(RpcFilterType::Memcmp(Memcmp::new_raw_bytes(
2273 SPL_TOKEN_ACCOUNT_OWNER_OFFSET,
2274 owner_key.to_bytes().into(),
2275 )));
2276
2277 if self
2278 .config
2279 .account_indexes
2280 .contains(&AccountIndex::SplTokenOwner)
2281 {
2282 if !self.config.account_indexes.include_key(&owner_key) {
2283 return Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
2284 index_key: owner_key.to_string(),
2285 });
2286 }
2287 self.get_filtered_indexed_accounts(
2288 &bank,
2289 &IndexKey::SplTokenOwner(owner_key),
2290 &program_id,
2291 filters,
2292 sort_results,
2293 )
2294 .await
2295 .map_err(|e| RpcCustomError::ScanError {
2296 message: e.to_string(),
2297 })
2298 } else {
2299 self.get_filtered_program_accounts(bank, program_id, filters, sort_results)
2300 .await
2301 }
2302 }
2303
2304 async fn get_filtered_spl_token_accounts_by_mint(
2306 &self,
2307 bank: Arc<Bank>,
2308 program_id: Pubkey,
2309 mint_key: Pubkey,
2310 mut filters: Vec<RpcFilterType>,
2311 sort_results: bool,
2312 ) -> RpcCustomResult<Vec<(Pubkey, AccountSharedData)>> {
2313 filters.push(RpcFilterType::TokenAccountState);
2320 filters.push(RpcFilterType::Memcmp(Memcmp::new_raw_bytes(
2322 SPL_TOKEN_ACCOUNT_MINT_OFFSET,
2323 mint_key.to_bytes().into(),
2324 )));
2325 if self
2326 .config
2327 .account_indexes
2328 .contains(&AccountIndex::SplTokenMint)
2329 {
2330 if !self.config.account_indexes.include_key(&mint_key) {
2331 return Err(RpcCustomError::KeyExcludedFromSecondaryIndex {
2332 index_key: mint_key.to_string(),
2333 });
2334 }
2335 self.get_filtered_indexed_accounts(
2336 &bank,
2337 &IndexKey::SplTokenMint(mint_key),
2338 &program_id,
2339 filters,
2340 sort_results,
2341 )
2342 .await
2343 .map_err(|e| RpcCustomError::ScanError {
2344 message: e.to_string(),
2345 })
2346 } else {
2347 self.get_filtered_program_accounts(bank, program_id, filters, sort_results)
2348 .await
2349 }
2350 }
2351
2352 fn get_latest_blockhash(&self, config: RpcContextConfig) -> Result<RpcResponse<RpcBlockhash>> {
2353 let bank = self.get_bank_with_config(config)?;
2354 let blockhash = bank.last_blockhash();
2355 let last_valid_block_height = bank
2356 .get_blockhash_last_valid_block_height(&blockhash)
2357 .expect("bank blockhash queue should contain blockhash");
2358 Ok(new_response(
2359 &bank,
2360 RpcBlockhash {
2361 blockhash: blockhash.to_string(),
2362 last_valid_block_height,
2363 },
2364 ))
2365 }
2366
2367 fn is_blockhash_valid(
2368 &self,
2369 blockhash: &Hash,
2370 config: RpcContextConfig,
2371 ) -> Result<RpcResponse<bool>> {
2372 let bank = self.get_bank_with_config(config)?;
2373 let is_valid = bank.is_blockhash_valid(blockhash);
2374 Ok(new_response(&bank, is_valid))
2375 }
2376
2377 fn get_stake_minimum_delegation(&self, config: RpcContextConfig) -> Result<RpcResponse<u64>> {
2378 let bank = self.get_bank_with_config(config)?;
2379 let stake_minimum_delegation = stake_utils::get_minimum_delegation(
2380 bank.feature_set
2381 .is_active(&agave_feature_set::stake_raise_minimum_delegation_to_1_sol::id()),
2382 );
2383 Ok(new_response(&bank, stake_minimum_delegation))
2384 }
2385
2386 fn get_recent_prioritization_fees(
2387 &self,
2388 pubkeys: Vec<Pubkey>,
2389 ) -> Result<Vec<RpcPrioritizationFee>> {
2390 Ok(self
2391 .prioritization_fee_cache
2392 .get_prioritization_fees(&pubkeys)
2393 .into_iter()
2394 .map(|(slot, prioritization_fee)| RpcPrioritizationFee {
2395 slot,
2396 prioritization_fee,
2397 })
2398 .collect())
2399 }
2400}
2401
2402pub(crate) fn optimize_filters(filters: &mut [RpcFilterType]) {
2403 filters.iter_mut().for_each(|filter_type| {
2404 if let RpcFilterType::Memcmp(compare) = filter_type {
2405 if let Err(err) = compare.convert_to_raw_bytes() {
2406 warn!("Invalid filter: bytes could not be decoded, {err}");
2408 }
2409 }
2410 })
2411}
2412
2413pub(crate) fn verify_filters(filters: &[RpcFilterType]) -> Result<()> {
2414 if filters.len() > MAX_GET_PROGRAM_ACCOUNT_FILTERS {
2415 return Err(Error::invalid_params(format!(
2416 "Too many filters provided; max {MAX_GET_PROGRAM_ACCOUNT_FILTERS}"
2417 )));
2418 }
2419 for filter in filters {
2420 verify_filter(filter)?;
2421 }
2422 Ok(())
2423}
2424
2425fn verify_filter(input: &RpcFilterType) -> Result<()> {
2426 input
2427 .verify()
2428 .map_err(|e| Error::invalid_params(format!("Invalid param: {e:?}")))
2429}
2430
2431pub fn verify_pubkey(input: &str) -> Result<Pubkey> {
2432 input
2433 .parse()
2434 .map_err(|e| Error::invalid_params(format!("Invalid param: {e:?}")))
2435}
2436
2437fn verify_hash(input: &str) -> Result<Hash> {
2438 input
2439 .parse()
2440 .map_err(|e| Error::invalid_params(format!("Invalid param: {e:?}")))
2441}
2442
2443fn verify_signature(input: &str) -> Result<Signature> {
2444 input
2445 .parse()
2446 .map_err(|e| Error::invalid_params(format!("Invalid param: {e:?}")))
2447}
2448
2449fn verify_token_account_filter(
2450 token_account_filter: RpcTokenAccountsFilter,
2451) -> Result<TokenAccountsFilter> {
2452 match token_account_filter {
2453 RpcTokenAccountsFilter::Mint(mint_str) => {
2454 let mint = verify_pubkey(&mint_str)?;
2455 Ok(TokenAccountsFilter::Mint(mint))
2456 }
2457 RpcTokenAccountsFilter::ProgramId(program_id_str) => {
2458 let program_id = verify_pubkey(&program_id_str)?;
2459 Ok(TokenAccountsFilter::ProgramId(program_id))
2460 }
2461 }
2462}
2463
2464fn verify_and_parse_signatures_for_address_params(
2465 address: String,
2466 before: Option<String>,
2467 until: Option<String>,
2468 limit: Option<usize>,
2469) -> Result<(Pubkey, Option<Signature>, Option<Signature>, usize)> {
2470 let address = verify_pubkey(&address)?;
2471 let before = before
2472 .map(|ref before| verify_signature(before))
2473 .transpose()?;
2474 let until = until.map(|ref until| verify_signature(until)).transpose()?;
2475 let limit = limit.unwrap_or(MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT);
2476
2477 if limit == 0 || limit > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT {
2478 return Err(Error::invalid_params(format!(
2479 "Invalid limit; max {MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT}"
2480 )));
2481 }
2482 Ok((address, before, until, limit))
2483}
2484
2485pub(crate) fn check_is_at_least_confirmed(commitment: CommitmentConfig) -> Result<()> {
2486 if !commitment.is_at_least_confirmed() {
2487 return Err(Error::invalid_params(
2488 "Method does not support commitment below `confirmed`",
2489 ));
2490 }
2491 Ok(())
2492}
2493
2494fn get_encoded_account(
2495 bank: &Bank,
2496 pubkey: &Pubkey,
2497 encoding: UiAccountEncoding,
2498 data_slice: Option<UiDataSliceConfig>,
2499 overwrite_accounts: Option<&HashMap<Pubkey, AccountSharedData>>,
2501) -> Result<Option<UiAccount>> {
2502 match account_resolver::get_account_from_overwrites_or_bank(pubkey, bank, overwrite_accounts) {
2503 Some(account) => {
2504 let response = if is_known_spl_token_id(account.owner())
2505 && encoding == UiAccountEncoding::JsonParsed
2506 {
2507 get_parsed_token_account(bank, pubkey, account, overwrite_accounts)
2508 } else {
2509 encode_account(&account, pubkey, encoding, data_slice)?
2510 };
2511 Ok(Some(response))
2512 }
2513 None => Ok(None),
2514 }
2515}
2516
2517fn encode_account<T: ReadableAccount>(
2518 account: &T,
2519 pubkey: &Pubkey,
2520 encoding: UiAccountEncoding,
2521 data_slice: Option<UiDataSliceConfig>,
2522) -> Result<UiAccount> {
2523 if (encoding == UiAccountEncoding::Binary || encoding == UiAccountEncoding::Base58)
2524 && data_slice
2525 .map(|s| min(s.length, account.data().len().saturating_sub(s.offset)))
2526 .unwrap_or(account.data().len())
2527 > MAX_BASE58_BYTES
2528 {
2529 let message = format!(
2530 "Encoded binary (base 58) data should be less than {MAX_BASE58_BYTES} bytes, please \
2531 use Base64 encoding."
2532 );
2533 Err(error::Error {
2534 code: error::ErrorCode::InvalidRequest,
2535 message,
2536 data: None,
2537 })
2538 } else {
2539 Ok(encode_ui_account(
2540 pubkey, account, encoding, None, data_slice,
2541 ))
2542 }
2543}
2544
2545fn get_spl_token_owner_filter(
2550 program_id: &Pubkey,
2551 filters: &[RpcFilterType],
2552) -> Result<Option<Pubkey>> {
2553 if !is_known_spl_token_id(program_id) {
2554 return Ok(None);
2555 }
2556 let mut data_size_filter: Option<u64> = None;
2557 let mut memcmp_filter: Option<&[u8]> = None;
2558 let mut owner_key: Option<Pubkey> = None;
2559 let mut token_account_state_filter = false;
2560 let account_packed_len = TokenAccount::get_packed_len();
2561 for filter in filters {
2562 match filter {
2563 RpcFilterType::DataSize(size) => data_size_filter = Some(*size),
2564 RpcFilterType::Memcmp(memcmp) => {
2565 let offset = memcmp.offset();
2566 if let Some(bytes) = memcmp.raw_bytes_as_ref() {
2567 if offset == account_packed_len && *program_id == token_2022::id() {
2568 memcmp_filter = Some(bytes);
2569 } else if offset == SPL_TOKEN_ACCOUNT_OWNER_OFFSET {
2570 if bytes.len() == PUBKEY_BYTES {
2571 owner_key = Pubkey::try_from(bytes).ok();
2572 } else {
2573 return Err(Error::invalid_params(format!(
2574 "Incorrect byte length {} for SPL token owner filter, expected {}",
2575 bytes.len(),
2576 PUBKEY_BYTES
2577 )));
2578 }
2579 }
2580 }
2581 }
2582 RpcFilterType::TokenAccountState => token_account_state_filter = true,
2583 }
2584 }
2585 if data_size_filter == Some(account_packed_len as u64)
2586 || memcmp_filter == Some(&[ACCOUNTTYPE_ACCOUNT])
2587 || token_account_state_filter
2588 {
2589 Ok(owner_key)
2590 } else {
2591 debug!("spl_token program filters do not match by-owner index requisites");
2592 Ok(None)
2593 }
2594}
2595
2596fn get_spl_token_mint_filter(
2601 program_id: &Pubkey,
2602 filters: &[RpcFilterType],
2603) -> Result<Option<Pubkey>> {
2604 if !is_known_spl_token_id(program_id) {
2605 return Ok(None);
2606 }
2607 let mut data_size_filter: Option<u64> = None;
2608 let mut memcmp_filter: Option<&[u8]> = None;
2609 let mut mint: Option<Pubkey> = None;
2610 let mut token_account_state_filter = false;
2611 let account_packed_len = TokenAccount::get_packed_len();
2612 for filter in filters {
2613 match filter {
2614 RpcFilterType::DataSize(size) => data_size_filter = Some(*size),
2615 RpcFilterType::Memcmp(memcmp) => {
2616 let offset = memcmp.offset();
2617 if let Some(bytes) = memcmp.raw_bytes_as_ref() {
2618 if offset == account_packed_len && *program_id == token_2022::id() {
2619 memcmp_filter = Some(bytes);
2620 } else if offset == SPL_TOKEN_ACCOUNT_MINT_OFFSET {
2621 if bytes.len() == PUBKEY_BYTES {
2622 mint = Pubkey::try_from(bytes).ok();
2623 } else {
2624 return Err(Error::invalid_params(format!(
2625 "Incorrect byte length {} for SPL token mint filter, expected {}",
2626 bytes.len(),
2627 PUBKEY_BYTES
2628 )));
2629 }
2630 }
2631 }
2632 }
2633 RpcFilterType::TokenAccountState => token_account_state_filter = true,
2634 }
2635 }
2636 if data_size_filter == Some(account_packed_len as u64)
2637 || memcmp_filter == Some(&[ACCOUNTTYPE_ACCOUNT])
2638 || token_account_state_filter
2639 {
2640 Ok(mint)
2641 } else {
2642 debug!("spl_token program filters do not match by-mint index requisites");
2643 Ok(None)
2644 }
2645}
2646
2647fn get_token_program_id_and_mint(
2650 bank: &Bank,
2651 token_account_filter: TokenAccountsFilter,
2652) -> Result<(Pubkey, Option<Pubkey>)> {
2653 match token_account_filter {
2654 TokenAccountsFilter::Mint(mint) => {
2655 let (mint_owner, _) = get_mint_owner_and_additional_data(bank, &mint)?;
2656 if !is_known_spl_token_id(&mint_owner) {
2657 return Err(Error::invalid_params(
2658 "Invalid param: not a Token mint".to_string(),
2659 ));
2660 }
2661 Ok((mint_owner, Some(mint)))
2662 }
2663 TokenAccountsFilter::ProgramId(program_id) => {
2664 if is_known_spl_token_id(&program_id) {
2665 Ok((program_id, None))
2666 } else {
2667 Err(Error::invalid_params(
2668 "Invalid param: unrecognized Token program id".to_string(),
2669 ))
2670 }
2671 }
2672 }
2673}
2674
2675fn _send_transaction(
2676 meta: JsonRpcRequestProcessor,
2677 message_hash: Hash,
2678 signature: Signature,
2679 blockhash: Hash,
2680 wire_transaction: Vec<u8>,
2681 last_valid_block_height: u64,
2682 durable_nonce_info: Option<(Pubkey, Hash)>,
2683 max_retries: Option<usize>,
2684) -> Result<String> {
2685 let transaction_info = TransactionInfo::new(
2686 message_hash,
2687 signature,
2688 blockhash,
2689 wire_transaction,
2690 last_valid_block_height,
2691 durable_nonce_info,
2692 max_retries,
2693 None,
2694 );
2695 meta.transaction_sender
2696 .send(transaction_info)
2697 .unwrap_or_else(|err| warn!("Failed to enqueue transaction: {err}"));
2698
2699 Ok(signature.to_string())
2700}
2701
2702pub mod rpc_minimal {
2704 use super::*;
2705 #[rpc]
2706 pub trait Minimal {
2707 type Metadata;
2708
2709 #[rpc(meta, name = "getBalance")]
2710 fn get_balance(
2711 &self,
2712 meta: Self::Metadata,
2713 pubkey_str: String,
2714 config: Option<RpcContextConfig>,
2715 ) -> Result<RpcResponse<u64>>;
2716
2717 #[rpc(meta, name = "getEpochInfo")]
2718 fn get_epoch_info(
2719 &self,
2720 meta: Self::Metadata,
2721 config: Option<RpcContextConfig>,
2722 ) -> Result<EpochInfo>;
2723
2724 #[rpc(meta, name = "getGenesisHash")]
2725 fn get_genesis_hash(&self, meta: Self::Metadata) -> Result<String>;
2726
2727 #[rpc(meta, name = "getHealth")]
2728 fn get_health(&self, meta: Self::Metadata) -> Result<String>;
2729
2730 #[rpc(meta, name = "getIdentity")]
2731 fn get_identity(&self, meta: Self::Metadata) -> Result<RpcIdentity>;
2732
2733 #[rpc(meta, name = "getSlot")]
2734 fn get_slot(&self, meta: Self::Metadata, config: Option<RpcContextConfig>) -> Result<Slot>;
2735
2736 #[rpc(meta, name = "getBlockHeight")]
2737 fn get_block_height(
2738 &self,
2739 meta: Self::Metadata,
2740 config: Option<RpcContextConfig>,
2741 ) -> Result<u64>;
2742
2743 #[rpc(meta, name = "getHighestSnapshotSlot")]
2744 fn get_highest_snapshot_slot(&self, meta: Self::Metadata) -> Result<RpcSnapshotSlotInfo>;
2745
2746 #[rpc(meta, name = "getTransactionCount")]
2747 fn get_transaction_count(
2748 &self,
2749 meta: Self::Metadata,
2750 config: Option<RpcContextConfig>,
2751 ) -> Result<u64>;
2752
2753 #[rpc(meta, name = "getVersion")]
2754 fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
2755
2756 #[rpc(meta, name = "getVoteAccounts")]
2759 fn get_vote_accounts(
2760 &self,
2761 meta: Self::Metadata,
2762 config: Option<RpcGetVoteAccountsConfig>,
2763 ) -> Result<RpcVoteAccountStatus>;
2764
2765 #[rpc(meta, name = "getLeaderSchedule")]
2768 fn get_leader_schedule(
2769 &self,
2770 meta: Self::Metadata,
2771 options: Option<RpcLeaderScheduleConfigWrapper>,
2772 config: Option<RpcLeaderScheduleConfig>,
2773 ) -> Result<Option<RpcLeaderSchedule>>;
2774 }
2775
2776 pub struct MinimalImpl;
2777 impl Minimal for MinimalImpl {
2778 type Metadata = JsonRpcRequestProcessor;
2779
2780 fn get_balance(
2781 &self,
2782 meta: Self::Metadata,
2783 pubkey_str: String,
2784 config: Option<RpcContextConfig>,
2785 ) -> Result<RpcResponse<u64>> {
2786 debug!("get_balance rpc request received: {pubkey_str:?}");
2787 let pubkey = verify_pubkey(&pubkey_str)?;
2788 meta.get_balance(&pubkey, config.unwrap_or_default())
2789 }
2790
2791 fn get_epoch_info(
2792 &self,
2793 meta: Self::Metadata,
2794 config: Option<RpcContextConfig>,
2795 ) -> Result<EpochInfo> {
2796 debug!("get_epoch_info rpc request received");
2797 let bank = meta.get_bank_with_config(config.unwrap_or_default())?;
2798 Ok(bank.get_epoch_info())
2799 }
2800
2801 fn get_genesis_hash(&self, meta: Self::Metadata) -> Result<String> {
2802 debug!("get_genesis_hash rpc request received");
2803 Ok(meta.genesis_hash.to_string())
2804 }
2805
2806 fn get_health(&self, meta: Self::Metadata) -> Result<String> {
2807 match meta.health.check() {
2808 RpcHealthStatus::Ok => Ok("ok".to_string()),
2809 RpcHealthStatus::Unknown => Err(RpcCustomError::NodeUnhealthy {
2810 num_slots_behind: None,
2811 }
2812 .into()),
2813 RpcHealthStatus::Behind { num_slots } => Err(RpcCustomError::NodeUnhealthy {
2814 num_slots_behind: Some(num_slots),
2815 }
2816 .into()),
2817 }
2818 }
2819
2820 fn get_identity(&self, meta: Self::Metadata) -> Result<RpcIdentity> {
2821 debug!("get_identity rpc request received");
2822 Ok(RpcIdentity {
2823 identity: meta.cluster_info.id().to_string(),
2824 })
2825 }
2826
2827 fn get_slot(&self, meta: Self::Metadata, config: Option<RpcContextConfig>) -> Result<Slot> {
2828 debug!("get_slot rpc request received");
2829 meta.get_slot(config.unwrap_or_default())
2830 }
2831
2832 fn get_block_height(
2833 &self,
2834 meta: Self::Metadata,
2835 config: Option<RpcContextConfig>,
2836 ) -> Result<u64> {
2837 debug!("get_block_height rpc request received");
2838 meta.get_block_height(config.unwrap_or_default())
2839 }
2840
2841 fn get_highest_snapshot_slot(&self, meta: Self::Metadata) -> Result<RpcSnapshotSlotInfo> {
2842 debug!("get_highest_snapshot_slot rpc request received");
2843
2844 if meta.snapshot_config.is_none() {
2845 return Err(RpcCustomError::NoSnapshot.into());
2846 }
2847
2848 let (full_snapshot_archives_dir, incremental_snapshot_archives_dir) = meta
2849 .snapshot_config
2850 .map(|snapshot_config| {
2851 (
2852 snapshot_config.full_snapshot_archives_dir,
2853 snapshot_config.incremental_snapshot_archives_dir,
2854 )
2855 })
2856 .unwrap();
2857
2858 let full_snapshot_slot =
2859 snapshot_paths::get_highest_full_snapshot_archive_slot(full_snapshot_archives_dir)
2860 .ok_or(RpcCustomError::NoSnapshot)?;
2861 let incremental_snapshot_slot =
2862 snapshot_paths::get_highest_incremental_snapshot_archive_slot(
2863 incremental_snapshot_archives_dir,
2864 full_snapshot_slot,
2865 );
2866
2867 Ok(RpcSnapshotSlotInfo {
2868 full: full_snapshot_slot,
2869 incremental: incremental_snapshot_slot,
2870 })
2871 }
2872
2873 fn get_transaction_count(
2874 &self,
2875 meta: Self::Metadata,
2876 config: Option<RpcContextConfig>,
2877 ) -> Result<u64> {
2878 debug!("get_transaction_count rpc request received");
2879 meta.get_transaction_count(config.unwrap_or_default())
2880 }
2881
2882 fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
2883 debug!("get_version rpc request received");
2884 let version = solana_version::Version::default();
2885 Ok(RpcVersionInfo {
2886 solana_core: version.to_string(),
2887 feature_set: Some(version.feature_set),
2888 })
2889 }
2890
2891 fn get_vote_accounts(
2894 &self,
2895 meta: Self::Metadata,
2896 config: Option<RpcGetVoteAccountsConfig>,
2897 ) -> Result<RpcVoteAccountStatus> {
2898 debug!("get_vote_accounts rpc request received");
2899 meta.get_vote_accounts(config)
2900 }
2901
2902 fn get_leader_schedule(
2905 &self,
2906 meta: Self::Metadata,
2907 options: Option<RpcLeaderScheduleConfigWrapper>,
2908 config: Option<RpcLeaderScheduleConfig>,
2909 ) -> Result<Option<RpcLeaderSchedule>> {
2910 let (slot, maybe_config) = options.map(|options| options.unzip()).unwrap_or_default();
2911 let config = maybe_config.or(config).unwrap_or_default();
2912
2913 if let Some(ref identity) = config.identity {
2914 let _ = verify_pubkey(identity)?;
2915 }
2916
2917 let bank = meta.bank(config.commitment);
2918 let slot = slot.unwrap_or_else(|| bank.slot());
2919 let epoch = bank.epoch_schedule().get_epoch(slot);
2920
2921 debug!("get_leader_schedule rpc request received: {slot:?}");
2922
2923 Ok(meta
2924 .leader_schedule_cache
2925 .get_epoch_leader_schedule(epoch)
2926 .map(|leader_schedule| {
2927 let mut schedule_by_identity =
2928 solana_ledger::leader_schedule_utils::leader_schedule_by_identity(
2929 leader_schedule.get_slot_leaders().iter().enumerate(),
2930 );
2931 if let Some(identity) = config.identity {
2932 schedule_by_identity.retain(|k, _| *k == identity);
2933 }
2934 schedule_by_identity
2935 }))
2936 }
2937 }
2938}
2939
2940pub mod rpc_bank {
2943 use super::*;
2944 #[rpc]
2945 pub trait BankData {
2946 type Metadata;
2947
2948 #[rpc(meta, name = "getMinimumBalanceForRentExemption")]
2949 fn get_minimum_balance_for_rent_exemption(
2950 &self,
2951 meta: Self::Metadata,
2952 data_len: usize,
2953 commitment: Option<CommitmentConfig>,
2954 ) -> Result<u64>;
2955
2956 #[rpc(meta, name = "getInflationGovernor")]
2957 fn get_inflation_governor(
2958 &self,
2959 meta: Self::Metadata,
2960 commitment: Option<CommitmentConfig>,
2961 ) -> Result<RpcInflationGovernor>;
2962
2963 #[rpc(meta, name = "getInflationRate")]
2964 fn get_inflation_rate(&self, meta: Self::Metadata) -> Result<RpcInflationRate>;
2965
2966 #[rpc(meta, name = "getEpochSchedule")]
2967 fn get_epoch_schedule(&self, meta: Self::Metadata) -> Result<EpochSchedule>;
2968
2969 #[rpc(meta, name = "getSlotLeader")]
2970 fn get_slot_leader(
2971 &self,
2972 meta: Self::Metadata,
2973 config: Option<RpcContextConfig>,
2974 ) -> Result<String>;
2975
2976 #[rpc(meta, name = "getSlotLeaders")]
2977 fn get_slot_leaders(
2978 &self,
2979 meta: Self::Metadata,
2980 start_slot: Slot,
2981 limit: u64,
2982 ) -> Result<Vec<String>>;
2983
2984 #[rpc(meta, name = "getBlockProduction")]
2985 fn get_block_production(
2986 &self,
2987 meta: Self::Metadata,
2988 config: Option<RpcBlockProductionConfig>,
2989 ) -> Result<RpcResponse<RpcBlockProduction>>;
2990 }
2991
2992 pub struct BankDataImpl;
2993 impl BankData for BankDataImpl {
2994 type Metadata = JsonRpcRequestProcessor;
2995
2996 fn get_minimum_balance_for_rent_exemption(
2997 &self,
2998 meta: Self::Metadata,
2999 data_len: usize,
3000 commitment: Option<CommitmentConfig>,
3001 ) -> Result<u64> {
3002 debug!("get_minimum_balance_for_rent_exemption rpc request received: {data_len:?}");
3003 if data_len as u64 > solana_system_interface::MAX_PERMITTED_DATA_LENGTH {
3004 return Err(Error::invalid_request());
3005 }
3006 Ok(meta.get_minimum_balance_for_rent_exemption(data_len, commitment))
3007 }
3008
3009 fn get_inflation_governor(
3010 &self,
3011 meta: Self::Metadata,
3012 commitment: Option<CommitmentConfig>,
3013 ) -> Result<RpcInflationGovernor> {
3014 debug!("get_inflation_governor rpc request received");
3015 Ok(meta.get_inflation_governor(commitment))
3016 }
3017
3018 fn get_inflation_rate(&self, meta: Self::Metadata) -> Result<RpcInflationRate> {
3019 debug!("get_inflation_rate rpc request received");
3020 Ok(meta.get_inflation_rate())
3021 }
3022
3023 fn get_epoch_schedule(&self, meta: Self::Metadata) -> Result<EpochSchedule> {
3024 debug!("get_epoch_schedule rpc request received");
3025 Ok(meta.get_epoch_schedule())
3026 }
3027
3028 fn get_slot_leader(
3029 &self,
3030 meta: Self::Metadata,
3031 config: Option<RpcContextConfig>,
3032 ) -> Result<String> {
3033 debug!("get_slot_leader rpc request received");
3034 meta.get_slot_leader(config.unwrap_or_default())
3035 }
3036
3037 fn get_slot_leaders(
3038 &self,
3039 meta: Self::Metadata,
3040 start_slot: Slot,
3041 limit: u64,
3042 ) -> Result<Vec<String>> {
3043 debug!("get_slot_leaders rpc request received (start: {start_slot} limit: {limit})");
3044
3045 let limit = limit as usize;
3046 if limit > MAX_GET_SLOT_LEADERS {
3047 return Err(Error::invalid_params(format!(
3048 "Invalid limit; max {MAX_GET_SLOT_LEADERS}"
3049 )));
3050 }
3051
3052 Ok(meta
3053 .get_slot_leaders(None, start_slot, limit)?
3054 .into_iter()
3055 .map(|identity| identity.to_string())
3056 .collect())
3057 }
3058
3059 fn get_block_production(
3060 &self,
3061 meta: Self::Metadata,
3062 config: Option<RpcBlockProductionConfig>,
3063 ) -> Result<RpcResponse<RpcBlockProduction>> {
3064 debug!("get_block_production rpc request received");
3065
3066 let config = config.unwrap_or_default();
3067 let filter_by_identity = if let Some(ref identity) = config.identity {
3068 Some(verify_pubkey(identity)?)
3069 } else {
3070 None
3071 };
3072
3073 let bank = meta.bank(config.commitment);
3074 let (first_slot, last_slot) = match config.range {
3075 None => (
3076 bank.epoch_schedule().get_first_slot_in_epoch(bank.epoch()),
3077 bank.slot(),
3078 ),
3079 Some(range) => {
3080 let first_slot = range.first_slot;
3081 let last_slot = range.last_slot.unwrap_or_else(|| bank.slot());
3082 if last_slot < first_slot {
3083 return Err(Error::invalid_params(format!(
3084 "lastSlot, {last_slot}, cannot be less than firstSlot, {first_slot}"
3085 )));
3086 }
3087 (first_slot, last_slot)
3088 }
3089 };
3090
3091 let slot_history = bank.get_slot_history();
3092 if first_slot < slot_history.oldest() {
3093 return Err(Error::invalid_params(format!(
3094 "firstSlot, {}, is too small; min {}",
3095 first_slot,
3096 slot_history.oldest()
3097 )));
3098 }
3099 if last_slot > slot_history.newest() {
3100 return Err(Error::invalid_params(format!(
3101 "lastSlot, {}, is too large; max {}",
3102 last_slot,
3103 slot_history.newest()
3104 )));
3105 }
3106
3107 let slot_leaders = meta.get_slot_leaders(
3108 config.commitment,
3109 first_slot,
3110 last_slot.saturating_sub(first_slot) as usize + 1, )?;
3112
3113 let mut block_production: HashMap<_, (usize, usize)> = HashMap::new();
3114
3115 let mut slot = first_slot;
3116 for identity in slot_leaders {
3117 if let Some(ref filter_by_identity) = filter_by_identity {
3118 if identity != *filter_by_identity {
3119 slot += 1;
3120 continue;
3121 }
3122 }
3123
3124 let entry = block_production.entry(identity).or_default();
3125 if slot_history.check(slot) == solana_slot_history::Check::Found {
3126 entry.1 += 1; }
3128 entry.0 += 1; slot += 1;
3130 }
3131
3132 Ok(new_response(
3133 &bank,
3134 RpcBlockProduction {
3135 by_identity: block_production
3136 .into_iter()
3137 .map(|(k, v)| (k.to_string(), v))
3138 .collect(),
3139 range: RpcBlockProductionRange {
3140 first_slot,
3141 last_slot,
3142 },
3143 },
3144 ))
3145 }
3146 }
3147}
3148
3149pub mod rpc_accounts {
3152 use super::*;
3153 #[rpc]
3154 pub trait AccountsData {
3155 type Metadata;
3156
3157 #[rpc(meta, name = "getAccountInfo")]
3158 fn get_account_info(
3159 &self,
3160 meta: Self::Metadata,
3161 pubkey_str: String,
3162 config: Option<RpcAccountInfoConfig>,
3163 ) -> BoxFuture<Result<RpcResponse<Option<UiAccount>>>>;
3164
3165 #[rpc(meta, name = "getMultipleAccounts")]
3166 fn get_multiple_accounts(
3167 &self,
3168 meta: Self::Metadata,
3169 pubkey_strs: Vec<String>,
3170 config: Option<RpcAccountInfoConfig>,
3171 ) -> BoxFuture<Result<RpcResponse<Vec<Option<UiAccount>>>>>;
3172
3173 #[rpc(meta, name = "getBlockCommitment")]
3174 fn get_block_commitment(
3175 &self,
3176 meta: Self::Metadata,
3177 block: Slot,
3178 ) -> Result<RpcBlockCommitment<BlockCommitmentArray>>;
3179
3180 #[rpc(meta, name = "getTokenAccountBalance")]
3185 fn get_token_account_balance(
3186 &self,
3187 meta: Self::Metadata,
3188 pubkey_str: String,
3189 commitment: Option<CommitmentConfig>,
3190 ) -> Result<RpcResponse<UiTokenAmount>>;
3191
3192 #[rpc(meta, name = "getTokenSupply")]
3193 fn get_token_supply(
3194 &self,
3195 meta: Self::Metadata,
3196 mint_str: String,
3197 commitment: Option<CommitmentConfig>,
3198 ) -> Result<RpcResponse<UiTokenAmount>>;
3199 }
3200
3201 pub struct AccountsDataImpl;
3202 impl AccountsData for AccountsDataImpl {
3203 type Metadata = JsonRpcRequestProcessor;
3204
3205 fn get_account_info(
3206 &self,
3207 meta: Self::Metadata,
3208 pubkey_str: String,
3209 config: Option<RpcAccountInfoConfig>,
3210 ) -> BoxFuture<Result<RpcResponse<Option<UiAccount>>>> {
3211 debug!("get_account_info rpc request received: {pubkey_str:?}");
3212 async move {
3213 let pubkey = verify_pubkey(&pubkey_str)?;
3214 meta.get_account_info(pubkey, config).await
3215 }
3216 .boxed()
3217 }
3218
3219 fn get_multiple_accounts(
3220 &self,
3221 meta: Self::Metadata,
3222 pubkey_strs: Vec<String>,
3223 config: Option<RpcAccountInfoConfig>,
3224 ) -> BoxFuture<Result<RpcResponse<Vec<Option<UiAccount>>>>> {
3225 debug!(
3226 "get_multiple_accounts rpc request received: {:?}",
3227 pubkey_strs.len()
3228 );
3229 async move {
3230 let max_multiple_accounts = meta
3231 .config
3232 .max_multiple_accounts
3233 .unwrap_or(MAX_MULTIPLE_ACCOUNTS);
3234 if pubkey_strs.len() > max_multiple_accounts {
3235 return Err(Error::invalid_params(format!(
3236 "Too many inputs provided; max {max_multiple_accounts}"
3237 )));
3238 }
3239 let pubkeys = pubkey_strs
3240 .into_iter()
3241 .map(|pubkey_str| verify_pubkey(&pubkey_str))
3242 .collect::<Result<Vec<_>>>()?;
3243 meta.get_multiple_accounts(pubkeys, config).await
3244 }
3245 .boxed()
3246 }
3247
3248 fn get_block_commitment(
3249 &self,
3250 meta: Self::Metadata,
3251 block: Slot,
3252 ) -> Result<RpcBlockCommitment<BlockCommitmentArray>> {
3253 debug!("get_block_commitment rpc request received");
3254 Ok(meta.get_block_commitment(block))
3255 }
3256
3257 fn get_token_account_balance(
3258 &self,
3259 meta: Self::Metadata,
3260 pubkey_str: String,
3261 commitment: Option<CommitmentConfig>,
3262 ) -> Result<RpcResponse<UiTokenAmount>> {
3263 debug!("get_token_account_balance rpc request received: {pubkey_str:?}");
3264 let pubkey = verify_pubkey(&pubkey_str)?;
3265 meta.get_token_account_balance(&pubkey, commitment)
3266 }
3267
3268 fn get_token_supply(
3269 &self,
3270 meta: Self::Metadata,
3271 mint_str: String,
3272 commitment: Option<CommitmentConfig>,
3273 ) -> Result<RpcResponse<UiTokenAmount>> {
3274 debug!("get_token_supply rpc request received: {mint_str:?}");
3275 let mint = verify_pubkey(&mint_str)?;
3276 meta.get_token_supply(&mint, commitment)
3277 }
3278 }
3279}
3280
3281pub mod rpc_accounts_scan {
3285 use super::*;
3286 #[rpc]
3287 pub trait AccountsScan {
3288 type Metadata;
3289
3290 #[rpc(meta, name = "getProgramAccounts")]
3291 fn get_program_accounts(
3292 &self,
3293 meta: Self::Metadata,
3294 program_id_str: String,
3295 config: Option<RpcProgramAccountsConfig>,
3296 ) -> BoxFuture<Result<OptionalContext<Vec<RpcKeyedAccount>>>>;
3297
3298 #[rpc(meta, name = "getLargestAccounts")]
3299 fn get_largest_accounts(
3300 &self,
3301 meta: Self::Metadata,
3302 config: Option<RpcLargestAccountsConfig>,
3303 ) -> BoxFuture<Result<RpcResponse<Vec<RpcAccountBalance>>>>;
3304
3305 #[rpc(meta, name = "getSupply")]
3306 fn get_supply(
3307 &self,
3308 meta: Self::Metadata,
3309 config: Option<RpcSupplyConfig>,
3310 ) -> BoxFuture<Result<RpcResponse<RpcSupply>>>;
3311
3312 #[rpc(meta, name = "getTokenLargestAccounts")]
3317 fn get_token_largest_accounts(
3318 &self,
3319 meta: Self::Metadata,
3320 mint_str: String,
3321 commitment: Option<CommitmentConfig>,
3322 ) -> BoxFuture<Result<RpcResponse<Vec<RpcTokenAccountBalance>>>>;
3323
3324 #[rpc(meta, name = "getTokenAccountsByOwner")]
3325 fn get_token_accounts_by_owner(
3326 &self,
3327 meta: Self::Metadata,
3328 owner_str: String,
3329 token_account_filter: RpcTokenAccountsFilter,
3330 config: Option<RpcAccountInfoConfig>,
3331 ) -> BoxFuture<Result<RpcResponse<Vec<RpcKeyedAccount>>>>;
3332
3333 #[rpc(meta, name = "getTokenAccountsByDelegate")]
3334 fn get_token_accounts_by_delegate(
3335 &self,
3336 meta: Self::Metadata,
3337 delegate_str: String,
3338 token_account_filter: RpcTokenAccountsFilter,
3339 config: Option<RpcAccountInfoConfig>,
3340 ) -> BoxFuture<Result<RpcResponse<Vec<RpcKeyedAccount>>>>;
3341 }
3342
3343 pub struct AccountsScanImpl;
3344 impl AccountsScan for AccountsScanImpl {
3345 type Metadata = JsonRpcRequestProcessor;
3346
3347 fn get_program_accounts(
3348 &self,
3349 meta: Self::Metadata,
3350 program_id_str: String,
3351 config: Option<RpcProgramAccountsConfig>,
3352 ) -> BoxFuture<Result<OptionalContext<Vec<RpcKeyedAccount>>>> {
3353 debug!("get_program_accounts rpc request received: {program_id_str:?}");
3354 async move {
3355 let program_id = verify_pubkey(&program_id_str)?;
3356 let (config, filters, with_context, sort_results) = if let Some(config) = config {
3357 (
3358 Some(config.account_config),
3359 config.filters.unwrap_or_default(),
3360 config.with_context.unwrap_or_default(),
3361 config.sort_results.unwrap_or(true),
3362 )
3363 } else {
3364 (None, vec![], false, true)
3365 };
3366 verify_filters(&filters)?;
3367 meta.get_program_accounts(program_id, config, filters, with_context, sort_results)
3368 .await
3369 }
3370 .boxed()
3371 }
3372
3373 fn get_largest_accounts(
3374 &self,
3375 meta: Self::Metadata,
3376 config: Option<RpcLargestAccountsConfig>,
3377 ) -> BoxFuture<Result<RpcResponse<Vec<RpcAccountBalance>>>> {
3378 debug!("get_largest_accounts rpc request received");
3379 async move { Ok(meta.get_largest_accounts(config).await?) }.boxed()
3380 }
3381
3382 fn get_supply(
3383 &self,
3384 meta: Self::Metadata,
3385 config: Option<RpcSupplyConfig>,
3386 ) -> BoxFuture<Result<RpcResponse<RpcSupply>>> {
3387 debug!("get_supply rpc request received");
3388 async move { Ok(meta.get_supply(config).await?) }.boxed()
3389 }
3390
3391 fn get_token_largest_accounts(
3392 &self,
3393 meta: Self::Metadata,
3394 mint_str: String,
3395 commitment: Option<CommitmentConfig>,
3396 ) -> BoxFuture<Result<RpcResponse<Vec<RpcTokenAccountBalance>>>> {
3397 debug!("get_token_largest_accounts rpc request received: {mint_str:?}");
3398 async move {
3399 let mint = verify_pubkey(&mint_str)?;
3400 meta.get_token_largest_accounts(mint, commitment).await
3401 }
3402 .boxed()
3403 }
3404
3405 fn get_token_accounts_by_owner(
3406 &self,
3407 meta: Self::Metadata,
3408 owner_str: String,
3409 token_account_filter: RpcTokenAccountsFilter,
3410 config: Option<RpcAccountInfoConfig>,
3411 ) -> BoxFuture<Result<RpcResponse<Vec<RpcKeyedAccount>>>> {
3412 debug!("get_token_accounts_by_owner rpc request received: {owner_str:?}");
3413 async move {
3414 let owner = verify_pubkey(&owner_str)?;
3415 let token_account_filter = verify_token_account_filter(token_account_filter)?;
3416 meta.get_token_accounts_by_owner(owner, token_account_filter, config, true)
3417 .await
3418 }
3419 .boxed()
3420 }
3421
3422 fn get_token_accounts_by_delegate(
3423 &self,
3424 meta: Self::Metadata,
3425 delegate_str: String,
3426 token_account_filter: RpcTokenAccountsFilter,
3427 config: Option<RpcAccountInfoConfig>,
3428 ) -> BoxFuture<Result<RpcResponse<Vec<RpcKeyedAccount>>>> {
3429 debug!("get_token_accounts_by_delegate rpc request received: {delegate_str:?}");
3430 async move {
3431 let delegate = verify_pubkey(&delegate_str)?;
3432 let token_account_filter = verify_token_account_filter(token_account_filter)?;
3433 meta.get_token_accounts_by_delegate(delegate, token_account_filter, config, true)
3434 .await
3435 }
3436 .boxed()
3437 }
3438 }
3439}
3440
3441pub mod rpc_full {
3444 use {
3445 super::*,
3446 solana_message::{SanitizedVersionedMessage, VersionedMessage},
3447 solana_transaction_status::{parse_ui_inner_instructions, UiLoadedAddresses},
3448 };
3449 #[rpc]
3450 pub trait Full {
3451 type Metadata;
3452
3453 #[rpc(meta, name = "getInflationReward")]
3454 fn get_inflation_reward(
3455 &self,
3456 meta: Self::Metadata,
3457 address_strs: Vec<String>,
3458 config: Option<RpcEpochConfig>,
3459 ) -> BoxFuture<Result<Vec<Option<RpcInflationReward>>>>;
3460
3461 #[rpc(meta, name = "getClusterNodes")]
3462 fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>>;
3463
3464 #[rpc(meta, name = "getRecentPerformanceSamples")]
3465 fn get_recent_performance_samples(
3466 &self,
3467 meta: Self::Metadata,
3468 limit: Option<usize>,
3469 ) -> Result<Vec<RpcPerfSample>>;
3470
3471 #[rpc(meta, name = "getSignatureStatuses")]
3472 fn get_signature_statuses(
3473 &self,
3474 meta: Self::Metadata,
3475 signature_strs: Vec<String>,
3476 config: Option<RpcSignatureStatusConfig>,
3477 ) -> BoxFuture<Result<RpcResponse<Vec<Option<TransactionStatus>>>>>;
3478
3479 #[rpc(meta, name = "getMaxRetransmitSlot")]
3480 fn get_max_retransmit_slot(&self, meta: Self::Metadata) -> Result<Slot>;
3481
3482 #[rpc(meta, name = "getMaxShredInsertSlot")]
3483 fn get_max_shred_insert_slot(&self, meta: Self::Metadata) -> Result<Slot>;
3484
3485 #[rpc(meta, name = "requestAirdrop")]
3486 fn request_airdrop(
3487 &self,
3488 meta: Self::Metadata,
3489 pubkey_str: String,
3490 lamports: u64,
3491 config: Option<RpcRequestAirdropConfig>,
3492 ) -> Result<String>;
3493
3494 #[rpc(meta, name = "sendTransaction")]
3495 fn send_transaction(
3496 &self,
3497 meta: Self::Metadata,
3498 data: String,
3499 config: Option<RpcSendTransactionConfig>,
3500 ) -> Result<String>;
3501
3502 #[rpc(meta, name = "simulateTransaction")]
3503 fn simulate_transaction(
3504 &self,
3505 meta: Self::Metadata,
3506 data: String,
3507 config: Option<RpcSimulateTransactionConfig>,
3508 ) -> Result<RpcResponse<RpcSimulateTransactionResult>>;
3509
3510 #[rpc(meta, name = "minimumLedgerSlot")]
3511 fn minimum_ledger_slot(&self, meta: Self::Metadata) -> Result<Slot>;
3512
3513 #[rpc(meta, name = "getBlock")]
3514 fn get_block(
3515 &self,
3516 meta: Self::Metadata,
3517 slot: Slot,
3518 config: Option<RpcEncodingConfigWrapper<RpcBlockConfig>>,
3519 ) -> BoxFuture<Result<Option<UiConfirmedBlock>>>;
3520
3521 #[rpc(meta, name = "getBlockTime")]
3522 fn get_block_time(
3523 &self,
3524 meta: Self::Metadata,
3525 slot: Slot,
3526 ) -> BoxFuture<Result<Option<UnixTimestamp>>>;
3527
3528 #[rpc(meta, name = "getBlocks")]
3529 fn get_blocks(
3530 &self,
3531 meta: Self::Metadata,
3532 start_slot: Slot,
3533 wrapper: Option<RpcBlocksConfigWrapper>,
3534 config: Option<RpcContextConfig>,
3535 ) -> BoxFuture<Result<Vec<Slot>>>;
3536
3537 #[rpc(meta, name = "getBlocksWithLimit")]
3538 fn get_blocks_with_limit(
3539 &self,
3540 meta: Self::Metadata,
3541 start_slot: Slot,
3542 limit: usize,
3543 config: Option<RpcContextConfig>,
3544 ) -> BoxFuture<Result<Vec<Slot>>>;
3545
3546 #[rpc(meta, name = "getTransaction")]
3547 fn get_transaction(
3548 &self,
3549 meta: Self::Metadata,
3550 signature_str: String,
3551 config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>,
3552 ) -> BoxFuture<Result<Option<EncodedConfirmedTransactionWithStatusMeta>>>;
3553
3554 #[rpc(meta, name = "getSignaturesForAddress")]
3555 fn get_signatures_for_address(
3556 &self,
3557 meta: Self::Metadata,
3558 address: String,
3559 config: Option<RpcSignaturesForAddressConfig>,
3560 ) -> BoxFuture<Result<Vec<RpcConfirmedTransactionStatusWithSignature>>>;
3561
3562 #[rpc(meta, name = "getFirstAvailableBlock")]
3563 fn get_first_available_block(&self, meta: Self::Metadata) -> BoxFuture<Result<Slot>>;
3564
3565 #[rpc(meta, name = "getLatestBlockhash")]
3566 fn get_latest_blockhash(
3567 &self,
3568 meta: Self::Metadata,
3569 config: Option<RpcContextConfig>,
3570 ) -> Result<RpcResponse<RpcBlockhash>>;
3571
3572 #[rpc(meta, name = "isBlockhashValid")]
3573 fn is_blockhash_valid(
3574 &self,
3575 meta: Self::Metadata,
3576 blockhash: String,
3577 config: Option<RpcContextConfig>,
3578 ) -> Result<RpcResponse<bool>>;
3579
3580 #[rpc(meta, name = "getFeeForMessage")]
3581 fn get_fee_for_message(
3582 &self,
3583 meta: Self::Metadata,
3584 data: String,
3585 config: Option<RpcContextConfig>,
3586 ) -> Result<RpcResponse<Option<u64>>>;
3587
3588 #[rpc(meta, name = "getStakeMinimumDelegation")]
3589 fn get_stake_minimum_delegation(
3590 &self,
3591 meta: Self::Metadata,
3592 config: Option<RpcContextConfig>,
3593 ) -> Result<RpcResponse<u64>>;
3594
3595 #[rpc(meta, name = "getRecentPrioritizationFees")]
3596 fn get_recent_prioritization_fees(
3597 &self,
3598 meta: Self::Metadata,
3599 pubkey_strs: Option<Vec<String>>,
3600 ) -> Result<Vec<RpcPrioritizationFee>>;
3601 }
3602
3603 pub struct FullImpl;
3604 impl Full for FullImpl {
3605 type Metadata = JsonRpcRequestProcessor;
3606
3607 fn get_recent_performance_samples(
3608 &self,
3609 meta: Self::Metadata,
3610 limit: Option<usize>,
3611 ) -> Result<Vec<RpcPerfSample>> {
3612 debug!("get_recent_performance_samples request received");
3613
3614 let limit = limit.unwrap_or(PERFORMANCE_SAMPLES_LIMIT);
3615
3616 if limit > PERFORMANCE_SAMPLES_LIMIT {
3617 return Err(Error::invalid_params(format!(
3618 "Invalid limit; max {PERFORMANCE_SAMPLES_LIMIT}"
3619 )));
3620 }
3621
3622 Ok(meta
3623 .blockstore
3624 .get_recent_perf_samples(limit)
3625 .map_err(|err| {
3626 warn!("get_recent_performance_samples failed: {err:?}");
3627 Error::invalid_request()
3628 })?
3629 .into_iter()
3630 .map(|(slot, sample)| rpc_perf_sample_from_perf_sample(slot, sample))
3631 .collect())
3632 }
3633
3634 fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>> {
3635 debug!("get_cluster_nodes rpc request received");
3636 let cluster_info = &meta.cluster_info;
3637 let socket_addr_space = cluster_info.socket_addr_space();
3638 let my_shred_version = cluster_info.my_shred_version();
3639 Ok(cluster_info
3640 .all_peers()
3641 .iter()
3642 .filter_map(|(contact_info, _)| {
3643 if my_shred_version == contact_info.shred_version()
3644 && contact_info
3645 .gossip()
3646 .map(|addr| socket_addr_space.check(&addr))
3647 .unwrap_or_default()
3648 {
3649 let (version, feature_set) = if let Some(version) =
3650 cluster_info.get_node_version(contact_info.pubkey())
3651 {
3652 (Some(version.to_string()), Some(version.feature_set))
3653 } else {
3654 (None, None)
3655 };
3656 Some(RpcContactInfo {
3657 pubkey: contact_info.pubkey().to_string(),
3658 gossip: contact_info.gossip(),
3659 tvu: contact_info
3660 .tvu(Protocol::UDP)
3661 .filter(|addr| socket_addr_space.check(addr)),
3662 tpu: contact_info
3663 .tpu(Protocol::UDP)
3664 .filter(|addr| socket_addr_space.check(addr)),
3665 tpu_quic: contact_info
3666 .tpu(Protocol::QUIC)
3667 .filter(|addr| socket_addr_space.check(addr)),
3668 tpu_forwards: contact_info
3669 .tpu_forwards(Protocol::UDP)
3670 .filter(|addr| socket_addr_space.check(addr)),
3671 tpu_forwards_quic: contact_info
3672 .tpu_forwards(Protocol::QUIC)
3673 .filter(|addr| socket_addr_space.check(addr)),
3674 tpu_vote: contact_info
3675 .tpu_vote(Protocol::UDP)
3676 .filter(|addr| socket_addr_space.check(addr)),
3677 serve_repair: contact_info
3678 .serve_repair(Protocol::UDP)
3679 .filter(|addr| socket_addr_space.check(addr)),
3680 rpc: contact_info
3681 .rpc()
3682 .filter(|addr| socket_addr_space.check(addr)),
3683 pubsub: contact_info
3684 .rpc_pubsub()
3685 .filter(|addr| socket_addr_space.check(addr)),
3686 version,
3687 feature_set,
3688 shred_version: Some(my_shred_version),
3689 })
3690 } else {
3691 None }
3693 })
3694 .collect())
3695 }
3696
3697 fn get_signature_statuses(
3698 &self,
3699 meta: Self::Metadata,
3700 signature_strs: Vec<String>,
3701 config: Option<RpcSignatureStatusConfig>,
3702 ) -> BoxFuture<Result<RpcResponse<Vec<Option<TransactionStatus>>>>> {
3703 debug!(
3704 "get_signature_statuses rpc request received: {:?}",
3705 signature_strs.len()
3706 );
3707 if signature_strs.len() > MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS {
3708 return Box::pin(future::err(Error::invalid_params(format!(
3709 "Too many inputs provided; max {MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS}"
3710 ))));
3711 }
3712 let mut signatures: Vec<Signature> = vec![];
3713 for signature_str in signature_strs {
3714 match verify_signature(&signature_str) {
3715 Ok(signature) => {
3716 signatures.push(signature);
3717 }
3718 Err(err) => return Box::pin(future::err(err)),
3719 }
3720 }
3721 Box::pin(async move { meta.get_signature_statuses(signatures, config).await })
3722 }
3723
3724 fn get_max_retransmit_slot(&self, meta: Self::Metadata) -> Result<Slot> {
3725 debug!("get_max_retransmit_slot rpc request received");
3726 Ok(meta.get_max_retransmit_slot())
3727 }
3728
3729 fn get_max_shred_insert_slot(&self, meta: Self::Metadata) -> Result<Slot> {
3730 debug!("get_max_shred_insert_slot rpc request received");
3731 Ok(meta.get_max_shred_insert_slot())
3732 }
3733
3734 fn request_airdrop(
3735 &self,
3736 meta: Self::Metadata,
3737 pubkey_str: String,
3738 lamports: u64,
3739 config: Option<RpcRequestAirdropConfig>,
3740 ) -> Result<String> {
3741 debug!("request_airdrop rpc request received");
3742 trace!(
3743 "request_airdrop id={} lamports={} config: {:?}",
3744 pubkey_str,
3745 lamports,
3746 &config
3747 );
3748
3749 let faucet_addr = meta.config.faucet_addr.ok_or_else(Error::invalid_request)?;
3750 let pubkey = verify_pubkey(&pubkey_str)?;
3751
3752 let config = config.unwrap_or_default();
3753 let bank = meta.bank(config.commitment);
3754
3755 let blockhash = if let Some(blockhash) = config.recent_blockhash {
3756 verify_hash(&blockhash)?
3757 } else {
3758 bank.confirmed_last_blockhash()
3759 };
3760 let last_valid_block_height = bank
3761 .get_blockhash_last_valid_block_height(&blockhash)
3762 .unwrap_or(0);
3763
3764 let transaction =
3765 request_airdrop_transaction(&faucet_addr, &pubkey, lamports, blockhash).map_err(
3766 |err| {
3767 info!("request_airdrop_transaction failed: {err:?}");
3768 Error::internal_error()
3769 },
3770 )?;
3771
3772 let wire_transaction = serialize(&transaction).map_err(|err| {
3773 info!("request_airdrop: serialize error: {err:?}");
3774 Error::internal_error()
3775 })?;
3776
3777 let message_hash = transaction.message().hash();
3778 let signature = if !transaction.signatures.is_empty() {
3779 transaction.signatures[0]
3780 } else {
3781 return Err(RpcCustomError::TransactionSignatureVerificationFailure.into());
3782 };
3783
3784 _send_transaction(
3785 meta,
3786 message_hash,
3787 signature,
3788 blockhash,
3789 wire_transaction,
3790 last_valid_block_height,
3791 None,
3792 None,
3793 )
3794 }
3795
3796 fn send_transaction(
3797 &self,
3798 meta: Self::Metadata,
3799 data: String,
3800 config: Option<RpcSendTransactionConfig>,
3801 ) -> Result<String> {
3802 debug!("send_transaction rpc request received");
3803 let RpcSendTransactionConfig {
3804 skip_preflight,
3805 preflight_commitment,
3806 encoding,
3807 max_retries,
3808 min_context_slot,
3809 } = config.unwrap_or_default();
3810 let tx_encoding = encoding.unwrap_or(UiTransactionEncoding::Base58);
3811 let binary_encoding = tx_encoding.into_binary_encoding().ok_or_else(|| {
3812 Error::invalid_params(format!(
3813 "unsupported encoding: {tx_encoding}. Supported encodings: base58, base64"
3814 ))
3815 })?;
3816 let (wire_transaction, unsanitized_tx) =
3817 decode_and_deserialize::<VersionedTransaction>(data, binary_encoding)?;
3818
3819 let preflight_commitment = if skip_preflight {
3820 Some(CommitmentConfig::processed())
3821 } else {
3822 preflight_commitment.map(|commitment| CommitmentConfig { commitment })
3823 };
3824 let preflight_bank = &*meta.get_bank_with_config(RpcContextConfig {
3825 commitment: preflight_commitment,
3826 min_context_slot,
3827 })?;
3828
3829 let transaction = sanitize_transaction(
3830 unsanitized_tx,
3831 preflight_bank,
3832 preflight_bank.get_reserved_account_keys(),
3833 preflight_bank
3834 .feature_set
3835 .is_active(&agave_feature_set::static_instruction_limit::id()),
3836 )?;
3837 let blockhash = *transaction.message().recent_blockhash();
3838 let message_hash = *transaction.message_hash();
3839 let signature = *transaction.signature();
3840
3841 let mut last_valid_block_height = preflight_bank
3842 .get_blockhash_last_valid_block_height(&blockhash)
3843 .unwrap_or(0);
3844
3845 let durable_nonce_info = transaction
3846 .get_durable_nonce()
3847 .map(|&pubkey| (pubkey, blockhash));
3848 if durable_nonce_info.is_some() || (skip_preflight && last_valid_block_height == 0) {
3849 last_valid_block_height = preflight_bank.block_height() + MAX_PROCESSING_AGE as u64;
3854 }
3855
3856 if !skip_preflight {
3857 let verification_error = transaction.verify().err();
3858
3859 if verification_error.is_none() && !meta.config.skip_preflight_health_check {
3860 match meta.health.check() {
3861 RpcHealthStatus::Ok => (),
3862 RpcHealthStatus::Unknown => {
3863 inc_new_counter_info!("rpc-send-tx_health-unknown", 1);
3864 return Err(RpcCustomError::NodeUnhealthy {
3865 num_slots_behind: None,
3866 }
3867 .into());
3868 }
3869 RpcHealthStatus::Behind { num_slots } => {
3870 inc_new_counter_info!("rpc-send-tx_health-behind", 1);
3871 return Err(RpcCustomError::NodeUnhealthy {
3872 num_slots_behind: Some(num_slots),
3873 }
3874 .into());
3875 }
3876 }
3877 }
3878
3879 let simulation_result = if let Some(err) = verification_error {
3880 TransactionSimulationResult::new_error(err)
3881 } else {
3882 preflight_bank.simulate_transaction(&transaction, false)
3883 };
3884
3885 if let TransactionSimulationResult {
3886 result: Err(err),
3887 logs,
3888 post_simulation_accounts: _,
3889 units_consumed,
3890 loaded_accounts_data_size,
3891 return_data,
3892 inner_instructions: _, fee,
3894 pre_balances: _,
3895 post_balances: _,
3896 pre_token_balances: _,
3897 post_token_balances: _,
3898 } = simulation_result
3899 {
3900 match err {
3901 TransactionError::BlockhashNotFound => {
3902 inc_new_counter_info!("rpc-send-tx_err-blockhash-not-found", 1);
3903 }
3904 _ => {
3905 inc_new_counter_info!("rpc-send-tx_err-other", 1);
3906 }
3907 }
3908 return Err(RpcCustomError::SendTransactionPreflightFailure {
3909 message: format!("Transaction simulation failed: {err}"),
3910 result: RpcSimulateTransactionResult {
3911 err: Some(err.into()),
3912 logs: Some(logs),
3913 accounts: None,
3914 units_consumed: Some(units_consumed),
3915 loaded_accounts_data_size: Some(loaded_accounts_data_size),
3916 return_data: return_data.map(|return_data| return_data.into()),
3917 inner_instructions: None,
3918 replacement_blockhash: None,
3919 fee,
3920 pre_balances: None,
3921 post_balances: None,
3922 pre_token_balances: None,
3923 post_token_balances: None,
3924 loaded_addresses: None,
3925 },
3926 }
3927 .into());
3928 }
3929 }
3930
3931 _send_transaction(
3932 meta,
3933 message_hash,
3934 signature,
3935 blockhash,
3936 wire_transaction,
3937 last_valid_block_height,
3938 durable_nonce_info,
3939 max_retries,
3940 )
3941 }
3942
3943 fn simulate_transaction(
3944 &self,
3945 meta: Self::Metadata,
3946 data: String,
3947 config: Option<RpcSimulateTransactionConfig>,
3948 ) -> Result<RpcResponse<RpcSimulateTransactionResult>> {
3949 debug!("simulate_transaction rpc request received");
3950 let RpcSimulateTransactionConfig {
3951 sig_verify,
3952 replace_recent_blockhash,
3953 commitment,
3954 encoding,
3955 accounts: config_accounts,
3956 min_context_slot,
3957 inner_instructions: enable_cpi_recording,
3958 } = config.unwrap_or_default();
3959 let tx_encoding = encoding.unwrap_or(UiTransactionEncoding::Base58);
3960 let binary_encoding = tx_encoding.into_binary_encoding().ok_or_else(|| {
3961 Error::invalid_params(format!(
3962 "unsupported encoding: {tx_encoding}. Supported encodings: base58, base64"
3963 ))
3964 })?;
3965 let (_, mut unsanitized_tx) =
3966 decode_and_deserialize::<VersionedTransaction>(data, binary_encoding)?;
3967
3968 let bank = &*meta.get_bank_with_config(RpcContextConfig {
3969 commitment,
3970 min_context_slot,
3971 })?;
3972 let mut blockhash: Option<RpcBlockhash> = None;
3973 if replace_recent_blockhash {
3974 if sig_verify {
3975 return Err(Error::invalid_params(
3976 "sigVerify may not be used with replaceRecentBlockhash",
3977 ));
3978 }
3979 let recent_blockhash = bank.last_blockhash();
3980 unsanitized_tx
3981 .message
3982 .set_recent_blockhash(recent_blockhash);
3983 let last_valid_block_height = bank
3984 .get_blockhash_last_valid_block_height(&recent_blockhash)
3985 .expect("bank blockhash queue should contain blockhash");
3986 blockhash.replace(RpcBlockhash {
3987 blockhash: recent_blockhash.to_string(),
3988 last_valid_block_height,
3989 });
3990 }
3991
3992 let transaction = sanitize_transaction(
3993 unsanitized_tx,
3994 bank,
3995 bank.get_reserved_account_keys(),
3996 bank.feature_set
3997 .is_active(&agave_feature_set::static_instruction_limit::id()),
3998 )?;
3999
4000 let verification_error = if sig_verify {
4001 transaction.verify().err()
4002 } else {
4003 None
4004 };
4005
4006 let simulation_result = if let Some(err) = verification_error {
4007 TransactionSimulationResult::new_error(err)
4008 } else {
4009 bank.simulate_transaction(&transaction, enable_cpi_recording)
4010 };
4011
4012 let TransactionSimulationResult {
4013 result,
4014 logs,
4015 post_simulation_accounts,
4016 units_consumed,
4017 loaded_accounts_data_size,
4018 return_data,
4019 inner_instructions,
4020 fee,
4021 pre_balances,
4022 post_balances,
4023 pre_token_balances,
4024 post_token_balances,
4025 } = simulation_result;
4026
4027 let account_keys = transaction.message().account_keys();
4028 let number_of_accounts = account_keys.len();
4029
4030 let accounts = if let Some(config_accounts) = config_accounts {
4031 let accounts_encoding = config_accounts
4032 .encoding
4033 .unwrap_or(UiAccountEncoding::Base64);
4034
4035 if accounts_encoding == UiAccountEncoding::Binary
4036 || accounts_encoding == UiAccountEncoding::Base58
4037 {
4038 return Err(Error::invalid_params("base58 encoding not supported"));
4039 }
4040
4041 if config_accounts.addresses.len() > number_of_accounts {
4042 return Err(Error::invalid_params(format!(
4043 "Too many accounts provided; max {number_of_accounts}"
4044 )));
4045 }
4046
4047 if result.is_err() {
4048 Some(vec![None; config_accounts.addresses.len()])
4049 } else {
4050 let mut post_simulation_accounts_map = HashMap::new();
4051 for (pubkey, data) in post_simulation_accounts {
4052 post_simulation_accounts_map.insert(pubkey, data);
4053 }
4054
4055 Some(
4056 config_accounts
4057 .addresses
4058 .iter()
4059 .map(|address_str| {
4060 let pubkey = verify_pubkey(address_str)?;
4061 get_encoded_account(
4062 bank,
4063 &pubkey,
4064 accounts_encoding,
4065 None,
4066 Some(&post_simulation_accounts_map),
4067 )
4068 })
4069 .collect::<Result<Vec<_>>>()?,
4070 )
4071 }
4072 } else {
4073 None
4074 };
4075
4076 let inner_instructions = inner_instructions.map(|info| {
4077 map_inner_instructions(info)
4078 .map(|converted| parse_ui_inner_instructions(converted, &account_keys))
4079 .collect()
4080 });
4081
4082 Ok(new_response(
4083 bank,
4084 RpcSimulateTransactionResult {
4085 err: result.err().map(Into::into),
4086 logs: Some(logs),
4087 accounts,
4088 units_consumed: Some(units_consumed),
4089 loaded_accounts_data_size: Some(loaded_accounts_data_size),
4090 return_data: return_data.map(|return_data| return_data.into()),
4091 inner_instructions,
4092 replacement_blockhash: blockhash,
4093 fee,
4094 pre_balances,
4095 post_balances,
4096 pre_token_balances: pre_token_balances.map(|balances| {
4097 balances.into_iter().map(|balance| solana_ledger::transaction_balances::svm_token_info_to_token_balance(balance).into()).collect()
4098 }),
4099 post_token_balances: post_token_balances.map(|balances| {
4100 balances.into_iter().map(|balance| solana_ledger::transaction_balances::svm_token_info_to_token_balance(balance).into()).collect()
4101 }),
4102 loaded_addresses: Some(UiLoadedAddresses::from(&transaction.get_loaded_addresses())),
4103 },
4104 ))
4105 }
4106
4107 fn minimum_ledger_slot(&self, meta: Self::Metadata) -> Result<Slot> {
4108 debug!("minimum_ledger_slot rpc request received");
4109 meta.minimum_ledger_slot()
4110 }
4111
4112 fn get_block(
4113 &self,
4114 meta: Self::Metadata,
4115 slot: Slot,
4116 config: Option<RpcEncodingConfigWrapper<RpcBlockConfig>>,
4117 ) -> BoxFuture<Result<Option<UiConfirmedBlock>>> {
4118 debug!("get_block rpc request received: {slot:?}");
4119 Box::pin(async move { meta.get_block(slot, config).await })
4120 }
4121
4122 fn get_blocks(
4123 &self,
4124 meta: Self::Metadata,
4125 start_slot: Slot,
4126 wrapper: Option<RpcBlocksConfigWrapper>,
4127 config: Option<RpcContextConfig>,
4128 ) -> BoxFuture<Result<Vec<Slot>>> {
4129 let (end_slot, maybe_config) =
4130 wrapper.map(|wrapper| wrapper.unzip()).unwrap_or_default();
4131 debug!("get_blocks rpc request received: {start_slot}-{end_slot:?}");
4132 Box::pin(async move {
4133 meta.get_blocks(start_slot, end_slot, config.or(maybe_config))
4134 .await
4135 })
4136 }
4137
4138 fn get_blocks_with_limit(
4139 &self,
4140 meta: Self::Metadata,
4141 start_slot: Slot,
4142 limit: usize,
4143 config: Option<RpcContextConfig>,
4144 ) -> BoxFuture<Result<Vec<Slot>>> {
4145 debug!("get_blocks_with_limit rpc request received: {start_slot}-{limit}",);
4146 Box::pin(async move { meta.get_blocks_with_limit(start_slot, limit, config).await })
4147 }
4148
4149 fn get_block_time(
4150 &self,
4151 meta: Self::Metadata,
4152 slot: Slot,
4153 ) -> BoxFuture<Result<Option<UnixTimestamp>>> {
4154 Box::pin(async move { meta.get_block_time(slot).await })
4155 }
4156
4157 fn get_transaction(
4158 &self,
4159 meta: Self::Metadata,
4160 signature_str: String,
4161 config: Option<RpcEncodingConfigWrapper<RpcTransactionConfig>>,
4162 ) -> BoxFuture<Result<Option<EncodedConfirmedTransactionWithStatusMeta>>> {
4163 debug!("get_transaction rpc request received: {signature_str:?}");
4164 let signature = verify_signature(&signature_str);
4165 if let Err(err) = signature {
4166 return Box::pin(future::err(err));
4167 }
4168 Box::pin(async move { meta.get_transaction(signature.unwrap(), config).await })
4169 }
4170
4171 fn get_signatures_for_address(
4172 &self,
4173 meta: Self::Metadata,
4174 address: String,
4175 config: Option<RpcSignaturesForAddressConfig>,
4176 ) -> BoxFuture<Result<Vec<RpcConfirmedTransactionStatusWithSignature>>> {
4177 let RpcSignaturesForAddressConfig {
4178 before,
4179 until,
4180 limit,
4181 commitment,
4182 min_context_slot,
4183 } = config.unwrap_or_default();
4184 let verification =
4185 verify_and_parse_signatures_for_address_params(address, before, until, limit);
4186
4187 match verification {
4188 Err(err) => Box::pin(future::err(err)),
4189 Ok((address, before, until, limit)) => Box::pin(async move {
4190 meta.get_signatures_for_address(
4191 address,
4192 before,
4193 until,
4194 limit,
4195 RpcContextConfig {
4196 commitment,
4197 min_context_slot,
4198 },
4199 )
4200 .await
4201 }),
4202 }
4203 }
4204
4205 fn get_first_available_block(&self, meta: Self::Metadata) -> BoxFuture<Result<Slot>> {
4206 debug!("get_first_available_block rpc request received");
4207 Box::pin(async move { Ok(meta.get_first_available_block().await) })
4208 }
4209
4210 fn get_inflation_reward(
4211 &self,
4212 meta: Self::Metadata,
4213 address_strs: Vec<String>,
4214 config: Option<RpcEpochConfig>,
4215 ) -> BoxFuture<Result<Vec<Option<RpcInflationReward>>>> {
4216 debug!(
4217 "get_inflation_reward rpc request received: {:?}",
4218 address_strs.len()
4219 );
4220
4221 let mut addresses: Vec<Pubkey> = vec![];
4222 for address_str in address_strs {
4223 match verify_pubkey(&address_str) {
4224 Ok(pubkey) => {
4225 addresses.push(pubkey);
4226 }
4227 Err(err) => return Box::pin(future::err(err)),
4228 }
4229 }
4230
4231 Box::pin(async move { meta.get_inflation_reward(addresses, config).await })
4232 }
4233
4234 fn get_latest_blockhash(
4235 &self,
4236 meta: Self::Metadata,
4237 config: Option<RpcContextConfig>,
4238 ) -> Result<RpcResponse<RpcBlockhash>> {
4239 debug!("get_latest_blockhash rpc request received");
4240 meta.get_latest_blockhash(config.unwrap_or_default())
4241 }
4242
4243 fn is_blockhash_valid(
4244 &self,
4245 meta: Self::Metadata,
4246 blockhash: String,
4247 config: Option<RpcContextConfig>,
4248 ) -> Result<RpcResponse<bool>> {
4249 let blockhash =
4250 Hash::from_str(&blockhash).map_err(|e| Error::invalid_params(format!("{e:?}")))?;
4251 meta.is_blockhash_valid(&blockhash, config.unwrap_or_default())
4252 }
4253
4254 fn get_fee_for_message(
4255 &self,
4256 meta: Self::Metadata,
4257 data: String,
4258 config: Option<RpcContextConfig>,
4259 ) -> Result<RpcResponse<Option<u64>>> {
4260 debug!("get_fee_for_message rpc request received");
4261 let (_, message) = decode_and_deserialize::<VersionedMessage>(
4262 data,
4263 TransactionBinaryEncoding::Base64,
4264 )?;
4265 let bank = &*meta.get_bank_with_config(config.unwrap_or_default())?;
4266 let sanitized_versioned_message = SanitizedVersionedMessage::try_from(message)
4267 .map_err(|err| {
4268 Error::invalid_params(format!("invalid transaction message: {err}"))
4269 })?;
4270 let sanitized_message = SanitizedMessage::try_new(
4271 sanitized_versioned_message,
4272 bank,
4273 bank.get_reserved_account_keys(),
4274 )
4275 .map_err(|err| Error::invalid_params(format!("invalid transaction message: {err}")))?;
4276 let fee = bank.get_fee_for_message(&sanitized_message);
4277 Ok(new_response(bank, fee))
4278 }
4279
4280 fn get_stake_minimum_delegation(
4281 &self,
4282 meta: Self::Metadata,
4283 config: Option<RpcContextConfig>,
4284 ) -> Result<RpcResponse<u64>> {
4285 debug!("get_stake_minimum_delegation rpc request received");
4286 meta.get_stake_minimum_delegation(config.unwrap_or_default())
4287 }
4288
4289 fn get_recent_prioritization_fees(
4290 &self,
4291 meta: Self::Metadata,
4292 pubkey_strs: Option<Vec<String>>,
4293 ) -> Result<Vec<RpcPrioritizationFee>> {
4294 let pubkey_strs = pubkey_strs.unwrap_or_default();
4295 debug!(
4296 "get_recent_prioritization_fees rpc request received: {:?} pubkeys",
4297 pubkey_strs.len()
4298 );
4299 if pubkey_strs.len() > MAX_TX_ACCOUNT_LOCKS {
4300 return Err(Error::invalid_params(format!(
4301 "Too many inputs provided; max {MAX_TX_ACCOUNT_LOCKS}"
4302 )));
4303 }
4304 let pubkeys = pubkey_strs
4305 .into_iter()
4306 .map(|pubkey_str| verify_pubkey(&pubkey_str))
4307 .collect::<Result<Vec<_>>>()?;
4308 meta.get_recent_prioritization_fees(pubkeys)
4309 }
4310 }
4311}
4312
4313fn rpc_perf_sample_from_perf_sample(slot: u64, sample: PerfSample) -> RpcPerfSample {
4314 match sample {
4315 PerfSample::V1(PerfSampleV1 {
4316 num_transactions,
4317 num_slots,
4318 sample_period_secs,
4319 }) => RpcPerfSample {
4320 slot,
4321 num_transactions,
4322 num_non_vote_transactions: None,
4323 num_slots,
4324 sample_period_secs,
4325 },
4326 PerfSample::V2(PerfSampleV2 {
4327 num_transactions,
4328 num_non_vote_transactions,
4329 num_slots,
4330 sample_period_secs,
4331 }) => RpcPerfSample {
4332 slot,
4333 num_transactions,
4334 num_non_vote_transactions: Some(num_non_vote_transactions),
4335 num_slots,
4336 sample_period_secs,
4337 },
4338 }
4339}
4340
4341const MAX_BASE58_SIZE: usize = 1683; const MAX_BASE64_SIZE: usize = 1644; fn decode_and_deserialize<T>(
4344 encoded: String,
4345 encoding: TransactionBinaryEncoding,
4346) -> Result<(Vec<u8>, T)>
4347where
4348 T: serde::de::DeserializeOwned,
4349{
4350 let wire_output = match encoding {
4351 TransactionBinaryEncoding::Base58 => {
4352 inc_new_counter_info!("rpc-base58_encoded_tx", 1);
4353 if encoded.len() > MAX_BASE58_SIZE {
4354 return Err(Error::invalid_params(format!(
4355 "base58 encoded {} too large: {} bytes (max: encoded/raw {}/{})",
4356 type_name::<T>(),
4357 encoded.len(),
4358 MAX_BASE58_SIZE,
4359 PACKET_DATA_SIZE,
4360 )));
4361 }
4362 bs58::decode(encoded)
4363 .into_vec()
4364 .map_err(|e| Error::invalid_params(format!("invalid base58 encoding: {e:?}")))?
4365 }
4366 TransactionBinaryEncoding::Base64 => {
4367 inc_new_counter_info!("rpc-base64_encoded_tx", 1);
4368 if encoded.len() > MAX_BASE64_SIZE {
4369 return Err(Error::invalid_params(format!(
4370 "base64 encoded {} too large: {} bytes (max: encoded/raw {}/{})",
4371 type_name::<T>(),
4372 encoded.len(),
4373 MAX_BASE64_SIZE,
4374 PACKET_DATA_SIZE,
4375 )));
4376 }
4377 BASE64_STANDARD
4378 .decode(encoded)
4379 .map_err(|e| Error::invalid_params(format!("invalid base64 encoding: {e:?}")))?
4380 }
4381 };
4382 if wire_output.len() > PACKET_DATA_SIZE {
4383 return Err(Error::invalid_params(format!(
4384 "decoded {} too large: {} bytes (max: {} bytes)",
4385 type_name::<T>(),
4386 wire_output.len(),
4387 PACKET_DATA_SIZE
4388 )));
4389 }
4390 bincode::options()
4391 .with_limit(PACKET_DATA_SIZE as u64)
4392 .with_fixint_encoding()
4393 .allow_trailing_bytes()
4394 .deserialize_from(&wire_output[..])
4395 .map_err(|err| {
4396 Error::invalid_params(format!(
4397 "failed to deserialize {}: {}",
4398 type_name::<T>(),
4399 &err.to_string()
4400 ))
4401 })
4402 .map(|output| (wire_output, output))
4403}
4404
4405fn sanitize_transaction(
4406 transaction: VersionedTransaction,
4407 address_loader: impl AddressLoader,
4408 reserved_account_keys: &HashSet<Pubkey>,
4409 enable_static_instruction_limit: bool,
4410) -> Result<RuntimeTransaction<SanitizedTransaction>> {
4411 RuntimeTransaction::try_create(
4412 transaction,
4413 MessageHash::Compute,
4414 None,
4415 address_loader,
4416 reserved_account_keys,
4417 enable_static_instruction_limit,
4418 )
4419 .map_err(|err| Error::invalid_params(format!("invalid transaction: {err}")))
4420}
4421
4422pub fn create_validator_exit(exit: Arc<AtomicBool>) -> Arc<RwLock<Exit>> {
4423 let mut validator_exit = Exit::default();
4424 validator_exit.register_exit(Box::new(move || exit.store(true, Ordering::Relaxed)));
4425 Arc::new(RwLock::new(validator_exit))
4426}
4427
4428pub fn create_test_transaction_entries(
4429 keypairs: Vec<&Keypair>,
4430 bank: Arc<Bank>,
4431) -> (Vec<Entry>, Vec<Signature>) {
4432 let mint_keypair = keypairs[0];
4433 let keypair1 = keypairs[1];
4434 let keypair2 = keypairs[2];
4435 let keypair3 = keypairs[3];
4436 let blockhash = bank.confirmed_last_blockhash();
4437 let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
4438
4439 let mut signatures = Vec::new();
4440 let success_tx = solana_system_transaction::transfer(
4443 mint_keypair,
4444 &keypair1.pubkey(),
4445 rent_exempt_amount,
4446 blockhash,
4447 );
4448 signatures.push(success_tx.signatures[0]);
4449 let entry_1 = solana_entry::entry::next_entry(&blockhash, 1, vec![success_tx]);
4450 let ix_error_tx = solana_system_transaction::transfer(
4452 keypair2,
4453 &keypair3.pubkey(),
4454 2 * rent_exempt_amount,
4455 blockhash,
4456 );
4457 signatures.push(ix_error_tx.signatures[0]);
4458 let entry_2 = solana_entry::entry::next_entry(&entry_1.hash, 1, vec![ix_error_tx]);
4459 (vec![entry_1, entry_2], signatures)
4460}
4461
4462#[cfg(feature = "dev-context-only-utils")]
4463pub fn populate_blockstore_for_tests(
4464 entries: Vec<Entry>,
4465 bank: Arc<Bank>,
4466 blockstore: Arc<Blockstore>,
4467 max_complete_transaction_status_slot: Arc<AtomicU64>,
4468) {
4469 let slot = bank.slot();
4470 let parent_slot = bank.parent_slot();
4471 let shreds =
4472 solana_ledger::blockstore::entries_to_test_shreds(&entries, slot, parent_slot, true, 0);
4473 blockstore.insert_shreds(shreds, None, false).unwrap();
4474 blockstore.set_roots(std::iter::once(&slot)).unwrap();
4475
4476 let (transaction_status_sender, transaction_status_receiver) = unbounded();
4477 let (replay_vote_sender, _replay_vote_receiver) = unbounded();
4478 let tss_exit = Arc::new(AtomicBool::new(false));
4479 let transaction_status_service =
4480 crate::transaction_status_service::TransactionStatusService::new(
4481 transaction_status_receiver,
4482 max_complete_transaction_status_slot,
4483 true,
4484 None,
4485 blockstore,
4486 false,
4487 None,
4488 tss_exit.clone(),
4489 );
4490
4491 assert_eq!(
4494 solana_ledger::blockstore_processor::process_entries_for_tests(
4495 &BankWithScheduler::new_without_scheduler(bank),
4496 entries,
4497 Some(
4498 &solana_ledger::blockstore_processor::TransactionStatusSender {
4499 sender: transaction_status_sender,
4500 dependency_tracker: None,
4501 },
4502 ),
4503 Some(&replay_vote_sender),
4504 ),
4505 Ok(())
4506 );
4507
4508 transaction_status_service.quiesce_and_join_for_tests(tss_exit);
4509}
4510
4511#[cfg(test)]
4512pub mod tests {
4513 use {
4514 super::{
4515 rpc_accounts::*, rpc_accounts_scan::*, rpc_bank::*, rpc_full::*, rpc_minimal::*, *,
4516 },
4517 crate::{
4518 optimistically_confirmed_bank_tracker::{
4519 BankNotification, OptimisticallyConfirmedBankTracker,
4520 },
4521 rpc_service::service_runtime,
4522 rpc_subscriptions::RpcSubscriptions,
4523 },
4524 agave_reserved_account_keys::ReservedAccountKeys,
4525 bincode::deserialize,
4526 jsonrpc_core::{futures, ErrorCode, MetaIoHandler, Output, Response, Value},
4527 jsonrpc_core_client::transports::local,
4528 serde::de::DeserializeOwned,
4529 solana_account::{state_traits::StateMut, Account, WritableAccount},
4530 solana_accounts_db::accounts_db::{AccountsDbConfig, ACCOUNTS_DB_CONFIG_FOR_TESTING},
4531 solana_address_lookup_table_interface::{
4532 self as address_lookup_table,
4533 state::{AddressLookupTable, LookupTableMeta},
4534 },
4535 solana_compute_budget_interface::ComputeBudgetInstruction,
4536 solana_entry::entry::next_versioned_entry,
4537 solana_fee_calculator::FeeRateGovernor,
4538 solana_gossip::{contact_info::ContactInfo, socketaddr},
4539 solana_instruction::{error::InstructionError, AccountMeta, Instruction},
4540 solana_keypair::Keypair,
4541 solana_ledger::{
4542 blockstore_meta::PerfSampleV2,
4543 blockstore_processor::fill_blockstore_slot_with_ticks,
4544 genesis_utils::{create_genesis_config, GenesisConfigInfo},
4545 get_tmp_ledger_path,
4546 },
4547 solana_message::{
4548 v0::{self, MessageAddressTableLookup},
4549 Message, MessageHeader, SimpleAddressLoader, VersionedMessage,
4550 },
4551 solana_nonce::{self as nonce, state::DurableNonce},
4552 solana_program_option::COption,
4553 solana_program_runtime::{
4554 invoke_context::InvokeContext,
4555 loaded_programs::ProgramCacheEntry,
4556 solana_sbpf::{declare_builtin_function, memory_region::MemoryMapping},
4557 },
4558 solana_rpc_client_api::{
4559 custom_error::{
4560 JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE,
4561 JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE,
4562 JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION,
4563 },
4564 filter::MemcmpEncodedBytes,
4565 },
4566 solana_runtime::{
4567 bank::BankTestConfig,
4568 commitment::{BlockCommitment, CommitmentSlots},
4569 non_circulating_supply::non_circulating_accounts,
4570 },
4571 solana_sdk_ids::bpf_loader_upgradeable,
4572 solana_send_transaction_service::{
4573 tpu_info::NullTpuInfo,
4574 transaction_client::{ConnectionCacheClient, TpuClientNextClient},
4575 },
4576 solana_sha256_hasher::hash,
4577 solana_signer::Signer,
4578 solana_svm::account_loader::TRANSACTION_ACCOUNT_BASE_SIZE,
4579 solana_svm_log_collector::ic_logger_msg,
4580 solana_system_interface::{instruction as system_instruction, program as system_program},
4581 solana_system_transaction as system_transaction,
4582 solana_sysvar::slot_hashes::SlotHashes,
4583 solana_time_utils::slot_duration_from_slots_per_year,
4584 solana_transaction::{versioned::TransactionVersion, Transaction},
4585 solana_transaction_error::TransactionError,
4586 solana_transaction_status::{
4587 EncodedConfirmedBlock, EncodedTransaction, EncodedTransactionWithStatusMeta,
4588 TransactionDetails,
4589 },
4590 solana_vote_interface::state::VoteStateV4,
4591 solana_vote_program::{
4592 vote_instruction,
4593 vote_state::{TowerSync, VoteInit, VoteStateVersions, MAX_LOCKOUT_HISTORY},
4594 },
4595 spl_pod::optional_keys::OptionalNonZeroPubkey,
4596 spl_token_2022_interface::{
4597 extension::{
4598 immutable_owner::ImmutableOwner, memo_transfer::MemoTransfer,
4599 mint_close_authority::MintCloseAuthority, BaseStateWithExtensionsMut,
4600 ExtensionType, StateWithExtensionsMut,
4601 },
4602 state::{AccountState as TokenAccountState, Mint},
4603 },
4604 std::{borrow::Cow, collections::HashMap, net::Ipv4Addr},
4605 test_case::test_case,
4606 };
4607
4608 const TEST_MINT_LAMPORTS: u64 = 1_000_000_000;
4609 const TEST_SIGNATURE_FEE: u64 = 5_000;
4610 const TEST_SLOTS_PER_EPOCH: u64 = DELINQUENT_VALIDATOR_SLOT_DISTANCE + 1;
4611
4612 pub(crate) fn new_test_cluster_info() -> ClusterInfo {
4613 let keypair = Arc::new(Keypair::new());
4614 let contact_info = ContactInfo::new_localhost(
4615 &keypair.pubkey(),
4616 solana_time_utils::timestamp(), );
4618 ClusterInfo::new(contact_info, keypair, SocketAddrSpace::Unspecified)
4619 }
4620
4621 fn create_test_request(method: &str, params: Option<serde_json::Value>) -> serde_json::Value {
4622 json!({
4623 "jsonrpc": "2.0",
4624 "id": 1u64,
4625 "method": method,
4626 "params": params,
4627 })
4628 }
4629
4630 fn parse_success_result<T: DeserializeOwned>(response: Response) -> T {
4631 if let Response::Single(output) = response {
4632 match output {
4633 Output::Success(success) => serde_json::from_value(success.result).unwrap(),
4634 Output::Failure(failure) => {
4635 panic!("Expected success but received: {failure:?}");
4636 }
4637 }
4638 } else {
4639 panic!("Expected single response");
4640 }
4641 }
4642
4643 fn parse_failure_response(response: Response) -> (i64, String) {
4644 if let Response::Single(output) = response {
4645 match output {
4646 Output::Success(success) => {
4647 panic!("Expected failure but received: {success:?}");
4648 }
4649 Output::Failure(failure) => (failure.error.code.code(), failure.error.message),
4650 }
4651 } else {
4652 panic!("Expected single response");
4653 }
4654 }
4655
4656 fn expected_loaded_accounts_data_size(bank: &Bank, tx: &Transaction) -> u32 {
4657 let mut loaded_accounts_data_size = 0;
4658 for key in tx.message.account_keys.iter() {
4659 if let Some(account) = bank.get_account(key) {
4660 assert!(
4661 *account.owner() != bpf_loader_upgradeable::id(),
4662 "LoaderV3 is not supported; to add it, parse the program account and add its \
4663 programdata size.",
4664 );
4665 loaded_accounts_data_size +=
4666 (account.data().len() + TRANSACTION_ACCOUNT_BASE_SIZE) as u32;
4667 }
4668 }
4669
4670 loaded_accounts_data_size
4671 }
4672
4673 fn test_builtin_processor(
4674 invoke_context: &mut InvokeContext,
4675 ) -> std::result::Result<u64, Box<dyn std::error::Error>> {
4676 let log_collector = invoke_context.get_log_collector();
4677 invoke_context.consume_checked(TestBuiltinEntrypoint::COMPUTE_UNITS)?;
4678
4679 let transaction_context = &invoke_context.transaction_context;
4680 let instruction_context = transaction_context.get_current_instruction_context()?;
4681
4682 let instruction_data = instruction_context.get_instruction_data();
4683 let (lamports, space) = {
4684 let (l_bytes, s_bytes) = instruction_data.split_at(8);
4685 let lamports = u64::from_le_bytes(l_bytes.try_into().unwrap());
4686 let space = u64::from_le_bytes(s_bytes.try_into().unwrap());
4687 (lamports, space)
4688 };
4689
4690 ic_logger_msg!(log_collector, "I am logging from a builtin program!");
4691 ic_logger_msg!(log_collector, "I am about to CPI to System!");
4692
4693 let from_pubkey = *instruction_context.get_key_of_instruction_account(0)?;
4694 let to_pubkey = *instruction_context.get_key_of_instruction_account(1)?;
4695 let owner_pubkey = *instruction_context.get_key_of_instruction_account(2)?;
4696
4697 invoke_context.native_invoke(
4698 system_instruction::create_account(
4699 &from_pubkey,
4700 &to_pubkey,
4701 lamports,
4702 space,
4703 &owner_pubkey,
4704 ),
4705 &[],
4706 )?;
4707
4708 ic_logger_msg!(log_collector, "All done!");
4709 Ok(0)
4710 }
4711
4712 declare_builtin_function!(
4713 TestBuiltinEntrypoint,
4714 fn rust(
4715 invoke_context: &mut InvokeContext,
4716 _arg0: u64,
4717 _arg1: u64,
4718 _arg2: u64,
4719 _arg3: u64,
4720 _arg4: u64,
4721 _memory_mapping: &mut MemoryMapping,
4722 ) -> std::result::Result<u64, Box<dyn std::error::Error>> {
4723 test_builtin_processor(invoke_context)
4724 }
4725 );
4726
4727 impl TestBuiltinEntrypoint {
4728 const COMPUTE_UNITS: u64 = 800;
4729 const NAME: &str = "test_builtin";
4730 const PROGRAM_ID: Pubkey =
4731 solana_pubkey::pubkey!("TestProgram11111111111111111111111111111111");
4732
4733 fn cache_entry() -> ProgramCacheEntry {
4734 ProgramCacheEntry::new_builtin(0, Self::NAME.len(), Self::vm)
4735 }
4736
4737 fn instruction(
4738 from: &Pubkey,
4739 to: &Pubkey,
4740 lamports: u64,
4741 space: u64,
4742 owner: &Pubkey,
4743 ) -> Instruction {
4744 let data = {
4745 let mut data = vec![0; 16];
4746 data[0..8].copy_from_slice(&lamports.to_le_bytes());
4747 data[8..16].copy_from_slice(&space.to_le_bytes());
4748 data
4749 };
4750 Instruction::new_with_bytes(
4751 Self::PROGRAM_ID,
4752 &data,
4753 vec![
4754 AccountMeta::new(*from, true),
4755 AccountMeta::new(*to, true),
4756 AccountMeta::new_readonly(*owner, false),
4757 AccountMeta::new_readonly(system_program::id(), false),
4758 ],
4759 )
4760 }
4761 }
4762
4763 struct RpcHandler {
4764 io: MetaIoHandler<JsonRpcRequestProcessor>,
4765 meta: JsonRpcRequestProcessor,
4766 identity: Pubkey,
4767 mint_keypair: Keypair,
4768 leader_vote_keypair: Arc<Keypair>,
4769 blockstore: Arc<Blockstore>,
4770 bank_forks: Arc<RwLock<BankForks>>,
4771 max_slots: Arc<MaxSlots>,
4772 max_complete_transaction_status_slot: Arc<AtomicU64>,
4773 block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
4774 }
4775
4776 impl RpcHandler {
4777 fn start() -> Self {
4778 Self::start_with_config(JsonRpcConfig {
4779 enable_rpc_transaction_history: true,
4780 ..JsonRpcConfig::default()
4781 })
4782 }
4783
4784 fn start_with_config(config: JsonRpcConfig) -> Self {
4785 let (bank_forks, mint_keypair, leader_vote_keypair) =
4786 new_bank_forks_with_config(BankTestConfig {
4787 accounts_db_config: AccountsDbConfig {
4788 account_indexes: Some(config.account_indexes.clone()),
4789 ..ACCOUNTS_DB_CONFIG_FOR_TESTING
4790 },
4791 });
4792
4793 let ledger_path = get_tmp_ledger_path!();
4794 let blockstore = Arc::new(Blockstore::open(&ledger_path).unwrap());
4795 let bank = bank_forks.read().unwrap().working_bank();
4796
4797 let leader_pubkey = *bank.collector_id();
4798 let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
4799 let exit = Arc::new(AtomicBool::new(false));
4800 let validator_exit = create_validator_exit(exit);
4801 let cluster_info = Arc::new(new_test_cluster_info());
4802 let identity = cluster_info.id();
4803 cluster_info.insert_info(ContactInfo::new_with_socketaddr(
4804 &leader_pubkey,
4805 &socketaddr!(Ipv4Addr::LOCALHOST, 1234),
4806 ));
4807 let max_slots = Arc::new(MaxSlots::default());
4808 let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(0));
4810 let optimistically_confirmed_bank =
4811 OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
4812
4813 let JsonRpcConfig {
4814 rpc_threads,
4815 rpc_blocking_threads,
4816 rpc_niceness_adj,
4817 ..
4818 } = config;
4819 let meta = JsonRpcRequestProcessor::new(
4820 config,
4821 None,
4822 bank_forks.clone(),
4823 block_commitment_cache.clone(),
4824 blockstore.clone(),
4825 validator_exit,
4826 RpcHealth::stub(optimistically_confirmed_bank.clone(), blockstore.clone()),
4827 cluster_info,
4828 Hash::default(),
4829 None,
4830 optimistically_confirmed_bank,
4831 Arc::new(RwLock::new(LargestAccountsCache::new(30))),
4832 max_slots.clone(),
4833 Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
4834 max_complete_transaction_status_slot.clone(),
4835 Arc::new(PrioritizationFeeCache::default()),
4836 service_runtime(rpc_threads, rpc_blocking_threads, rpc_niceness_adj),
4837 )
4838 .0;
4839
4840 let mut io = MetaIoHandler::default();
4841 io.extend_with(rpc_minimal::MinimalImpl.to_delegate());
4842 io.extend_with(rpc_bank::BankDataImpl.to_delegate());
4843 io.extend_with(rpc_accounts::AccountsDataImpl.to_delegate());
4844 io.extend_with(rpc_accounts_scan::AccountsScanImpl.to_delegate());
4845 io.extend_with(rpc_full::FullImpl.to_delegate());
4846 Self {
4847 io,
4848 meta,
4849 identity,
4850 mint_keypair,
4851 leader_vote_keypair,
4852 bank_forks,
4853 blockstore,
4854 max_slots,
4855 max_complete_transaction_status_slot,
4856 block_commitment_cache,
4857 }
4858 }
4859
4860 fn handle_request_sync(&self, req: serde_json::Value) -> Response {
4861 let response = &self
4862 .io
4863 .handle_request_sync(&req.to_string(), self.meta.clone())
4864 .expect("no response");
4865 serde_json::from_str(response).expect("failed to deserialize response")
4866 }
4867
4868 fn overwrite_working_bank_entries(&self, entries: Vec<Entry>) {
4869 populate_blockstore_for_tests(
4870 entries,
4871 self.working_bank(),
4872 self.blockstore.clone(),
4873 self.max_complete_transaction_status_slot.clone(),
4874 );
4875 }
4876
4877 fn create_test_transactions_and_populate_blockstore(&self) -> Vec<Signature> {
4878 let mint_keypair = &self.mint_keypair;
4879 let keypair1 = Keypair::new();
4880 let keypair2 = Keypair::new();
4881 let keypair3 = Keypair::new();
4882 let bank = self.working_bank();
4883 let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
4884 bank.transfer(
4885 rent_exempt_amount + TEST_SIGNATURE_FEE,
4886 mint_keypair,
4887 &keypair2.pubkey(),
4888 )
4889 .unwrap();
4890
4891 let (entries, signatures) = create_test_transaction_entries(
4892 vec![&self.mint_keypair, &keypair1, &keypair2, &keypair3],
4893 bank,
4894 );
4895 self.overwrite_working_bank_entries(entries);
4896 signatures
4897 }
4898
4899 fn create_test_versioned_transactions_and_populate_blockstore(
4900 &self,
4901 address_table_key: Option<Pubkey>,
4902 ) -> Vec<Signature> {
4903 let address_table_key =
4904 address_table_key.unwrap_or_else(|| self.store_address_lookup_table());
4905
4906 let bank = self.working_bank();
4907 let recent_blockhash = bank.confirmed_last_blockhash();
4908 let legacy_message = VersionedMessage::Legacy(Message {
4909 header: MessageHeader {
4910 num_required_signatures: 1,
4911 num_readonly_signed_accounts: 0,
4912 num_readonly_unsigned_accounts: 0,
4913 },
4914 recent_blockhash,
4915 account_keys: vec![self.mint_keypair.pubkey()],
4916 instructions: vec![],
4917 });
4918 let version_0_message = VersionedMessage::V0(v0::Message {
4919 header: MessageHeader {
4920 num_required_signatures: 1,
4921 num_readonly_signed_accounts: 0,
4922 num_readonly_unsigned_accounts: 0,
4923 },
4924 recent_blockhash,
4925 account_keys: vec![self.mint_keypair.pubkey()],
4926 address_table_lookups: vec![MessageAddressTableLookup {
4927 account_key: address_table_key,
4928 writable_indexes: vec![0],
4929 readonly_indexes: vec![],
4930 }],
4931 instructions: vec![],
4932 });
4933
4934 let mut signatures = Vec::new();
4935 let legacy_tx =
4936 VersionedTransaction::try_new(legacy_message, &[&self.mint_keypair]).unwrap();
4937 signatures.push(legacy_tx.signatures[0]);
4938 let version_0_tx =
4939 VersionedTransaction::try_new(version_0_message, &[&self.mint_keypair]).unwrap();
4940 signatures.push(version_0_tx.signatures[0]);
4941 let entry1 = next_versioned_entry(&recent_blockhash, 1, vec![legacy_tx]);
4942 let entry2 = next_versioned_entry(&entry1.hash, 1, vec![version_0_tx]);
4943 let entries = vec![entry1, entry2];
4944 self.overwrite_working_bank_entries(entries);
4945 signatures
4946 }
4947
4948 fn store_address_lookup_table(&self) -> Pubkey {
4949 let bank = self.working_bank();
4950 let address_table_pubkey = Pubkey::new_unique();
4951 let address_table_account = {
4952 let address_table_state = AddressLookupTable {
4953 meta: LookupTableMeta {
4954 last_extended_slot_start_index: 1,
4956 ..LookupTableMeta::default()
4957 },
4958 addresses: Cow::Owned(vec![Pubkey::new_unique()]),
4959 };
4960 let address_table_data = address_table_state.serialize_for_tests().unwrap();
4961 let min_balance_lamports =
4962 bank.get_minimum_balance_for_rent_exemption(address_table_data.len());
4963 AccountSharedData::create(
4964 min_balance_lamports,
4965 address_table_data,
4966 address_lookup_table::program::id(),
4967 false,
4968 0,
4969 )
4970 };
4971 bank.store_account(&address_table_pubkey, &address_table_account);
4972 address_table_pubkey
4973 }
4974
4975 fn add_roots_to_blockstore(&self, mut roots: Vec<Slot>) {
4976 roots.retain(|&slot| slot > 0);
4977 if roots.is_empty() {
4978 return;
4979 }
4980
4981 let mut parent_bank = self.bank_forks.read().unwrap().working_bank();
4982 for (i, root) in roots.iter().enumerate() {
4983 let new_bank =
4984 Bank::new_from_parent(parent_bank.clone(), parent_bank.collector_id(), *root);
4985 parent_bank = self
4986 .bank_forks
4987 .write()
4988 .unwrap()
4989 .insert(new_bank)
4990 .clone_without_scheduler();
4991 let parent = if i > 0 { roots[i - 1] } else { 0 };
4992 fill_blockstore_slot_with_ticks(
4993 &self.blockstore,
4994 5,
4995 *root,
4996 parent,
4997 Hash::default(),
4998 );
4999 }
5000 self.blockstore.set_roots(roots.iter()).unwrap();
5001 let new_bank = Bank::new_from_parent(
5002 parent_bank.clone(),
5003 parent_bank.collector_id(),
5004 roots.iter().max().unwrap() + 1,
5005 );
5006 self.bank_forks.write().unwrap().insert(new_bank);
5007
5008 for root in roots.iter() {
5009 self.bank_forks
5010 .write()
5011 .unwrap()
5012 .set_root(*root, None, Some(0));
5013 let block_time = self
5014 .bank_forks
5015 .read()
5016 .unwrap()
5017 .get(*root)
5018 .unwrap()
5019 .clock()
5020 .unix_timestamp;
5021 self.blockstore.set_block_time(*root, block_time).unwrap();
5022 }
5023 }
5024
5025 fn advance_bank_to_confirmed_slot(&self, slot: Slot) -> Arc<Bank> {
5026 let parent_bank = self.working_bank();
5027 let bank = self
5028 .bank_forks
5029 .write()
5030 .unwrap()
5031 .insert(Bank::new_from_parent(parent_bank, &Pubkey::default(), slot))
5032 .clone_without_scheduler();
5033
5034 let new_block_commitment = BlockCommitmentCache::new(
5035 HashMap::new(),
5036 0,
5037 CommitmentSlots::new_from_slot(self.bank_forks.read().unwrap().highest_slot()),
5038 );
5039 *self.block_commitment_cache.write().unwrap() = new_block_commitment;
5040 bank
5041 }
5042
5043 fn store_vote_account(&self, vote_pubkey: &Pubkey, vote_state: VoteStateV4) {
5044 let bank = self.working_bank();
5045 let versioned = VoteStateVersions::new_v4(vote_state);
5046 let space = VoteStateV4::size_of();
5047 let balance = bank.get_minimum_balance_for_rent_exemption(space);
5048 let mut vote_account =
5049 AccountSharedData::new(balance, space, &solana_vote_program::id());
5050 vote_account.set_state(&versioned).unwrap();
5051 bank.store_account(vote_pubkey, &vote_account);
5052 }
5053
5054 fn update_prioritization_fee_cache(&self, transactions: Vec<Transaction>) {
5055 let bank = self.working_bank();
5056
5057 let transactions: Vec<_> = transactions
5058 .into_iter()
5059 .map(RuntimeTransaction::from_transaction_for_tests)
5060 .collect();
5061
5062 let prioritization_fee_cache = &self.meta.prioritization_fee_cache;
5063 prioritization_fee_cache.update(&bank, transactions.iter());
5064 }
5065
5066 fn get_prioritization_fee_cache(&self) -> &PrioritizationFeeCache {
5067 &self.meta.prioritization_fee_cache
5068 }
5069
5070 fn working_bank(&self) -> Arc<Bank> {
5071 self.bank_forks.read().unwrap().working_bank()
5072 }
5073
5074 fn leader_pubkey(&self) -> Pubkey {
5075 *self.working_bank().collector_id()
5076 }
5077 }
5078
5079 fn rpc_request_processor_new<Client: ClientWithCreator>() {
5080 let bob_pubkey = solana_pubkey::new_rand();
5081 let genesis = create_genesis_config(100);
5082 let bank = Bank::new_for_tests(&genesis.genesis_config);
5083 let meta =
5084 JsonRpcRequestProcessor::new_from_bank::<Client>(bank, SocketAddrSpace::Unspecified);
5085
5086 let bank = meta.bank_forks.read().unwrap().root_bank();
5087 bank.transfer(20, &genesis.mint_keypair, &bob_pubkey)
5088 .unwrap();
5089
5090 assert_eq!(
5091 meta.get_transaction_count(RpcContextConfig::default())
5092 .unwrap(),
5093 1
5094 );
5095 }
5096
5097 #[test]
5099 fn test_rpc_request_processor_new_connection_cache() {
5100 rpc_request_processor_new::<ConnectionCacheClient<NullTpuInfo>>();
5101 }
5102
5103 #[test]
5104 fn test_rpc_request_processor_new_tpu_client_next() {
5105 rpc_request_processor_new::<TpuClientNextClient>();
5106 }
5107
5108 fn rpc_get_balance<Client: ClientWithCreator>() {
5109 let genesis = create_genesis_config(20);
5110 let mint_pubkey = genesis.mint_keypair.pubkey();
5111 let bank = Bank::new_for_tests(&genesis.genesis_config);
5112 let meta =
5113 JsonRpcRequestProcessor::new_from_bank::<Client>(bank, SocketAddrSpace::Unspecified);
5114
5115 let mut io = MetaIoHandler::default();
5116 io.extend_with(rpc_minimal::MinimalImpl.to_delegate());
5117
5118 let req = format!(
5119 r#"{{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["{mint_pubkey}"]}}"#
5120 );
5121 let res = io.handle_request_sync(&req, meta);
5122 let expected = json!({
5123 "jsonrpc": "2.0",
5124 "result": {
5125 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
5126 "value":20,
5127 },
5128 "id": 1,
5129 });
5130 let result = serde_json::from_str::<Value>(&res.expect("actual response"))
5131 .expect("actual response deserialization");
5132 assert_eq!(result, expected);
5133 }
5134
5135 #[test]
5136 fn test_rpc_get_balance_new_connection_cache() {
5137 rpc_get_balance::<ConnectionCacheClient<NullTpuInfo>>();
5138 }
5139
5140 #[test]
5141 fn test_rpc_get_balance_new_tpu_client_next() {
5142 rpc_get_balance::<TpuClientNextClient>();
5143 }
5144
5145 fn rpc_get_balance_via_client<Client: ClientWithCreator>() {
5146 let genesis = create_genesis_config(20);
5147 let mint_pubkey = genesis.mint_keypair.pubkey();
5148 let bank = Bank::new_for_tests(&genesis.genesis_config);
5149 let meta =
5150 JsonRpcRequestProcessor::new_from_bank::<Client>(bank, SocketAddrSpace::Unspecified);
5151
5152 let mut io = MetaIoHandler::default();
5153 io.extend_with(rpc_minimal::MinimalImpl.to_delegate());
5154
5155 async fn use_client(client: rpc_minimal::gen_client::Client, mint_pubkey: Pubkey) -> u64 {
5156 client
5157 .get_balance(mint_pubkey.to_string(), None)
5158 .await
5159 .unwrap()
5160 .value
5161 }
5162
5163 let fut = async {
5164 let (client, server) =
5165 local::connect_with_metadata::<rpc_minimal::gen_client::Client, _, _>(&io, meta);
5166 let client = use_client(client, mint_pubkey);
5167
5168 futures::join!(client, server)
5169 };
5170 let (response, _) = futures::executor::block_on(fut);
5171 assert_eq!(response, 20);
5172 }
5173
5174 #[test]
5175 fn test_rpc_get_balance_via_client_connection_cache() {
5176 rpc_get_balance_via_client::<ConnectionCacheClient<NullTpuInfo>>();
5177 }
5178
5179 #[test]
5180 fn test_rpc_get_balance_via_client_tpu_client_next() {
5181 rpc_get_balance_via_client::<TpuClientNextClient>();
5182 }
5183
5184 #[test]
5185 fn test_rpc_get_cluster_nodes() {
5186 let rpc = RpcHandler::start();
5187 let version = solana_version::Version::default();
5188 let request = create_test_request("getClusterNodes", None);
5189 let result: Value = parse_success_result(rpc.handle_request_sync(request));
5190 let expected = json!([{
5191 "pubkey": rpc.identity.to_string(),
5192 "gossip": "127.0.0.1:8000",
5193 "shredVersion": 0u16,
5194 "tvu": "127.0.0.1:8001",
5195 "tpu": "127.0.0.1:8003",
5196 "tpuQuic": "127.0.0.1:8009",
5197 "tpuForwards": "127.0.0.1:8004",
5198 "tpuForwardsQuic": "127.0.0.1:8010",
5199 "tpuVote": "127.0.0.1:8005",
5200 "serveRepair": "127.0.0.1:8008",
5201 "rpc": format!("127.0.0.1:8899"),
5202 "pubsub": format!("127.0.0.1:8900"),
5203 "version": format!("{version}"),
5204 "featureSet": version.feature_set,
5205 }, {
5206 "pubkey": rpc.leader_pubkey().to_string(),
5207 "gossip": "127.0.0.1:1235",
5208 "shredVersion": 0u16,
5209 "tvu": "127.0.0.1:1236",
5210 "tpu": "127.0.0.1:1234",
5211 "tpuQuic": "127.0.0.1:1240",
5212 "tpuForwards": "127.0.0.1:1239",
5213 "tpuForwardsQuic": "127.0.0.1:1245",
5214 "tpuVote": "127.0.0.1:1241",
5215 "serveRepair": "127.0.0.1:1242",
5216 "rpc": format!("127.0.0.1:8899"),
5217 "pubsub": format!("127.0.0.1:8900"),
5218 "version": format!("{version}"),
5219 "featureSet": version.feature_set,
5220 }]);
5221 assert_eq!(result, expected);
5222 }
5223
5224 #[test]
5225 fn test_rpc_get_recent_performance_samples() {
5226 let rpc = RpcHandler::start();
5227
5228 let slot = 0;
5229 let num_slots = 1;
5230 let num_transactions = 4;
5231 let num_non_vote_transactions = 1;
5232 let sample_period_secs = 60;
5233 rpc.blockstore
5234 .write_perf_sample(
5235 slot,
5236 &PerfSampleV2 {
5237 num_slots,
5238 num_transactions,
5239 num_non_vote_transactions,
5240 sample_period_secs,
5241 },
5242 )
5243 .expect("write to blockstore");
5244
5245 let request = create_test_request("getRecentPerformanceSamples", None);
5246 let result: Value = parse_success_result(rpc.handle_request_sync(request));
5247 let expected = json!([{
5248 "slot": slot,
5249 "numSlots": num_slots,
5250 "numTransactions": num_transactions,
5251 "numNonVoteTransactions": num_non_vote_transactions,
5252 "samplePeriodSecs": sample_period_secs,
5253 }]);
5254 assert_eq!(result, expected);
5255 }
5256
5257 #[test]
5258 fn test_rpc_get_recent_performance_samples_invalid_limit() {
5259 let rpc = RpcHandler::start();
5260 let request = create_test_request("getRecentPerformanceSamples", Some(json!([10_000])));
5261 let response = parse_failure_response(rpc.handle_request_sync(request));
5262 let expected = (
5263 ErrorCode::InvalidParams.code(),
5264 String::from("Invalid limit; max 720"),
5265 );
5266 assert_eq!(response, expected);
5267 }
5268
5269 #[test]
5270 fn test_rpc_get_slot_leader() {
5271 let rpc = RpcHandler::start();
5272 let request = create_test_request("getSlotLeader", None);
5273 let result: String = parse_success_result(rpc.handle_request_sync(request));
5274 let expected = rpc.leader_pubkey().to_string();
5275 assert_eq!(result, expected);
5276 }
5277
5278 fn rpc_get_tx_count<Client: ClientWithCreator>() {
5279 let bob_pubkey = solana_pubkey::new_rand();
5280 let genesis = create_genesis_config(10);
5281 let bank = Bank::new_for_tests(&genesis.genesis_config);
5282 let meta =
5283 JsonRpcRequestProcessor::new_from_bank::<Client>(bank, SocketAddrSpace::Unspecified);
5284
5285 let mut io = MetaIoHandler::default();
5286 io.extend_with(rpc_minimal::MinimalImpl.to_delegate());
5287
5288 let bank = meta.bank_forks.read().unwrap().root_bank();
5290 bank.transfer(1, &genesis.mint_keypair, &bob_pubkey)
5291 .unwrap();
5292 bank.transfer(2, &genesis.mint_keypair, &bob_pubkey)
5293 .unwrap();
5294 bank.transfer(3, &genesis.mint_keypair, &bob_pubkey)
5295 .unwrap();
5296 bank.transfer(4, &genesis.mint_keypair, &bob_pubkey)
5297 .unwrap();
5298
5299 let req = r#"{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}"#;
5300 let res = io.handle_request_sync(req, meta);
5301 let expected = r#"{"jsonrpc":"2.0","result":4,"id":1}"#;
5302 let expected: Response =
5303 serde_json::from_str(expected).expect("expected response deserialization");
5304 let result: Response = serde_json::from_str(&res.expect("actual response"))
5305 .expect("actual response deserialization");
5306 assert_eq!(result, expected);
5307 }
5308
5309 #[test]
5310 fn test_rpc_get_tx_count_connection_cache() {
5311 rpc_get_tx_count::<ConnectionCacheClient<NullTpuInfo>>();
5312 }
5313
5314 #[test]
5315 fn test_rpc_get_tx_count_tpu_client_next() {
5316 rpc_get_tx_count::<TpuClientNextClient>();
5317 }
5318
5319 #[test]
5320 fn test_rpc_minimum_ledger_slot() {
5321 let rpc = RpcHandler::start();
5322 rpc.create_test_transactions_and_populate_blockstore();
5324 let request = create_test_request("minimumLedgerSlot", None);
5325 let result: Slot = parse_success_result(rpc.handle_request_sync(request));
5326 assert_eq!(0, result);
5327 }
5328
5329 #[test]
5330 fn test_get_supply() {
5331 let rpc = RpcHandler::start();
5332 let request = create_test_request("getSupply", None);
5333 let result = {
5334 let mut result: RpcResponse<RpcSupply> =
5335 parse_success_result(rpc.handle_request_sync(request));
5336 result.value.non_circulating_accounts.sort();
5337 result.value
5338 };
5339 let expected = {
5340 let mut non_circulating_accounts: Vec<String> = non_circulating_accounts()
5341 .iter()
5342 .map(|pubkey| pubkey.to_string())
5343 .collect();
5344 non_circulating_accounts.sort();
5345 let total_capitalization = rpc.working_bank().capitalization();
5346 RpcSupply {
5347 non_circulating: 0,
5348 circulating: total_capitalization,
5349 total: total_capitalization,
5350 non_circulating_accounts,
5351 }
5352 };
5353 assert_eq!(result, expected);
5354 }
5355
5356 #[test]
5357 fn test_get_supply_exclude_account_list() {
5358 let rpc = RpcHandler::start();
5359 let request = create_test_request(
5360 "getSupply",
5361 Some(json!([{"excludeNonCirculatingAccountsList": true}])),
5362 );
5363 let result: RpcResponse<RpcSupply> = parse_success_result(rpc.handle_request_sync(request));
5364 let expected = {
5365 let total_capitalization = rpc.working_bank().capitalization();
5366 RpcSupply {
5367 non_circulating: 0,
5368 circulating: total_capitalization,
5369 total: total_capitalization,
5370 non_circulating_accounts: vec![],
5371 }
5372 };
5373 assert_eq!(result.value, expected);
5374 }
5375
5376 #[test]
5377 fn test_get_largest_accounts() {
5378 let rpc = RpcHandler::start();
5379
5380 let non_circulating_key = &non_circulating_accounts()[0];
5382 let bank = rpc.working_bank();
5383 bank.process_transaction(&system_transaction::transfer(
5384 &rpc.mint_keypair,
5385 non_circulating_key,
5386 500_000,
5387 bank.confirmed_last_blockhash(),
5388 ))
5389 .expect("process transaction");
5390
5391 let request = create_test_request("getLargestAccounts", None);
5392 let largest_accounts_result: RpcResponse<Vec<RpcAccountBalance>> =
5393 parse_success_result(rpc.handle_request_sync(request));
5394 assert_eq!(largest_accounts_result.value.len(), 20);
5395
5396 let request = create_test_request(
5398 "getBalance",
5399 Some(json!([rpc.mint_keypair.pubkey().to_string()])),
5400 );
5401 let mint_balance_result: RpcResponse<u64> =
5402 parse_success_result(rpc.handle_request_sync(request));
5403 assert!(largest_accounts_result.value.contains(&RpcAccountBalance {
5404 address: rpc.mint_keypair.pubkey().to_string(),
5405 lamports: mint_balance_result.value,
5406 }));
5407
5408 let request =
5410 create_test_request("getBalance", Some(json!([non_circulating_key.to_string()])));
5411 let non_circulating_balance_result: RpcResponse<u64> =
5412 parse_success_result(rpc.handle_request_sync(request));
5413 assert!(largest_accounts_result.value.contains(&RpcAccountBalance {
5414 address: non_circulating_key.to_string(),
5415 lamports: non_circulating_balance_result.value,
5416 }));
5417
5418 let request = create_test_request(
5420 "getLargestAccounts",
5421 Some(json!([{"filter":"circulating"}])),
5422 );
5423 let largest_accounts_result: RpcResponse<Vec<RpcAccountBalance>> =
5424 parse_success_result(rpc.handle_request_sync(request));
5425 assert_eq!(largest_accounts_result.value.len(), 20);
5426 assert!(!largest_accounts_result.value.contains(&RpcAccountBalance {
5427 address: non_circulating_key.to_string(),
5428 lamports: non_circulating_balance_result.value,
5429 }));
5430
5431 let request = create_test_request(
5432 "getLargestAccounts",
5433 Some(json!([{"filter":"nonCirculating"}])),
5434 );
5435 let largest_accounts_result: RpcResponse<Vec<RpcAccountBalance>> =
5436 parse_success_result(rpc.handle_request_sync(request));
5437 assert_eq!(largest_accounts_result.value.len(), 1);
5438 assert!(largest_accounts_result.value.contains(&RpcAccountBalance {
5439 address: non_circulating_key.to_string(),
5440 lamports: non_circulating_balance_result.value,
5441 }));
5442 }
5443
5444 #[test]
5445 fn test_rpc_get_minimum_balance_for_rent_exemption() {
5446 let rpc = RpcHandler::start();
5447 let data_len = 50;
5448 let request =
5449 create_test_request("getMinimumBalanceForRentExemption", Some(json!([data_len])));
5450 let result: u64 = parse_success_result(rpc.handle_request_sync(request));
5451 let expected = rpc
5452 .working_bank()
5453 .get_minimum_balance_for_rent_exemption(data_len);
5454 assert_eq!(result, expected);
5455 }
5456
5457 #[test]
5458 fn test_rpc_get_inflation() {
5459 let rpc = RpcHandler::start();
5460 let bank = rpc.working_bank();
5461 let request = create_test_request("getInflationGovernor", None);
5462 let result: RpcInflationGovernor = parse_success_result(rpc.handle_request_sync(request));
5463 let expected: RpcInflationGovernor = bank.inflation().into();
5464 assert_eq!(result, expected);
5465
5466 let request = create_test_request("getInflationRate", None);
5468 let result: RpcInflationRate = parse_success_result(rpc.handle_request_sync(request));
5469 let inflation = bank.inflation();
5470 let epoch = bank.epoch();
5471 let slot_in_year = bank.slot_in_year_for_inflation();
5472 let expected = RpcInflationRate {
5473 total: inflation.total(slot_in_year),
5474 validator: inflation.validator(slot_in_year),
5475 foundation: inflation.foundation(slot_in_year),
5476 epoch,
5477 };
5478 assert_eq!(result, expected);
5479 }
5480
5481 #[test]
5482 fn test_rpc_get_epoch_schedule() {
5483 let rpc = RpcHandler::start();
5484 let bank = rpc.working_bank();
5485 let request = create_test_request("getEpochSchedule", None);
5486 let result: EpochSchedule = parse_success_result(rpc.handle_request_sync(request));
5487 let expected = bank.epoch_schedule();
5488 assert_eq!(expected, &result);
5489 }
5490
5491 #[test]
5492 fn test_rpc_get_leader_schedule() {
5493 let rpc = RpcHandler::start();
5494
5495 for params in [
5496 None,
5497 Some(json!([0u64])),
5498 Some(json!([null, {"identity": rpc.leader_pubkey().to_string()}])),
5499 Some(json!([{"identity": rpc.leader_pubkey().to_string()}])),
5500 ] {
5501 let request = create_test_request("getLeaderSchedule", params);
5502 let result: Option<RpcLeaderSchedule> =
5503 parse_success_result(rpc.handle_request_sync(request));
5504 let expected = Some(HashMap::from_iter(std::iter::once((
5505 rpc.leader_pubkey().to_string(),
5506 Vec::from_iter(0..=128),
5507 ))));
5508 assert_eq!(result, expected);
5509 }
5510
5511 let request = create_test_request("getLeaderSchedule", Some(json!([42424242])));
5512 let result: Option<RpcLeaderSchedule> =
5513 parse_success_result(rpc.handle_request_sync(request));
5514 let expected: Option<RpcLeaderSchedule> = None;
5515 assert_eq!(result, expected);
5516
5517 let request = create_test_request(
5518 "getLeaderSchedule",
5519 Some(json!([{"identity": Pubkey::new_unique().to_string() }])),
5520 );
5521 let result: Option<RpcLeaderSchedule> =
5522 parse_success_result(rpc.handle_request_sync(request));
5523 let expected = Some(HashMap::default());
5524 assert_eq!(result, expected);
5525 }
5526
5527 #[test]
5528 fn test_rpc_get_slot_leaders() {
5529 let rpc = RpcHandler::start();
5530 let bank = rpc.working_bank();
5531
5532 let query_start = 0;
5534 let query_limit = 2 * bank.epoch_schedule().slots_per_epoch;
5535
5536 let request =
5537 create_test_request("getSlotLeaders", Some(json!([query_start, query_limit])));
5538 let result: Vec<String> = parse_success_result(rpc.handle_request_sync(request));
5539 assert_eq!(result.len(), query_limit as usize);
5540
5541 let query_start = 0;
5543 let query_limit = 5001;
5544
5545 let request =
5546 create_test_request("getSlotLeaders", Some(json!([query_start, query_limit])));
5547 let response = parse_failure_response(rpc.handle_request_sync(request));
5548 let expected = (
5549 ErrorCode::InvalidParams.code(),
5550 String::from("Invalid limit; max 5000"),
5551 );
5552 assert_eq!(response, expected);
5553
5554 let query_start = 2 * bank.epoch_schedule().slots_per_epoch;
5556 let query_limit = 10;
5557
5558 let request =
5559 create_test_request("getSlotLeaders", Some(json!([query_start, query_limit])));
5560 let response = parse_failure_response(rpc.handle_request_sync(request));
5561 let expected = (
5562 ErrorCode::InvalidParams.code(),
5563 String::from("Invalid slot range: leader schedule for epoch 2 is unavailable"),
5564 );
5565 assert_eq!(response, expected);
5566 }
5567
5568 #[test]
5569 fn test_rpc_get_account_info() {
5570 let rpc = RpcHandler::start();
5571 let bank = rpc.working_bank();
5572
5573 let request = create_test_request(
5574 "getAccountInfo",
5575 Some(json!([rpc.mint_keypair.pubkey().to_string()])),
5576 );
5577 let result: Value = parse_success_result(rpc.handle_request_sync(request));
5578 let expected = json!({
5579 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
5580 "value":{
5581 "owner": "11111111111111111111111111111111",
5582 "lamports": TEST_MINT_LAMPORTS,
5583 "data": "",
5584 "executable": false,
5585 "rentEpoch": 0,
5586 "space": 0,
5587 },
5588 });
5589 assert_eq!(result, expected);
5590
5591 let pubkey = Pubkey::new_unique();
5592 let address = pubkey.to_string();
5593 let data = vec![1, 2, 3, 4, 5];
5594 let account = AccountSharedData::create(42, data.clone(), Pubkey::default(), false, 0);
5595 bank.store_account(&pubkey, &account);
5596
5597 let request = create_test_request(
5598 "getAccountInfo",
5599 Some(json!([address, {"encoding": "base64"}])),
5600 );
5601 let result: Value = parse_success_result(rpc.handle_request_sync(request));
5602 let expected = json!([BASE64_STANDARD.encode(&data), "base64"]);
5603 assert_eq!(result["value"]["data"], expected);
5604 assert_eq!(result["value"]["space"], 5);
5605
5606 let request = create_test_request(
5607 "getAccountInfo",
5608 Some(json!([address, {"encoding": "base64", "dataSlice": {"length": 2, "offset": 1}}])),
5609 );
5610 let result: Value = parse_success_result(rpc.handle_request_sync(request));
5611 let expected = json!([BASE64_STANDARD.encode(&data[1..3]), "base64"]);
5612 assert_eq!(result["value"]["data"], expected);
5613 assert_eq!(result["value"]["space"], 5);
5614
5615 let request = create_test_request(
5616 "getAccountInfo",
5617 Some(json!([address, {"encoding": "binary", "dataSlice": {"length": 2, "offset": 1}}])),
5618 );
5619 let result: Value = parse_success_result(rpc.handle_request_sync(request));
5620 let expected = bs58::encode(&data[1..3]).into_string();
5621 assert_eq!(result["value"]["data"], expected);
5622 assert_eq!(result["value"]["space"], 5);
5623
5624 let request = create_test_request(
5625 "getAccountInfo",
5626 Some(
5627 json!([address, {"encoding": "jsonParsed", "dataSlice": {"length": 2, "offset": 1}}]),
5628 ),
5629 );
5630 let result: Value = parse_success_result(rpc.handle_request_sync(request));
5631 let expected = json!([BASE64_STANDARD.encode(&data[1..3]), "base64"]);
5632 assert_eq!(
5633 result["value"]["data"], expected,
5634 "should use data slice if parsing fails"
5635 );
5636 }
5637
5638 #[test]
5639 fn test_encode_account_does_not_throw_when_slice_larger_than_account() {
5640 let data = vec![42; 5];
5641 let pubkey = Pubkey::new_unique();
5642 let account = AccountSharedData::create(42, data, pubkey, false, 0);
5643 let result = encode_account(
5644 &account,
5645 &pubkey,
5646 UiAccountEncoding::Base58,
5647 Some(UiDataSliceConfig {
5648 length: account.data().len() + 1,
5649 offset: 0,
5650 }),
5651 );
5652 assert!(result.is_ok());
5653 }
5654 #[test]
5655 #[should_panic(expected = "should be less than 128 bytes")] fn test_encode_account_throws_when_data_too_large_to_base58_encode() {
5657 let data = vec![42; MAX_BASE58_BYTES + 1];
5658 let pubkey = Pubkey::new_unique();
5659 let account = AccountSharedData::create(42, data, pubkey, false, 0);
5660 let _ = encode_account(&account, &pubkey, UiAccountEncoding::Base58, None).unwrap();
5661 }
5662
5663 #[test]
5664 fn test_encode_account_does_not_throw_despite_data_too_large_to_base58_encode_because_dataslice_makes_it_fit(
5665 ) {
5666 let data = vec![42; MAX_BASE58_BYTES + 1];
5667 let pubkey = Pubkey::new_unique();
5668 let account = AccountSharedData::create(42, data, pubkey, false, 0);
5669 let result = encode_account(
5670 &account,
5671 &pubkey,
5672 UiAccountEncoding::Base58,
5673 Some(UiDataSliceConfig {
5674 length: MAX_BASE58_BYTES,
5675 offset: 1,
5676 }),
5677 );
5678 assert!(result.is_ok());
5679 }
5680
5681 #[test]
5682 fn test_encode_account_does_not_throw_despite_dataslice_being_too_large_to_base58_encode_because_account_is_small_enough_to_fit(
5683 ) {
5684 let data = vec![42; MAX_BASE58_BYTES];
5685 let pubkey = Pubkey::new_unique();
5686 let account = AccountSharedData::create(42, data, pubkey, false, 0);
5687 let result = encode_account(
5688 &account,
5689 &pubkey,
5690 UiAccountEncoding::Base58,
5691 Some(UiDataSliceConfig {
5692 length: MAX_BASE58_BYTES + 1,
5693 offset: 0,
5694 }),
5695 );
5696 assert!(result.is_ok());
5697 }
5698
5699 #[test]
5700 fn test_encode_account_does_not_throw_despite_account_and_dataslice_being_too_large_to_base58_encode_because_their_intersection_fits(
5701 ) {
5702 let data = vec![42; MAX_BASE58_BYTES + 1];
5703 let pubkey = Pubkey::new_unique();
5704 let account = AccountSharedData::create(42, data, pubkey, false, 0);
5705 let result = encode_account(
5706 &account,
5707 &pubkey,
5708 UiAccountEncoding::Base58,
5709 Some(UiDataSliceConfig {
5710 length: MAX_BASE58_BYTES + 1,
5711 offset: 1,
5712 }),
5713 );
5714 assert!(result.is_ok());
5715 }
5716
5717 #[test]
5718 fn test_rpc_get_multiple_accounts() {
5719 let rpc = RpcHandler::start();
5720 let bank = rpc.working_bank();
5721
5722 let non_existent_pubkey = Pubkey::new_unique();
5723 let pubkey = Pubkey::new_unique();
5724 let address = pubkey.to_string();
5725 let data = vec![1, 2, 3, 4, 5];
5726 let account = AccountSharedData::create(42, data.clone(), Pubkey::default(), false, 0);
5727 bank.store_account(&pubkey, &account);
5728
5729 let request = create_test_request(
5731 "getMultipleAccounts",
5732 Some(json!([[
5733 rpc.mint_keypair.pubkey().to_string(),
5734 non_existent_pubkey.to_string(),
5735 address,
5736 ]])),
5737 );
5738 let result: RpcResponse<Value> = parse_success_result(rpc.handle_request_sync(request));
5739 let expected = json!([
5740 {
5741 "owner": "11111111111111111111111111111111",
5742 "lamports": TEST_MINT_LAMPORTS,
5743 "data": ["", "base64"],
5744 "executable": false,
5745 "rentEpoch": 0,
5746 "space": 0,
5747 },
5748 null,
5749 {
5750 "owner": "11111111111111111111111111111111",
5751 "lamports": 42,
5752 "data": [BASE64_STANDARD.encode(&data), "base64"],
5753 "executable": false,
5754 "rentEpoch": 0,
5755 "space": 5,
5756 }
5757 ]);
5758 assert_eq!(result.value, expected);
5759
5760 let request = create_test_request(
5762 "getMultipleAccounts",
5763 Some(json!([
5764 [
5765 rpc.mint_keypair.pubkey().to_string(),
5766 non_existent_pubkey.to_string(),
5767 address,
5768 ],
5769 {"encoding": "base58"},
5770 ])),
5771 );
5772 let result: RpcResponse<Value> = parse_success_result(rpc.handle_request_sync(request));
5773 let expected = json!([
5774 {
5775 "owner": "11111111111111111111111111111111",
5776 "lamports": TEST_MINT_LAMPORTS,
5777 "data": ["", "base58"],
5778 "executable": false,
5779 "rentEpoch": 0,
5780 "space": 0,
5781 },
5782 null,
5783 {
5784 "owner": "11111111111111111111111111111111",
5785 "lamports": 42,
5786 "data": [bs58::encode(&data).into_string(), "base58"],
5787 "executable": false,
5788 "rentEpoch": 0,
5789 "space": 5,
5790 }
5791 ]);
5792 assert_eq!(result.value, expected);
5793
5794 let request = create_test_request(
5795 "getMultipleAccounts",
5796 Some(json!([
5797 [
5798 rpc.mint_keypair.pubkey().to_string(),
5799 non_existent_pubkey.to_string(),
5800 address,
5801 ],
5802 {"encoding": "jsonParsed", "dataSlice": {"length": 2, "offset": 1}},
5803 ])),
5804 );
5805 let result: RpcResponse<Value> = parse_success_result(rpc.handle_request_sync(request));
5806 let expected = json!([
5807 {
5808 "owner": "11111111111111111111111111111111",
5809 "lamports": TEST_MINT_LAMPORTS,
5810 "data": ["", "base64"],
5811 "executable": false,
5812 "rentEpoch": 0,
5813 "space": 0,
5814 },
5815 null,
5816 {
5817 "owner": "11111111111111111111111111111111",
5818 "lamports": 42,
5819 "data": [BASE64_STANDARD.encode(&data[1..3]), "base64"],
5820 "executable": false,
5821 "rentEpoch": 0,
5822 "space": 5,
5823 }
5824 ]);
5825 assert_eq!(
5826 result.value, expected,
5827 "should use data slice if parsing fails"
5828 );
5829 }
5830
5831 #[test]
5832 fn test_rpc_get_program_accounts() {
5833 let rpc = RpcHandler::start();
5834 let bank = rpc.working_bank();
5835
5836 let new_program_id = Pubkey::new_unique();
5837 let new_program_account_key = Pubkey::new_unique();
5838 let new_program_account = AccountSharedData::new(42, 0, &new_program_id);
5839 bank.store_account(&new_program_account_key, &new_program_account);
5840
5841 let request = create_test_request(
5842 "getProgramAccounts",
5843 Some(json!([new_program_id.to_string()])),
5844 );
5845 let result: Vec<RpcKeyedAccount> = parse_success_result(rpc.handle_request_sync(request));
5846 let expected_value = vec![RpcKeyedAccount {
5847 pubkey: new_program_account_key.to_string(),
5848 account: encode_ui_account(
5849 &new_program_account_key,
5850 &new_program_account,
5851 UiAccountEncoding::Binary,
5852 None,
5853 None,
5854 ),
5855 }];
5856 assert_eq!(result, expected_value);
5857
5858 let request = create_test_request(
5860 "getProgramAccounts",
5861 Some(json!([
5862 new_program_id.to_string(),
5863 {"withContext": true},
5864 ])),
5865 );
5866 let result: RpcResponse<Vec<RpcKeyedAccount>> =
5867 parse_success_result(rpc.handle_request_sync(request));
5868 let expected = RpcResponse {
5869 context: RpcResponseContext::new(0),
5870 value: expected_value,
5871 };
5872 assert_eq!(result, expected);
5873
5874 let nonce_authorities = (0..2)
5876 .map(|_| {
5877 let pubkey = Pubkey::new_unique();
5878 let authority = Pubkey::new_unique();
5879 let account = AccountSharedData::new_data(
5880 42,
5881 &nonce::versions::Versions::new(nonce::state::State::new_initialized(
5882 &authority,
5883 DurableNonce::default(),
5884 1000,
5885 )),
5886 &system_program::id(),
5887 )
5888 .unwrap();
5889 bank.store_account(&pubkey, &account);
5890 authority
5891 })
5892 .collect::<Vec<_>>();
5893
5894 let request = create_test_request(
5896 "getProgramAccounts",
5897 Some(json!([
5898 system_program::id().to_string(),
5899 {"filters": [{
5900 "memcmp": {
5901 "offset": 4,
5902 "bytes": bs58::encode(vec![1, 0, 0, 0]).into_string(),
5903 },
5904 }]},
5905 ])),
5906 );
5907 let result: Vec<RpcKeyedAccount> = parse_success_result(rpc.handle_request_sync(request));
5908 assert_eq!(result.len(), 2);
5909
5910 let request = create_test_request(
5911 "getProgramAccounts",
5912 Some(json!([
5913 system_program::id().to_string(),
5914 {"filters": [{
5915 "memcmp": {
5916 "offset": 4,
5917 "bytes": bs58::encode(vec![0, 0, 0, 0]).into_string(),
5918 },
5919 }]},
5920 ])),
5921 );
5922 let result: Vec<RpcKeyedAccount> = parse_success_result(rpc.handle_request_sync(request));
5923 assert_eq!(result.len(), 0);
5924
5925 let request = create_test_request(
5927 "getProgramAccounts",
5928 Some(json!([
5929 system_program::id().to_string(),
5930 {"filters": [{"dataSize": nonce::state::State::size()}]},
5931 ])),
5932 );
5933 let result: Vec<RpcKeyedAccount> = parse_success_result(rpc.handle_request_sync(request));
5934 assert_eq!(result.len(), 2);
5935
5936 let request = create_test_request(
5937 "getProgramAccounts",
5938 Some(json!([
5939 system_program::id().to_string(),
5940 {"filters": [{"dataSize": 1}]},
5941 ])),
5942 );
5943 let result: Vec<RpcKeyedAccount> = parse_success_result(rpc.handle_request_sync(request));
5944 assert_eq!(result.len(), 0);
5945
5946 let request = create_test_request(
5948 "getProgramAccounts",
5949 Some(json!([
5950 system_program::id().to_string(),
5951 {"filters": [{
5952 "memcmp": {
5953 "offset": 4,
5954 "bytes": bs58::encode(vec![1, 0, 0, 0]).into_string(),
5955 },
5956 }, {
5957 "memcmp": {
5958 "offset": 8,
5959 "bytes": nonce_authorities[0].to_string(),
5960 },
5961 }]}, ])),
5963 );
5964 let result: Vec<RpcKeyedAccount> = parse_success_result(rpc.handle_request_sync(request));
5965 assert_eq!(result.len(), 1);
5966
5967 let request = create_test_request(
5968 "getProgramAccounts",
5969 Some(json!([
5970 system_program::id().to_string(),
5971 {"filters": [{
5972 "memcmp": {
5973 "offset": 4,
5974 "bytes": bs58::encode(vec![1, 0, 0, 0]).into_string(),
5975 },
5976 }, {
5977 "dataSize": 1,
5978 }]}, ])),
5980 );
5981 let result: Vec<RpcKeyedAccount> = parse_success_result(rpc.handle_request_sync(request));
5982 assert_eq!(result.len(), 0);
5983 }
5984
5985 #[test]
5986 fn test_rpc_simulate_transaction() {
5987 let rpc = RpcHandler::start();
5988 let bank = rpc.working_bank();
5989 let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
5990 let recent_blockhash = bank.confirmed_last_blockhash();
5991 let RpcHandler {
5992 ref meta, ref io, ..
5993 } = rpc;
5994
5995 let bob_pubkey = solana_pubkey::new_rand();
5996 let mut tx = system_transaction::transfer(
5997 &rpc.mint_keypair,
5998 &bob_pubkey,
5999 rent_exempt_amount,
6000 recent_blockhash,
6001 );
6002 let tx_serialized_encoded = bs58::encode(serialize(&tx).unwrap()).into_string();
6003 tx.signatures[0] = Signature::default();
6004 let tx_badsig_serialized_encoded = bs58::encode(serialize(&tx).unwrap()).into_string();
6005 tx.message.recent_blockhash = Hash::default();
6006 let tx_invalid_recent_blockhash = bs58::encode(serialize(&tx).unwrap()).into_string();
6007
6008 bank.freeze();
6010
6011 let loaded_accounts_data_size = expected_loaded_accounts_data_size(&bank, &tx);
6012
6013 let req = format!(
6015 r#"{{"jsonrpc":"2.0",
6016 "id":1,
6017 "method":"simulateTransaction",
6018 "params":[
6019 "{}",
6020 {{
6021 "sigVerify": true,
6022 "accounts": {{
6023 "encoding": "jsonParsed",
6024 "addresses": ["{}", "{}"]
6025 }}
6026 }}
6027 ]
6028 }}"#,
6029 tx_serialized_encoded,
6030 solana_pubkey::new_rand(),
6031 bob_pubkey,
6032 );
6033 let res = io.handle_request_sync(&req, meta.clone());
6034 let expected = json!({
6035 "jsonrpc": "2.0",
6036 "result": {
6037 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
6038 "value":{
6039 "accounts": [
6040 null,
6041 {
6042 "data": ["", "base64"],
6043 "executable": false,
6044 "owner": "11111111111111111111111111111111",
6045 "lamports": rent_exempt_amount,
6046 "rentEpoch": u64::MAX,
6047 "space": 0,
6048 }
6049 ],
6050 "err":null,
6051 "innerInstructions": null,
6052 "loadedAccountsDataSize": loaded_accounts_data_size,
6053 "fee": 5000,
6054 "loadedAddresses": {"readonly": [], "writable": []},
6055 "preBalances": [1000000000, 0, 1],
6056 "postBalances": [999982200, 12800, 1],
6057 "preTokenBalances": [],
6058 "postTokenBalances": [],
6059 "logs":[
6060 "Program 11111111111111111111111111111111 invoke [1]",
6061 "Program 11111111111111111111111111111111 success"
6062 ],
6063 "replacementBlockhash": null,
6064 "returnData":null,
6065 "unitsConsumed":150,
6066 }
6067 },
6068 "id": 1,
6069 });
6070 let expected: Response =
6071 serde_json::from_value(expected).expect("expected response deserialization");
6072 let result: Response = serde_json::from_str(&res.expect("actual response"))
6073 .expect("actual response deserialization");
6074 assert_eq!(result, expected);
6075
6076 let req = format!(
6078 r#"{{"jsonrpc":"2.0",
6079 "id":1,
6080 "method":"simulateTransaction",
6081 "params":[
6082 "{tx_serialized_encoded}",
6083 {{
6084 "sigVerify": true,
6085 "accounts": {{
6086 "addresses": [
6087 "11111111111111111111111111111111",
6088 "11111111111111111111111111111111",
6089 "11111111111111111111111111111111",
6090 "11111111111111111111111111111111"
6091 ]
6092 }}
6093 }}
6094 ]
6095 }}"#,
6096 );
6097 let res = io.handle_request_sync(&req, meta.clone());
6098 let expected = json!({
6099 "jsonrpc":"2.0",
6100 "error": {
6101 "code": error::ErrorCode::InvalidParams.code(),
6102 "message": "Too many accounts provided; max 3"
6103 },
6104 "id":1
6105 });
6106 let expected: Response =
6107 serde_json::from_value(expected).expect("expected response deserialization");
6108 let result: Response = serde_json::from_str(&res.expect("actual response"))
6109 .expect("actual response deserialization");
6110 assert_eq!(result, expected);
6111
6112 let req = format!(
6114 r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_badsig_serialized_encoded}", {{"sigVerify": true}}]}}"#,
6115 );
6116 let res = io.handle_request_sync(&req, meta.clone());
6117 let expected = json!({
6118 "jsonrpc": "2.0",
6119 "result": {
6120 "context": { "slot": 0, "apiVersion": RpcApiVersion::default() },
6121 "value": {
6122 "accounts": null,
6123 "err": "SignatureFailure",
6124 "innerInstructions": null,
6125 "loadedAccountsDataSize": 0,
6126 "fee": null,
6127 "loadedAddresses": { "readonly": [], "writable": [] },
6128 "preBalances": null,
6129 "postBalances": null,
6130 "preTokenBalances": null,
6131 "postTokenBalances": null,
6132 "logs": [],
6133 "replacementBlockhash": null,
6134 "returnData": null,
6135 "unitsConsumed": 0,
6136 }
6137 },
6138 "id": 1,
6139 });
6140
6141 let expected: Response =
6142 serde_json::from_value(expected).expect("expected response deserialization");
6143 let result: Response = serde_json::from_str(&res.expect("actual response"))
6144 .expect("actual response deserialization");
6145 assert_eq!(result, expected);
6146
6147 let req = format!(
6149 r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_serialized_encoded}", {{"sigVerify": false}}]}}"#,
6150 );
6151 let res = io.handle_request_sync(&req, meta.clone());
6152 let expected = json!({
6153 "jsonrpc": "2.0",
6154 "result": {
6155 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
6156 "value":{
6157 "accounts":null,
6158 "err":null,
6159 "innerInstructions":null,
6160 "loadedAccountsDataSize": loaded_accounts_data_size,
6161 "fee": 5000,
6162 "loadedAddresses": {"readonly": [], "writable": []},
6163 "preBalances": [1000000000, 0, 1],
6164 "postBalances": [999982200, 12800, 1],
6165 "preTokenBalances": [],
6166 "postTokenBalances": [],
6167 "logs":[
6168 "Program 11111111111111111111111111111111 invoke [1]",
6169 "Program 11111111111111111111111111111111 success"
6170 ],
6171 "replacementBlockhash": null,
6172 "returnData":null,
6173 "unitsConsumed":150,
6174 }
6175 },
6176 "id": 1,
6177 });
6178 let expected: Response =
6179 serde_json::from_value(expected).expect("expected response deserialization");
6180 let result: Response = serde_json::from_str(&res.expect("actual response"))
6181 .expect("actual response deserialization");
6182 assert_eq!(result, expected);
6183
6184 let req = format!(
6186 r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_serialized_encoded}"]}}"#,
6187 );
6188 let res = io.handle_request_sync(&req, meta.clone());
6189 let expected = json!({
6190 "jsonrpc": "2.0",
6191 "result": {
6192 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
6193 "value":{
6194 "accounts":null,
6195 "err":null,
6196 "innerInstructions":null,
6197 "loadedAccountsDataSize": loaded_accounts_data_size,
6198 "fee": 5000,
6199 "loadedAddresses": {"readonly": [], "writable": []},
6200 "preBalances": [1000000000, 0, 1],
6201 "postBalances": [999982200, 12800, 1],
6202 "preTokenBalances": [],
6203 "postTokenBalances": [],
6204 "logs":[
6205 "Program 11111111111111111111111111111111 invoke [1]",
6206 "Program 11111111111111111111111111111111 success"
6207 ],
6208 "replacementBlockhash": null,
6209 "returnData": null,
6210 "unitsConsumed":150,
6211 }
6212 },
6213 "id": 1,
6214 });
6215 let expected: Response =
6216 serde_json::from_value(expected).expect("expected response deserialization");
6217 let result: Response = serde_json::from_str(&res.expect("actual response"))
6218 .expect("actual response deserialization");
6219 assert_eq!(result, expected);
6220
6221 let req = format!(
6223 r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}", {}]}}"#,
6224 tx_serialized_encoded,
6225 json!({
6226 "sigVerify": true,
6227 "replaceRecentBlockhash": true,
6228 })
6229 );
6230 let res = io.handle_request_sync(&req, meta.clone());
6231 let expected = json!({
6232 "jsonrpc":"2.0",
6233 "error": {
6234 "code": ErrorCode::InvalidParams,
6235 "message": "sigVerify may not be used with replaceRecentBlockhash"
6236 },
6237 "id":1
6238 });
6239 let expected: Response =
6240 serde_json::from_value(expected).expect("expected response deserialization");
6241 let result: Response = serde_json::from_str(&res.expect("actual response"))
6242 .expect("actual response deserialization");
6243 assert_eq!(result, expected);
6244
6245 let req = format!(
6247 r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_invalid_recent_blockhash}", {{"replaceRecentBlockhash": false}}]}}"#,
6248 );
6249 let res = io.handle_request_sync(&req, meta.clone());
6250 let expected = json!({
6251 "jsonrpc":"2.0",
6252 "result": {
6253 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
6254 "value":{
6255 "err":"BlockhashNotFound",
6256 "accounts":null,
6257 "innerInstructions":null,
6258 "loadedAccountsDataSize":0,
6259 "fee": null,
6260 "loadedAddresses": {"readonly": [], "writable": []},
6261 "preBalances": [1000000000, 0, 1],
6262 "postBalances": [1000000000, 0, 1],
6263 "preTokenBalances": [],
6264 "postTokenBalances": [],
6265 "logs":[],
6266 "replacementBlockhash": null,
6267 "returnData": null,
6268 "unitsConsumed":0,
6269 }
6270 },
6271 "id":1
6272 });
6273
6274 let expected: Response =
6275 serde_json::from_value(expected).expect("expected response deserialization");
6276 let result: Response = serde_json::from_str(&res.expect("actual response"))
6277 .expect("actual response deserialization");
6278 assert_eq!(result, expected);
6279
6280 let req = format!(
6282 r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_invalid_recent_blockhash}", {{"replaceRecentBlockhash": true}}]}}"#,
6283 );
6284 let res = io.handle_request_sync(&req, meta.clone());
6285 let latest_blockhash = bank.confirmed_last_blockhash();
6286 let expiry_slot = bank
6287 .get_blockhash_last_valid_block_height(&latest_blockhash)
6288 .expect("blockhash exists");
6289
6290 let expected = json!({
6291 "jsonrpc": "2.0",
6292 "result": {
6293 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
6294 "value":{
6295 "accounts":null,
6296 "err":null,
6297 "innerInstructions":null,
6298 "loadedAccountsDataSize": loaded_accounts_data_size,
6299 "fee": 5000,
6300 "loadedAddresses": {"readonly": [], "writable": []},
6301 "preBalances": [1000000000, 0, 1],
6302 "postBalances": [999982200, 12800, 1],
6303 "preTokenBalances": [],
6304 "postTokenBalances": [],
6305 "logs":[
6306 "Program 11111111111111111111111111111111 invoke [1]",
6307 "Program 11111111111111111111111111111111 success"
6308 ],
6309 "replacementBlockhash": {
6310 "blockhash": latest_blockhash.to_string(),
6311 "lastValidBlockHeight": expiry_slot
6312 },
6313 "returnData":null,
6314 "unitsConsumed":150,
6315 }
6316 },
6317 "id": 1,
6318 });
6319
6320 let expected: Response =
6321 serde_json::from_value(expected).expect("expected response deserialization");
6322 let result: Response = serde_json::from_str(&res.expect("actual response"))
6323 .expect("actual response deserialization");
6324 assert_eq!(result, expected);
6325 }
6326
6327 #[test]
6328 fn test_rpc_simulate_transaction_with_parsing_token_accounts() {
6329 let rpc = RpcHandler::start();
6330 let bank = rpc.working_bank();
6331 let RpcHandler {
6332 ref meta, ref io, ..
6333 } = rpc;
6334
6335 let mint_rent_exempt_amount =
6337 bank.get_minimum_balance_for_rent_exemption(spl_token_interface::state::Mint::LEN);
6338 let mint_pubkey = Pubkey::from_str("mint111111111111111111111111111111111111111").unwrap();
6339 let mut mint_data = [0u8; spl_token_interface::state::Mint::LEN];
6340 Pack::pack_into_slice(
6341 &spl_token_interface::state::Mint {
6342 mint_authority: COption::None,
6343 supply: 0,
6344 decimals: 8,
6345 is_initialized: true,
6346 freeze_authority: COption::None,
6347 },
6348 &mut mint_data,
6349 );
6350 let account = AccountSharedData::create(
6351 mint_rent_exempt_amount,
6352 mint_data.into(),
6353 spl_token_interface::id(),
6354 false,
6355 0,
6356 );
6357 bank.store_account(&mint_pubkey, &account);
6358
6359 let token_account_rent_exempt_amount =
6361 bank.get_minimum_balance_for_rent_exemption(spl_token_interface::state::Account::LEN);
6362 let token_account_pubkey = Pubkey::new_unique();
6363 let owner_pubkey = Pubkey::from_str("owner11111111111111111111111111111111111111").unwrap();
6364 let mut token_account_data = [0u8; spl_token_interface::state::Account::LEN];
6365 Pack::pack_into_slice(
6366 &spl_token_interface::state::Account {
6367 mint: mint_pubkey,
6368 owner: owner_pubkey,
6369 amount: 1,
6370 delegate: COption::None,
6371 state: spl_token_interface::state::AccountState::Initialized,
6372 is_native: COption::None,
6373 delegated_amount: 0,
6374 close_authority: COption::None,
6375 },
6376 &mut token_account_data,
6377 );
6378 let account = AccountSharedData::create(
6379 token_account_rent_exempt_amount,
6380 token_account_data.into(),
6381 spl_token_interface::id(),
6382 false,
6383 0,
6384 );
6385 bank.store_account(&token_account_pubkey, &account);
6386
6387 let fee_payer = rpc.mint_keypair;
6389 let recent_blockhash = bank.confirmed_last_blockhash();
6390 let tx =
6391 system_transaction::transfer(&fee_payer, &token_account_pubkey, 1, recent_blockhash);
6392 let tx_serialized_encoded = bs58::encode(serialize(&tx).unwrap()).into_string();
6393
6394 bank.freeze();
6396
6397 let loaded_accounts_data_size = expected_loaded_accounts_data_size(&bank, &tx);
6398
6399 let req = format!(
6400 r#"{{"jsonrpc":"2.0",
6401 "id":1,
6402 "method":"simulateTransaction",
6403 "params":[
6404 "{}",
6405 {{
6406 "sigVerify": true,
6407 "accounts": {{
6408 "encoding": "jsonParsed",
6409 "addresses": ["{}", "{}"]
6410 }}
6411 }}
6412 ]
6413 }}"#,
6414 tx_serialized_encoded,
6415 solana_pubkey::new_rand(),
6416 token_account_pubkey,
6417 );
6418 let res = io.handle_request_sync(&req, meta.clone());
6419 let expected = json!({
6420 "jsonrpc": "2.0",
6421 "result": {
6422 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
6423 "value":{
6424 "accounts": [
6425 null,
6426 {
6427 "data": {
6428 "parsed": {
6429 "info": {
6430 "isNative": false,
6431 "mint": "mint111111111111111111111111111111111111111",
6432 "owner": "owner11111111111111111111111111111111111111",
6433 "state": "initialized",
6434 "tokenAmount": {
6435 "amount": "1",
6436 "decimals": 8,
6437 "uiAmount": 0.00000001,
6438 "uiAmountString": "0.00000001"
6439 }
6440 },
6441 "type": "account"
6442 },
6443 "program": "spl-token",
6444 "space": 165
6445 },
6446 "executable": false,
6447 "lamports": (token_account_rent_exempt_amount + 1),
6448 "owner": bs58::encode(spl_token_interface::id()).into_string(),
6449 "rentEpoch": u64::MAX,
6450 "space": spl_token_interface::state::Account::LEN
6451 },
6452 ],
6453 "err": null,
6454 "innerInstructions": null,
6455 "loadedAccountsDataSize": loaded_accounts_data_size,
6456 "fee": 5000,
6457 "loadedAddresses": {"readonly": [], "writable": []},
6458 "preBalances": [1000000000, 29300, 1],
6459 "postBalances": [999994999, 29301, 1],
6460 "preTokenBalances": [],
6461 "postTokenBalances": [],
6462 "logs":[
6463 "Program 11111111111111111111111111111111 invoke [1]",
6464 "Program 11111111111111111111111111111111 success"
6465 ],
6466 "replacementBlockhash": null,
6467 "returnData": null,
6468 "unitsConsumed": 150,
6469 }
6470 },
6471 "id": 1,
6472 });
6473 let expected: Response =
6474 serde_json::from_value(expected).expect("expected response deserialization");
6475 let result: Response = serde_json::from_str(&res.expect("actual response"))
6476 .expect("actual response deserialization");
6477 assert_eq!(result, expected);
6478 }
6479
6480 #[test]
6481 fn test_rpc_simulate_transaction_with_inner_instructions() {
6482 let rpc = RpcHandler::start();
6483 let bank = rpc.working_bank();
6484 let recent_blockhash = bank.confirmed_last_blockhash();
6485 let RpcHandler {
6486 ref meta, ref io, ..
6487 } = rpc;
6488
6489 let from = rpc.mint_keypair;
6490 let from_pubkey = from.pubkey();
6491 let to = Keypair::new();
6492 let to_pubkey = to.pubkey();
6493
6494 let space = 0;
6495 let lamports = bank.rent_collector().rent.minimum_balance(space);
6496 let owner_pubkey = Pubkey::new_unique();
6497
6498 let instruction = TestBuiltinEntrypoint::instruction(
6499 &from_pubkey,
6500 &to_pubkey,
6501 lamports,
6502 space as u64,
6503 &owner_pubkey,
6504 );
6505
6506 let tx = Transaction::new_signed_with_payer(
6507 &[instruction],
6508 Some(&from_pubkey),
6509 &[&from, &to],
6510 recent_blockhash,
6511 );
6512 let tx_serialized_encoded =
6513 base64::prelude::BASE64_STANDARD.encode(serialize(&tx).unwrap());
6514
6515 bank.freeze();
6517
6518 let loaded_accounts_data_size = expected_loaded_accounts_data_size(&bank, &tx);
6519
6520 let req = format!(
6522 r#"{{"jsonrpc":"2.0",
6523 "id":1,
6524 "method":"simulateTransaction",
6525 "params":[
6526 "{tx_serialized_encoded}",
6527 {{ "encoding": "base64" }}
6528 ]
6529 }}"#,
6530 );
6531 let res = io.handle_request_sync(&req, meta.clone());
6532 let expected = json!({
6533 "jsonrpc": "2.0",
6534 "result": {
6535 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
6536 "value":{
6537 "accounts": null,
6538 "err":null,
6539 "innerInstructions": null,
6540 "loadedAccountsDataSize": loaded_accounts_data_size,
6541 "fee": 10000,
6542 "loadedAddresses": {"readonly": [], "writable": []},
6543 "preBalances": [1000000000, 0, 1, 0, 1],
6544 "postBalances": [999977200, 12800, 1, 0, 1],
6545 "preTokenBalances": [],
6546 "postTokenBalances": [],
6547 "logs":[
6548 "Program TestProgram11111111111111111111111111111111 invoke [1]",
6549 "I am logging from a builtin program!",
6550 "I am about to CPI to System!",
6551 "Program 11111111111111111111111111111111 invoke [2]",
6552 "Program 11111111111111111111111111111111 success",
6553 "All done!",
6554 "Program TestProgram11111111111111111111111111111111 success"
6555 ],
6556 "replacementBlockhash": null,
6557 "returnData":null,
6558 "unitsConsumed":TestBuiltinEntrypoint::COMPUTE_UNITS + 150,
6559 }
6560 },
6561 "id": 1,
6562 });
6563 let expected: Response =
6564 serde_json::from_value(expected).expect("expected response deserialization");
6565 let result: Response = serde_json::from_str(&res.expect("actual response"))
6566 .expect("actual response deserialization");
6567 assert_eq!(result, expected);
6568
6569 let req = format!(
6571 r#"{{"jsonrpc":"2.0",
6572 "id":1,
6573 "method":"simulateTransaction",
6574 "params":[
6575 "{tx_serialized_encoded}",
6576 {{ "innerInstructions": false, "encoding": "base64" }}
6577 ]
6578 }}"#,
6579 );
6580 let res = io.handle_request_sync(&req, meta.clone());
6581 let expected = json!({
6582 "jsonrpc": "2.0",
6583 "result": {
6584 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
6585 "value":{
6586 "accounts": null,
6587 "err":null,
6588 "innerInstructions": null,
6589 "loadedAccountsDataSize": loaded_accounts_data_size,
6590 "fee": 10000,
6591 "loadedAddresses": {"readonly": [], "writable": []},
6592 "preBalances": [1000000000, 0, 1, 0, 1],
6593 "postBalances": [999977200, 12800, 1, 0, 1],
6594 "preTokenBalances": [],
6595 "postTokenBalances": [],
6596 "logs":[
6597 "Program TestProgram11111111111111111111111111111111 invoke [1]",
6598 "I am logging from a builtin program!",
6599 "I am about to CPI to System!",
6600 "Program 11111111111111111111111111111111 invoke [2]",
6601 "Program 11111111111111111111111111111111 success",
6602 "All done!",
6603 "Program TestProgram11111111111111111111111111111111 success"
6604 ],
6605 "replacementBlockhash": null,
6606 "returnData":null,
6607 "unitsConsumed":TestBuiltinEntrypoint::COMPUTE_UNITS + 150,
6608 }
6609 },
6610 "id": 1,
6611 });
6612 let expected: Response =
6613 serde_json::from_value(expected).expect("expected response deserialization");
6614 let result: Response = serde_json::from_str(&res.expect("actual response"))
6615 .expect("actual response deserialization");
6616 assert_eq!(result, expected);
6617
6618 let req = format!(
6620 r#"{{"jsonrpc":"2.0",
6621 "id":1,
6622 "method":"simulateTransaction",
6623 "params":[
6624 "{tx_serialized_encoded}",
6625 {{ "innerInstructions": true, "encoding": "base64" }}
6626 ]
6627 }}"#,
6628 );
6629 let res = io.handle_request_sync(&req, meta.clone());
6630 let expected = json!({
6631 "jsonrpc": "2.0",
6632 "result": {
6633 "context": {"slot": 0, "apiVersion": RpcApiVersion::default()},
6634 "value":{
6635 "accounts": null,
6636 "err":null,
6637 "innerInstructions": [
6638 {
6639 "index": 0,
6640 "instructions": [
6641 {
6642 "parsed": {
6643 "info": {
6644 "lamports": lamports,
6645 "newAccount": to_pubkey.to_string(),
6646 "owner": owner_pubkey.to_string(),
6647 "source": from_pubkey.to_string(),
6648 "space": space,
6649 },
6650 "type": "createAccount"
6651 },
6652 "program": "system",
6653 "programId": "11111111111111111111111111111111",
6654 "stackHeight": 2
6655 }
6656 ]
6657 }
6658 ],
6659 "loadedAccountsDataSize": loaded_accounts_data_size,
6660 "fee": 10000,
6661 "loadedAddresses": {"readonly": [], "writable": []},
6662 "preBalances": [1000000000, 0, 1, 0, 1],
6663 "postBalances": [999977200, 12800, 1, 0, 1],
6664 "preTokenBalances": [],
6665 "postTokenBalances": [],
6666 "logs":[
6667 "Program TestProgram11111111111111111111111111111111 invoke [1]",
6668 "I am logging from a builtin program!",
6669 "I am about to CPI to System!",
6670 "Program 11111111111111111111111111111111 invoke [2]",
6671 "Program 11111111111111111111111111111111 success",
6672 "All done!",
6673 "Program TestProgram11111111111111111111111111111111 success"
6674 ],
6675 "replacementBlockhash": null,
6676 "returnData":null,
6677 "unitsConsumed":TestBuiltinEntrypoint::COMPUTE_UNITS + 150,
6678 }
6679 },
6680 "id": 1,
6681 });
6682 let expected: Response =
6683 serde_json::from_value(expected).expect("expected response deserialization");
6684 let result: Response = serde_json::from_str(&res.expect("actual response"))
6685 .expect("actual response deserialization");
6686 assert_eq!(result, expected);
6687 }
6688
6689 #[test]
6690 #[should_panic(expected = "simulation bank must be frozen")]
6691 fn test_rpc_simulate_transaction_panic_on_unfrozen_bank() {
6692 let rpc = RpcHandler::start();
6693 let bank = rpc.working_bank();
6694 let recent_blockhash = bank.confirmed_last_blockhash();
6695 let RpcHandler {
6696 meta,
6697 io,
6698 mint_keypair,
6699 ..
6700 } = rpc;
6701
6702 let bob_pubkey = Pubkey::new_unique();
6703 let tx = system_transaction::transfer(&mint_keypair, &bob_pubkey, 1234, recent_blockhash);
6704 let tx_serialized_encoded = bs58::encode(serialize(&tx).unwrap()).into_string();
6705
6706 assert!(!bank.is_frozen());
6707
6708 let req = format!(
6709 r#"{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_serialized_encoded}", {{"sigVerify": true}}]}}"#,
6710 );
6711
6712 let _ = io.handle_request_sync(&req, meta);
6714 }
6715
6716 #[test]
6717 fn test_rpc_get_signature_statuses() {
6718 let rpc = RpcHandler::start();
6719 let bank = rpc.working_bank();
6720 let recent_blockhash = bank.confirmed_last_blockhash();
6721 let confirmed_block_signatures = rpc.create_test_transactions_and_populate_blockstore();
6722 let RpcHandler {
6723 mut meta,
6724 io,
6725 mint_keypair,
6726 ..
6727 } = rpc;
6728
6729 let req = format!(
6730 r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"#,
6731 confirmed_block_signatures[0]
6732 );
6733 let res = io.handle_request_sync(&req, meta.clone());
6734 let expected_res: transaction::Result<()> = Ok(());
6735 let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
6736 let result: Option<TransactionStatus> =
6737 serde_json::from_value(json["result"]["value"][0].clone())
6738 .expect("actual response deserialization");
6739 let result = result.as_ref().unwrap();
6740 assert_eq!(expected_res, result.status);
6741 assert_eq!(None, result.confirmations);
6742
6743 let bob_pubkey = solana_pubkey::new_rand();
6745 let tx = system_transaction::transfer(
6746 &mint_keypair,
6747 &bob_pubkey,
6748 bank.get_minimum_balance_for_rent_exemption(0) + 10,
6749 recent_blockhash,
6750 );
6751 let req = format!(
6752 r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"#,
6753 tx.signatures[0]
6754 );
6755 let res = io.handle_request_sync(&req, meta.clone());
6756 let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
6757 let result: Option<TransactionStatus> =
6758 serde_json::from_value(json["result"]["value"][0].clone())
6759 .expect("actual response deserialization");
6760 assert!(result.is_none());
6761
6762 let req = format!(
6764 r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"#,
6765 confirmed_block_signatures[1]
6766 );
6767 let res = io.handle_request_sync(&req, meta.clone());
6768 let expected_res: transaction::Result<()> = Err(TransactionError::InstructionError(
6769 0,
6770 InstructionError::Custom(1),
6771 ));
6772 let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
6773 let result: Option<TransactionStatus> =
6774 serde_json::from_value(json["result"]["value"][0].clone())
6775 .expect("actual response deserialization");
6776 assert_eq!(expected_res, result.as_ref().unwrap().status);
6777
6778 meta.config.enable_rpc_transaction_history = false;
6780 let req = format!(
6781 r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"], {{"searchTransactionHistory": true}}]}}"#,
6782 confirmed_block_signatures[1]
6783 );
6784 let res = io.handle_request_sync(&req, meta);
6785 assert_eq!(
6786 res,
6787 Some(
6788 r#"{"jsonrpc":"2.0","error":{"code":-32011,"message":"Transaction history is not available from this node"},"id":1}"#.to_string(),
6789 )
6790 );
6791 }
6792
6793 #[test]
6794 fn test_rpc_fail_request_airdrop() {
6795 let RpcHandler { meta, io, .. } = RpcHandler::start();
6796
6797 let bob_pubkey = solana_pubkey::new_rand();
6799 let req = format!(
6800 r#"{{"jsonrpc":"2.0","id":1,"method":"requestAirdrop","params":["{bob_pubkey}", 50]}}"#
6801 );
6802 let res = io.handle_request_sync(&req, meta);
6803 let expected =
6804 r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":1}"#;
6805 let expected: Response =
6806 serde_json::from_str(expected).expect("expected response deserialization");
6807 let result: Response = serde_json::from_str(&res.expect("actual response"))
6808 .expect("actual response deserialization");
6809 assert_eq!(result, expected);
6810 }
6811
6812 fn rpc_send_bad_tx<Client: ClientWithCreator>() {
6813 let genesis = create_genesis_config(100);
6814 let bank = Bank::new_for_tests(&genesis.genesis_config);
6815 let meta =
6816 JsonRpcRequestProcessor::new_from_bank::<Client>(bank, SocketAddrSpace::Unspecified);
6817
6818 let mut io = MetaIoHandler::default();
6819 io.extend_with(rpc_full::FullImpl.to_delegate());
6820
6821 let req = r#"{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["37u9WtQpcm6ULa3Vmu7ySnANv"]}"#;
6822 let res = io.handle_request_sync(req, meta);
6823 let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
6824 let error = &json["error"];
6825 assert_eq!(error["code"], ErrorCode::InvalidParams.code());
6826 }
6827
6828 #[test]
6829 fn test_rpc_send_bad_tx_connection_cache() {
6830 rpc_send_bad_tx::<ConnectionCacheClient<NullTpuInfo>>();
6831 }
6832
6833 #[test]
6834 fn test_rpc_send_bad_tx_tpu_client_next() {
6835 rpc_send_bad_tx::<TpuClientNextClient>();
6836 }
6837
6838 fn rpc_send_transaction_preflight<Client: ClientWithCreator>() {
6839 let exit = Arc::new(AtomicBool::new(false));
6840 let validator_exit = create_validator_exit(exit.clone());
6841 let ledger_path = get_tmp_ledger_path!();
6842 let blockstore = Arc::new(Blockstore::open(&ledger_path).unwrap());
6843 let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
6844 let (bank_forks, mint_keypair, ..) = new_bank_forks();
6845 let optimistically_confirmed_bank =
6846 OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
6847 let health = RpcHealth::stub(optimistically_confirmed_bank.clone(), blockstore.clone());
6848 health.stub_set_health_status(Some(RpcHealthStatus::Ok));
6850
6851 bank_forks.write().unwrap().get(0).unwrap().freeze();
6853
6854 let mut io = MetaIoHandler::default();
6855 io.extend_with(rpc_full::FullImpl.to_delegate());
6856 let cluster_info = Arc::new({
6857 let keypair = Arc::new(Keypair::new());
6858 let contact_info = ContactInfo::new_with_socketaddr(
6859 &keypair.pubkey(),
6860 &socketaddr!(Ipv4Addr::LOCALHOST, 1234),
6861 );
6862 ClusterInfo::new(contact_info, keypair, SocketAddrSpace::Unspecified)
6863 });
6864 let my_tpu_address = cluster_info.my_contact_info().tpu(Protocol::QUIC).unwrap();
6865 let config = JsonRpcConfig::default();
6866 let JsonRpcConfig {
6867 rpc_threads,
6868 rpc_blocking_threads,
6869 rpc_niceness_adj,
6870 ..
6871 } = config;
6872 let runtime = service_runtime(rpc_threads, rpc_blocking_threads, rpc_niceness_adj);
6873 let (meta, receiver) = JsonRpcRequestProcessor::new(
6874 config,
6875 None,
6876 bank_forks.clone(),
6877 block_commitment_cache,
6878 blockstore,
6879 validator_exit,
6880 health.clone(),
6881 cluster_info,
6882 Hash::default(),
6883 None,
6884 optimistically_confirmed_bank,
6885 Arc::new(RwLock::new(LargestAccountsCache::new(30))),
6886 Arc::new(MaxSlots::default()),
6887 Arc::new(LeaderScheduleCache::default()),
6888 Arc::new(AtomicU64::default()),
6889 Arc::new(PrioritizationFeeCache::default()),
6890 runtime.clone(),
6891 );
6892
6893 let client = Client::create_client(Some(runtime.handle().clone()), my_tpu_address, None, 1);
6894 assert!(
6895 client.protocol() == Protocol::QUIC,
6896 "UDP is not supported by this test."
6897 );
6898 SendTransactionService::new_with_client(
6899 &bank_forks,
6900 receiver,
6901 client,
6902 SendTransactionServiceConfig {
6903 retry_rate_ms: 1_000,
6904 leader_forward_count: 1,
6905 ..SendTransactionServiceConfig::default()
6906 },
6907 exit.clone(),
6908 );
6909
6910 let mut bad_transaction = system_transaction::transfer(
6911 &mint_keypair,
6912 &solana_pubkey::new_rand(),
6913 42,
6914 Hash::default(),
6915 );
6916
6917 let req = format!(
6919 r#"{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"#,
6920 bs58::encode(serialize(&bad_transaction).unwrap()).into_string()
6921 );
6922 let res = io.handle_request_sync(&req, meta.clone());
6923 assert_eq!(
6924 res,
6925 Some(
6926 r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found","data":{"accounts":null,"err":"BlockhashNotFound","fee":null,"innerInstructions":null,"loadedAccountsDataSize":0,"loadedAddresses":null,"logs":[],"postBalances":null,"postTokenBalances":null,"preBalances":null,"preTokenBalances":null,"replacementBlockhash":null,"returnData":null,"unitsConsumed":0}},"id":1}"#.to_string(),
6927 )
6928 );
6929
6930 bad_transaction.message.instructions[0].program_id_index = 0u8;
6932 let recent_blockhash = bank_forks.read().unwrap().root_bank().last_blockhash();
6933 bad_transaction.sign(&[&mint_keypair], recent_blockhash);
6934 let req = format!(
6935 r#"{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"#,
6936 bs58::encode(serialize(&bad_transaction).unwrap()).into_string()
6937 );
6938 let res = io.handle_request_sync(&req, meta.clone());
6939 assert_eq!(
6940 res,
6941 Some(
6942 r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"invalid transaction: Transaction failed to sanitize accounts offsets correctly"},"id":1}"#.to_string(),
6943 )
6944 );
6945 let mut bad_transaction = system_transaction::transfer(
6946 &mint_keypair,
6947 &solana_pubkey::new_rand(),
6948 42,
6949 recent_blockhash,
6950 );
6951
6952 health.stub_set_health_status(Some(RpcHealthStatus::Behind { num_slots: 42 }));
6954 let req = format!(
6955 r#"{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"#,
6956 bs58::encode(serialize(&bad_transaction).unwrap()).into_string()
6957 );
6958 let res = io.handle_request_sync(&req, meta.clone());
6959 assert_eq!(
6960 res,
6961 Some(
6962 r#"{"jsonrpc":"2.0","error":{"code":-32005,"message":"Node is behind by 42 slots","data":{"numSlotsBehind":42}},"id":1}"#.to_string(),
6963 )
6964 );
6965 health.stub_set_health_status(Some(RpcHealthStatus::Ok));
6966
6967 bad_transaction.signatures[0] = Signature::default();
6969
6970 let req = format!(
6971 r#"{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"#,
6972 bs58::encode(serialize(&bad_transaction).unwrap()).into_string()
6973 );
6974 let res = io.handle_request_sync(&req, meta.clone());
6975 let expected = json!({
6976 "jsonrpc": "2.0",
6977 "error": {
6978 "code": -32002,
6979 "data": {
6980 "accounts": null,
6981 "err": "SignatureFailure",
6982 "innerInstructions": null,
6983 "loadedAccountsDataSize": 0,
6984 "fee": null,
6985 "loadedAddresses": null,
6986 "preBalances": null,
6987 "postBalances": null,
6988 "preTokenBalances": null,
6989 "postTokenBalances": null,
6990 "logs": [],
6991 "replacementBlockhash": null,
6992 "returnData": null,
6993 "unitsConsumed": 0,
6994 },
6995 "message": "Transaction simulation failed: Transaction did not pass signature verification",
6996 },
6997 "id": 1,
6998 });
6999
7000 let expected: Response =
7001 serde_json::from_value(expected).expect("expected response deserialization");
7002 let result: Response = serde_json::from_str(&res.expect("actual response"))
7003 .expect("actual response deserialization");
7004 assert_eq!(result, expected);
7005
7006 let req = format!(
7009 r#"{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}", {{"skipPreflight": true}}]}}"#,
7010 bs58::encode(serialize(&bad_transaction).unwrap()).into_string()
7011 );
7012 let res = io.handle_request_sync(&req, meta.clone());
7013 assert_eq!(
7014 res,
7015 Some(
7016 r#"{"jsonrpc":"2.0","result":"1111111111111111111111111111111111111111111111111111111111111111","id":1}"#.to_string(),
7017 )
7018 );
7019
7020 bad_transaction.signatures.clear();
7022 let req = format!(
7023 r#"{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"#,
7024 bs58::encode(serialize(&bad_transaction).unwrap()).into_string()
7025 );
7026 let res = io.handle_request_sync(&req, meta);
7027 assert_eq!(
7028 res,
7029 Some(
7030 r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"invalid transaction: Transaction failed to sanitize accounts offsets correctly"},"id":1}"#.to_string(),
7031 )
7032 );
7033 }
7034
7035 #[test]
7036 fn test_rpc_send_transaction_preflight_with_connection_cache() {
7037 rpc_send_transaction_preflight::<ConnectionCacheClient<NullTpuInfo>>();
7038 }
7039
7040 #[test]
7041 fn test_rpc_send_transaction_preflight_with_tpu_client_next() {
7042 rpc_send_transaction_preflight::<TpuClientNextClient>();
7043 }
7044
7045 #[test]
7046 fn test_rpc_verify_filter() {
7047 let filter = RpcFilterType::Memcmp(Memcmp::new(
7048 0, MemcmpEncodedBytes::Base58("13LeFbG6m2EP1fqCj9k66fcXsoTHMMtgr7c78AivUrYD".to_string()), ));
7051 assert_eq!(verify_filter(&filter), Ok(()));
7052 let filter = RpcFilterType::Memcmp(Memcmp::new(
7054 0, MemcmpEncodedBytes::Base58("III".to_string()), ));
7057 assert!(verify_filter(&filter).is_err());
7058 }
7059
7060 #[test]
7061 fn test_rpc_verify_pubkey() {
7062 let pubkey = solana_pubkey::new_rand();
7063 assert_eq!(verify_pubkey(&pubkey.to_string()).unwrap(), pubkey);
7064 let bad_pubkey = "a1b2c3d4";
7065 assert_eq!(
7066 verify_pubkey(bad_pubkey),
7067 Err(Error::invalid_params("Invalid param: WrongSize"))
7068 );
7069 }
7070
7071 #[test]
7072 fn test_rpc_verify_signature() {
7073 let tx = system_transaction::transfer(
7074 &Keypair::new(),
7075 &solana_pubkey::new_rand(),
7076 20,
7077 hash(&[0]),
7078 );
7079 assert_eq!(
7080 verify_signature(&tx.signatures[0].to_string()).unwrap(),
7081 tx.signatures[0]
7082 );
7083 let bad_signature = "a1b2c3d4";
7084 assert_eq!(
7085 verify_signature(bad_signature),
7086 Err(Error::invalid_params("Invalid param: WrongSize"))
7087 );
7088 }
7089
7090 fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair, Arc<Keypair>) {
7091 new_bank_forks_with_config(BankTestConfig::default())
7092 }
7093
7094 fn new_bank_forks_with_config(
7095 config: BankTestConfig,
7096 ) -> (Arc<RwLock<BankForks>>, Keypair, Arc<Keypair>) {
7097 let GenesisConfigInfo {
7098 mut genesis_config,
7099 mint_keypair,
7100 voting_keypair,
7101 ..
7102 } = create_genesis_config(TEST_MINT_LAMPORTS);
7103
7104 genesis_config.rent.lamports_per_byte_year = 50;
7105 genesis_config.rent.exemption_threshold = 2.0;
7106 genesis_config.epoch_schedule =
7107 EpochSchedule::custom(TEST_SLOTS_PER_EPOCH, TEST_SLOTS_PER_EPOCH, false);
7108 genesis_config.fee_rate_governor = FeeRateGovernor::new(TEST_SIGNATURE_FEE, 0);
7109
7110 let bank = Bank::new_with_config_for_tests(&genesis_config, config);
7111
7112 bank.add_builtin(
7114 TestBuiltinEntrypoint::PROGRAM_ID,
7115 TestBuiltinEntrypoint::NAME,
7116 TestBuiltinEntrypoint::cache_entry(),
7117 );
7118
7119 (
7120 BankForks::new_rw_arc(bank),
7121 mint_keypair,
7122 Arc::new(voting_keypair),
7123 )
7124 }
7125
7126 #[test]
7127 fn test_rpc_get_identity() {
7128 let rpc = RpcHandler::start();
7129 let request = create_test_request("getIdentity", None);
7130 let result: Value = parse_success_result(rpc.handle_request_sync(request));
7131 let expected: Value = json!({ "identity": rpc.identity.to_string() });
7132 assert_eq!(result, expected);
7133 }
7134
7135 #[test]
7136 fn test_rpc_get_max_slots() {
7137 let rpc = RpcHandler::start();
7138 rpc.max_slots.retransmit.store(42, Ordering::Relaxed);
7139 rpc.max_slots.shred_insert.store(43, Ordering::Relaxed);
7140
7141 let request = create_test_request("getMaxRetransmitSlot", None);
7142 let result: Slot = parse_success_result(rpc.handle_request_sync(request));
7143 assert_eq!(result, 42);
7144
7145 let request = create_test_request("getMaxShredInsertSlot", None);
7146 let result: Slot = parse_success_result(rpc.handle_request_sync(request));
7147 assert_eq!(result, 43);
7148 }
7149
7150 #[test]
7151 fn test_rpc_get_version() {
7152 let rpc = RpcHandler::start();
7153 let request = create_test_request("getVersion", None);
7154 let result: Value = parse_success_result(rpc.handle_request_sync(request));
7155 let expected = {
7156 let version = solana_version::Version::default();
7157 json!({
7158 "solana-core": version.to_string(),
7159 "feature-set": version.feature_set,
7160 })
7161 };
7162 assert_eq!(result, expected);
7163 }
7164
7165 fn rpc_processor_get_block_commitment<Client: ClientWithCreator>() {
7166 let exit = Arc::new(AtomicBool::new(false));
7167 let validator_exit = create_validator_exit(exit.clone());
7168 let bank_forks = new_bank_forks().0;
7169 let ledger_path = get_tmp_ledger_path!();
7170 let blockstore = Arc::new(Blockstore::open(&ledger_path).unwrap());
7171
7172 let commitment_slot0 = BlockCommitment::new([8; MAX_LOCKOUT_HISTORY + 1]);
7173 let commitment_slot1 = BlockCommitment::new([9; MAX_LOCKOUT_HISTORY + 1]);
7174 let mut block_commitment: HashMap<u64, BlockCommitment> = HashMap::new();
7175 block_commitment
7176 .entry(0)
7177 .or_insert_with(|| commitment_slot0.clone());
7178 block_commitment
7179 .entry(1)
7180 .or_insert_with(|| commitment_slot1.clone());
7181 let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new(
7182 block_commitment,
7183 42,
7184 CommitmentSlots::new_from_slot(bank_forks.read().unwrap().highest_slot()),
7185 )));
7186
7187 let cluster_info = Arc::new(new_test_cluster_info());
7188 let my_tpu_address = cluster_info.my_contact_info().tpu(Protocol::QUIC).unwrap();
7189 let optimistically_confirmed_bank =
7190 OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
7191 let config = JsonRpcConfig::default();
7192 let JsonRpcConfig {
7193 rpc_threads,
7194 rpc_blocking_threads,
7195 rpc_niceness_adj,
7196 ..
7197 } = config;
7198 let runtime = service_runtime(rpc_threads, rpc_blocking_threads, rpc_niceness_adj);
7199 let client = Client::create_client(Some(runtime.handle().clone()), my_tpu_address, None, 1);
7200 let (request_processor, receiver) = JsonRpcRequestProcessor::new(
7201 config,
7202 None,
7203 bank_forks.clone(),
7204 block_commitment_cache,
7205 blockstore.clone(),
7206 validator_exit,
7207 RpcHealth::stub(optimistically_confirmed_bank.clone(), blockstore),
7208 cluster_info,
7209 Hash::default(),
7210 None,
7211 optimistically_confirmed_bank,
7212 Arc::new(RwLock::new(LargestAccountsCache::new(30))),
7213 Arc::new(MaxSlots::default()),
7214 Arc::new(LeaderScheduleCache::default()),
7215 Arc::new(AtomicU64::default()),
7216 Arc::new(PrioritizationFeeCache::default()),
7217 runtime,
7218 );
7219
7220 SendTransactionService::new_with_client(
7221 &bank_forks,
7222 receiver,
7223 client,
7224 SendTransactionServiceConfig {
7225 retry_rate_ms: 1_000,
7226 leader_forward_count: 1,
7227 ..SendTransactionServiceConfig::default()
7228 },
7229 exit.clone(),
7230 );
7231
7232 assert_eq!(
7233 request_processor.get_block_commitment(0),
7234 RpcBlockCommitment {
7235 commitment: Some(commitment_slot0.commitment),
7236 total_stake: 42,
7237 }
7238 );
7239 assert_eq!(
7240 request_processor.get_block_commitment(1),
7241 RpcBlockCommitment {
7242 commitment: Some(commitment_slot1.commitment),
7243 total_stake: 42,
7244 }
7245 );
7246 assert_eq!(
7247 request_processor.get_block_commitment(2),
7248 RpcBlockCommitment {
7249 commitment: None,
7250 total_stake: 42,
7251 }
7252 );
7253 }
7254
7255 #[test]
7256 fn test_rpc_processor_get_block_commitment_with_connection_cache() {
7257 rpc_processor_get_block_commitment::<ConnectionCacheClient<NullTpuInfo>>();
7258 }
7259
7260 #[test]
7261 fn test_rpc_processor_get_block_commitment_with_tpu_client_next() {
7262 rpc_processor_get_block_commitment::<TpuClientNextClient>();
7263 }
7264
7265 #[test]
7266 fn test_rpc_get_block_commitment() {
7267 let rpc = RpcHandler::start();
7268
7269 let expected_total_stake = 42;
7270 let mut block_0_commitment = BlockCommitment::default();
7271 block_0_commitment.increase_confirmation_stake(2, 9);
7272 let _ = std::mem::replace(
7273 &mut *rpc.block_commitment_cache.write().unwrap(),
7274 BlockCommitmentCache::new(
7275 HashMap::from_iter(std::iter::once((0, block_0_commitment.clone()))),
7276 expected_total_stake,
7277 CommitmentSlots::new_from_slot(0),
7278 ),
7279 );
7280
7281 let request = create_test_request("getBlockCommitment", Some(json!([0u64])));
7282 let result: RpcBlockCommitment<_> = parse_success_result(rpc.handle_request_sync(request));
7283 let expected = RpcBlockCommitment {
7284 commitment: Some(block_0_commitment.commitment),
7285 total_stake: expected_total_stake,
7286 };
7287 assert_eq!(result, expected);
7288
7289 let request = create_test_request("getBlockCommitment", Some(json!([1u64])));
7290 let result: Value = parse_success_result(rpc.handle_request_sync(request));
7291 let expected = json!({
7292 "commitment": null,
7293 "totalStake": expected_total_stake,
7294 });
7295 assert_eq!(result, expected);
7296 }
7297
7298 #[test]
7299 fn test_get_block_with_versioned_tx() {
7300 let rpc = RpcHandler::start();
7301
7302 let bank = rpc.working_bank();
7303 bank.set_sysvar_for_tests(&SlotHashes::default());
7305 rpc.create_test_versioned_transactions_and_populate_blockstore(None);
7307
7308 let request = create_test_request(
7309 "getBlock",
7310 Some(json!([
7311 0u64,
7312 {"maxSupportedTransactionVersion": 0},
7313 ])),
7314 );
7315 let result: Option<EncodedConfirmedBlock> =
7316 parse_success_result(rpc.handle_request_sync(request));
7317 let confirmed_block = result.unwrap();
7318 assert_eq!(confirmed_block.transactions.len(), 2);
7319 assert_eq!(
7320 confirmed_block.transactions[0].version,
7321 Some(TransactionVersion::LEGACY)
7322 );
7323 assert_eq!(
7324 confirmed_block.transactions[1].version,
7325 Some(TransactionVersion::Number(0))
7326 );
7327
7328 let request = create_test_request("getBlock", Some(json!([0u64,])));
7329 let response = parse_failure_response(rpc.handle_request_sync(request));
7330 let expected = (
7331 JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION,
7332 String::from(
7333 "Transaction version (0) is not supported by the requesting client. Please try \
7334 the request again with the following configuration parameter: \
7335 \"maxSupportedTransactionVersion\": 0",
7336 ),
7337 );
7338 assert_eq!(response, expected);
7339 }
7340
7341 #[test]
7342 fn test_get_block() {
7343 let mut rpc = RpcHandler::start();
7344 let confirmed_block_signatures = rpc.create_test_transactions_and_populate_blockstore();
7345
7346 let request = create_test_request("getBlock", Some(json!([0u64])));
7347 let result: Option<EncodedConfirmedBlock> =
7348 parse_success_result(rpc.handle_request_sync(request));
7349
7350 let confirmed_block = result.unwrap();
7351 assert_eq!(confirmed_block.transactions.len(), 2);
7352 assert_eq!(confirmed_block.rewards, vec![]);
7353
7354 for EncodedTransactionWithStatusMeta {
7355 transaction,
7356 meta,
7357 version,
7358 } in confirmed_block.transactions.into_iter()
7359 {
7360 assert_eq!(
7361 version, None,
7362 "requests which don't set max_supported_transaction_version shouldn't receive a \
7363 version"
7364 );
7365 if let EncodedTransaction::Json(transaction) = transaction {
7366 if transaction.signatures[0] == confirmed_block_signatures[0].to_string() {
7367 let meta = meta.unwrap();
7368 assert_eq!(meta.status, Ok(()));
7369 assert_eq!(meta.err, None);
7370 } else if transaction.signatures[0] == confirmed_block_signatures[1].to_string() {
7371 let meta = meta.unwrap();
7372 assert_eq!(
7373 meta.err,
7374 Some(
7375 TransactionError::InstructionError(0, InstructionError::Custom(1))
7376 .into()
7377 )
7378 );
7379 assert_eq!(
7380 meta.status,
7381 Err(
7382 TransactionError::InstructionError(0, InstructionError::Custom(1))
7383 .into()
7384 ),
7385 );
7386 } else {
7387 assert_eq!(meta, None);
7388 }
7389 }
7390 }
7391
7392 let request = create_test_request("getBlock", Some(json!([0u64, "binary"])));
7393 let result: Option<EncodedConfirmedBlock> =
7394 parse_success_result(rpc.handle_request_sync(request));
7395 let confirmed_block = result.unwrap();
7396 assert_eq!(confirmed_block.transactions.len(), 2);
7397 assert_eq!(confirmed_block.rewards, vec![]);
7398
7399 for EncodedTransactionWithStatusMeta {
7400 transaction,
7401 meta,
7402 version,
7403 } in confirmed_block.transactions.into_iter()
7404 {
7405 assert_eq!(
7406 version, None,
7407 "requests which don't set max_supported_transaction_version shouldn't receive a \
7408 version"
7409 );
7410 if let EncodedTransaction::LegacyBinary(transaction) = transaction {
7411 let decoded_transaction: Transaction =
7412 deserialize(&bs58::decode(&transaction).into_vec().unwrap()).unwrap();
7413 if decoded_transaction.signatures[0] == confirmed_block_signatures[0] {
7414 let meta = meta.unwrap();
7415 assert_eq!(meta.status, Ok(()));
7416 assert_eq!(meta.err, None);
7417 } else if decoded_transaction.signatures[0] == confirmed_block_signatures[1] {
7418 let meta = meta.unwrap();
7419 assert_eq!(
7420 meta.err,
7421 Some(
7422 TransactionError::InstructionError(0, InstructionError::Custom(1))
7423 .into()
7424 )
7425 );
7426 assert_eq!(
7427 meta.status,
7428 Err(
7429 TransactionError::InstructionError(0, InstructionError::Custom(1))
7430 .into()
7431 ),
7432 );
7433 } else {
7434 assert_eq!(meta, None);
7435 }
7436 }
7437 }
7438
7439 rpc.meta.config.enable_rpc_transaction_history = false;
7441 let request = create_test_request("getBlock", Some(json!([0u64])));
7442 let response = parse_failure_response(rpc.handle_request_sync(request));
7443 let expected = (
7444 JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE,
7445 String::from("Transaction history is not available from this node"),
7446 );
7447 assert_eq!(response, expected);
7448 }
7449
7450 #[test]
7451 fn test_get_block_config() {
7452 let rpc = RpcHandler::start();
7453 let confirmed_block_signatures = rpc.create_test_transactions_and_populate_blockstore();
7454
7455 let request = create_test_request(
7456 "getBlock",
7457 Some(json!([
7458 0u64,
7459 RpcBlockConfig {
7460 encoding: None,
7461 transaction_details: Some(TransactionDetails::Signatures),
7462 rewards: Some(false),
7463 commitment: None,
7464 max_supported_transaction_version: None,
7465 },
7466 ])),
7467 );
7468 let result: Option<UiConfirmedBlock> =
7469 parse_success_result(rpc.handle_request_sync(request));
7470
7471 let confirmed_block = result.unwrap();
7472 assert!(confirmed_block.transactions.is_none());
7473 assert!(confirmed_block.rewards.is_none());
7474 for (i, signature) in confirmed_block.signatures.unwrap()[..2].iter().enumerate() {
7475 assert_eq!(*signature, confirmed_block_signatures[i].to_string());
7476 }
7477
7478 let request = create_test_request(
7479 "getBlock",
7480 Some(json!([
7481 0u64,
7482 RpcBlockConfig {
7483 encoding: None,
7484 transaction_details: Some(TransactionDetails::None),
7485 rewards: Some(true),
7486 commitment: None,
7487 max_supported_transaction_version: None,
7488 },
7489 ])),
7490 );
7491 let result: Option<UiConfirmedBlock> =
7492 parse_success_result(rpc.handle_request_sync(request));
7493 let confirmed_block = result.unwrap();
7494 assert!(confirmed_block.transactions.is_none());
7495 assert!(confirmed_block.signatures.is_none());
7496 assert_eq!(confirmed_block.rewards.unwrap(), vec![]);
7497 }
7498
7499 #[test]
7500 fn test_get_block_production() {
7501 let rpc = RpcHandler::start();
7502 rpc.add_roots_to_blockstore(vec![0, 1, 3, 4, 8]);
7503 rpc.block_commitment_cache
7504 .write()
7505 .unwrap()
7506 .set_highest_super_majority_root(8);
7507
7508 let request = create_test_request("getBlockProduction", Some(json!([])));
7509 let result: RpcResponse<RpcBlockProduction> =
7510 parse_success_result(rpc.handle_request_sync(request));
7511 let expected = RpcBlockProduction {
7512 by_identity: HashMap::from_iter(std::iter::once((
7513 rpc.leader_pubkey().to_string(),
7514 (9, 5),
7515 ))),
7516 range: RpcBlockProductionRange {
7517 first_slot: 0,
7518 last_slot: 8,
7519 },
7520 };
7521 assert_eq!(result.value, expected);
7522
7523 let request = create_test_request(
7524 "getBlockProduction",
7525 Some(json!([{
7526 "identity": rpc.leader_pubkey().to_string()
7527 }])),
7528 );
7529 let result: RpcResponse<RpcBlockProduction> =
7530 parse_success_result(rpc.handle_request_sync(request));
7531 assert_eq!(result.value, expected);
7532
7533 let request = create_test_request(
7534 "getBlockProduction",
7535 Some(json!([{
7536 "identity": Pubkey::new_unique().to_string(),
7537 "range": {
7538 "firstSlot": 0u64,
7539 "lastSlot": 4u64,
7540 },
7541 }])),
7542 );
7543 let result: RpcResponse<RpcBlockProduction> =
7544 parse_success_result(rpc.handle_request_sync(request));
7545 let expected = RpcBlockProduction {
7546 by_identity: HashMap::new(),
7547 range: RpcBlockProductionRange {
7548 first_slot: 0,
7549 last_slot: 4,
7550 },
7551 };
7552 assert_eq!(result.value, expected);
7553 }
7554
7555 #[test]
7556 fn test_get_blocks() {
7557 let rpc = RpcHandler::start();
7558 let _ = rpc.create_test_transactions_and_populate_blockstore();
7559 rpc.add_roots_to_blockstore(vec![0, 1, 3, 4, 8]);
7560 rpc.block_commitment_cache
7561 .write()
7562 .unwrap()
7563 .set_highest_super_majority_root(8);
7564
7565 let request = create_test_request("getBlocks", Some(json!([0u64])));
7566 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7567 assert_eq!(result, vec![0, 1, 3, 4, 8]);
7568
7569 let request = create_test_request("getBlocks", Some(json!([2u64])));
7570 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7571 assert_eq!(result, vec![3, 4, 8]);
7572
7573 let request = create_test_request("getBlocks", Some(json!([0u64, 4u64])));
7574 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7575 assert_eq!(result, vec![0, 1, 3, 4]);
7576
7577 let request = create_test_request("getBlocks", Some(json!([0u64, 7u64])));
7578 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7579 assert_eq!(result, vec![0, 1, 3, 4]);
7580
7581 let request = create_test_request("getBlocks", Some(json!([9u64, 11u64])));
7582 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7583 assert_eq!(result, Vec::<Slot>::new());
7584
7585 rpc.block_commitment_cache
7586 .write()
7587 .unwrap()
7588 .set_highest_super_majority_root(u64::MAX);
7589
7590 let request = create_test_request(
7591 "getBlocks",
7592 Some(json!([0u64, MAX_GET_CONFIRMED_BLOCKS_RANGE])),
7593 );
7594 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7595 assert_eq!(result, vec![0, 1, 3, 4, 8]);
7596
7597 let request = create_test_request(
7598 "getBlocks",
7599 Some(json!([0u64, MAX_GET_CONFIRMED_BLOCKS_RANGE + 1])),
7600 );
7601 let response = parse_failure_response(rpc.handle_request_sync(request));
7602 let expected = (
7603 ErrorCode::InvalidParams.code(),
7604 String::from("Slot range too large; max 500000"),
7605 );
7606 assert_eq!(response, expected);
7607 }
7608
7609 #[test]
7610 fn test_get_blocks_with_limit() {
7611 let rpc = RpcHandler::start();
7612 rpc.add_roots_to_blockstore(vec![0, 1, 3, 4, 8]);
7613 rpc.block_commitment_cache
7614 .write()
7615 .unwrap()
7616 .set_highest_super_majority_root(8);
7617
7618 let request = create_test_request("getBlocksWithLimit", Some(json!([0u64, 500_001u64])));
7619 let response = parse_failure_response(rpc.handle_request_sync(request));
7620 let expected = (
7621 ErrorCode::InvalidParams.code(),
7622 String::from("Limit too large; max 500000"),
7623 );
7624 assert_eq!(response, expected);
7625
7626 let request = create_test_request("getBlocksWithLimit", Some(json!([0u64, 0u64])));
7627 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7628 assert_eq!(result, Vec::<Slot>::new());
7629
7630 let request = create_test_request("getBlocksWithLimit", Some(json!([2u64, 2u64])));
7631 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7632 assert_eq!(result, vec![3, 4]);
7633
7634 let request = create_test_request("getBlocksWithLimit", Some(json!([2u64, 3u64])));
7635 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7636 assert_eq!(result, vec![3, 4, 8]);
7637
7638 let request = create_test_request("getBlocksWithLimit", Some(json!([2u64, 500_000u64])));
7639 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7640 assert_eq!(result, vec![3, 4, 8]);
7641
7642 let request = create_test_request("getBlocksWithLimit", Some(json!([9u64, 500_000u64])));
7643 let result: Vec<Slot> = parse_success_result(rpc.handle_request_sync(request));
7644 assert_eq!(result, Vec::<Slot>::new());
7645 }
7646
7647 #[test]
7648 fn test_get_block_time() {
7649 let rpc = RpcHandler::start();
7650 rpc.add_roots_to_blockstore(vec![1, 2, 3, 4, 5, 6, 7]);
7651
7652 let base_timestamp = rpc
7653 .bank_forks
7654 .read()
7655 .unwrap()
7656 .get(0)
7657 .unwrap()
7658 .unix_timestamp_from_genesis();
7659 rpc.block_commitment_cache
7660 .write()
7661 .unwrap()
7662 .set_highest_super_majority_root(7);
7663
7664 let slot_duration = slot_duration_from_slots_per_year(rpc.working_bank().slots_per_year());
7665
7666 let request = create_test_request("getBlockTime", Some(json!([2u64])));
7667 let result: Option<UnixTimestamp> = parse_success_result(rpc.handle_request_sync(request));
7668 let expected = Some(base_timestamp);
7669 assert_eq!(result, expected);
7670
7671 let request = create_test_request("getBlockTime", Some(json!([7u64])));
7672 let result: Option<UnixTimestamp> = parse_success_result(rpc.handle_request_sync(request));
7673 let expected = Some(base_timestamp + (7 * slot_duration).as_secs() as i64);
7674 assert_eq!(result, expected);
7675
7676 let request = create_test_request("getBlockTime", Some(json!([12345u64])));
7677 let response = parse_failure_response(rpc.handle_request_sync(request));
7678 let expected = (
7679 JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE,
7680 String::from("Block not available for slot 12345"),
7681 );
7682 assert_eq!(response, expected);
7683 }
7684
7685 #[test]
7686 fn test_get_vote_accounts() {
7687 let rpc = RpcHandler::start();
7688 let mut bank = rpc.working_bank();
7689 let RpcHandler {
7690 ref io,
7691 ref meta,
7692 ref mint_keypair,
7693 ref leader_vote_keypair,
7694 ..
7695 } = rpc;
7696
7697 assert_eq!(bank.vote_accounts().len(), 1);
7698
7699 let alice_vote_keypair = Keypair::new();
7701 let alice_vote_state = VoteStateV4::new(
7702 &alice_vote_keypair.pubkey(),
7703 &VoteInit {
7704 node_pubkey: mint_keypair.pubkey(),
7705 authorized_voter: alice_vote_keypair.pubkey(),
7706 authorized_withdrawer: alice_vote_keypair.pubkey(),
7707 commission: 0,
7708 },
7709 &bank.get_sysvar_cache_for_tests().get_clock().unwrap(),
7710 );
7711 rpc.store_vote_account(&alice_vote_keypair.pubkey(), alice_vote_state);
7712 assert_eq!(bank.vote_accounts().len(), 2);
7713
7714 {
7717 let req = r#"{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts"}"#;
7718 let res = io.handle_request_sync(req, meta.clone());
7719 let result: Value = serde_json::from_str(&res.expect("actual response"))
7720 .expect("actual response deserialization");
7721
7722 let vote_account_status: RpcVoteAccountStatus =
7723 serde_json::from_value(result["result"].clone()).unwrap();
7724
7725 assert!(vote_account_status.current.is_empty());
7726 assert_eq!(vote_account_status.delinquent.len(), 1);
7727 for vote_account_info in vote_account_status.delinquent {
7728 assert_ne!(vote_account_info.activated_stake, 0);
7729 }
7730 }
7731
7732 let mut advance_bank = || {
7733 bank.freeze();
7734
7735 let instructions = [
7737 vote_instruction::tower_sync(
7738 &leader_vote_keypair.pubkey(),
7739 &leader_vote_keypair.pubkey(),
7740 TowerSync::new_from_slot(bank.slot(), bank.hash()),
7741 ),
7742 vote_instruction::tower_sync(
7743 &alice_vote_keypair.pubkey(),
7744 &alice_vote_keypair.pubkey(),
7745 TowerSync::new_from_slot(bank.slot(), bank.hash()),
7746 ),
7747 ];
7748
7749 bank = rpc.advance_bank_to_confirmed_slot(bank.slot() + 1);
7750
7751 let transaction = Transaction::new_signed_with_payer(
7752 &instructions,
7753 Some(&rpc.mint_keypair.pubkey()),
7754 &[&rpc.mint_keypair, leader_vote_keypair, &alice_vote_keypair],
7755 bank.last_blockhash(),
7756 );
7757
7758 bank.process_transaction(&transaction)
7759 .expect("process transaction");
7760 };
7761
7762 for _ in 0..TEST_SLOTS_PER_EPOCH {
7764 advance_bank();
7765 }
7766
7767 let req = format!(
7768 r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"#,
7769 json!([CommitmentConfig::processed()])
7770 );
7771
7772 let res = io.handle_request_sync(&req, meta.clone());
7773 let result: Value = serde_json::from_str(&res.expect("actual response"))
7774 .expect("actual response deserialization");
7775
7776 let vote_account_status: RpcVoteAccountStatus =
7777 serde_json::from_value(result["result"].clone()).unwrap();
7778
7779 assert!(vote_account_status.delinquent.is_empty());
7781
7782 assert_eq!(vote_account_status.current.len(), 2);
7784 let leader_info = vote_account_status
7785 .current
7786 .iter()
7787 .find(|x| x.vote_pubkey == leader_vote_keypair.pubkey().to_string())
7788 .unwrap();
7789 assert_ne!(leader_info.activated_stake, 0);
7790 let credits_per_slot =
7793 solana_vote_program::vote_state::VOTE_CREDITS_MAXIMUM_PER_SLOT as u64;
7794 let expected_credits =
7795 (TEST_SLOTS_PER_EPOCH - MAX_LOCKOUT_HISTORY as u64 - 1) * credits_per_slot;
7796 assert_eq!(
7797 leader_info.epoch_credits,
7798 vec![
7799 (0, expected_credits, 0),
7800 (1, expected_credits + credits_per_slot, expected_credits) ]
7802 );
7803
7804 {
7806 let req = format!(
7807 r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"#,
7808 json!([RpcGetVoteAccountsConfig {
7809 vote_pubkey: Some(leader_vote_keypair.pubkey().to_string()),
7810 commitment: Some(CommitmentConfig::processed()),
7811 ..RpcGetVoteAccountsConfig::default()
7812 }])
7813 );
7814
7815 let res = io.handle_request_sync(&req, meta.clone());
7816 let result: Value = serde_json::from_str(&res.expect("actual response"))
7817 .expect("actual response deserialization");
7818
7819 let vote_account_status: RpcVoteAccountStatus =
7820 serde_json::from_value(result["result"].clone()).unwrap();
7821
7822 assert_eq!(vote_account_status.current.len(), 1);
7823 assert_eq!(vote_account_status.delinquent.len(), 0);
7824 for vote_account_info in vote_account_status.current {
7825 assert_eq!(
7826 vote_account_info.vote_pubkey,
7827 leader_vote_keypair.pubkey().to_string()
7828 );
7829 }
7830 }
7831
7832 for _ in
7835 0..(TEST_SLOTS_PER_EPOCH * (MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY) as u64)
7836 {
7837 advance_bank();
7838 }
7839
7840 let req = format!(
7841 r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"#,
7842 json!([CommitmentConfig::processed()])
7843 );
7844
7845 let res = io.handle_request_sync(&req, meta.clone());
7846 let result: Value = serde_json::from_str(&res.expect("actual response"))
7847 .expect("actual response deserialization");
7848
7849 let vote_account_status: RpcVoteAccountStatus =
7850 serde_json::from_value(result["result"].clone()).unwrap();
7851
7852 assert!(vote_account_status.delinquent.is_empty());
7853 assert!(!vote_account_status
7854 .current
7855 .iter()
7856 .any(|x| x.epoch_credits.len() != MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY));
7857
7858 rpc.advance_bank_to_confirmed_slot(bank.slot() + TEST_SLOTS_PER_EPOCH);
7860
7861 {
7864 let req = format!(
7865 r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"#,
7866 json!([CommitmentConfig::processed()])
7867 );
7868
7869 let res = io.handle_request_sync(&req, meta.clone());
7870 let result: Value = serde_json::from_str(&res.expect("actual response"))
7871 .expect("actual response deserialization");
7872
7873 let vote_account_status: RpcVoteAccountStatus =
7874 serde_json::from_value(result["result"].clone()).unwrap();
7875
7876 assert!(vote_account_status.current.is_empty());
7877 assert_eq!(vote_account_status.delinquent.len(), 1);
7878 for vote_account_info in vote_account_status.delinquent {
7879 assert_eq!(
7880 vote_account_info.vote_pubkey,
7881 rpc.leader_vote_keypair.pubkey().to_string()
7882 );
7883 }
7884 }
7885 }
7886
7887 #[test]
7888 fn test_is_finalized() {
7889 let bank = Arc::new(Bank::default_for_tests());
7890 let ledger_path = get_tmp_ledger_path!();
7891 let blockstore = Arc::new(Blockstore::open(&ledger_path).unwrap());
7892 blockstore.set_roots([0, 1].iter()).unwrap();
7893 let mut cache0 = BlockCommitment::default();
7895 cache0.increase_rooted_stake(50);
7896 let mut cache1 = BlockCommitment::default();
7897 cache1.increase_rooted_stake(40);
7898 let mut cache2 = BlockCommitment::default();
7899 cache2.increase_rooted_stake(20);
7900
7901 let mut block_commitment = HashMap::new();
7902 block_commitment.entry(1).or_insert(cache0);
7903 block_commitment.entry(2).or_insert(cache1);
7904 block_commitment.entry(3).or_insert(cache2);
7905 let highest_super_majority_root = 1;
7906 let block_commitment_cache = BlockCommitmentCache::new(
7907 block_commitment,
7908 50,
7909 CommitmentSlots {
7910 slot: bank.slot(),
7911 highest_super_majority_root,
7912 ..CommitmentSlots::default()
7913 },
7914 );
7915
7916 assert!(is_finalized(&block_commitment_cache, &bank, &blockstore, 0));
7917 assert!(is_finalized(&block_commitment_cache, &bank, &blockstore, 1));
7918 assert!(!is_finalized(
7919 &block_commitment_cache,
7920 &bank,
7921 &blockstore,
7922 2
7923 ));
7924 assert!(!is_finalized(
7925 &block_commitment_cache,
7926 &bank,
7927 &blockstore,
7928 3
7929 ));
7930 }
7931
7932 #[test]
7933 fn test_token_rpcs() {
7934 for program_id in solana_account_decoder::parse_token::spl_token_ids() {
7935 let rpc = RpcHandler::start();
7936 let bank = rpc.working_bank();
7937 let RpcHandler { io, meta, .. } = rpc;
7938 let mint = Pubkey::new_from_array([2; 32]);
7939 let owner = Pubkey::new_from_array([3; 32]);
7940 let delegate = Pubkey::new_from_array([4; 32]);
7941 let token_account_pubkey = solana_pubkey::new_rand();
7942 let token_with_different_mint_pubkey = solana_pubkey::new_rand();
7943 let new_mint = Pubkey::new_from_array([5; 32]);
7944 if program_id == spl_generic_token::token_2022::id() {
7945 let account_base = TokenAccount {
7947 mint,
7948 owner,
7949 delegate: COption::Some(delegate),
7950 amount: 420,
7951 state: TokenAccountState::Initialized,
7952 is_native: COption::None,
7953 delegated_amount: 30,
7954 close_authority: COption::Some(owner),
7955 };
7956 let account_size = ExtensionType::try_calculate_account_len::<TokenAccount>(&[
7957 ExtensionType::ImmutableOwner,
7958 ExtensionType::MemoTransfer,
7959 ])
7960 .unwrap();
7961 let mut account_data = vec![0; account_size];
7962 let mut account_state =
7963 StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data)
7964 .unwrap();
7965
7966 account_state.base = account_base;
7967 account_state.pack_base();
7968 account_state.init_account_type().unwrap();
7969 account_state
7970 .init_extension::<ImmutableOwner>(true)
7971 .unwrap();
7972 let memo_transfer = account_state.init_extension::<MemoTransfer>(true).unwrap();
7973 memo_transfer.require_incoming_transfer_memos = true.into();
7974
7975 let token_account = AccountSharedData::from(Account {
7976 lamports: 111,
7977 data: account_data.to_vec(),
7978 owner: program_id,
7979 ..Account::default()
7980 });
7981 bank.store_account(&token_account_pubkey, &token_account);
7982
7983 let mint_size = ExtensionType::try_calculate_account_len::<Mint>(&[
7985 ExtensionType::MintCloseAuthority,
7986 ])
7987 .unwrap();
7988 let mint_base = Mint {
7989 mint_authority: COption::Some(owner),
7990 supply: 500,
7991 decimals: 2,
7992 is_initialized: true,
7993 freeze_authority: COption::Some(owner),
7994 };
7995 let mut mint_data = vec![0; mint_size];
7996 let mut mint_state =
7997 StateWithExtensionsMut::<Mint>::unpack_uninitialized(&mut mint_data).unwrap();
7998
7999 mint_state.base = mint_base;
8000 mint_state.pack_base();
8001 mint_state.init_account_type().unwrap();
8002 let mint_close_authority = mint_state
8003 .init_extension::<MintCloseAuthority>(true)
8004 .unwrap();
8005 mint_close_authority.close_authority =
8006 OptionalNonZeroPubkey::try_from(Some(owner)).unwrap();
8007
8008 let mint_account = AccountSharedData::from(Account {
8009 lamports: 111,
8010 data: mint_data.to_vec(),
8011 owner: program_id,
8012 ..Account::default()
8013 });
8014 bank.store_account(&Pubkey::from_str(&mint.to_string()).unwrap(), &mint_account);
8015
8016 let other_token_account_pubkey = solana_pubkey::new_rand();
8018 bank.store_account(&other_token_account_pubkey, &token_account);
8019
8020 let mut account_data = vec![0; TokenAccount::get_packed_len()];
8022 let token_account = TokenAccount {
8023 mint: new_mint,
8024 owner,
8025 delegate: COption::Some(delegate),
8026 amount: 42,
8027 state: TokenAccountState::Initialized,
8028 is_native: COption::None,
8029 delegated_amount: 30,
8030 close_authority: COption::Some(owner),
8031 };
8032 TokenAccount::pack(token_account, &mut account_data).unwrap();
8033 let token_account = AccountSharedData::from(Account {
8034 lamports: 111,
8035 data: account_data.to_vec(),
8036 owner: program_id,
8037 ..Account::default()
8038 });
8039 bank.store_account(&token_with_different_mint_pubkey, &token_account);
8040 } else {
8041 let mut account_data = vec![0; TokenAccount::get_packed_len()];
8043 let token_account = TokenAccount {
8044 mint,
8045 owner,
8046 delegate: COption::Some(delegate),
8047 amount: 420,
8048 state: TokenAccountState::Initialized,
8049 is_native: COption::None,
8050 delegated_amount: 30,
8051 close_authority: COption::Some(owner),
8052 };
8053 TokenAccount::pack(token_account, &mut account_data).unwrap();
8054 let token_account = AccountSharedData::from(Account {
8055 lamports: 111,
8056 data: account_data.to_vec(),
8057 owner: program_id,
8058 ..Account::default()
8059 });
8060 bank.store_account(&token_account_pubkey, &token_account);
8061
8062 let mut mint_data = vec![0; Mint::get_packed_len()];
8064 let mint_state = Mint {
8065 mint_authority: COption::Some(owner),
8066 supply: 500,
8067 decimals: 2,
8068 is_initialized: true,
8069 freeze_authority: COption::Some(owner),
8070 };
8071 Mint::pack(mint_state, &mut mint_data).unwrap();
8072 let mint_account = AccountSharedData::from(Account {
8073 lamports: 111,
8074 data: mint_data.to_vec(),
8075 owner: program_id,
8076 ..Account::default()
8077 });
8078 bank.store_account(&Pubkey::from_str(&mint.to_string()).unwrap(), &mint_account);
8079
8080 let other_token_account_pubkey = solana_pubkey::new_rand();
8082 bank.store_account(&other_token_account_pubkey, &token_account);
8083
8084 let mut account_data = vec![0; TokenAccount::get_packed_len()];
8086 let token_account = TokenAccount {
8087 mint: new_mint,
8088 owner,
8089 delegate: COption::Some(delegate),
8090 amount: 42,
8091 state: TokenAccountState::Initialized,
8092 is_native: COption::None,
8093 delegated_amount: 30,
8094 close_authority: COption::Some(owner),
8095 };
8096 TokenAccount::pack(token_account, &mut account_data).unwrap();
8097 let token_account = AccountSharedData::from(Account {
8098 lamports: 111,
8099 data: account_data.to_vec(),
8100 owner: program_id,
8101 ..Account::default()
8102 });
8103 bank.store_account(&token_with_different_mint_pubkey, &token_account);
8104 }
8105
8106 let req = format!(
8107 r#"{{"jsonrpc":"2.0","id":1,"method":"getTokenAccountBalance","params":["{token_account_pubkey}"]}}"#,
8108 );
8109 let res = io.handle_request_sync(&req, meta.clone());
8110 let result: Value = serde_json::from_str(&res.expect("actual response"))
8111 .expect("actual response deserialization");
8112 let balance: UiTokenAmount =
8113 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8114 let error = f64::EPSILON;
8115 assert!((balance.ui_amount.unwrap() - 4.2).abs() < error);
8116 assert_eq!(balance.amount, 420.to_string());
8117 assert_eq!(balance.decimals, 2);
8118 assert_eq!(balance.ui_amount_string, "4.2".to_string());
8119
8120 let req = format!(
8122 r#"{{"jsonrpc":"2.0","id":1,"method":"getTokenAccountBalance","params":["{}"]}}"#,
8123 solana_pubkey::new_rand(),
8124 );
8125 let res = io.handle_request_sync(&req, meta.clone());
8126 let result: Value = serde_json::from_str(&res.expect("actual response"))
8127 .expect("actual response deserialization");
8128 assert!(result.get("error").is_some());
8129
8130 let req = format!(
8132 r#"{{"jsonrpc":"2.0","id":1,"method":"getTokenSupply","params":["{mint}"]}}"#,
8133 );
8134 let res = io.handle_request_sync(&req, meta.clone());
8135 let result: Value = serde_json::from_str(&res.expect("actual response"))
8136 .expect("actual response deserialization");
8137 let supply: UiTokenAmount =
8138 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8139 let error = f64::EPSILON;
8140 assert!((supply.ui_amount.unwrap() - 5.0).abs() < error);
8141 assert_eq!(supply.amount, 500.to_string());
8142 assert_eq!(supply.decimals, 2);
8143 assert_eq!(supply.ui_amount_string, "5".to_string());
8144
8145 let req = format!(
8147 r#"{{"jsonrpc":"2.0","id":1,"method":"getTokenSupply","params":["{}"]}}"#,
8148 solana_pubkey::new_rand(),
8149 );
8150 let res = io.handle_request_sync(&req, meta.clone());
8151 let result: Value = serde_json::from_str(&res.expect("actual response"))
8152 .expect("actual response deserialization");
8153 assert!(result.get("error").is_some());
8154
8155 let req = format!(
8157 r#"{{
8158 "jsonrpc":"2.0",
8159 "id":1,
8160 "method":"getTokenAccountsByOwner",
8161 "params":["{owner}", {{"programId": "{program_id}"}}, {{"encoding":"base64"}}]
8162 }}"#,
8163 );
8164 let res = io.handle_request_sync(&req, meta.clone());
8165 let result: Value = serde_json::from_str(&res.expect("actual response"))
8166 .expect("actual response deserialization");
8167 let accounts: Vec<RpcKeyedAccount> =
8168 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8169 assert_eq!(accounts.len(), 3);
8170
8171 let req = format!(
8173 r#"{{
8174 "jsonrpc":"2.0",
8175 "id":1,
8176 "method":"getTokenAccountsByOwner",
8177 "params":["{owner}", {{"programId": "{program_id}"}}, {{"encoding": "jsonParsed"}}]
8178 }}"#,
8179 );
8180 let res = io.handle_request_sync(&req, meta.clone());
8181 let result: Value = serde_json::from_str(&res.expect("actual response"))
8182 .expect("actual response deserialization");
8183 let accounts: Vec<RpcKeyedAccount> =
8184 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8185 assert_eq!(accounts.len(), 2);
8186
8187 let req = format!(
8189 r#"{{
8190 "jsonrpc":"2.0",
8191 "id":1,
8192 "method":"getProgramAccounts",
8193 "params":["{program_id}", {{"encoding": "jsonParsed"}}]
8194 }}"#,
8195 );
8196 let res = io.handle_request_sync(&req, meta.clone());
8197 let result: Value = serde_json::from_str(&res.expect("actual response"))
8198 .expect("actual response deserialization");
8199 let accounts: Vec<RpcKeyedAccount> =
8200 serde_json::from_value(result["result"].clone()).unwrap();
8201 if program_id == spl_generic_token::token::id() {
8202 assert_eq!(accounts.len(), 4);
8204 } else {
8205 assert_eq!(accounts.len(), 3);
8206 }
8207
8208 let req = format!(
8210 r#"{{
8211 "jsonrpc":"2.0",
8212 "id":1,"method":"getTokenAccountsByOwner",
8213 "params":["{owner}", {{"mint": "{mint}"}}, {{"encoding":"base64"}}]
8214 }}"#,
8215 );
8216 let res = io.handle_request_sync(&req, meta.clone());
8217 let result: Value = serde_json::from_str(&res.expect("actual response"))
8218 .expect("actual response deserialization");
8219 let accounts: Vec<RpcKeyedAccount> =
8220 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8221 assert_eq!(accounts.len(), 2);
8222
8223 let req = format!(
8225 r#"{{
8226 "jsonrpc":"2.0",
8227 "id":1,
8228 "method":"getTokenAccountsByOwner",
8229 "params":["{}", {{"programId": "{}"}}]
8230 }}"#,
8231 owner,
8232 solana_pubkey::new_rand(),
8233 );
8234 let res = io.handle_request_sync(&req, meta.clone());
8235 let result: Value = serde_json::from_str(&res.expect("actual response"))
8236 .expect("actual response deserialization");
8237 assert!(result.get("error").is_some());
8238 let req = format!(
8239 r#"{{
8240 "jsonrpc":"2.0",
8241 "id":1,
8242 "method":"getTokenAccountsByOwner",
8243 "params":["{}", {{"mint": "{}"}}]
8244 }}"#,
8245 owner,
8246 solana_pubkey::new_rand(),
8247 );
8248 let res = io.handle_request_sync(&req, meta.clone());
8249 let result: Value = serde_json::from_str(&res.expect("actual response"))
8250 .expect("actual response deserialization");
8251 assert!(result.get("error").is_some());
8252
8253 let req = format!(
8255 r#"{{
8256 "jsonrpc":"2.0",
8257 "id":1,
8258 "method":"getTokenAccountsByOwner",
8259 "params":["{}", {{"programId": "{}"}}]
8260 }}"#,
8261 solana_pubkey::new_rand(),
8262 program_id,
8263 );
8264 let res = io.handle_request_sync(&req, meta.clone());
8265 let result: Value = serde_json::from_str(&res.expect("actual response"))
8266 .expect("actual response deserialization");
8267 let accounts: Vec<RpcKeyedAccount> =
8268 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8269 assert!(accounts.is_empty());
8270
8271 let req = format!(
8273 r#"{{
8274 "jsonrpc":"2.0",
8275 "id":1,
8276 "method":"getTokenAccountsByDelegate",
8277 "params":["{delegate}", {{"programId": "{program_id}"}}, {{"encoding":"base64"}}]
8278 }}"#,
8279 );
8280 let res = io.handle_request_sync(&req, meta.clone());
8281 let result: Value = serde_json::from_str(&res.expect("actual response"))
8282 .expect("actual response deserialization");
8283 let accounts: Vec<RpcKeyedAccount> =
8284 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8285 assert_eq!(accounts.len(), 3);
8286
8287 let req = format!(
8289 r#"{{
8290 "jsonrpc":"2.0",
8291 "id":1,"method":
8292 "getTokenAccountsByDelegate",
8293 "params":["{delegate}", {{"mint": "{mint}"}}, {{"encoding":"base64"}}]
8294 }}"#,
8295 );
8296 let res = io.handle_request_sync(&req, meta.clone());
8297 let result: Value = serde_json::from_str(&res.expect("actual response"))
8298 .expect("actual response deserialization");
8299 let accounts: Vec<RpcKeyedAccount> =
8300 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8301 assert_eq!(accounts.len(), 2);
8302
8303 let req = format!(
8305 r#"{{
8306 "jsonrpc":"2.0",
8307 "id":1,
8308 "method":"getTokenAccountsByDelegate",
8309 "params":["{}", {{"programId": "{}"}}]
8310 }}"#,
8311 delegate,
8312 solana_pubkey::new_rand(),
8313 );
8314 let res = io.handle_request_sync(&req, meta.clone());
8315 let result: Value = serde_json::from_str(&res.expect("actual response"))
8316 .expect("actual response deserialization");
8317 assert!(result.get("error").is_some());
8318 let req = format!(
8319 r#"{{
8320 "jsonrpc":"2.0",
8321 "id":1,
8322 "method":"getTokenAccountsByDelegate",
8323 "params":["{}", {{"mint": "{}"}}]
8324 }}"#,
8325 delegate,
8326 solana_pubkey::new_rand(),
8327 );
8328 let res = io.handle_request_sync(&req, meta.clone());
8329 let result: Value = serde_json::from_str(&res.expect("actual response"))
8330 .expect("actual response deserialization");
8331 assert!(result.get("error").is_some());
8332
8333 let req = format!(
8335 r#"{{
8336 "jsonrpc":"2.0",
8337 "id":1,
8338 "method":"getTokenAccountsByDelegate",
8339 "params":["{}", {{"programId": "{}"}}]
8340 }}"#,
8341 solana_pubkey::new_rand(),
8342 program_id,
8343 );
8344 let res = io.handle_request_sync(&req, meta.clone());
8345 let result: Value = serde_json::from_str(&res.expect("actual response"))
8346 .expect("actual response deserialization");
8347 let accounts: Vec<RpcKeyedAccount> =
8348 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8349 assert!(accounts.is_empty());
8350
8351 let mut mint_data = vec![0; Mint::get_packed_len()];
8353 let mint_state = Mint {
8354 mint_authority: COption::Some(owner),
8355 supply: 500,
8356 decimals: 2,
8357 is_initialized: true,
8358 freeze_authority: COption::Some(owner),
8359 };
8360 Mint::pack(mint_state, &mut mint_data).unwrap();
8361 let mint_account = AccountSharedData::from(Account {
8362 lamports: 111,
8363 data: mint_data.to_vec(),
8364 owner: program_id,
8365 ..Account::default()
8366 });
8367 bank.store_account(
8368 &Pubkey::from_str(&new_mint.to_string()).unwrap(),
8369 &mint_account,
8370 );
8371 let mut account_data = vec![0; TokenAccount::get_packed_len()];
8372 let token_account = TokenAccount {
8373 mint: new_mint,
8374 owner,
8375 delegate: COption::Some(delegate),
8376 amount: 10,
8377 state: TokenAccountState::Initialized,
8378 is_native: COption::None,
8379 delegated_amount: 30,
8380 close_authority: COption::Some(owner),
8381 };
8382 TokenAccount::pack(token_account, &mut account_data).unwrap();
8383 let token_account = AccountSharedData::from(Account {
8384 lamports: 111,
8385 data: account_data.to_vec(),
8386 owner: program_id,
8387 ..Account::default()
8388 });
8389 let token_with_smaller_balance = solana_pubkey::new_rand();
8390 bank.store_account(&token_with_smaller_balance, &token_account);
8391
8392 let req = format!(
8394 r#"{{"jsonrpc":"2.0","id":1,"method":"getTokenLargestAccounts","params":["{new_mint}"]}}"#,
8395 );
8396 let res = io.handle_request_sync(&req, meta);
8397 let result: Value = serde_json::from_str(&res.expect("actual response"))
8398 .expect("actual response deserialization");
8399 let largest_accounts: Vec<RpcTokenAccountBalance> =
8400 serde_json::from_value(result["result"]["value"].clone()).unwrap();
8401 assert_eq!(
8402 largest_accounts,
8403 vec![
8404 RpcTokenAccountBalance {
8405 address: token_with_different_mint_pubkey.to_string(),
8406 amount: UiTokenAmount {
8407 ui_amount: Some(0.42),
8408 decimals: 2,
8409 amount: "42".to_string(),
8410 ui_amount_string: "0.42".to_string(),
8411 }
8412 },
8413 RpcTokenAccountBalance {
8414 address: token_with_smaller_balance.to_string(),
8415 amount: UiTokenAmount {
8416 ui_amount: Some(0.1),
8417 decimals: 2,
8418 amount: "10".to_string(),
8419 ui_amount_string: "0.1".to_string(),
8420 }
8421 }
8422 ]
8423 );
8424 }
8425 }
8426
8427 #[test_case(spl_token_interface::id(), None, None; "spl_token")]
8428 #[test_case(spl_token_2022_interface::id(), Some(InterestBearingConfig { pre_update_average_rate: 500.into(), current_rate: 500.into(),..Default::default() }), None; "spl_token_2022_with _interest")]
8429 #[test_case(spl_token_2022_interface::id(), None, Some(ScaledUiAmountConfig { new_multiplier: 2.0f64.into(), ..Default::default() }); "spl-token-2022 with multiplier")]
8430 fn test_token_parsing(
8431 program_id: Pubkey,
8432 mut interest_bearing_config: Option<InterestBearingConfig>,
8433 scaled_ui_amount_config: Option<ScaledUiAmountConfig>,
8434 ) {
8435 let rpc = RpcHandler::start();
8436 let bank = rpc.working_bank();
8437 let RpcHandler { io, meta, .. } = rpc;
8438
8439 let mint = Pubkey::new_from_array([2; 32]);
8440 let owner = Pubkey::new_from_array([3; 32]);
8441 let delegate = Pubkey::new_from_array([4; 32]);
8442 let token_account_pubkey = solana_pubkey::new_rand();
8443 let amount = 420;
8444 let delegated_amount = 30;
8445 let rent_exempt_amount = 10;
8446 let supply = 500;
8447 let decimals = 2;
8448 let (program_name, account_size, mint_size, additional_data) = if program_id
8449 == spl_generic_token::token_2022::id()
8450 {
8451 let account_base = TokenAccount {
8452 mint,
8453 owner,
8454 delegate: COption::Some(delegate),
8455 amount,
8456 state: TokenAccountState::Initialized,
8457 is_native: COption::Some(rent_exempt_amount),
8458 delegated_amount,
8459 close_authority: COption::Some(owner),
8460 };
8461 let account_size = ExtensionType::try_calculate_account_len::<TokenAccount>(&[
8462 ExtensionType::ImmutableOwner,
8463 ExtensionType::MemoTransfer,
8464 ])
8465 .unwrap();
8466 let mut account_data = vec![0; account_size];
8467 let mut account_state =
8468 StateWithExtensionsMut::<TokenAccount>::unpack_uninitialized(&mut account_data)
8469 .unwrap();
8470
8471 account_state.base = account_base;
8472 account_state.pack_base();
8473 account_state.init_account_type().unwrap();
8474 account_state
8475 .init_extension::<ImmutableOwner>(true)
8476 .unwrap();
8477 let memo_transfer = account_state.init_extension::<MemoTransfer>(true).unwrap();
8478 memo_transfer.require_incoming_transfer_memos = true.into();
8479
8480 let token_account = AccountSharedData::from(Account {
8481 lamports: 111,
8482 data: account_data.to_vec(),
8483 owner: program_id,
8484 ..Account::default()
8485 });
8486 bank.store_account(&token_account_pubkey, &token_account);
8487
8488 let mint_base = Mint {
8489 mint_authority: COption::Some(owner),
8490 supply,
8491 decimals,
8492 is_initialized: true,
8493 freeze_authority: COption::Some(owner),
8494 };
8495 let mut extensions = vec![ExtensionType::MintCloseAuthority];
8496 if interest_bearing_config.is_some() {
8497 extensions.push(ExtensionType::InterestBearingConfig);
8498 }
8499 if scaled_ui_amount_config.is_some() {
8500 extensions.push(ExtensionType::ScaledUiAmount);
8501 }
8502 let mint_size = ExtensionType::try_calculate_account_len::<Mint>(&extensions).unwrap();
8503 let mut mint_data = vec![0; mint_size];
8504 let mut mint_state =
8505 StateWithExtensionsMut::<Mint>::unpack_uninitialized(&mut mint_data).unwrap();
8506
8507 mint_state.base = mint_base;
8508 mint_state.pack_base();
8509 mint_state.init_account_type().unwrap();
8510 let mint_close_authority = mint_state
8511 .init_extension::<MintCloseAuthority>(true)
8512 .unwrap();
8513 mint_close_authority.close_authority =
8514 OptionalNonZeroPubkey::try_from(Some(owner)).unwrap();
8515 if let Some(interest_bearing_config) = interest_bearing_config.as_mut() {
8516 interest_bearing_config.initialization_timestamp =
8517 bank.clock().unix_timestamp.saturating_sub(1_000_000).into();
8518 interest_bearing_config.last_update_timestamp = bank.clock().unix_timestamp.into();
8519 let extension = mint_state
8520 .init_extension::<InterestBearingConfig>(true)
8521 .unwrap();
8522 *extension = *interest_bearing_config;
8523 }
8524
8525 if let Some(scaled_ui_amount_config) = scaled_ui_amount_config.as_ref() {
8526 let extension = mint_state
8527 .init_extension::<ScaledUiAmountConfig>(true)
8528 .unwrap();
8529 *extension = *scaled_ui_amount_config;
8530 }
8531
8532 let additional_data = SplTokenAdditionalDataV2 {
8533 decimals,
8534 interest_bearing_config: interest_bearing_config
8535 .map(|v| (v, bank.clock().unix_timestamp)),
8536 scaled_ui_amount_config: scaled_ui_amount_config
8537 .map(|v| (v, bank.clock().unix_timestamp)),
8538 };
8539
8540 let mint_account = AccountSharedData::from(Account {
8541 lamports: 111,
8542 data: mint_data.to_vec(),
8543 owner: program_id,
8544 ..Account::default()
8545 });
8546 bank.store_account(&Pubkey::from_str(&mint.to_string()).unwrap(), &mint_account);
8547 ("spl-token-2022", account_size, mint_size, additional_data)
8548 } else {
8549 let account_size = TokenAccount::get_packed_len();
8550 let mut account_data = vec![0; account_size];
8551 let token_account = TokenAccount {
8552 mint,
8553 owner,
8554 delegate: COption::Some(delegate),
8555 amount,
8556 state: TokenAccountState::Initialized,
8557 is_native: COption::Some(rent_exempt_amount),
8558 delegated_amount,
8559 close_authority: COption::Some(owner),
8560 };
8561 TokenAccount::pack(token_account, &mut account_data).unwrap();
8562 let token_account = AccountSharedData::from(Account {
8563 lamports: 111,
8564 data: account_data.to_vec(),
8565 owner: program_id,
8566 ..Account::default()
8567 });
8568 bank.store_account(&token_account_pubkey, &token_account);
8569
8570 let mint_size = Mint::get_packed_len();
8572 let mut mint_data = vec![0; mint_size];
8573 let mint_state = Mint {
8574 mint_authority: COption::Some(owner),
8575 supply,
8576 decimals,
8577 is_initialized: true,
8578 freeze_authority: COption::Some(owner),
8579 };
8580 Mint::pack(mint_state, &mut mint_data).unwrap();
8581 let mint_account = AccountSharedData::from(Account {
8582 lamports: 111,
8583 data: mint_data.to_vec(),
8584 owner: program_id,
8585 ..Account::default()
8586 });
8587 bank.store_account(&Pubkey::from_str(&mint.to_string()).unwrap(), &mint_account);
8588 let additional_data = SplTokenAdditionalDataV2::with_decimals(decimals);
8589 ("spl-token", account_size, mint_size, additional_data)
8590 };
8591
8592 let req = format!(
8593 r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{token_account_pubkey}", {{"encoding": "jsonParsed"}}]}}"#,
8594 );
8595 let res = io.handle_request_sync(&req, meta.clone());
8596 let result: Value = serde_json::from_str(&res.expect("actual response"))
8597 .expect("actual response deserialization");
8598 let token_ui_amount = token_amount_to_ui_amount_v3(amount, &additional_data);
8599 let delegated_ui_amount = token_amount_to_ui_amount_v3(delegated_amount, &additional_data);
8600 let rent_exempt_ui_amount =
8601 token_amount_to_ui_amount_v3(rent_exempt_amount, &additional_data);
8602 let mut expected_value = json!({
8603 "program": program_name,
8604 "space": account_size,
8605 "parsed": {
8606 "type": "account",
8607 "info": {
8608 "mint": mint.to_string(),
8609 "owner": owner.to_string(),
8610 "tokenAmount": json!(token_ui_amount),
8611 "delegate": delegate.to_string(),
8612 "state": "initialized",
8613 "isNative": true,
8614 "rentExemptReserve": json!(rent_exempt_ui_amount),
8615 "delegatedAmount": json!(delegated_ui_amount),
8616 "closeAuthority": owner.to_string(),
8617 }
8618 }
8619 });
8620 if program_id == spl_generic_token::token_2022::id() {
8621 expected_value["parsed"]["info"]["extensions"] = json!([
8622 {
8623 "extension": "immutableOwner"
8624 },
8625 {
8626 "extension": "memoTransfer",
8627 "state": {
8628 "requireIncomingTransferMemos": true
8629 }
8630 },
8631 ]);
8632 }
8633 assert_eq!(result["result"]["value"]["data"], expected_value,);
8634
8635 let req = format!(
8637 r#"{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{mint}", {{"encoding": "jsonParsed"}}]}}"#,
8638 );
8639 let res = io.handle_request_sync(&req, meta);
8640 let result: Value = serde_json::from_str(&res.expect("actual response"))
8641 .expect("actual response deserialization");
8642 let mut expected_value = json!({
8643 "program": program_name,
8644 "space": mint_size,
8645 "parsed": {
8646 "type": "mint",
8647 "info": {
8648 "mintAuthority": owner.to_string(),
8649 "decimals": 2,
8650 "supply": "500".to_string(),
8651 "isInitialized": true,
8652 "freezeAuthority": owner.to_string(),
8653 }
8654 }
8655 });
8656 if program_id == spl_generic_token::token_2022::id() {
8657 if interest_bearing_config.is_some() {
8658 expected_value["parsed"]["info"]["extensions"] = json!([
8659 {
8660 "extension": "mintCloseAuthority",
8661 "state": {
8662 "closeAuthority": owner.to_string(),
8663 }
8664 },
8665 {
8666 "extension": "interestBearingConfig",
8667 "state": {
8668 "currentRate": 500,
8669 "initializationTimestamp": bank.clock().unix_timestamp.saturating_sub(1_000_000),
8670 "lastUpdateTimestamp": bank.clock().unix_timestamp,
8671 "preUpdateAverageRate": 500,
8672 "rateAuthority": null,
8673 }
8674 }
8675 ]);
8676 }
8677 if scaled_ui_amount_config.is_some() {
8678 expected_value["parsed"]["info"]["extensions"] = json!([
8679 {
8680 "extension": "mintCloseAuthority",
8681 "state": {
8682 "closeAuthority": owner.to_string(),
8683 }
8684 },
8685 {
8686 "extension": "scaledUiAmountConfig",
8687 "state": {
8688 "multiplier": "0",
8689 "newMultiplier": "2",
8690 "newMultiplierEffectiveTimestamp": 0,
8691 "authority": null,
8692 }
8693 }
8694 ]);
8695 }
8696 }
8697 assert_eq!(result["result"]["value"]["data"], expected_value,);
8698 }
8699
8700 #[test]
8701 fn test_get_spl_token_owner_filter() {
8702 let owner = Pubkey::new_unique();
8704 assert_eq!(
8705 get_spl_token_owner_filter(
8706 &spl_token_interface::id(),
8707 &[
8708 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(32, owner.to_bytes().to_vec())),
8709 RpcFilterType::DataSize(165)
8710 ],
8711 )
8712 .unwrap()
8713 .unwrap(),
8714 owner
8715 );
8716
8717 assert_eq!(
8719 get_spl_token_owner_filter(
8720 &token_2022::id(),
8721 &[
8722 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(32, owner.to_bytes().to_vec())),
8723 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(165, vec![ACCOUNTTYPE_ACCOUNT])),
8724 ],
8725 )
8726 .unwrap()
8727 .unwrap(),
8728 owner
8729 );
8730
8731 assert_eq!(
8733 get_spl_token_owner_filter(
8734 &token_2022::id(),
8735 &[
8736 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(32, owner.to_bytes().to_vec())),
8737 RpcFilterType::TokenAccountState,
8738 ],
8739 )
8740 .unwrap()
8741 .unwrap(),
8742 owner
8743 );
8744
8745 assert!(get_spl_token_owner_filter(
8747 &spl_generic_token::token::id(),
8748 &[
8749 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(32, owner.to_bytes().to_vec())),
8750 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(165, vec![ACCOUNTTYPE_ACCOUNT])),
8751 ],
8752 )
8753 .unwrap()
8754 .is_none());
8755
8756 assert!(get_spl_token_owner_filter(
8758 &spl_generic_token::token::id(),
8759 &[
8760 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(0, owner.to_bytes().to_vec())),
8761 RpcFilterType::DataSize(165)
8762 ],
8763 )
8764 .unwrap()
8765 .is_none());
8766
8767 assert!(get_spl_token_owner_filter(
8769 &Pubkey::new_unique(),
8770 &[
8771 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(32, owner.to_bytes().to_vec())),
8772 RpcFilterType::DataSize(165)
8773 ],
8774 )
8775 .unwrap()
8776 .is_none());
8777 assert!(get_spl_token_owner_filter(
8778 &Pubkey::new_unique(),
8779 &[
8780 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(32, owner.to_bytes().to_vec())),
8781 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(165, vec![ACCOUNTTYPE_ACCOUNT])),
8782 ],
8783 )
8784 .unwrap()
8785 .is_none());
8786
8787 let owner = Pubkey::new_unique();
8791 let mut first_half_bytes = owner.to_bytes().to_vec();
8792 first_half_bytes.resize(16, 0);
8793 assert!(get_spl_token_owner_filter(
8794 &spl_generic_token::token::id(),
8795 &[
8796 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(32, first_half_bytes)),
8797 RpcFilterType::DataSize(165)
8798 ],
8799 )
8800 .is_err_and(|err| err.code == ErrorCode::InvalidParams
8801 && err.message == "Incorrect byte length 16 for SPL token owner filter, expected 32"));
8802 }
8803
8804 #[test]
8805 fn test_get_spl_token_mint_filter() {
8806 let mint = Pubkey::new_unique();
8808 assert_eq!(
8809 get_spl_token_mint_filter(
8810 &spl_generic_token::token::id(),
8811 &[
8812 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(0, mint.to_bytes().to_vec())),
8813 RpcFilterType::DataSize(165)
8814 ],
8815 )
8816 .unwrap()
8817 .unwrap(),
8818 mint
8819 );
8820
8821 assert_eq!(
8823 get_spl_token_mint_filter(
8824 &spl_generic_token::token_2022::id(),
8825 &[
8826 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(0, mint.to_bytes().to_vec())),
8827 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(165, vec![ACCOUNTTYPE_ACCOUNT])),
8828 ],
8829 )
8830 .unwrap()
8831 .unwrap(),
8832 mint
8833 );
8834
8835 assert_eq!(
8837 get_spl_token_mint_filter(
8838 &spl_generic_token::token::id(),
8839 &[
8840 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(0, mint.to_bytes().to_vec())),
8841 RpcFilterType::TokenAccountState,
8842 ],
8843 )
8844 .unwrap()
8845 .unwrap(),
8846 mint
8847 );
8848
8849 assert!(get_spl_token_mint_filter(
8851 &spl_generic_token::token::id(),
8852 &[
8853 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(0, mint.to_bytes().to_vec())),
8854 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(165, vec![ACCOUNTTYPE_ACCOUNT])),
8855 ],
8856 )
8857 .unwrap()
8858 .is_none());
8859
8860 assert!(get_spl_token_mint_filter(
8862 &spl_generic_token::token::id(),
8863 &[
8864 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(32, mint.to_bytes().to_vec())),
8865 RpcFilterType::DataSize(165)
8866 ],
8867 )
8868 .unwrap()
8869 .is_none());
8870
8871 assert!(get_spl_token_mint_filter(
8873 &Pubkey::new_unique(),
8874 &[
8875 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(0, mint.to_bytes().to_vec())),
8876 RpcFilterType::DataSize(165)
8877 ],
8878 )
8879 .unwrap()
8880 .is_none());
8881 assert!(get_spl_token_mint_filter(
8882 &Pubkey::new_unique(),
8883 &[
8884 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(0, mint.to_bytes().to_vec())),
8885 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(165, vec![ACCOUNTTYPE_ACCOUNT])),
8886 ],
8887 )
8888 .unwrap()
8889 .is_none());
8890
8891 let owner = Pubkey::new_unique();
8895 let mut first_half_bytes = owner.to_bytes().to_vec();
8896 first_half_bytes.resize(16, 0);
8897 assert!(get_spl_token_mint_filter(
8898 &spl_generic_token::token::id(),
8899 &[
8900 RpcFilterType::Memcmp(Memcmp::new_raw_bytes(0, first_half_bytes)),
8901 RpcFilterType::DataSize(165)
8902 ],
8903 )
8904 .is_err_and(|err| {
8905 print!("{err:?}");
8906 err.code == ErrorCode::InvalidParams
8907 && err.message == "Incorrect byte length 16 for SPL token mint filter, expected 32"
8908 }));
8909 }
8910
8911 #[test]
8912 fn test_rpc_single_gossip() {
8913 let exit = Arc::new(AtomicBool::new(false));
8914 let validator_exit = create_validator_exit(exit.clone());
8915 let ledger_path = get_tmp_ledger_path!();
8916 let blockstore = Arc::new(Blockstore::open(&ledger_path).unwrap());
8917 let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
8918 let cluster_info = Arc::new(new_test_cluster_info());
8919 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(100);
8920 let bank = Bank::new_for_tests(&genesis_config);
8921
8922 let bank_forks = BankForks::new_rw_arc(bank);
8923 let bank0 = bank_forks.read().unwrap().get(0).unwrap();
8924 let bank1 = Bank::new_from_parent(bank0, &Pubkey::default(), 1);
8925 bank_forks.write().unwrap().insert(bank1);
8926 let bank1 = bank_forks.read().unwrap().get(1).unwrap();
8927 let bank2 = Bank::new_from_parent(bank1, &Pubkey::default(), 2);
8928 bank_forks.write().unwrap().insert(bank2);
8929 let bank2 = bank_forks.read().unwrap().get(2).unwrap();
8930 let bank3 = Bank::new_from_parent(bank2, &Pubkey::default(), 3);
8931 bank_forks.write().unwrap().insert(bank3);
8932
8933 let optimistically_confirmed_bank =
8934 OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
8935 let mut pending_optimistically_confirmed_banks = HashSet::new();
8936 let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
8937 let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
8938 exit,
8939 max_complete_transaction_status_slot.clone(),
8940 bank_forks.clone(),
8941 block_commitment_cache.clone(),
8942 optimistically_confirmed_bank.clone(),
8943 ));
8944
8945 let config = JsonRpcConfig::default();
8946 let JsonRpcConfig {
8947 rpc_threads,
8948 rpc_blocking_threads,
8949 rpc_niceness_adj,
8950 ..
8951 } = config;
8952 let (meta, _receiver) = JsonRpcRequestProcessor::new(
8953 config,
8954 None,
8955 bank_forks.clone(),
8956 block_commitment_cache,
8957 blockstore.clone(),
8958 validator_exit,
8959 RpcHealth::stub(optimistically_confirmed_bank.clone(), blockstore.clone()),
8960 cluster_info,
8961 Hash::default(),
8962 None,
8963 optimistically_confirmed_bank.clone(),
8964 Arc::new(RwLock::new(LargestAccountsCache::new(30))),
8965 Arc::new(MaxSlots::default()),
8966 Arc::new(LeaderScheduleCache::default()),
8967 max_complete_transaction_status_slot,
8968 Arc::new(PrioritizationFeeCache::default()),
8969 service_runtime(rpc_threads, rpc_blocking_threads, rpc_niceness_adj),
8970 );
8971
8972 let mut io = MetaIoHandler::default();
8973 io.extend_with(rpc_minimal::MinimalImpl.to_delegate());
8974 io.extend_with(rpc_full::FullImpl.to_delegate());
8975
8976 let req =
8977 r#"{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment":"confirmed"}]}"#;
8978 let res = io.handle_request_sync(req, meta.clone());
8979 let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
8980 let slot: Slot = serde_json::from_value(json["result"].clone()).unwrap();
8981 assert_eq!(slot, 0);
8982 let mut highest_confirmed_slot: Slot = 0;
8983 let mut highest_root_slot: Slot = 0;
8984 let mut last_notified_confirmed_slot: Slot = 0;
8985
8986 OptimisticallyConfirmedBankTracker::process_notification(
8987 (
8988 BankNotification::OptimisticallyConfirmed(2),
8989 None, ),
8991 &bank_forks,
8992 &optimistically_confirmed_bank,
8993 &subscriptions,
8994 &mut pending_optimistically_confirmed_banks,
8995 &mut last_notified_confirmed_slot,
8996 &mut highest_confirmed_slot,
8997 &mut highest_root_slot,
8998 &None,
8999 &PrioritizationFeeCache::default(),
9000 &None, );
9002 let req =
9003 r#"{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"#;
9004 let res = io.handle_request_sync(req, meta.clone());
9005 let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
9006 let slot: Slot = serde_json::from_value(json["result"].clone()).unwrap();
9007 assert_eq!(slot, 2);
9008
9009 OptimisticallyConfirmedBankTracker::process_notification(
9011 (
9012 BankNotification::OptimisticallyConfirmed(1),
9013 None, ),
9015 &bank_forks,
9016 &optimistically_confirmed_bank,
9017 &subscriptions,
9018 &mut pending_optimistically_confirmed_banks,
9019 &mut last_notified_confirmed_slot,
9020 &mut highest_confirmed_slot,
9021 &mut highest_root_slot,
9022 &None,
9023 &PrioritizationFeeCache::default(),
9024 &None, );
9026 let req =
9027 r#"{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"#;
9028 let res = io.handle_request_sync(req, meta.clone());
9029 let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
9030 let slot: Slot = serde_json::from_value(json["result"].clone()).unwrap();
9031 assert_eq!(slot, 2);
9032
9033 OptimisticallyConfirmedBankTracker::process_notification(
9035 (
9036 BankNotification::OptimisticallyConfirmed(3),
9037 None, ),
9039 &bank_forks,
9040 &optimistically_confirmed_bank,
9041 &subscriptions,
9042 &mut pending_optimistically_confirmed_banks,
9043 &mut last_notified_confirmed_slot,
9044 &mut highest_confirmed_slot,
9045 &mut highest_root_slot,
9046 &None,
9047 &PrioritizationFeeCache::default(),
9048 &None, );
9050 let req =
9051 r#"{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"#;
9052 let res = io.handle_request_sync(req, meta.clone());
9053 let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
9054 let slot: Slot = serde_json::from_value(json["result"].clone()).unwrap();
9055 assert_eq!(slot, 2);
9056
9057 let bank3 = bank_forks.read().unwrap().get(3).unwrap();
9059 OptimisticallyConfirmedBankTracker::process_notification(
9060 (
9061 BankNotification::Frozen(bank3),
9062 None, ),
9064 &bank_forks,
9065 &optimistically_confirmed_bank,
9066 &subscriptions,
9067 &mut pending_optimistically_confirmed_banks,
9068 &mut last_notified_confirmed_slot,
9069 &mut highest_confirmed_slot,
9070 &mut highest_root_slot,
9071 &None,
9072 &PrioritizationFeeCache::default(),
9073 &None, );
9075 let req =
9076 r#"{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"#;
9077 let res = io.handle_request_sync(req, meta);
9078 let json: Value = serde_json::from_str(&res.unwrap()).unwrap();
9079 let slot: Slot = serde_json::from_value(json["result"].clone()).unwrap();
9080 assert_eq!(slot, 3);
9081 }
9082
9083 #[test]
9084 fn test_worst_case_encoded_tx_goldens() {
9085 let ff_tx = vec![0xffu8; PACKET_DATA_SIZE];
9086 let tx58 = bs58::encode(&ff_tx).into_string();
9087 assert_eq!(tx58.len(), MAX_BASE58_SIZE);
9088 let tx64 = BASE64_STANDARD.encode(&ff_tx);
9089 assert_eq!(tx64.len(), MAX_BASE64_SIZE);
9090 }
9091
9092 #[test]
9093 fn test_decode_and_deserialize_too_large_payloads_fail() {
9094 let too_big = PACKET_DATA_SIZE + 2;
9096 let tx_ser = vec![0xffu8; too_big];
9097
9098 let tx58 = bs58::encode(&tx_ser).into_string();
9099 let tx58_len = tx58.len();
9100 assert_eq!(
9101 decode_and_deserialize::<Transaction>(tx58, TransactionBinaryEncoding::Base58)
9102 .unwrap_err(),
9103 Error::invalid_params(format!(
9104 "base58 encoded solana_transaction::Transaction too large: {tx58_len} bytes (max: \
9105 encoded/raw {MAX_BASE58_SIZE}/{PACKET_DATA_SIZE})",
9106 ))
9107 );
9108
9109 let tx64 = BASE64_STANDARD.encode(&tx_ser);
9110 let tx64_len = tx64.len();
9111 assert_eq!(
9112 decode_and_deserialize::<Transaction>(tx64, TransactionBinaryEncoding::Base64)
9113 .unwrap_err(),
9114 Error::invalid_params(format!(
9115 "base64 encoded solana_transaction::Transaction too large: {tx64_len} bytes (max: \
9116 encoded/raw {MAX_BASE64_SIZE}/{PACKET_DATA_SIZE})",
9117 ))
9118 );
9119
9120 let too_big = PACKET_DATA_SIZE + 1;
9121 let tx_ser = vec![0x00u8; too_big];
9122 let tx58 = bs58::encode(&tx_ser).into_string();
9123 assert_eq!(
9124 decode_and_deserialize::<Transaction>(tx58, TransactionBinaryEncoding::Base58)
9125 .unwrap_err(),
9126 Error::invalid_params(format!(
9127 "decoded solana_transaction::Transaction too large: {too_big} bytes (max: \
9128 {PACKET_DATA_SIZE} bytes)"
9129 ))
9130 );
9131
9132 let tx64 = BASE64_STANDARD.encode(&tx_ser);
9133 assert_eq!(
9134 decode_and_deserialize::<Transaction>(tx64, TransactionBinaryEncoding::Base64)
9135 .unwrap_err(),
9136 Error::invalid_params(format!(
9137 "decoded solana_transaction::Transaction too large: {too_big} bytes (max: \
9138 {PACKET_DATA_SIZE} bytes)"
9139 ))
9140 );
9141
9142 let tx_ser = vec![0xffu8; PACKET_DATA_SIZE - 2];
9143 let mut tx64 = BASE64_STANDARD.encode(&tx_ser);
9144 assert_eq!(
9145 decode_and_deserialize::<Transaction>(tx64.clone(), TransactionBinaryEncoding::Base64)
9146 .unwrap_err(),
9147 Error::invalid_params(
9148 "failed to deserialize solana_transaction::Transaction: invalid value: continue \
9149 signal on byte-three, expected a terminal signal on or before byte-three"
9150 .to_string()
9151 )
9152 );
9153
9154 tx64.push('!');
9155 assert_eq!(
9156 decode_and_deserialize::<Transaction>(tx64, TransactionBinaryEncoding::Base64)
9157 .unwrap_err(),
9158 Error::invalid_params("invalid base64 encoding: InvalidByte(1640, 33)".to_string())
9159 );
9160
9161 let mut tx58 = bs58::encode(&tx_ser).into_string();
9162 assert_eq!(
9163 decode_and_deserialize::<Transaction>(tx58.clone(), TransactionBinaryEncoding::Base58)
9164 .unwrap_err(),
9165 Error::invalid_params(
9166 "failed to deserialize solana_transaction::Transaction: invalid value: continue \
9167 signal on byte-three, expected a terminal signal on or before byte-three"
9168 .to_string()
9169 )
9170 );
9171
9172 tx58.push('!');
9173 assert_eq!(
9174 decode_and_deserialize::<Transaction>(tx58, TransactionBinaryEncoding::Base58)
9175 .unwrap_err(),
9176 Error::invalid_params(
9177 "invalid base58 encoding: InvalidCharacter { character: '!', index: 1680 }"
9178 .to_string(),
9179 )
9180 );
9181 }
9182
9183 #[test]
9184 fn test_sanitize_unsanitary() {
9185 let unsanitary_tx58 = "ju9xZWuDBX4pRxX2oZkTjxU5jB4SSTgEGhX8bQ8PURNzyzqKMPPpNvWihx8zUe\
9186 FfrbVNoAaEsNKZvGzAnTDy5bhNT9kt6KFCTBixpvrLCzg4M5UdFUQYrn1gdgjX\
9187 pLHxcaShD81xBNaFDgnA2nkkdHnKtZt4hVSfKAmw3VRZbjrZ7L2fKZBx21CwsG\
9188 hD6onjM2M3qZW5C8J6d1pj41MxKmZgPBSha3MyKkNLkAGFASK"
9189 .to_string();
9190
9191 let unsanitary_versioned_tx = decode_and_deserialize::<VersionedTransaction>(
9192 unsanitary_tx58,
9193 TransactionBinaryEncoding::Base58,
9194 )
9195 .unwrap()
9196 .1;
9197 let expect58 = Error::invalid_params(
9198 "invalid transaction: Transaction failed to sanitize accounts offsets correctly"
9199 .to_string(),
9200 );
9201 assert_eq!(
9202 sanitize_transaction(
9203 unsanitary_versioned_tx,
9204 SimpleAddressLoader::Disabled,
9205 &ReservedAccountKeys::empty_key_set(),
9206 true,
9207 )
9208 .unwrap_err(),
9209 expect58
9210 );
9211 }
9212
9213 #[test]
9214 fn test_sanitize_unsupported_transaction_version() {
9215 let versioned_tx = VersionedTransaction {
9216 signatures: vec![Signature::default()],
9217 message: VersionedMessage::V0(v0::Message {
9218 header: MessageHeader {
9219 num_required_signatures: 1,
9220 ..MessageHeader::default()
9221 },
9222 account_keys: vec![Pubkey::new_unique()],
9223 ..v0::Message::default()
9224 }),
9225 };
9226
9227 assert_eq!(
9228 sanitize_transaction(
9229 versioned_tx,
9230 SimpleAddressLoader::Disabled,
9231 &ReservedAccountKeys::empty_key_set(),
9232 true,
9233 )
9234 .unwrap_err(),
9235 Error::invalid_params(
9236 "invalid transaction: Transaction version is unsupported".to_string(),
9237 )
9238 );
9239 }
9240
9241 #[test]
9242 fn test_rpc_get_stake_minimum_delegation() {
9243 let rpc = RpcHandler::start();
9244 let bank = rpc.working_bank();
9245 let expected_stake_minimum_delegation = stake_utils::get_minimum_delegation(
9246 bank.feature_set
9247 .is_active(&agave_feature_set::stake_raise_minimum_delegation_to_1_sol::id()),
9248 );
9249
9250 let request = create_test_request("getStakeMinimumDelegation", None);
9251 let response: RpcResponse<u64> = parse_success_result(rpc.handle_request_sync(request));
9252 let actual_stake_minimum_delegation = response.value;
9253
9254 assert_eq!(
9255 actual_stake_minimum_delegation,
9256 expected_stake_minimum_delegation
9257 );
9258 }
9259
9260 #[test]
9261 fn test_get_fee_for_message() {
9262 let rpc = RpcHandler::start();
9263 let bank = rpc.working_bank();
9264 bank.set_sysvar_for_tests(&SlotHashes::default());
9266 let recent_blockhash = bank.last_blockhash();
9268
9269 {
9270 let legacy_msg = VersionedMessage::Legacy(Message {
9271 header: MessageHeader {
9272 num_required_signatures: 1,
9273 ..MessageHeader::default()
9274 },
9275 recent_blockhash,
9276 account_keys: vec![Pubkey::new_unique()],
9277 ..Message::default()
9278 });
9279
9280 let request = create_test_request(
9281 "getFeeForMessage",
9282 Some(json!([
9283 BASE64_STANDARD.encode(serialize(&legacy_msg).unwrap())
9284 ])),
9285 );
9286 let response: RpcResponse<u64> = parse_success_result(rpc.handle_request_sync(request));
9287 assert_eq!(response.value, TEST_SIGNATURE_FEE);
9288 }
9289
9290 {
9291 let v0_msg = VersionedMessage::V0(v0::Message {
9292 header: MessageHeader {
9293 num_required_signatures: 1,
9294 ..MessageHeader::default()
9295 },
9296 recent_blockhash,
9297 account_keys: vec![Pubkey::new_unique()],
9298 ..v0::Message::default()
9299 });
9300
9301 let request = create_test_request(
9302 "getFeeForMessage",
9303 Some(json!([BASE64_STANDARD.encode(serialize(&v0_msg).unwrap())])),
9304 );
9305 let response: RpcResponse<u64> = parse_success_result(rpc.handle_request_sync(request));
9306 assert_eq!(response.value, TEST_SIGNATURE_FEE);
9307 }
9308 }
9309
9310 #[test]
9311 fn test_rpc_get_recent_prioritization_fees() {
9312 fn wait_for_cache_blocks(cache: &PrioritizationFeeCache, num_blocks: usize) {
9313 while cache.available_block_count() < num_blocks {
9314 std::thread::sleep(std::time::Duration::from_millis(100));
9315 }
9316 }
9317
9318 fn assert_fee_vec_eq(
9319 expected: &mut Vec<RpcPrioritizationFee>,
9320 actual: &mut Vec<RpcPrioritizationFee>,
9321 ) {
9322 expected.sort_by(|a, b| a.slot.partial_cmp(&b.slot).unwrap());
9323 actual.sort_by(|a, b| a.slot.partial_cmp(&b.slot).unwrap());
9324 assert_eq!(expected, actual);
9325 }
9326
9327 let rpc = RpcHandler::start();
9328 assert_eq!(
9329 rpc.get_prioritization_fee_cache().available_block_count(),
9330 0
9331 );
9332 let slot0 = rpc.working_bank().slot();
9333 let bank0_id = rpc.working_bank().bank_id();
9334 let account0 = Pubkey::new_unique();
9335 let account1 = Pubkey::new_unique();
9336 let account2 = Pubkey::new_unique();
9337 let price0 = 42;
9338 let transactions = vec![
9339 Transaction::new_unsigned(Message::new(
9340 &[
9341 system_instruction::transfer(&account0, &account1, 1),
9342 ComputeBudgetInstruction::set_compute_unit_price(price0),
9343 ],
9344 Some(&account0),
9345 )),
9346 Transaction::new_unsigned(Message::new(
9347 &[system_instruction::transfer(&account0, &account2, 1)],
9348 Some(&account0),
9349 )),
9350 ];
9351 rpc.update_prioritization_fee_cache(transactions);
9352 let cache = rpc.get_prioritization_fee_cache();
9353 cache.finalize_priority_fee(slot0, bank0_id);
9354 wait_for_cache_blocks(cache, 1);
9355
9356 let request = create_test_request("getRecentPrioritizationFees", None);
9357 let mut response: Vec<RpcPrioritizationFee> =
9358 parse_success_result(rpc.handle_request_sync(request));
9359 assert_fee_vec_eq(
9360 &mut response,
9361 &mut vec![RpcPrioritizationFee {
9362 slot: slot0,
9363 prioritization_fee: 0,
9364 }],
9365 );
9366
9367 let request = create_test_request(
9368 "getRecentPrioritizationFees",
9369 Some(json!([[account1.to_string()]])),
9370 );
9371 let mut response: Vec<RpcPrioritizationFee> =
9372 parse_success_result(rpc.handle_request_sync(request));
9373 assert_fee_vec_eq(
9374 &mut response,
9375 &mut vec![RpcPrioritizationFee {
9376 slot: slot0,
9377 prioritization_fee: price0,
9378 }],
9379 );
9380
9381 let request = create_test_request(
9382 "getRecentPrioritizationFees",
9383 Some(json!([[account2.to_string()]])),
9384 );
9385 let mut response: Vec<RpcPrioritizationFee> =
9386 parse_success_result(rpc.handle_request_sync(request));
9387 assert_fee_vec_eq(
9388 &mut response,
9389 &mut vec![RpcPrioritizationFee {
9390 slot: slot0,
9391 prioritization_fee: 0,
9392 }],
9393 );
9394
9395 rpc.advance_bank_to_confirmed_slot(1);
9396 let slot1 = rpc.working_bank().slot();
9397 let bank1_id = rpc.working_bank().bank_id();
9398 let price1 = 11;
9399 let transactions = vec![
9400 Transaction::new_unsigned(Message::new(
9401 &[
9402 system_instruction::transfer(&account0, &account2, 1),
9403 ComputeBudgetInstruction::set_compute_unit_price(price1),
9404 ],
9405 Some(&account0),
9406 )),
9407 Transaction::new_unsigned(Message::new(
9408 &[system_instruction::transfer(&account0, &account1, 1)],
9409 Some(&account0),
9410 )),
9411 ];
9412 rpc.update_prioritization_fee_cache(transactions);
9413 let cache = rpc.get_prioritization_fee_cache();
9414 cache.finalize_priority_fee(slot1, bank1_id);
9415 wait_for_cache_blocks(cache, 2);
9416
9417 let request = create_test_request("getRecentPrioritizationFees", None);
9418 let mut response: Vec<RpcPrioritizationFee> =
9419 parse_success_result(rpc.handle_request_sync(request));
9420 assert_fee_vec_eq(
9421 &mut response,
9422 &mut vec![
9423 RpcPrioritizationFee {
9424 slot: slot0,
9425 prioritization_fee: 0,
9426 },
9427 RpcPrioritizationFee {
9428 slot: slot1,
9429 prioritization_fee: 0,
9430 },
9431 ],
9432 );
9433
9434 let request = create_test_request(
9435 "getRecentPrioritizationFees",
9436 Some(json!([[account1.to_string()]])),
9437 );
9438 let mut response: Vec<RpcPrioritizationFee> =
9439 parse_success_result(rpc.handle_request_sync(request));
9440 assert_fee_vec_eq(
9441 &mut response,
9442 &mut vec![
9443 RpcPrioritizationFee {
9444 slot: slot0,
9445 prioritization_fee: price0,
9446 },
9447 RpcPrioritizationFee {
9448 slot: slot1,
9449 prioritization_fee: 0,
9450 },
9451 ],
9452 );
9453
9454 let request = create_test_request(
9455 "getRecentPrioritizationFees",
9456 Some(json!([[account2.to_string()]])),
9457 );
9458 let mut response: Vec<RpcPrioritizationFee> =
9459 parse_success_result(rpc.handle_request_sync(request));
9460 assert_fee_vec_eq(
9461 &mut response,
9462 &mut vec![
9463 RpcPrioritizationFee {
9464 slot: slot0,
9465 prioritization_fee: 0,
9466 },
9467 RpcPrioritizationFee {
9468 slot: slot1,
9469 prioritization_fee: price1,
9470 },
9471 ],
9472 );
9473 }
9474}