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