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