2018-08-16 07:46:07 -07:00
//! The `rpc` module implements the Solana RPC interface.
2018-08-10 16:05:23 -07:00
2021-06-04 08:23:06 -07:00
use {
crate ::{
2021-08-23 15:32:15 -07:00
max_slots ::MaxSlots , optimistically_confirmed_bank_tracker ::OptimisticallyConfirmedBank ,
2022-08-23 22:34:35 -07:00
parsed_token_accounts ::* , rpc_cache ::LargestAccountsCache , rpc_health ::* ,
2020-04-20 22:01:09 -07:00
} ,
2021-06-04 08:23:06 -07:00
bincode ::{ config ::Options , serialize } ,
2022-01-11 02:44:46 -08:00
crossbeam_channel ::{ unbounded , Receiver , Sender } ,
2021-07-26 11:32:17 -07:00
jsonrpc_core ::{ futures ::future , types ::error , BoxFuture , Error , Metadata , Result } ,
2021-06-04 08:23:06 -07:00
jsonrpc_derive ::rpc ,
solana_account_decoder ::{
2022-01-25 20:32:21 -08:00
parse_token ::{ is_known_spl_token_id , token_amount_to_ui_amount , UiTokenAmount } ,
2021-08-20 13:30:59 -07:00
UiAccount , UiAccountEncoding , UiDataSliceConfig , MAX_BASE58_BYTES ,
2021-06-04 08:23:06 -07:00
} ,
2022-11-18 11:21:45 -08:00
solana_client ::connection_cache ::ConnectionCache ,
2022-03-07 23:20:34 -08:00
solana_entry ::entry ::Entry ,
2021-06-04 08:23:06 -07:00
solana_faucet ::faucet ::request_airdrop_transaction ,
2023-01-08 08:00:55 -08:00
solana_gossip ::{
cluster_info ::ClusterInfo , legacy_contact_info ::LegacyContactInfo as ContactInfo ,
} ,
2021-06-04 08:23:06 -07:00
solana_ledger ::{
2021-12-29 09:25:10 -08:00
blockstore ::{ Blockstore , SignatureInfosForAddress } ,
blockstore_db ::BlockstoreError ,
2023-01-12 19:14:04 -08:00
blockstore_meta ::{ PerfSample , PerfSampleV1 , PerfSampleV2 } ,
2021-12-29 09:25:10 -08:00
get_tmp_ledger_path ,
2021-06-04 08:23:06 -07:00
leader_schedule_cache ::LeaderScheduleCache ,
} ,
solana_metrics ::inc_new_counter_info ,
solana_perf ::packet ::PACKET_DATA_SIZE ,
2022-08-24 09:47:02 -07:00
solana_rpc_client_api ::{
config ::* ,
custom_error ::RpcCustomError ,
deprecated_config ::* ,
filter ::{ Memcmp , MemcmpEncodedBytes , RpcFilterType } ,
request ::{
TokenAccountsFilter , DELINQUENT_VALIDATOR_SLOT_DISTANCE ,
MAX_GET_CONFIRMED_BLOCKS_RANGE , MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT ,
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE , MAX_GET_PROGRAM_ACCOUNT_FILTERS ,
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS , MAX_GET_SLOT_LEADERS , MAX_MULTIPLE_ACCOUNTS ,
2022-09-26 16:28:29 -07:00
MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY , NUM_LARGEST_ACCOUNTS ,
2022-08-24 09:47:02 -07:00
} ,
response ::{ Response as RpcResponse , * } ,
} ,
2021-06-04 08:23:06 -07:00
solana_runtime ::{
accounts ::AccountAddressFilter ,
2021-11-17 11:10:29 -08:00
accounts_index ::{ AccountIndex , AccountSecondaryIndexes , IndexKey , ScanConfig } ,
2021-07-16 14:58:15 -07:00
bank ::{ Bank , TransactionSimulationResult } ,
2021-07-01 06:55:26 -07:00
bank_forks ::BankForks ,
2021-06-04 08:23:06 -07:00
commitment ::{ BlockCommitmentArray , BlockCommitmentCache , CommitmentSlots } ,
2021-11-21 05:27:03 -08:00
inline_spl_token ::{ SPL_TOKEN_ACCOUNT_MINT_OFFSET , SPL_TOKEN_ACCOUNT_OWNER_OFFSET } ,
2022-05-17 12:02:43 -07:00
inline_spl_token_2022 ::{ self , ACCOUNTTYPE_ACCOUNT } ,
2021-06-04 08:23:06 -07:00
non_circulating_supply ::calculate_non_circulating_supply ,
2022-09-01 16:12:12 -07:00
prioritization_fee_cache ::PrioritizationFeeCache ,
2021-07-01 06:55:26 -07:00
snapshot_config ::SnapshotConfig ,
2021-07-01 10:20:56 -07:00
snapshot_utils ,
2021-06-04 08:23:06 -07:00
} ,
solana_sdk ::{
account ::{ AccountSharedData , ReadableAccount } ,
account_utils ::StateMut ,
clock ::{ Slot , UnixTimestamp , MAX_RECENT_BLOCKHASHES } ,
commitment_config ::{ CommitmentConfig , CommitmentLevel } ,
epoch_info ::EpochInfo ,
epoch_schedule ::EpochSchedule ,
exit ::Exit ,
2022-07-07 07:45:19 -07:00
feature_set ,
2021-10-22 14:32:40 -07:00
fee_calculator ::FeeCalculator ,
2021-06-04 08:23:06 -07:00
hash ::Hash ,
2022-10-04 09:00:34 -07:00
message ::SanitizedMessage ,
2021-10-26 14:44:24 -07:00
pubkey ::{ Pubkey , PUBKEY_BYTES } ,
2021-06-04 08:23:06 -07:00
signature ::{ Keypair , Signature , Signer } ,
2021-10-04 15:59:11 -07:00
stake ::state ::{ StakeActivationStatus , StakeState } ,
2021-06-04 08:23:06 -07:00
stake_history ::StakeHistory ,
system_instruction ,
sysvar ::stake_history ,
2022-02-03 03:00:12 -08:00
transaction ::{
2022-03-14 21:02:22 -07:00
self , AddressLoader , MessageHash , SanitizedTransaction , TransactionError ,
2022-09-01 16:12:12 -07:00
VersionedTransaction , MAX_TX_ACCOUNT_LOCKS ,
2022-02-03 03:00:12 -08:00
} ,
2021-06-04 08:23:06 -07:00
} ,
2021-08-23 15:32:15 -07:00
solana_send_transaction_service ::{
2022-06-08 04:57:12 -07:00
send_transaction_service ::{ SendTransactionService , TransactionInfo } ,
2021-08-23 15:32:15 -07:00
tpu_info ::NullTpuInfo ,
} ,
2022-07-17 11:39:39 -07:00
solana_stake_program ,
2021-12-31 12:36:57 -08:00
solana_storage_bigtable ::Error as StorageError ,
2021-07-23 08:25:03 -07:00
solana_streamer ::socket ::SocketAddrSpace ,
2021-06-04 08:23:06 -07:00
solana_transaction_status ::{
2022-03-07 23:20:34 -08:00
BlockEncodingOptions , ConfirmedBlock , ConfirmedTransactionStatusWithSignature ,
ConfirmedTransactionWithStatusMeta , EncodedConfirmedTransactionWithStatusMeta , Reward ,
2022-03-09 00:09:08 -08:00
RewardType , TransactionBinaryEncoding , TransactionConfirmationStatus , TransactionStatus ,
UiConfirmedBlock , UiTransactionEncoding ,
2021-06-04 08:23:06 -07:00
} ,
solana_vote_program ::vote_state ::{ VoteState , MAX_LOCKOUT_HISTORY } ,
2022-05-17 12:02:43 -07:00
spl_token_2022 ::{
extension ::StateWithExtensions ,
2021-06-04 08:23:06 -07:00
solana_program ::program_pack ::Pack ,
state ::{ Account as TokenAccount , Mint } ,
} ,
std ::{
2021-08-13 09:08:20 -07:00
any ::type_name ,
2021-06-04 08:23:06 -07:00
cmp ::{ max , min } ,
collections ::{ HashMap , HashSet } ,
2021-08-17 15:17:56 -07:00
convert ::TryFrom ,
2021-06-04 08:23:06 -07:00
net ::SocketAddr ,
str ::FromStr ,
sync ::{
atomic ::{ AtomicBool , AtomicU64 , Ordering } ,
Arc , Mutex , RwLock ,
} ,
time ::Duration ,
} ,
2019-10-14 15:24:10 -07:00
} ;
2018-08-10 16:05:23 -07:00
2021-06-14 21:04:01 -07:00
type RpcCustomResult < T > = std ::result ::Result < T , RpcCustomError > ;
2022-08-08 05:50:05 -07:00
pub const MAX_REQUEST_BODY_SIZE : usize = 50 * ( 1 < < 10 ) ; // 50kB
2020-09-22 12:26:32 -07:00
pub const PERFORMANCE_SAMPLES_LIMIT : usize = 720 ;
2020-09-16 11:50:43 -07:00
2020-07-03 16:39:14 -07:00
fn new_response < T > ( bank : & Bank , value : T ) -> RpcResponse < T > {
2022-05-11 21:17:21 -07:00
RpcResponse {
context : RpcResponseContext ::new ( bank . slot ( ) ) ,
value ,
}
2019-11-12 11:49:41 -08:00
}
2021-03-26 15:47:35 -07:00
fn is_finalized (
2020-06-25 21:06:58 -07:00
block_commitment_cache : & BlockCommitmentCache ,
2020-07-07 19:13:30 -07:00
bank : & Bank ,
2020-06-25 21:06:58 -07:00
blockstore : & Blockstore ,
slot : Slot ,
) -> bool {
2020-07-07 16:59:46 -07:00
slot < = block_commitment_cache . highest_confirmed_root ( )
2020-07-07 19:13:30 -07:00
& & ( blockstore . is_root ( slot ) | | bank . status_cache_ancestors ( ) . contains ( & slot ) )
2020-06-25 21:06:58 -07:00
}
2020-01-30 09:17:01 -08:00
#[ derive(Debug, Default, Clone) ]
2019-03-05 21:12:30 -08:00
pub struct JsonRpcConfig {
2020-03-23 10:25:39 -07:00
pub enable_rpc_transaction_history : bool ,
2022-03-22 15:17:05 -07:00
pub enable_extended_tx_metadata_storage : bool ,
2019-12-16 13:05:17 -08:00
pub faucet_addr : Option < SocketAddr > ,
2020-05-29 15:31:52 -07:00
pub health_check_slot_distance : u64 ,
2022-03-18 11:36:52 -07:00
pub rpc_bigtable_config : Option < RpcBigtableConfig > ,
2020-12-07 09:22:35 -08:00
pub max_multiple_accounts : Option < usize > ,
2021-05-13 14:04:21 -07:00
pub account_indexes : AccountSecondaryIndexes ,
2021-01-12 17:13:47 -08:00
pub rpc_threads : usize ,
2021-10-26 20:13:19 -07:00
pub rpc_niceness_adj : i8 ,
2022-01-28 18:00:18 -08:00
pub full_api : bool ,
2021-04-12 19:33:40 -07:00
pub obsolete_v1_7_api : bool ,
2021-05-24 12:24:47 -07:00
pub rpc_scan_and_fix_roots : bool ,
2022-08-08 05:50:05 -07:00
pub max_request_body_size : Option < usize > ,
2019-03-03 22:01:09 -08:00
}
2022-02-02 14:46:16 -08:00
impl JsonRpcConfig {
pub fn default_for_test ( ) -> Self {
Self {
full_api : true ,
.. Self ::default ( )
}
}
}
2022-03-19 00:04:17 -07:00
#[ derive(Debug, Clone) ]
2022-03-18 11:36:52 -07:00
pub struct RpcBigtableConfig {
pub enable_bigtable_ledger_upload : bool ,
2022-03-19 00:04:17 -07:00
pub bigtable_instance_name : String ,
2022-06-15 17:58:16 -07:00
pub bigtable_app_profile_id : String ,
2022-03-18 11:36:52 -07:00
pub timeout : Option < Duration > ,
}
2022-03-19 00:04:17 -07:00
impl Default for RpcBigtableConfig {
fn default ( ) -> Self {
let bigtable_instance_name = solana_storage_bigtable ::DEFAULT_INSTANCE_NAME . to_string ( ) ;
2022-06-15 17:58:16 -07:00
let bigtable_app_profile_id = solana_storage_bigtable ::DEFAULT_APP_PROFILE_ID . to_string ( ) ;
2022-03-19 00:04:17 -07:00
Self {
enable_bigtable_ledger_upload : false ,
bigtable_instance_name ,
2022-06-15 17:58:16 -07:00
bigtable_app_profile_id ,
2022-03-19 00:04:17 -07:00
timeout : None ,
}
}
}
2019-02-17 09:29:08 -08:00
#[ derive(Clone) ]
pub struct JsonRpcRequestProcessor {
2019-03-18 14:18:43 -07:00
bank_forks : Arc < RwLock < BankForks > > ,
2019-11-04 15:44:27 -08:00
block_commitment_cache : Arc < RwLock < BlockCommitmentCache > > ,
2020-01-13 13:13:52 -08:00
blockstore : Arc < Blockstore > ,
2019-03-03 22:01:09 -08:00
config : JsonRpcConfig ,
2021-01-14 21:45:11 -08:00
snapshot_config : Option < SnapshotConfig > ,
2021-10-05 22:24:48 -07:00
#[ allow(dead_code) ]
2021-06-03 20:06:13 -07:00
validator_exit : Arc < RwLock < Exit > > ,
2020-05-30 00:39:24 -07:00
health : Arc < RpcHealth > ,
2020-06-07 20:54:03 -07:00
cluster_info : Arc < ClusterInfo > ,
genesis_hash : Hash ,
2020-07-10 18:14:41 -07:00
transaction_sender : Arc < Mutex < Sender < TransactionInfo > > > ,
2020-07-23 09:54:57 -07:00
bigtable_ledger_storage : Option < solana_storage_bigtable ::LedgerStorage > ,
2020-09-28 19:43:05 -07:00
optimistically_confirmed_bank : Arc < RwLock < OptimisticallyConfirmedBank > > ,
2021-02-11 11:32:46 -08:00
largest_accounts_cache : Arc < RwLock < LargestAccountsCache > > ,
2021-02-23 13:06:33 -08:00
max_slots : Arc < MaxSlots > ,
2021-03-23 10:48:54 -07:00
leader_schedule_cache : Arc < LeaderScheduleCache > ,
2021-03-26 15:47:35 -07:00
max_complete_transaction_status_slot : Arc < AtomicU64 > ,
2022-09-01 16:12:12 -07:00
prioritization_fee_cache : Arc < PrioritizationFeeCache > ,
2018-08-14 17:03:48 -07:00
}
2020-06-07 20:54:03 -07:00
impl Metadata for JsonRpcRequestProcessor { }
2018-08-14 17:03:48 -07:00
2019-02-17 09:29:08 -08:00
impl JsonRpcRequestProcessor {
2022-05-16 23:46:02 -07:00
fn get_bank_with_config ( & self , config : RpcContextConfig ) -> Result < Arc < Bank > > {
let RpcContextConfig {
commitment ,
min_context_slot ,
} = config ;
let bank = self . bank ( commitment ) ;
if let Some ( min_context_slot ) = min_context_slot {
if bank . slot ( ) < min_context_slot {
return Err ( RpcCustomError ::MinContextSlotNotReached {
context_slot : bank . slot ( ) ,
}
. into ( ) ) ;
}
}
Ok ( bank )
}
2021-01-26 11:23:07 -08:00
#[ allow(deprecated) ]
2020-07-03 16:39:14 -07:00
fn bank ( & self , commitment : Option < CommitmentConfig > ) -> Arc < Bank > {
2019-11-06 13:15:00 -08:00
debug! ( " RPC commitment_config: {:?} " , commitment ) ;
2020-05-18 11:49:01 -07:00
2021-01-26 11:23:07 -08:00
let commitment = commitment . unwrap_or_default ( ) ;
if commitment . is_confirmed ( ) {
2020-09-28 19:43:05 -07:00
let bank = self
. optimistically_confirmed_bank
. read ( )
. unwrap ( )
. bank
. clone ( ) ;
debug! ( " RPC using optimistically confirmed slot: {:?} " , bank . slot ( ) ) ;
return bank ;
}
2020-07-20 16:03:40 -07:00
let slot = self
. block_commitment_cache
. read ( )
. unwrap ( )
2021-01-26 11:23:07 -08:00
. slot_with_commitment ( commitment . commitment ) ;
2020-07-20 16:03:40 -07:00
2021-01-26 11:23:07 -08:00
match commitment . commitment {
// Recent variant is deprecated
CommitmentLevel ::Recent | CommitmentLevel ::Processed = > {
2020-07-20 16:03:40 -07:00
debug! ( " RPC using the heaviest slot: {:?} " , slot ) ;
2020-05-18 11:49:01 -07:00
}
2021-01-26 11:23:07 -08:00
// Root variant is deprecated
2020-06-25 16:08:55 -07:00
CommitmentLevel ::Root = > {
2020-05-18 11:49:01 -07:00
debug! ( " RPC using node root: {:?} " , slot ) ;
}
2021-01-26 11:23:07 -08:00
// Single variant is deprecated
2020-09-28 19:43:05 -07:00
CommitmentLevel ::Single = > {
2020-05-18 11:49:01 -07:00
debug! ( " RPC using confirmed slot: {:?} " , slot ) ;
}
2021-01-26 11:23:07 -08:00
// Max variant is deprecated
CommitmentLevel ::Max | CommitmentLevel ::Finalized = > {
2020-07-03 16:39:14 -07:00
debug! ( " RPC using block: {:?} " , slot ) ;
2020-05-18 11:49:01 -07:00
}
2021-01-26 11:23:07 -08:00
CommitmentLevel ::SingleGossip | CommitmentLevel ::Confirmed = > unreachable! ( ) , // SingleGossip variant is deprecated
2020-07-03 16:39:14 -07:00
} ;
2020-07-20 16:03:40 -07:00
2022-04-29 01:32:46 -07:00
let r_bank_forks = self . bank_forks . read ( ) . unwrap ( ) ;
2022-04-28 11:51:00 -07:00
r_bank_forks . get ( slot ) . unwrap_or_else ( | | {
2020-11-18 19:36:10 -08:00
// We log a warning instead of returning an error, because all known error cases
2020-07-23 17:57:15 -07:00
// are due to known bugs that should be fixed instead.
//
// The slot may not be found as a result of a known bug in snapshot creation, where
// the bank at the given slot was not included in the snapshot.
// Also, it may occur after an old bank has been purged from BankForks and a new
// BlockCommitmentCache has not yet arrived. To make this case impossible,
// BlockCommitmentCache should hold an `Arc<Bank>` everywhere it currently holds
// a slot.
//
// For more information, see https://github.com/solana-labs/solana/issues/11078
2020-11-18 19:36:10 -08:00
warn! (
2020-07-23 17:57:15 -07:00
" Bank with {:?} not found at slot: {:?} " ,
2021-01-26 11:23:07 -08:00
commitment . commitment , slot
2020-07-23 17:57:15 -07:00
) ;
2020-12-27 05:28:05 -08:00
r_bank_forks . root_bank ( )
2020-07-23 17:57:15 -07:00
} )
2019-02-20 21:23:44 -08:00
}
2021-08-17 15:29:34 -07:00
fn genesis_creation_time ( & self ) -> UnixTimestamp {
self . bank ( None ) . genesis_creation_time ( )
}
2020-07-23 09:54:57 -07:00
#[ allow(clippy::too_many_arguments) ]
2019-03-03 22:01:09 -08:00
pub fn new (
config : JsonRpcConfig ,
2021-01-14 21:45:11 -08:00
snapshot_config : Option < SnapshotConfig > ,
2019-03-18 14:18:43 -07:00
bank_forks : Arc < RwLock < BankForks > > ,
2019-11-04 15:44:27 -08:00
block_commitment_cache : Arc < RwLock < BlockCommitmentCache > > ,
2020-01-13 13:13:52 -08:00
blockstore : Arc < Blockstore > ,
2021-06-03 20:06:13 -07:00
validator_exit : Arc < RwLock < Exit > > ,
2020-05-30 00:39:24 -07:00
health : Arc < RpcHealth > ,
2020-06-07 20:54:03 -07:00
cluster_info : Arc < ClusterInfo > ,
genesis_hash : Hash ,
2020-07-23 09:54:57 -07:00
bigtable_ledger_storage : Option < solana_storage_bigtable ::LedgerStorage > ,
2020-09-28 19:43:05 -07:00
optimistically_confirmed_bank : Arc < RwLock < OptimisticallyConfirmedBank > > ,
2021-02-11 11:32:46 -08:00
largest_accounts_cache : Arc < RwLock < LargestAccountsCache > > ,
2021-02-23 13:06:33 -08:00
max_slots : Arc < MaxSlots > ,
2021-03-23 10:48:54 -07:00
leader_schedule_cache : Arc < LeaderScheduleCache > ,
2021-03-26 15:47:35 -07:00
max_complete_transaction_status_slot : Arc < AtomicU64 > ,
2022-09-01 16:12:12 -07:00
prioritization_fee_cache : Arc < PrioritizationFeeCache > ,
2020-07-10 18:14:41 -07:00
) -> ( Self , Receiver < TransactionInfo > ) {
2022-01-11 02:44:46 -08:00
let ( sender , receiver ) = unbounded ( ) ;
2020-07-10 18:14:41 -07:00
(
Self {
config ,
2021-01-14 21:45:11 -08:00
snapshot_config ,
2020-07-10 18:14:41 -07:00
bank_forks ,
block_commitment_cache ,
blockstore ,
validator_exit ,
health ,
cluster_info ,
genesis_hash ,
transaction_sender : Arc ::new ( Mutex ::new ( sender ) ) ,
2020-07-23 09:54:57 -07:00
bigtable_ledger_storage ,
2020-09-28 19:43:05 -07:00
optimistically_confirmed_bank ,
2021-02-11 11:32:46 -08:00
largest_accounts_cache ,
2021-02-23 13:06:33 -08:00
max_slots ,
2021-03-23 10:48:54 -07:00
leader_schedule_cache ,
2021-03-26 15:47:35 -07:00
max_complete_transaction_status_slot ,
2022-09-01 16:12:12 -07:00
prioritization_fee_cache ,
2020-07-10 18:14:41 -07:00
} ,
receiver ,
)
2019-01-15 12:20:07 -08:00
}
2020-06-16 22:30:59 -07:00
// Useful for unit testing
2022-06-08 04:57:12 -07:00
pub fn new_from_bank (
bank : & Arc < Bank > ,
socket_addr_space : SocketAddrSpace ,
connection_cache : Arc < ConnectionCache > ,
) -> Self {
2020-06-16 22:30:59 -07:00
let genesis_hash = bank . hash ( ) ;
let bank_forks = Arc ::new ( RwLock ::new ( BankForks ::new_from_banks (
& [ bank . clone ( ) ] ,
bank . slot ( ) ,
) ) ) ;
let blockstore = Arc ::new ( Blockstore ::open ( & get_tmp_ledger_path! ( ) ) . unwrap ( ) ) ;
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
2023-01-24 08:57:55 -08:00
let cluster_info = Arc ::new ( {
let keypair = Arc ::new ( Keypair ::new ( ) ) ;
let contact_info = ContactInfo {
id : keypair . pubkey ( ) ,
.. ContactInfo ::default ( )
} ;
ClusterInfo ::new ( contact_info , keypair , socket_addr_space )
} ) ;
2020-07-08 18:13:42 -07:00
let tpu_address = cluster_info . my_contact_info ( ) . tpu ;
2022-01-11 02:44:46 -08:00
let ( sender , receiver ) = unbounded ( ) ;
2021-08-23 15:32:15 -07:00
SendTransactionService ::new ::< NullTpuInfo > (
tpu_address ,
& bank_forks ,
None ,
receiver ,
2022-06-08 04:57:12 -07:00
& connection_cache ,
2021-08-23 15:32:15 -07:00
1000 ,
1 ,
) ;
2020-07-10 18:14:41 -07:00
2020-06-16 22:30:59 -07:00
Self {
config : JsonRpcConfig ::default ( ) ,
2021-01-14 21:45:11 -08:00
snapshot_config : None ,
2020-07-10 18:14:41 -07:00
bank_forks ,
2020-06-16 22:30:59 -07:00
block_commitment_cache : Arc ::new ( RwLock ::new ( BlockCommitmentCache ::new (
HashMap ::new ( ) ,
0 ,
2020-08-12 20:51:15 -07:00
CommitmentSlots ::new_from_slot ( bank . slot ( ) ) ,
2020-06-16 22:30:59 -07:00
) ) ) ,
blockstore ,
validator_exit : create_validator_exit ( & exit ) ,
2022-06-29 14:48:33 -07:00
health : Arc ::new ( RpcHealth ::new (
cluster_info . clone ( ) ,
None ,
0 ,
exit . clone ( ) ,
Arc ::clone ( bank . get_startup_verification_complete ( ) ) ,
) ) ,
2020-07-08 18:13:42 -07:00
cluster_info ,
2020-06-16 22:30:59 -07:00
genesis_hash ,
2020-07-10 18:14:41 -07:00
transaction_sender : Arc ::new ( Mutex ::new ( sender ) ) ,
2020-07-23 09:54:57 -07:00
bigtable_ledger_storage : None ,
2020-09-28 19:43:05 -07:00
optimistically_confirmed_bank : Arc ::new ( RwLock ::new ( OptimisticallyConfirmedBank {
bank : bank . clone ( ) ,
} ) ) ,
2021-02-11 11:32:46 -08:00
largest_accounts_cache : Arc ::new ( RwLock ::new ( LargestAccountsCache ::new ( 30 ) ) ) ,
2021-02-23 13:06:33 -08:00
max_slots : Arc ::new ( MaxSlots ::default ( ) ) ,
2021-03-23 10:48:54 -07:00
leader_schedule_cache : Arc ::new ( LeaderScheduleCache ::new_from_bank ( bank ) ) ,
2021-03-26 15:47:35 -07:00
max_complete_transaction_status_slot : Arc ::new ( AtomicU64 ::default ( ) ) ,
2022-09-01 16:12:12 -07:00
prioritization_fee_cache : Arc ::new ( PrioritizationFeeCache ::default ( ) ) ,
2020-06-16 22:30:59 -07:00
}
}
2019-11-06 13:15:00 -08:00
pub fn get_account_info (
& self ,
2020-06-25 16:08:55 -07:00
pubkey : & Pubkey ,
2020-06-30 21:55:11 -07:00
config : Option < RpcAccountInfoConfig > ,
2020-08-08 22:40:13 -07:00
) -> Result < RpcResponse < Option < UiAccount > > > {
2022-05-16 23:46:02 -07:00
let RpcAccountInfoConfig {
encoding ,
data_slice ,
commitment ,
min_context_slot ,
} = config . unwrap_or_default ( ) ;
let bank = self . get_bank_with_config ( RpcContextConfig {
commitment ,
min_context_slot ,
} ) ? ;
let encoding = encoding . unwrap_or ( UiAccountEncoding ::Binary ) ;
2020-08-08 22:40:13 -07:00
2022-05-16 23:46:02 -07:00
let response = get_encoded_account ( & bank , pubkey , encoding , data_slice ) ? ;
2020-08-08 22:40:13 -07:00
Ok ( new_response ( & bank , response ) )
2018-10-25 16:58:40 -07:00
}
2019-02-26 12:25:46 -08:00
2020-09-03 10:35:06 -07:00
pub fn get_multiple_accounts (
& self ,
pubkeys : Vec < Pubkey > ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Vec < Option < UiAccount > > > > {
2022-05-16 23:46:02 -07:00
let RpcAccountInfoConfig {
encoding ,
data_slice ,
commitment ,
min_context_slot ,
} = config . unwrap_or_default ( ) ;
let bank = self . get_bank_with_config ( RpcContextConfig {
commitment ,
min_context_slot ,
} ) ? ;
let encoding = encoding . unwrap_or ( UiAccountEncoding ::Base64 ) ;
2020-09-03 10:35:06 -07:00
2021-09-16 12:40:01 -07:00
let accounts = pubkeys
. into_iter ( )
2022-05-16 23:46:02 -07:00
. map ( | pubkey | get_encoded_account ( & bank , & pubkey , encoding , data_slice ) )
2021-09-16 12:40:01 -07:00
. collect ::< Result < Vec < _ > > > ( ) ? ;
2020-09-03 10:57:57 -07:00
Ok ( new_response ( & bank , accounts ) )
2020-09-03 10:35:06 -07:00
}
2019-11-06 13:15:00 -08:00
pub fn get_minimum_balance_for_rent_exemption (
& self ,
data_len : usize ,
commitment : Option < CommitmentConfig > ,
2020-07-03 16:39:14 -07:00
) -> u64 {
self . bank ( commitment )
. get_minimum_balance_for_rent_exemption ( data_len )
2019-09-26 10:57:13 -07:00
}
2019-11-06 13:15:00 -08:00
pub fn get_program_accounts (
& self ,
program_id : & Pubkey ,
2020-06-30 21:55:11 -07:00
config : Option < RpcAccountInfoConfig > ,
2021-10-26 14:44:24 -07:00
mut filters : Vec < RpcFilterType > ,
2021-05-22 00:12:21 -07:00
with_context : bool ,
) -> Result < OptionalContext < Vec < RpcKeyedAccount > > > {
2022-05-16 23:46:02 -07:00
let RpcAccountInfoConfig {
encoding ,
data_slice : data_slice_config ,
commitment ,
min_context_slot ,
} = config . unwrap_or_default ( ) ;
let bank = self . get_bank_with_config ( RpcContextConfig {
commitment ,
min_context_slot ,
} ) ? ;
let encoding = encoding . unwrap_or ( UiAccountEncoding ::Binary ) ;
2021-10-26 14:44:24 -07:00
optimize_filters ( & mut filters ) ;
2020-12-31 18:06:03 -08:00
let keyed_accounts = {
if let Some ( owner ) = get_spl_token_owner_filter ( program_id , & filters ) {
2022-01-25 20:32:21 -08:00
self . get_filtered_spl_token_accounts_by_owner ( & bank , program_id , & owner , filters ) ?
2021-02-09 14:49:13 -08:00
} else if let Some ( mint ) = get_spl_token_mint_filter ( program_id , & filters ) {
2022-01-25 20:32:21 -08:00
self . get_filtered_spl_token_accounts_by_mint ( & bank , program_id , & mint , filters ) ?
2020-12-31 18:06:03 -08:00
} else {
2021-05-13 14:04:21 -07:00
self . get_filtered_program_accounts ( & bank , program_id , filters ) ?
2020-12-31 18:06:03 -08:00
}
} ;
2022-01-25 20:32:21 -08:00
let accounts = if is_known_spl_token_id ( program_id )
& & encoding = = UiAccountEncoding ::JsonParsed
2022-02-08 11:01:40 -08:00
{
2021-09-16 12:40:01 -07:00
get_parsed_token_accounts ( bank . clone ( ) , keyed_accounts . into_iter ( ) ) . collect ( )
} else {
keyed_accounts
. into_iter ( )
. map ( | ( pubkey , account ) | {
Ok ( RpcKeyedAccount {
2020-08-10 15:35:29 -07:00
pubkey : pubkey . to_string ( ) ,
2021-07-22 20:56:27 -07:00
account : encode_account ( & account , & pubkey , encoding , data_slice_config ) ? ,
2021-09-16 12:40:01 -07:00
} )
} )
. collect ::< Result < Vec < _ > > > ( ) ?
} ;
2022-02-08 11:01:40 -08:00
Ok ( match with_context {
true = > OptionalContext ::Context ( new_response ( & bank , accounts ) ) ,
false = > OptionalContext ::NoContext ( accounts ) ,
2021-05-22 00:12:21 -07:00
} )
2019-06-29 09:59:07 -07:00
}
2021-07-26 11:32:17 -07:00
pub async fn get_inflation_reward (
2021-04-06 18:10:53 -07:00
& self ,
addresses : Vec < Pubkey > ,
config : Option < RpcEpochConfig > ,
) -> Result < Vec < Option < RpcInflationReward > > > {
let config = config . unwrap_or_default ( ) ;
let epoch_schedule = self . get_epoch_schedule ( ) ;
2021-07-26 11:32:17 -07:00
let first_available_block = self . get_first_available_block ( ) . await ;
2022-05-16 23:46:02 -07:00
let epoch = match config . epoch {
Some ( epoch ) = > epoch ,
None = > epoch_schedule
. get_epoch ( self . get_slot ( RpcContextConfig {
commitment : config . commitment ,
min_context_slot : config . min_context_slot ,
} ) ? )
. saturating_sub ( 1 ) ,
} ;
2021-04-06 18:10:53 -07:00
// Rewards for this epoch are found in the first confirmed block of the next epoch
let first_slot_in_epoch = epoch_schedule . get_first_slot_in_epoch ( epoch . saturating_add ( 1 ) ) ;
if first_slot_in_epoch < first_available_block {
if self . bigtable_ledger_storage . is_some ( ) {
return Err ( RpcCustomError ::LongTermStorageSlotSkipped {
slot : first_slot_in_epoch ,
}
. into ( ) ) ;
} else {
return Err ( RpcCustomError ::BlockCleanedUp {
slot : first_slot_in_epoch ,
first_available_block ,
}
. into ( ) ) ;
}
}
let first_confirmed_block_in_epoch = * self
2021-07-26 11:32:17 -07:00
. get_blocks_with_limit ( first_slot_in_epoch , 1 , config . commitment )
. await ?
2022-06-21 13:26:51 -07:00
. first ( )
2021-04-06 18:10:53 -07:00
. ok_or ( RpcCustomError ::BlockNotAvailable {
slot : first_slot_in_epoch ,
} ) ? ;
2021-07-26 11:32:17 -07:00
let first_confirmed_block = if let Ok ( Some ( first_confirmed_block ) ) = self
. get_block (
first_confirmed_block_in_epoch ,
Some ( RpcBlockConfig ::rewards_with_commitment ( config . commitment ) . into ( ) ) ,
)
. await
{
2021-04-06 18:10:53 -07:00
first_confirmed_block
} else {
return Err ( RpcCustomError ::BlockNotAvailable {
slot : first_confirmed_block_in_epoch ,
}
. into ( ) ) ;
} ;
let addresses : Vec < String > = addresses
. into_iter ( )
. map ( | pubkey | pubkey . to_string ( ) )
. collect ( ) ;
let reward_hash : HashMap < String , Reward > = first_confirmed_block
. rewards
. unwrap_or_default ( )
. into_iter ( )
. filter_map ( | reward | match reward . reward_type ? {
RewardType ::Staking | RewardType ::Voting = > addresses
. contains ( & reward . pubkey )
. then ( | | ( reward . clone ( ) . pubkey , reward ) ) ,
_ = > None ,
} )
. collect ( ) ;
let rewards = addresses
. iter ( )
. map ( | address | {
if let Some ( reward ) = reward_hash . get ( address ) {
return Some ( RpcInflationReward {
epoch ,
effective_slot : first_confirmed_block_in_epoch ,
2022-04-20 10:01:33 -07:00
amount : reward . lamports . unsigned_abs ( ) ,
2021-04-06 18:10:53 -07:00
post_balance : reward . post_balance ,
2021-07-10 23:18:42 -07:00
commission : reward . commission ,
2021-04-06 18:10:53 -07:00
} ) ;
}
None
} )
. collect ( ) ;
Ok ( rewards )
}
2020-05-29 11:50:25 -07:00
pub fn get_inflation_governor (
& self ,
commitment : Option < CommitmentConfig > ,
2020-07-03 16:39:14 -07:00
) -> RpcInflationGovernor {
self . bank ( commitment ) . inflation ( ) . into ( )
2020-05-29 11:50:25 -07:00
}
2020-07-03 16:39:14 -07:00
pub fn get_inflation_rate ( & self ) -> RpcInflationRate {
let bank = self . bank ( None ) ;
2020-07-01 15:43:25 -07:00
let epoch = bank . epoch ( ) ;
let inflation = bank . inflation ( ) ;
2020-12-10 23:42:39 -08:00
let slot_in_year = bank . slot_in_year_for_inflation ( ) ;
2020-05-29 11:50:25 -07:00
2020-07-03 16:39:14 -07:00
RpcInflationRate {
2020-12-10 23:42:39 -08:00
total : inflation . total ( slot_in_year ) ,
validator : inflation . validator ( slot_in_year ) ,
foundation : inflation . foundation ( slot_in_year ) ,
2020-05-29 11:50:25 -07:00
epoch ,
2020-07-03 16:39:14 -07:00
}
2019-08-27 15:17:03 -07:00
}
2020-07-03 16:39:14 -07:00
pub fn get_epoch_schedule ( & self ) -> EpochSchedule {
2019-11-08 20:56:57 -08:00
// Since epoch schedule data comes from the genesis config, any commitment level should be
2019-11-06 13:15:00 -08:00
// fine
2021-01-26 11:23:07 -08:00
let bank = self . bank ( Some ( CommitmentConfig ::finalized ( ) ) ) ;
2020-07-03 16:39:14 -07:00
* bank . epoch_schedule ( )
2019-10-22 13:41:18 -07:00
}
2019-11-12 11:49:41 -08:00
pub fn get_balance (
& self ,
2020-06-25 16:08:55 -07:00
pubkey : & Pubkey ,
2022-05-16 23:46:02 -07:00
config : RpcContextConfig ,
) -> Result < RpcResponse < u64 > > {
let bank = self . get_bank_with_config ( config ) ? ;
Ok ( new_response ( & bank , bank . get_balance ( pubkey ) ) )
2019-02-17 09:29:08 -08:00
}
2019-02-26 12:25:46 -08:00
2019-11-06 13:15:00 -08:00
fn get_recent_blockhash (
& self ,
commitment : Option < CommitmentConfig > ,
2022-05-16 23:46:02 -07:00
) -> Result < RpcResponse < RpcBlockhashFeeCalculator > > {
2020-07-03 16:39:14 -07:00
let bank = self . bank ( commitment ) ;
2021-10-22 14:32:40 -07:00
let blockhash = bank . confirmed_last_blockhash ( ) ;
let lamports_per_signature = bank
. get_lamports_per_signature_for_blockhash ( & blockhash )
. unwrap ( ) ;
2022-05-16 23:46:02 -07:00
Ok ( new_response (
2020-06-25 16:08:55 -07:00
& bank ,
2020-01-14 23:25:45 -08:00
RpcBlockhashFeeCalculator {
blockhash : blockhash . to_string ( ) ,
2021-10-22 14:32:40 -07:00
fee_calculator : FeeCalculator ::new ( lamports_per_signature ) ,
2020-01-14 23:25:45 -08:00
} ,
2022-05-16 23:46:02 -07:00
) )
2019-11-12 11:49:41 -08:00
}
2022-05-16 23:46:02 -07:00
fn get_fees ( & self , commitment : Option < CommitmentConfig > ) -> Result < RpcResponse < RpcFees > > {
2020-07-03 16:39:14 -07:00
let bank = self . bank ( commitment ) ;
2021-10-22 14:32:40 -07:00
let blockhash = bank . confirmed_last_blockhash ( ) ;
let lamports_per_signature = bank
. get_lamports_per_signature_for_blockhash ( & blockhash )
. unwrap ( ) ;
2021-08-11 00:04:00 -07:00
#[ allow(deprecated) ]
2020-05-26 12:06:21 -07:00
let last_valid_slot = bank
. get_blockhash_last_valid_slot ( & blockhash )
. expect ( " bank blockhash queue should contain blockhash " ) ;
2021-05-26 00:26:19 -07:00
let last_valid_block_height = bank
. get_blockhash_last_valid_block_height ( & blockhash )
. expect ( " bank blockhash queue should contain blockhash " ) ;
2022-05-16 23:46:02 -07:00
Ok ( new_response (
2020-06-25 16:08:55 -07:00
& bank ,
2020-05-26 12:06:21 -07:00
RpcFees {
blockhash : blockhash . to_string ( ) ,
2021-10-22 14:32:40 -07:00
fee_calculator : FeeCalculator ::new ( lamports_per_signature ) ,
2020-05-26 12:06:21 -07:00
last_valid_slot ,
2021-05-26 00:26:19 -07:00
last_valid_block_height ,
2020-05-26 12:06:21 -07:00
} ,
2022-05-16 23:46:02 -07:00
) )
2020-05-26 12:06:21 -07:00
}
2020-03-06 16:01:31 -08:00
fn get_fee_calculator_for_blockhash (
& self ,
blockhash : & Hash ,
2020-05-26 16:23:58 -07:00
commitment : Option < CommitmentConfig > ,
2022-05-16 23:46:02 -07:00
) -> Result < RpcResponse < Option < RpcFeeCalculator > > > {
2020-07-03 16:39:14 -07:00
let bank = self . bank ( commitment ) ;
2021-10-22 14:32:40 -07:00
let lamports_per_signature = bank . get_lamports_per_signature_for_blockhash ( blockhash ) ;
2022-05-16 23:46:02 -07:00
Ok ( new_response (
2020-06-25 16:08:55 -07:00
& bank ,
2021-10-22 14:32:40 -07:00
lamports_per_signature . map ( | lamports_per_signature | RpcFeeCalculator {
fee_calculator : FeeCalculator ::new ( lamports_per_signature ) ,
} ) ,
2022-05-16 23:46:02 -07:00
) )
2020-03-06 16:01:31 -08:00
}
2020-07-03 16:39:14 -07:00
fn get_fee_rate_governor ( & self ) -> RpcResponse < RpcFeeRateGovernor > {
let bank = self . bank ( None ) ;
2021-08-13 09:08:20 -07:00
#[ allow(deprecated) ]
2020-02-28 12:27:01 -08:00
let fee_rate_governor = bank . get_fee_rate_governor ( ) ;
new_response (
2020-06-25 16:08:55 -07:00
& bank ,
2020-02-28 12:27:01 -08:00
RpcFeeRateGovernor {
fee_rate_governor : fee_rate_governor . clone ( ) ,
} ,
)
}
2019-11-12 11:49:41 -08:00
pub fn confirm_transaction (
& self ,
2020-06-25 16:08:55 -07:00
signature : & Signature ,
2019-11-12 11:49:41 -08:00
commitment : Option < CommitmentConfig > ,
2022-05-16 23:46:02 -07:00
) -> Result < RpcResponse < bool > > {
2020-07-03 16:39:14 -07:00
let bank = self . bank ( commitment ) ;
2020-06-25 16:08:55 -07:00
let status = bank . get_signature_status ( signature ) ;
match status {
2022-05-16 23:46:02 -07:00
Some ( status ) = > Ok ( new_response ( & bank , status . is_ok ( ) ) ) ,
None = > Ok ( new_response ( & bank , false ) ) ,
2019-11-12 11:49:41 -08:00
}
2019-02-17 09:29:08 -08:00
}
2019-02-26 12:25:46 -08:00
2020-04-20 22:25:49 -07:00
fn get_block_commitment ( & self , block : Slot ) -> RpcBlockCommitment < BlockCommitmentArray > {
2019-11-04 15:44:27 -08:00
let r_block_commitment = self . block_commitment_cache . read ( ) . unwrap ( ) ;
2020-01-14 23:25:45 -08:00
RpcBlockCommitment {
2020-01-21 19:17:33 -08:00
commitment : r_block_commitment
. get_block_commitment ( block )
. map ( | block_commitment | block_commitment . commitment ) ,
2020-01-14 23:25:45 -08:00
total_stake : r_block_commitment . total_stake ( ) ,
}
2019-10-14 15:24:10 -07:00
}
2022-05-16 23:46:02 -07:00
fn get_slot ( & self , config : RpcContextConfig ) -> Result < Slot > {
let bank = self . get_bank_with_config ( config ) ? ;
Ok ( bank . slot ( ) )
2019-06-12 16:43:05 -07:00
}
2022-05-16 23:46:02 -07:00
fn get_block_height ( & self , config : RpcContextConfig ) -> Result < u64 > {
let bank = self . get_bank_with_config ( config ) ? ;
Ok ( bank . block_height ( ) )
2021-05-26 00:26:19 -07:00
}
2021-02-23 13:06:33 -08:00
fn get_max_retransmit_slot ( & self ) -> Slot {
self . max_slots . retransmit . load ( Ordering ::Relaxed )
}
fn get_max_shred_insert_slot ( & self ) -> Slot {
self . max_slots . shred_insert . load ( Ordering ::Relaxed )
}
2022-05-16 23:46:02 -07:00
fn get_slot_leader ( & self , config : RpcContextConfig ) -> Result < String > {
let bank = self . get_bank_with_config ( config ) ? ;
Ok ( bank . collector_id ( ) . to_string ( ) )
2019-07-09 22:06:47 -07:00
}
2021-04-28 09:57:05 -07:00
fn get_slot_leaders (
& self ,
commitment : Option < CommitmentConfig > ,
start_slot : Slot ,
limit : usize ,
) -> Result < Vec < Pubkey > > {
let bank = self . bank ( commitment ) ;
let ( mut epoch , mut slot_index ) =
bank . epoch_schedule ( ) . get_epoch_and_slot_index ( start_slot ) ;
let mut slot_leaders = Vec ::with_capacity ( limit ) ;
while slot_leaders . len ( ) < limit {
if let Some ( leader_schedule ) =
self . leader_schedule_cache . get_epoch_leader_schedule ( epoch )
{
slot_leaders . extend (
leader_schedule
. get_slot_leaders ( )
. iter ( )
. skip ( slot_index as usize )
. take ( limit . saturating_sub ( slot_leaders . len ( ) ) ) ,
) ;
} else {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Invalid slot range: leader schedule for epoch {epoch} is unavailable "
2021-04-28 09:57:05 -07:00
) ) ) ;
}
epoch + = 1 ;
slot_index = 0 ;
}
Ok ( slot_leaders )
}
2020-01-21 12:05:04 -08:00
fn minimum_ledger_slot ( & self ) -> Result < Slot > {
match self . blockstore . slot_meta_iterator ( 0 ) {
Ok ( mut metas ) = > match metas . next ( ) {
Some ( ( slot , _meta ) ) = > Ok ( slot ) ,
None = > Err ( Error ::invalid_request ( ) ) ,
} ,
Err ( err ) = > {
warn! ( " slot_meta_iterator failed: {:?} " , err ) ;
Err ( Error ::invalid_request ( ) )
}
}
}
2022-05-16 23:46:02 -07:00
fn get_transaction_count ( & self , config : RpcContextConfig ) -> Result < u64 > {
let bank = self . get_bank_with_config ( config ) ? ;
2022-11-09 11:39:38 -08:00
Ok ( bank . transaction_count ( ) )
2019-02-17 09:29:08 -08:00
}
2019-02-26 12:25:46 -08:00
2022-05-16 23:46:02 -07:00
fn get_total_supply ( & self , commitment : Option < CommitmentConfig > ) -> Result < u64 > {
let bank = self . bank ( commitment ) ;
Ok ( bank . capitalization ( ) )
2019-06-21 21:00:26 -07:00
}
2021-02-11 11:32:46 -08:00
fn get_cached_largest_accounts (
& self ,
filter : & Option < RpcLargestAccountsFilter > ,
) -> Option < ( u64 , Vec < RpcAccountBalance > ) > {
let largest_accounts_cache = self . largest_accounts_cache . read ( ) . unwrap ( ) ;
largest_accounts_cache . get_largest_accounts ( filter )
}
fn set_cached_largest_accounts (
& self ,
filter : & Option < RpcLargestAccountsFilter > ,
slot : u64 ,
accounts : & [ RpcAccountBalance ] ,
) {
let mut largest_accounts_cache = self . largest_accounts_cache . write ( ) . unwrap ( ) ;
largest_accounts_cache . set_largest_accounts ( filter , slot , accounts )
}
2020-05-04 16:46:10 -07:00
fn get_largest_accounts (
& self ,
2020-05-12 20:05:05 -07:00
config : Option < RpcLargestAccountsConfig > ,
2021-06-14 21:04:01 -07:00
) -> RpcCustomResult < RpcResponse < Vec < RpcAccountBalance > > > {
2020-05-12 20:05:05 -07:00
let config = config . unwrap_or_default ( ) ;
2020-07-03 16:39:14 -07:00
let bank = self . bank ( config . commitment ) ;
2021-02-11 11:32:46 -08:00
if let Some ( ( slot , accounts ) ) = self . get_cached_largest_accounts ( & config . filter ) {
2022-02-08 11:01:40 -08:00
Ok ( RpcResponse {
2022-05-11 21:17:21 -07:00
context : RpcResponseContext ::new ( slot ) ,
2021-02-11 11:32:46 -08:00
value : accounts ,
2021-06-14 21:04:01 -07:00
} )
2020-05-12 20:05:05 -07:00
} else {
2021-02-11 11:32:46 -08:00
let ( addresses , address_filter ) = if let Some ( filter ) = config . clone ( ) . filter {
2021-06-14 21:04:01 -07:00
let non_circulating_supply =
calculate_non_circulating_supply ( & bank ) . map_err ( | e | {
RpcCustomError ::ScanError {
message : e . to_string ( ) ,
}
} ) ? ;
2021-02-11 11:32:46 -08:00
let addresses = non_circulating_supply . accounts . into_iter ( ) . collect ( ) ;
let address_filter = match filter {
RpcLargestAccountsFilter ::Circulating = > AccountAddressFilter ::Exclude ,
RpcLargestAccountsFilter ::NonCirculating = > AccountAddressFilter ::Include ,
} ;
( addresses , address_filter )
} else {
( HashSet ::new ( ) , AccountAddressFilter ::Exclude )
} ;
let accounts = bank
. get_largest_accounts ( NUM_LARGEST_ACCOUNTS , & addresses , address_filter )
2021-06-14 21:04:01 -07:00
. map_err ( | e | RpcCustomError ::ScanError {
message : e . to_string ( ) ,
} ) ?
2020-05-12 20:05:05 -07:00
. into_iter ( )
. map ( | ( address , lamports ) | RpcAccountBalance {
address : address . to_string ( ) ,
lamports ,
} )
2021-02-11 11:32:46 -08:00
. collect ::< Vec < RpcAccountBalance > > ( ) ;
self . set_cached_largest_accounts ( & config . filter , bank . slot ( ) , & accounts ) ;
2021-06-14 21:04:01 -07:00
Ok ( new_response ( & bank , accounts ) )
2021-02-11 11:32:46 -08:00
}
2020-05-04 16:46:10 -07:00
}
2021-06-14 21:04:01 -07:00
fn get_supply (
& self ,
2021-08-17 16:32:58 -07:00
config : Option < RpcSupplyConfig > ,
2021-06-14 21:04:01 -07:00
) -> RpcCustomResult < RpcResponse < RpcSupply > > {
2021-08-17 16:32:58 -07:00
let config = config . unwrap_or_default ( ) ;
let bank = self . bank ( config . commitment ) ;
2021-06-14 21:04:01 -07:00
let non_circulating_supply =
calculate_non_circulating_supply ( & bank ) . map_err ( | e | RpcCustomError ::ScanError {
message : e . to_string ( ) ,
} ) ? ;
2020-05-09 11:05:29 -07:00
let total_supply = bank . capitalization ( ) ;
2021-08-17 16:32:58 -07:00
let non_circulating_accounts = if config . exclude_non_circulating_accounts_list {
vec! [ ]
} else {
non_circulating_supply
. accounts
. iter ( )
. map ( | pubkey | pubkey . to_string ( ) )
. collect ( )
} ;
2021-06-14 21:04:01 -07:00
Ok ( new_response (
2020-05-09 11:05:29 -07:00
& bank ,
RpcSupply {
total : total_supply ,
circulating : total_supply - non_circulating_supply . lamports ,
non_circulating : non_circulating_supply . lamports ,
2021-08-17 16:32:58 -07:00
non_circulating_accounts ,
2020-05-09 11:05:29 -07:00
} ,
2021-06-14 21:04:01 -07:00
) )
2020-05-09 11:05:29 -07:00
}
2019-11-06 13:15:00 -08:00
fn get_vote_accounts (
& self ,
2021-04-26 18:27:35 -07:00
config : Option < RpcGetVoteAccountsConfig > ,
2019-11-06 13:15:00 -08:00
) -> Result < RpcVoteAccountStatus > {
2021-04-26 18:27:35 -07:00
let config = config . unwrap_or_default ( ) ;
let filter_by_vote_pubkey = if let Some ( ref vote_pubkey ) = config . vote_pubkey {
Some ( verify_pubkey ( vote_pubkey ) ? )
} else {
None
} ;
let bank = self . bank ( config . commitment ) ;
2019-08-16 16:02:19 -07:00
let vote_accounts = bank . vote_accounts ( ) ;
let epoch_vote_accounts = bank
2019-06-11 16:57:47 -07:00
. epoch_vote_accounts ( bank . get_epoch_and_slot_index ( bank . slot ( ) ) . 0 )
2019-08-16 16:02:19 -07:00
. ok_or_else ( Error ::invalid_request ) ? ;
2020-11-30 09:18:33 -08:00
let default_vote_state = VoteState ::default ( ) ;
2021-07-02 22:51:41 -07:00
let delinquent_validator_slot_distance = config
. delinquent_slot_distance
. unwrap_or ( DELINQUENT_VALIDATOR_SLOT_DISTANCE ) ;
2019-08-16 16:02:19 -07:00
let ( current_vote_accounts , delinquent_vote_accounts ) : (
Vec < RpcVoteAccountInfo > ,
Vec < RpcVoteAccountInfo > ,
) = vote_accounts
2019-05-20 22:21:13 -07:00
. iter ( )
2021-04-26 18:27:35 -07:00
. filter_map ( | ( vote_pubkey , ( activated_stake , account ) ) | {
if let Some ( filter_by_vote_pubkey ) = filter_by_vote_pubkey {
if * vote_pubkey ! = filter_by_vote_pubkey {
return None ;
}
}
2020-11-30 09:18:33 -08:00
let vote_state = account . vote_state ( ) ;
let vote_state = vote_state . as_ref ( ) . unwrap_or ( & default_vote_state ) ;
2019-08-16 16:02:19 -07:00
let last_vote = if let Some ( vote ) = vote_state . votes . iter ( ) . last ( ) {
2023-01-18 18:28:28 -08:00
vote . slot ( )
2019-08-16 16:02:19 -07:00
} else {
0
} ;
2021-04-20 00:31:38 -07:00
let epoch_credits = vote_state . epoch_credits ( ) ;
2022-09-26 16:28:29 -07:00
let epoch_credits = if epoch_credits . len ( )
> MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY
{
2021-04-20 00:31:38 -07:00
epoch_credits
. iter ( )
2022-09-26 16:28:29 -07:00
. skip ( epoch_credits . len ( ) - MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY )
2021-04-20 00:31:38 -07:00
. cloned ( )
. collect ( )
} else {
epoch_credits . clone ( )
} ;
2021-04-26 18:27:35 -07:00
Some ( RpcVoteAccountInfo {
vote_pubkey : vote_pubkey . to_string ( ) ,
2019-06-12 14:12:08 -07:00
node_pubkey : vote_state . node_pubkey . to_string ( ) ,
2019-08-16 16:02:19 -07:00
activated_stake : * activated_stake ,
2019-06-12 14:12:08 -07:00
commission : vote_state . commission ,
2019-10-06 20:24:26 -07:00
root_slot : vote_state . root_slot . unwrap_or ( 0 ) ,
2021-04-20 00:31:38 -07:00
epoch_credits ,
2021-04-26 18:27:35 -07:00
epoch_vote_account : epoch_vote_accounts . contains_key ( vote_pubkey ) ,
2019-08-16 16:02:19 -07:00
last_vote ,
2021-04-26 18:27:35 -07:00
} )
2019-06-12 14:12:08 -07:00
} )
2019-08-16 16:02:19 -07:00
. partition ( | vote_account_info | {
2022-11-09 11:39:38 -08:00
if bank . slot ( ) > = delinquent_validator_slot_distance {
vote_account_info . last_vote > bank . slot ( ) - delinquent_validator_slot_distance
2019-09-26 18:40:18 -07:00
} else {
vote_account_info . last_vote > 0
}
2019-08-16 16:02:19 -07:00
} ) ;
2019-12-14 00:53:45 -08:00
2021-07-02 22:51:41 -07:00
let keep_unstaked_delinquents = config . keep_unstaked_delinquents . unwrap_or_default ( ) ;
let delinquent_vote_accounts = if ! keep_unstaked_delinquents {
delinquent_vote_accounts
. into_iter ( )
. filter ( | vote_account_info | vote_account_info . activated_stake > 0 )
. collect ::< Vec < _ > > ( )
} else {
delinquent_vote_accounts
} ;
2019-12-14 00:53:45 -08:00
2019-08-16 16:02:19 -07:00
Ok ( RpcVoteAccountStatus {
current : current_vote_accounts ,
2021-07-02 22:51:41 -07:00
delinquent : delinquent_vote_accounts ,
2019-08-16 16:02:19 -07:00
} )
2019-05-20 22:21:13 -07:00
}
2020-12-16 12:40:36 -08:00
fn check_blockstore_root < T > (
2020-11-25 14:59:38 -08:00
& self ,
result : & std ::result ::Result < T , BlockstoreError > ,
slot : Slot ,
2022-02-09 21:28:18 -08:00
) -> Result < ( ) > {
if let Err ( err ) = result {
2020-11-30 23:44:18 -08:00
debug! (
2020-12-16 12:40:36 -08:00
" check_blockstore_root, slot: {:?}, max root: {:?}, err: {:?} " ,
2020-11-30 23:44:18 -08:00
slot ,
self . blockstore . max_root ( ) ,
err
) ;
if slot > = self . blockstore . max_root ( ) {
return Err ( RpcCustomError ::BlockNotAvailable { slot } . into ( ) ) ;
2020-11-25 14:59:38 -08:00
}
2020-12-16 12:40:36 -08:00
if self . blockstore . is_skipped ( slot ) {
return Err ( RpcCustomError ::SlotSkipped { slot } . into ( ) ) ;
}
2020-11-25 14:59:38 -08:00
}
Ok ( ( ) )
}
fn check_slot_cleaned_up < T > (
2020-05-11 14:47:40 -07:00
& self ,
result : & std ::result ::Result < T , BlockstoreError > ,
slot : Slot ,
2022-02-09 21:28:18 -08:00
) -> Result < ( ) > {
2022-02-28 22:57:41 -08:00
let first_available_block = self
. blockstore
. get_first_available_block ( )
. unwrap_or_default ( ) ;
let err : Error = RpcCustomError ::BlockCleanedUp {
slot ,
first_available_block ,
}
. into ( ) ;
2022-02-09 21:28:18 -08:00
if let Err ( BlockstoreError ::SlotCleanedUp ) = result {
2022-02-28 22:57:41 -08:00
return Err ( err ) ;
}
if slot < first_available_block {
return Err ( err ) ;
2020-05-11 14:47:40 -07:00
}
Ok ( ( ) )
}
2021-01-21 20:40:47 -08:00
fn check_bigtable_result < T > (
& self ,
result : & std ::result ::Result < T , solana_storage_bigtable ::Error > ,
2022-02-09 21:28:18 -08:00
) -> Result < ( ) > {
if let Err ( solana_storage_bigtable ::Error ::BlockNotFound ( slot ) ) = result {
return Err ( RpcCustomError ::LongTermStorageSlotSkipped { slot : * slot } . into ( ) ) ;
2021-01-21 20:40:47 -08:00
}
Ok ( ( ) )
}
2021-10-27 12:11:27 -07:00
fn check_status_is_complete ( & self , slot : Slot ) -> Result < ( ) > {
if slot
> self
. max_complete_transaction_status_slot
. load ( Ordering ::SeqCst )
{
Err ( RpcCustomError ::BlockStatusNotAvailableYet { slot } . into ( ) )
} else {
Ok ( ( ) )
}
}
2021-07-26 11:32:17 -07:00
pub async fn get_block (
2020-01-12 21:34:30 -08:00
& self ,
slot : Slot ,
2021-04-15 16:00:14 -07:00
config : Option < RpcEncodingConfigWrapper < RpcBlockConfig > > ,
2021-03-18 10:58:20 -07:00
) -> Result < Option < UiConfirmedBlock > > {
2021-03-26 15:47:35 -07:00
if self . config . enable_rpc_transaction_history {
let config = config
. map ( | config | config . convert_to_current ( ) )
. unwrap_or_default ( ) ;
let encoding = config . encoding . unwrap_or ( UiTransactionEncoding ::Json ) ;
2022-03-07 23:20:34 -08:00
let encoding_options = BlockEncodingOptions {
transaction_details : config . transaction_details . unwrap_or_default ( ) ,
show_rewards : config . rewards . unwrap_or ( true ) ,
max_supported_transaction_version : config . max_supported_transaction_version ,
} ;
2021-03-26 15:47:35 -07:00
let commitment = config . commitment . unwrap_or_default ( ) ;
check_is_at_least_confirmed ( commitment ) ? ;
// Block is old enough to be finalized
if slot
2020-05-04 18:39:27 -07:00
< = self
. block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 16:59:46 -07:00
. highest_confirmed_root ( )
2021-03-26 15:47:35 -07:00
{
2021-10-27 12:11:27 -07:00
self . check_status_is_complete ( slot ) ? ;
2021-03-26 15:47:35 -07:00
let result = self . blockstore . get_rooted_block ( slot , true ) ;
self . check_blockstore_root ( & result , slot ) ? ;
2022-03-07 23:20:34 -08:00
let encode_block = | confirmed_block : ConfirmedBlock | -> Result < UiConfirmedBlock > {
let mut encoded_block = confirmed_block
. encode_with_options ( encoding , encoding_options )
. map_err ( RpcCustomError ::from ) ? ;
2021-08-17 15:29:34 -07:00
if slot = = 0 {
2022-03-07 23:20:34 -08:00
encoded_block . block_time = Some ( self . genesis_creation_time ( ) ) ;
encoded_block . block_height = Some ( 0 ) ;
2021-08-17 15:29:34 -07:00
}
2022-03-07 23:20:34 -08:00
Ok ( encoded_block )
2021-08-17 15:29:34 -07:00
} ;
2021-03-26 15:47:35 -07:00
if result . is_err ( ) {
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-07-26 11:32:17 -07:00
let bigtable_result =
bigtable_ledger_storage . get_confirmed_block ( slot ) . await ;
2021-03-26 15:47:35 -07:00
self . check_bigtable_result ( & bigtable_result ) ? ;
2022-03-07 23:20:34 -08:00
return bigtable_result . ok ( ) . map ( encode_block ) . transpose ( ) ;
2021-03-26 15:47:35 -07:00
}
}
self . check_slot_cleaned_up ( & result , slot ) ? ;
2022-02-09 21:28:18 -08:00
return result
. ok ( )
. map ( ConfirmedBlock ::from )
2022-03-07 23:20:34 -08:00
. map ( encode_block )
2022-02-09 21:28:18 -08:00
. transpose ( ) ;
2021-03-26 15:47:35 -07:00
} else if commitment . is_confirmed ( ) {
// Check if block is confirmed
let confirmed_bank = self . bank ( Some ( CommitmentConfig ::confirmed ( ) ) ) ;
2021-10-27 12:11:27 -07:00
if confirmed_bank . status_cache_ancestors ( ) . contains ( & slot ) {
self . check_status_is_complete ( slot ) ? ;
2021-03-26 15:47:35 -07:00
let result = self . blockstore . get_complete_block ( slot , true ) ;
2022-01-13 23:24:41 -08:00
return result
. ok ( )
2022-02-09 21:28:18 -08:00
. map ( ConfirmedBlock ::from )
2022-03-07 23:20:34 -08:00
. map ( | mut confirmed_block | -> Result < UiConfirmedBlock > {
if confirmed_block . block_time . is_none ( )
| | confirmed_block . block_height . is_none ( )
2022-01-13 23:24:41 -08:00
{
let r_bank_forks = self . bank_forks . read ( ) . unwrap ( ) ;
2022-04-28 11:51:00 -07:00
if let Some ( bank ) = r_bank_forks . get ( slot ) {
2022-03-07 23:20:34 -08:00
if confirmed_block . block_time . is_none ( ) {
confirmed_block . block_time =
Some ( bank . clock ( ) . unix_timestamp ) ;
2022-01-13 23:24:41 -08:00
}
2022-03-07 23:20:34 -08:00
if confirmed_block . block_height . is_none ( ) {
confirmed_block . block_height = Some ( bank . block_height ( ) ) ;
2022-01-13 23:24:41 -08:00
}
2021-05-26 21:16:16 -07:00
}
}
2022-02-09 21:28:18 -08:00
2022-03-07 23:20:34 -08:00
Ok ( confirmed_block
. encode_with_options ( encoding , encoding_options )
. map_err ( RpcCustomError ::from ) ? )
2022-01-13 23:24:41 -08:00
} )
. transpose ( ) ;
2020-07-23 09:54:57 -07:00
}
}
2021-05-26 12:27:41 -07:00
} else {
return Err ( RpcCustomError ::TransactionHistoryNotAvailable . into ( ) ) ;
2020-02-11 17:01:49 -08:00
}
2021-03-26 15:47:35 -07:00
Err ( RpcCustomError ::BlockNotAvailable { slot } . into ( ) )
2019-11-11 10:18:34 -08:00
}
2019-11-25 23:40:36 -08:00
2021-07-26 11:32:17 -07:00
pub async fn get_blocks (
2019-12-18 15:51:47 -08:00
& self ,
start_slot : Slot ,
end_slot : Option < Slot > ,
2021-03-29 11:41:31 -07:00
commitment : Option < CommitmentConfig > ,
2019-12-18 15:51:47 -08:00
) -> Result < Vec < Slot > > {
2021-03-29 11:41:31 -07:00
let commitment = commitment . unwrap_or_default ( ) ;
check_is_at_least_confirmed ( commitment ) ? ;
let highest_confirmed_root = self
. block_commitment_cache
. read ( )
. unwrap ( )
. highest_confirmed_root ( ) ;
2020-05-04 18:39:27 -07:00
let end_slot = min (
2021-03-29 11:41:31 -07:00
end_slot . unwrap_or_else ( | | start_slot . saturating_add ( MAX_GET_CONFIRMED_BLOCKS_RANGE ) ) ,
if commitment . is_finalized ( ) {
highest_confirmed_root
} else {
self . bank ( Some ( CommitmentConfig ::confirmed ( ) ) ) . slot ( )
} ,
2020-05-04 18:39:27 -07:00
) ;
2019-12-18 15:51:47 -08:00
if end_slot < start_slot {
return Ok ( vec! [ ] ) ;
}
2020-07-06 08:37:04 -07:00
if end_slot - start_slot > MAX_GET_CONFIRMED_BLOCKS_RANGE {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Slot range too large; max {MAX_GET_CONFIRMED_BLOCKS_RANGE} "
2020-07-06 08:37:04 -07:00
) ) ) ;
}
2020-07-23 09:54:57 -07:00
2022-04-27 23:36:19 -07:00
let lowest_blockstore_slot = self
. blockstore
. get_first_available_block ( )
. unwrap_or_default ( ) ;
2020-09-30 13:47:12 -07:00
if start_slot < lowest_blockstore_slot {
2020-07-23 09:54:57 -07:00
// If the starting slot is lower than what's available in blockstore assume the entire
2021-03-29 11:41:31 -07:00
// [start_slot..end_slot] can be fetched from BigTable. This range should not ever run
// into unfinalized confirmed blocks due to MAX_GET_CONFIRMED_BLOCKS_RANGE
2020-07-23 09:54:57 -07:00
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-07-26 11:32:17 -07:00
return bigtable_ledger_storage
. get_confirmed_blocks ( start_slot , ( end_slot - start_slot ) as usize + 1 ) // increment limit by 1 to ensure returned range is inclusive of both start_slot and end_slot
. await
2021-01-18 18:14:10 -08:00
. map ( | mut bigtable_blocks | {
bigtable_blocks . retain ( | & slot | slot < = end_slot ) ;
bigtable_blocks
} )
2021-01-19 05:57:16 -08:00
. map_err ( | _ | {
Error ::invalid_params (
" BigTable query failed (maybe timeout due to too large range?) "
. to_string ( ) ,
)
2021-01-23 11:55:15 -08:00
} ) ;
2020-07-23 09:54:57 -07:00
}
}
2021-03-29 11:41:31 -07:00
// Finalized blocks
let mut blocks : Vec < _ > = self
2020-04-22 13:33:06 -07:00
. blockstore
2020-09-30 13:47:12 -07:00
. rooted_slot_iterator ( max ( start_slot , lowest_blockstore_slot ) )
2020-04-22 13:33:06 -07:00
. map_err ( | _ | Error ::internal_error ( ) ) ?
2021-03-29 11:41:31 -07:00
. filter ( | & slot | slot < = end_slot & & slot < = highest_confirmed_root )
. collect ( ) ;
2021-07-28 14:23:19 -07:00
let last_element = blocks
. last ( )
. cloned ( )
. unwrap_or_else ( | | start_slot . saturating_sub ( 1 ) ) ;
2021-03-29 11:41:31 -07:00
// Maybe add confirmed blocks
if commitment . is_confirmed ( ) & & last_element < end_slot {
let confirmed_bank = self . bank ( Some ( CommitmentConfig ::confirmed ( ) ) ) ;
let mut confirmed_blocks = confirmed_bank
. status_cache_ancestors ( )
. into_iter ( )
. filter ( | & slot | slot < = end_slot & & slot > last_element )
. collect ( ) ;
blocks . append ( & mut confirmed_blocks ) ;
}
Ok ( blocks )
2019-12-18 15:51:47 -08:00
}
2021-07-26 11:32:17 -07:00
pub async fn get_blocks_with_limit (
2020-09-30 13:47:12 -07:00
& self ,
start_slot : Slot ,
limit : usize ,
2021-03-29 11:41:31 -07:00
commitment : Option < CommitmentConfig > ,
2020-09-30 13:47:12 -07:00
) -> Result < Vec < Slot > > {
2021-03-29 11:41:31 -07:00
let commitment = commitment . unwrap_or_default ( ) ;
check_is_at_least_confirmed ( commitment ) ? ;
2020-09-30 13:47:12 -07:00
if limit > MAX_GET_CONFIRMED_BLOCKS_RANGE as usize {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Limit too large; max {MAX_GET_CONFIRMED_BLOCKS_RANGE} "
2020-09-30 13:47:12 -07:00
) ) ) ;
}
2022-04-27 23:36:19 -07:00
let lowest_blockstore_slot = self
. blockstore
. get_first_available_block ( )
. unwrap_or_default ( ) ;
2020-09-30 13:47:12 -07:00
if start_slot < lowest_blockstore_slot {
// If the starting slot is lower than what's available in blockstore assume the entire
2021-03-29 11:41:31 -07:00
// range can be fetched from BigTable. This range should not ever run into unfinalized
// confirmed blocks due to MAX_GET_CONFIRMED_BLOCKS_RANGE
2020-09-30 13:47:12 -07:00
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-07-26 11:32:17 -07:00
return Ok ( bigtable_ledger_storage
. get_confirmed_blocks ( start_slot , limit )
. await
2021-04-18 10:27:36 -07:00
. unwrap_or_default ( ) ) ;
2020-09-30 13:47:12 -07:00
}
}
2021-03-29 11:41:31 -07:00
let highest_confirmed_root = self
. block_commitment_cache
. read ( )
. unwrap ( )
. highest_confirmed_root ( ) ;
// Finalized blocks
let mut blocks : Vec < _ > = self
2020-09-30 13:47:12 -07:00
. blockstore
. rooted_slot_iterator ( max ( start_slot , lowest_blockstore_slot ) )
. map_err ( | _ | Error ::internal_error ( ) ) ?
. take ( limit )
2021-03-29 11:41:31 -07:00
. filter ( | & slot | slot < = highest_confirmed_root )
. collect ( ) ;
// Maybe add confirmed blocks
if commitment . is_confirmed ( ) & & blocks . len ( ) < limit {
2021-04-08 09:57:33 -07:00
let last_element = blocks
. last ( )
. cloned ( )
. unwrap_or_else ( | | start_slot . saturating_sub ( 1 ) ) ;
2021-03-29 11:41:31 -07:00
let confirmed_bank = self . bank ( Some ( CommitmentConfig ::confirmed ( ) ) ) ;
let mut confirmed_blocks = confirmed_bank
. status_cache_ancestors ( )
. into_iter ( )
. filter ( | & slot | slot > last_element )
. collect ( ) ;
blocks . append ( & mut confirmed_blocks ) ;
blocks . truncate ( limit ) ;
}
Ok ( blocks )
2020-09-30 13:47:12 -07:00
}
2021-07-26 11:32:17 -07:00
pub async fn get_block_time ( & self , slot : Slot ) -> Result < Option < UnixTimestamp > > {
2021-08-17 15:29:34 -07:00
if slot = = 0 {
return Ok ( Some ( self . genesis_creation_time ( ) ) ) ;
}
2020-05-04 18:39:27 -07:00
if slot
< = self
. block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 16:59:46 -07:00
. highest_confirmed_root ( )
2020-05-04 18:39:27 -07:00
{
2020-09-09 08:33:14 -07:00
let result = self . blockstore . get_block_time ( slot ) ;
2020-12-16 12:40:36 -08:00
self . check_blockstore_root ( & result , slot ) ? ;
2020-12-18 10:54:41 -08:00
if result . is_err ( ) | | matches! ( result , Ok ( None ) ) {
2020-09-29 14:39:36 -07:00
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-07-26 11:32:17 -07:00
let bigtable_result = bigtable_ledger_storage . get_confirmed_block ( slot ) . await ;
2021-01-21 20:40:47 -08:00
self . check_bigtable_result ( & bigtable_result ) ? ;
return Ok ( bigtable_result
2020-09-29 14:39:36 -07:00
. ok ( )
. and_then ( | confirmed_block | confirmed_block . block_time ) ) ;
}
}
2020-11-25 14:59:38 -08:00
self . check_slot_cleaned_up ( & result , slot ) ? ;
2020-05-11 14:47:40 -07:00
Ok ( result . ok ( ) . unwrap_or ( None ) )
2020-05-04 18:39:27 -07:00
} else {
2021-03-24 19:52:08 -07:00
let r_bank_forks = self . bank_forks . read ( ) . unwrap ( ) ;
if let Some ( bank ) = r_bank_forks . get ( slot ) {
Ok ( Some ( bank . clock ( ) . unix_timestamp ) )
} else {
Err ( RpcCustomError ::BlockNotAvailable { slot } . into ( ) )
}
2020-05-04 18:39:27 -07:00
}
2019-11-25 23:40:36 -08:00
}
2020-03-23 10:25:39 -07:00
2020-04-01 16:56:18 -07:00
pub fn get_signature_confirmation_status (
& self ,
signature : Signature ,
commitment : Option < CommitmentConfig > ,
2022-05-16 23:46:02 -07:00
) -> Result < Option < RpcSignatureConfirmation > > {
2020-07-03 16:39:14 -07:00
let bank = self . bank ( commitment ) ;
2022-05-16 23:46:02 -07:00
Ok ( self
. get_transaction_status ( signature , & bank )
. map ( | transaction_status | {
let confirmations = transaction_status
. confirmations
. unwrap_or ( MAX_LOCKOUT_HISTORY + 1 ) ;
RpcSignatureConfirmation {
confirmations ,
status : transaction_status . status ,
}
} ) )
2020-04-01 16:56:18 -07:00
}
2020-03-23 10:25:39 -07:00
pub fn get_signature_status (
2020-04-01 11:30:58 -07:00
& self ,
signature : Signature ,
commitment : Option < CommitmentConfig > ,
2022-05-16 23:46:02 -07:00
) -> Result < Option < transaction ::Result < ( ) > > > {
2020-07-03 16:39:14 -07:00
let bank = self . bank ( commitment ) ;
2022-05-16 23:46:02 -07:00
Ok ( bank
. get_signature_status_slot ( & signature )
. map ( | ( _ , status ) | status ) )
2020-04-01 11:30:58 -07:00
}
2021-07-26 11:32:17 -07:00
pub async fn get_signature_statuses (
2020-03-23 10:25:39 -07:00
& self ,
signatures : Vec < Signature > ,
2020-04-06 03:04:54 -07:00
config : Option < RpcSignatureStatusConfig > ,
2020-06-11 15:51:25 -07:00
) -> Result < RpcResponse < Vec < Option < TransactionStatus > > > > {
2020-03-26 13:29:30 -07:00
let mut statuses : Vec < Option < TransactionStatus > > = vec! [ ] ;
2020-03-23 10:25:39 -07:00
2020-04-06 03:04:54 -07:00
let search_transaction_history = config
. map ( | x | x . search_transaction_history )
. unwrap_or ( false ) ;
2021-01-26 11:23:07 -08:00
let bank = self . bank ( Some ( CommitmentConfig ::processed ( ) ) ) ;
2020-03-23 10:25:39 -07:00
2021-05-26 12:27:41 -07:00
if search_transaction_history & & ! self . config . enable_rpc_transaction_history {
return Err ( RpcCustomError ::TransactionHistoryNotAvailable . into ( ) ) ;
}
2020-03-23 10:25:39 -07:00
for signature in signatures {
2020-04-06 03:04:54 -07:00
let status = if let Some ( status ) = self . get_transaction_status ( signature , & bank ) {
Some ( status )
} else if self . config . enable_rpc_transaction_history & & search_transaction_history {
2021-07-26 11:32:17 -07:00
if let Some ( status ) = self
. blockstore
2021-03-31 20:04:00 -07:00
. get_rooted_transaction_status ( signature )
2020-04-06 03:04:54 -07:00
. map_err ( | _ | Error ::internal_error ( ) ) ?
2020-05-04 18:39:27 -07:00
. filter ( | ( slot , _status_meta ) | {
slot < = & self
. block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 16:59:46 -07:00
. highest_confirmed_root ( )
2020-05-04 18:39:27 -07:00
} )
2020-04-06 03:04:54 -07:00
. map ( | ( slot , status_meta ) | {
let err = status_meta . status . clone ( ) . err ( ) ;
TransactionStatus {
slot ,
status : status_meta . status ,
confirmations : None ,
err ,
2021-01-15 08:05:05 -08:00
confirmation_status : Some ( TransactionConfirmationStatus ::Finalized ) ,
2020-04-06 03:04:54 -07:00
}
} )
2021-07-26 11:32:17 -07:00
{
Some ( status )
} else if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
bigtable_ledger_storage
. get_signature_status ( & signature )
. await
. map ( Some )
. unwrap_or ( None )
} else {
None
}
2020-04-06 03:04:54 -07:00
} else {
None
} ;
2020-03-23 10:25:39 -07:00
statuses . push ( status ) ;
}
2020-09-03 10:57:57 -07:00
Ok ( new_response ( & bank , statuses ) )
2020-03-23 10:25:39 -07:00
}
2020-04-01 16:56:18 -07:00
fn get_transaction_status (
& self ,
signature : Signature ,
bank : & Arc < Bank > ,
) -> Option < TransactionStatus > {
2020-06-25 16:08:55 -07:00
let ( slot , status ) = bank . get_signature_status_slot ( & signature ) ? ;
2021-01-26 11:23:07 -08:00
let optimistically_confirmed_bank = self . bank ( Some ( CommitmentConfig ::confirmed ( ) ) ) ;
2021-01-15 08:05:05 -08:00
let optimistically_confirmed =
optimistically_confirmed_bank . get_signature_status_slot ( & signature ) ;
2022-06-23 13:09:07 -07:00
let r_block_commitment_cache = self . block_commitment_cache . read ( ) . unwrap ( ) ;
2020-06-25 16:08:55 -07:00
let confirmations = if r_block_commitment_cache . root ( ) > = slot
2021-03-26 15:47:35 -07:00
& & is_finalized ( & r_block_commitment_cache , bank , & self . blockstore , slot )
2020-06-25 16:08:55 -07:00
{
None
} else {
r_block_commitment_cache
. get_confirmation_count ( slot )
. or ( Some ( 0 ) )
} ;
let err = status . clone ( ) . err ( ) ;
Some ( TransactionStatus {
slot ,
status ,
confirmations ,
err ,
2021-01-15 08:05:05 -08:00
confirmation_status : if confirmations . is_none ( ) {
Some ( TransactionConfirmationStatus ::Finalized )
} else if optimistically_confirmed . is_some ( ) {
Some ( TransactionConfirmationStatus ::Confirmed )
} else {
Some ( TransactionConfirmationStatus ::Processed )
} ,
2020-06-25 16:08:55 -07:00
} )
2020-04-01 16:56:18 -07:00
}
2020-04-08 23:57:30 -07:00
2021-07-26 11:32:17 -07:00
pub async fn get_transaction (
2020-04-08 23:57:30 -07:00
& self ,
signature : Signature ,
2021-04-15 16:00:14 -07:00
config : Option < RpcEncodingConfigWrapper < RpcTransactionConfig > > ,
2022-01-03 07:45:18 -08:00
) -> Result < Option < EncodedConfirmedTransactionWithStatusMeta > > {
2021-03-12 14:19:45 -08:00
let config = config
. map ( | config | config . convert_to_current ( ) )
. unwrap_or_default ( ) ;
let encoding = config . encoding . unwrap_or ( UiTransactionEncoding ::Json ) ;
2022-03-07 23:20:34 -08:00
let max_supported_transaction_version = config . max_supported_transaction_version ;
2021-03-26 15:47:35 -07:00
let commitment = config . commitment . unwrap_or_default ( ) ;
check_is_at_least_confirmed ( commitment ) ? ;
2020-04-08 23:57:30 -07:00
if self . config . enable_rpc_transaction_history {
2021-03-31 20:04:00 -07:00
let confirmed_bank = self . bank ( Some ( CommitmentConfig ::confirmed ( ) ) ) ;
2022-02-09 21:28:18 -08:00
let confirmed_transaction = if commitment . is_confirmed ( ) {
2021-03-31 20:04:00 -07:00
let highest_confirmed_slot = confirmed_bank . slot ( ) ;
self . blockstore
. get_complete_transaction ( signature , highest_confirmed_slot )
} else {
self . blockstore . get_rooted_transaction ( signature )
} ;
2022-01-13 23:24:41 -08:00
2022-02-09 21:28:18 -08:00
let encode_transaction =
| confirmed_tx_with_meta : ConfirmedTransactionWithStatusMeta | -> Result < EncodedConfirmedTransactionWithStatusMeta > {
2022-03-07 23:20:34 -08:00
Ok ( confirmed_tx_with_meta . encode ( encoding , max_supported_transaction_version ) . map_err ( RpcCustomError ::from ) ? )
2022-02-09 21:28:18 -08:00
} ;
match confirmed_transaction . unwrap_or ( None ) {
Some ( mut confirmed_transaction ) = > {
2021-03-31 20:04:00 -07:00
if commitment . is_confirmed ( )
& & confirmed_bank // should be redundant
2021-03-26 15:47:35 -07:00
. status_cache_ancestors ( )
. contains ( & confirmed_transaction . slot )
2021-03-31 20:04:00 -07:00
{
2021-04-09 13:25:47 -07:00
if confirmed_transaction . block_time . is_none ( ) {
let r_bank_forks = self . bank_forks . read ( ) . unwrap ( ) ;
confirmed_transaction . block_time = r_bank_forks
. get ( confirmed_transaction . slot )
. map ( | bank | bank . clock ( ) . unix_timestamp ) ;
}
2022-02-09 21:28:18 -08:00
return Ok ( Some ( encode_transaction ( confirmed_transaction ) ? ) ) ;
2021-03-26 15:47:35 -07:00
}
2022-02-09 21:28:18 -08:00
2020-07-23 09:54:57 -07:00
if confirmed_transaction . slot
2020-05-04 18:39:27 -07:00
< = self
. block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 16:59:46 -07:00
. highest_confirmed_root ( )
2020-07-23 09:54:57 -07:00
{
2022-02-09 21:28:18 -08:00
return Ok ( Some ( encode_transaction ( confirmed_transaction ) ? ) ) ;
2020-07-23 09:54:57 -07:00
}
}
None = > {
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2022-01-13 23:24:41 -08:00
return bigtable_ledger_storage
2021-07-26 11:32:17 -07:00
. get_confirmed_transaction ( & signature )
. await
2020-09-23 22:10:29 -07:00
. unwrap_or ( None )
2022-02-09 21:28:18 -08:00
. map ( encode_transaction )
2022-01-13 23:24:41 -08:00
. transpose ( ) ;
2020-07-23 09:54:57 -07:00
}
}
}
2021-05-26 12:27:41 -07:00
} else {
return Err ( RpcCustomError ::TransactionHistoryNotAvailable . into ( ) ) ;
2020-04-08 23:57:30 -07:00
}
2021-03-26 15:47:35 -07:00
Ok ( None )
2020-04-08 23:57:30 -07:00
}
2020-04-09 20:21:31 -07:00
pub fn get_confirmed_signatures_for_address (
& self ,
pubkey : Pubkey ,
start_slot : Slot ,
end_slot : Slot ,
2020-07-03 16:39:14 -07:00
) -> Vec < Signature > {
2020-04-09 20:21:31 -07:00
if self . config . enable_rpc_transaction_history {
2020-07-23 09:54:57 -07:00
// TODO: Add bigtable_ledger_storage support as a part of
// https://github.com/solana-labs/solana/pull/10928
2020-05-04 18:39:27 -07:00
let end_slot = min (
end_slot ,
self . block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 16:59:46 -07:00
. highest_confirmed_root ( ) ,
2020-05-04 18:39:27 -07:00
) ;
2020-07-03 16:39:14 -07:00
self . blockstore
2020-04-09 20:21:31 -07:00
. get_confirmed_signatures_for_address ( pubkey , start_slot , end_slot )
2021-04-18 10:27:36 -07:00
. unwrap_or_default ( )
2020-04-09 20:21:31 -07:00
} else {
2020-07-03 16:39:14 -07:00
vec! [ ]
2020-04-09 20:21:31 -07:00
}
}
2020-04-22 13:33:06 -07:00
2021-07-26 11:32:17 -07:00
pub async fn get_signatures_for_address (
2020-07-27 11:42:49 -07:00
& self ,
address : Pubkey ,
2021-12-29 09:25:10 -08:00
before : Option < Signature > ,
2020-08-15 09:42:17 -07:00
until : Option < Signature > ,
2020-07-30 09:54:06 -07:00
mut limit : usize ,
2022-05-16 23:46:02 -07:00
config : RpcContextConfig ,
2020-07-27 11:42:49 -07:00
) -> Result < Vec < RpcConfirmedTransactionStatusWithSignature > > {
2022-05-16 23:46:02 -07:00
let commitment = config . commitment . unwrap_or_default ( ) ;
2021-03-31 21:35:57 -07:00
check_is_at_least_confirmed ( commitment ) ? ;
2020-07-27 11:42:49 -07:00
if self . config . enable_rpc_transaction_history {
let highest_confirmed_root = self
. block_commitment_cache
. read ( )
. unwrap ( )
. highest_confirmed_root ( ) ;
2021-03-31 21:35:57 -07:00
let highest_slot = if commitment . is_confirmed ( ) {
2022-05-16 23:46:02 -07:00
let confirmed_bank = self . get_bank_with_config ( config ) ? ;
2021-03-31 21:35:57 -07:00
confirmed_bank . slot ( )
} else {
2022-05-16 23:46:02 -07:00
let min_context_slot = config . min_context_slot . unwrap_or_default ( ) ;
if highest_confirmed_root < min_context_slot {
return Err ( RpcCustomError ::MinContextSlotNotReached {
context_slot : highest_confirmed_root ,
}
. into ( ) ) ;
}
2021-03-31 21:35:57 -07:00
highest_confirmed_root
} ;
2020-07-27 11:42:49 -07:00
2021-12-29 09:25:10 -08:00
let SignatureInfosForAddress {
infos : mut results ,
found_before ,
} = self
2020-07-27 11:42:49 -07:00
. blockstore
2021-03-31 21:35:57 -07:00
. get_confirmed_signatures_for_address2 ( address , highest_slot , before , until , limit )
2022-12-06 06:30:06 -08:00
. map_err ( | err | Error ::invalid_params ( format! ( " {err} " ) ) ) ? ;
2020-07-27 11:42:49 -07:00
2021-12-31 12:36:57 -08:00
let map_results = | results : Vec < ConfirmedTransactionStatusWithSignature > | {
results
. into_iter ( )
. map ( | x | {
let mut item : RpcConfirmedTransactionStatusWithSignature = x . into ( ) ;
if item . slot < = highest_confirmed_root {
item . confirmation_status =
Some ( TransactionConfirmationStatus ::Finalized ) ;
} else {
item . confirmation_status =
Some ( TransactionConfirmationStatus ::Confirmed ) ;
if item . block_time . is_none ( ) {
let r_bank_forks = self . bank_forks . read ( ) . unwrap ( ) ;
item . block_time = r_bank_forks
. get ( item . slot )
. map ( | bank | bank . clock ( ) . unix_timestamp ) ;
}
}
item
} )
. collect ( )
} ;
2020-07-30 09:54:06 -07:00
if results . len ( ) < limit {
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-12-29 09:25:10 -08:00
let mut bigtable_before = before ;
2020-07-30 09:54:06 -07:00
if ! results . is_empty ( ) {
limit - = results . len ( ) ;
2021-12-29 09:25:10 -08:00
bigtable_before = results . last ( ) . map ( | x | x . signature ) ;
}
// If the oldest address-signature found in Blockstore has not yet been
// uploaded to long-term storage, modify the storage query to return all latest
// signatures to prevent erroring on RowNotFound. This can race with upload.
2021-12-31 12:36:57 -08:00
if found_before & & bigtable_before . is_some ( ) {
match bigtable_ledger_storage
. get_signature_status ( & bigtable_before . unwrap ( ) )
2021-12-29 09:25:10 -08:00
. await
2021-12-31 12:36:57 -08:00
{
Err ( StorageError ::SignatureNotFound ) = > {
bigtable_before = None ;
}
Err ( err ) = > {
warn! ( " {:?} " , err ) ;
return Ok ( map_results ( results ) ) ;
}
Ok ( _ ) = > { }
}
2020-07-30 09:54:06 -07:00
}
2021-07-26 11:32:17 -07:00
let bigtable_results = bigtable_ledger_storage
. get_confirmed_signatures_for_address (
2020-08-12 16:57:05 -07:00
& address ,
2021-12-29 09:25:10 -08:00
bigtable_before . as_ref ( ) ,
2020-08-15 09:42:17 -07:00
until . as_ref ( ) ,
2020-08-12 16:57:05 -07:00
limit ,
2021-07-26 11:32:17 -07:00
)
. await ;
2020-08-12 16:57:05 -07:00
match bigtable_results {
2020-09-09 20:21:52 -07:00
Ok ( bigtable_results ) = > {
2021-12-29 09:25:10 -08:00
let results_set : HashSet < _ > =
results . iter ( ) . map ( | result | result . signature ) . collect ( ) ;
for ( bigtable_result , _ ) in bigtable_results {
// In the upload race condition, latest address-signatures in
// long-term storage may include original `before` signature...
if before ! = Some ( bigtable_result . signature )
// ...or earlier Blockstore signatures
& & ! results_set . contains ( & bigtable_result . signature )
{
results . push ( bigtable_result ) ;
}
}
2020-08-12 16:57:05 -07:00
}
Err ( err ) = > {
warn! ( " {:?} " , err ) ;
}
}
2020-07-30 09:54:06 -07:00
}
}
2021-12-31 12:36:57 -08:00
Ok ( map_results ( results ) )
2020-07-27 11:42:49 -07:00
} else {
2021-05-26 12:27:41 -07:00
Err ( RpcCustomError ::TransactionHistoryNotAvailable . into ( ) )
2020-07-27 11:42:49 -07:00
}
}
2021-07-26 11:32:17 -07:00
pub async fn get_first_available_block ( & self ) -> Slot {
2020-07-23 09:54:57 -07:00
let slot = self
. blockstore
2020-04-22 13:33:06 -07:00
. get_first_available_block ( )
2020-07-23 09:54:57 -07:00
. unwrap_or_default ( ) ;
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-07-26 11:32:17 -07:00
let bigtable_slot = bigtable_ledger_storage
. get_first_available_block ( )
. await
2020-07-23 09:54:57 -07:00
. unwrap_or ( None )
. unwrap_or ( slot ) ;
if bigtable_slot < slot {
return bigtable_slot ;
}
}
slot
2020-04-22 13:33:06 -07:00
}
2020-07-06 12:28:40 -07:00
pub fn get_stake_activation (
& self ,
pubkey : & Pubkey ,
2021-04-06 18:10:53 -07:00
config : Option < RpcEpochConfig > ,
2020-07-06 12:28:40 -07:00
) -> Result < RpcStakeActivation > {
let config = config . unwrap_or_default ( ) ;
2022-05-16 23:46:02 -07:00
let bank = self . get_bank_with_config ( RpcContextConfig {
commitment : config . commitment ,
min_context_slot : config . min_context_slot ,
} ) ? ;
2020-07-06 12:28:40 -07:00
let epoch = config . epoch . unwrap_or_else ( | | bank . epoch ( ) ) ;
if bank . epoch ( ) . saturating_sub ( epoch ) > solana_sdk ::stake_history ::MAX_ENTRIES as u64 {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Invalid param: epoch {epoch:?} is too far in the past "
2020-07-06 12:28:40 -07:00
) ) ) ;
}
if epoch > bank . epoch ( ) {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Invalid param: epoch {epoch:?} has not yet started "
2020-07-06 12:28:40 -07:00
) ) ) ;
}
let stake_account = bank
. get_account ( pubkey )
. ok_or_else ( | | Error ::invalid_params ( " Invalid param: account not found " . to_string ( ) ) ) ? ;
let stake_state : StakeState = stake_account
. state ( )
. map_err ( | _ | Error ::invalid_params ( " Invalid param: not a stake account " . to_string ( ) ) ) ? ;
2021-03-19 13:54:56 -07:00
let delegation = stake_state . delegation ( ) ;
2022-07-12 13:21:07 -07:00
let rent_exempt_reserve = stake_state
. meta ( )
. ok_or_else ( | | {
Error ::invalid_params ( " Invalid param: stake account not initialized " . to_string ( ) )
} ) ?
. rent_exempt_reserve ;
let delegation = match delegation {
None = > {
return Ok ( RpcStakeActivation {
state : StakeActivationState ::Inactive ,
active : 0 ,
inactive : stake_account . lamports ( ) . saturating_sub ( rent_exempt_reserve ) ,
} )
2021-03-19 13:54:56 -07:00
}
2022-07-12 13:21:07 -07:00
Some ( delegation ) = > delegation ,
} ;
2020-07-06 12:28:40 -07:00
let stake_history_account = bank
. get_account ( & stake_history ::id ( ) )
. ok_or_else ( Error ::internal_error ) ? ;
let stake_history =
2021-03-09 13:06:07 -08:00
solana_sdk ::account ::from_account ::< StakeHistory , _ > ( & stake_history_account )
2020-10-28 22:01:07 -07:00
. ok_or_else ( Error ::internal_error ) ? ;
2020-07-06 12:28:40 -07:00
2021-10-04 15:59:11 -07:00
let StakeActivationStatus {
effective ,
activating ,
deactivating ,
} = delegation . stake_activating_and_deactivating ( epoch , Some ( & stake_history ) ) ;
2020-07-06 12:28:40 -07:00
let stake_activation_state = if deactivating > 0 {
StakeActivationState ::Deactivating
} else if activating > 0 {
StakeActivationState ::Activating
2021-10-04 15:59:11 -07:00
} else if effective > 0 {
2020-07-06 12:28:40 -07:00
StakeActivationState ::Active
} else {
StakeActivationState ::Inactive
} ;
let inactive_stake = match stake_activation_state {
StakeActivationState ::Activating = > activating ,
StakeActivationState ::Active = > 0 ,
2022-07-12 13:21:07 -07:00
StakeActivationState ::Deactivating = > stake_account
. lamports ( )
. saturating_sub ( effective + rent_exempt_reserve ) ,
StakeActivationState ::Inactive = > {
stake_account . lamports ( ) . saturating_sub ( rent_exempt_reserve )
}
2020-07-06 12:28:40 -07:00
} ;
Ok ( RpcStakeActivation {
state : stake_activation_state ,
2021-10-04 15:59:11 -07:00
active : effective ,
2020-07-06 12:28:40 -07:00
inactive : inactive_stake ,
} )
}
2020-07-28 22:00:48 -07:00
pub fn get_token_account_balance (
& self ,
pubkey : & Pubkey ,
commitment : Option < CommitmentConfig > ,
2020-08-07 10:37:39 -07:00
) -> Result < RpcResponse < UiTokenAmount > > {
2020-07-28 22:00:48 -07:00
let bank = self . bank ( commitment ) ;
let account = bank . get_account ( pubkey ) . ok_or_else ( | | {
Error ::invalid_params ( " Invalid param: could not find account " . to_string ( ) )
} ) ? ;
2022-01-25 20:32:21 -08:00
if ! is_known_spl_token_id ( account . owner ( ) ) {
2020-07-28 22:00:48 -07:00
return Err ( Error ::invalid_params (
2021-11-21 05:27:03 -08:00
" Invalid param: not a Token account " . to_string ( ) ,
2020-07-28 22:00:48 -07:00
) ) ;
}
2022-05-17 12:02:43 -07:00
let token_account = StateWithExtensions ::< TokenAccount > ::unpack ( account . data ( ) )
2021-11-21 05:27:03 -08:00
. map_err ( | _ | Error ::invalid_params ( " Invalid param: not a Token account " . to_string ( ) ) ) ? ;
2022-05-17 12:02:43 -07:00
let mint = & Pubkey ::from_str ( & token_account . base . mint . to_string ( ) )
2020-08-04 23:48:09 -07:00
. expect ( " Token account mint should be convertible to Pubkey " ) ;
2021-06-18 06:34:46 -07:00
let ( _ , decimals ) = get_mint_owner_and_decimals ( & bank , mint ) ? ;
2022-05-17 12:02:43 -07:00
let balance = token_amount_to_ui_amount ( token_account . base . amount , decimals ) ;
2020-07-28 22:00:48 -07:00
Ok ( new_response ( & bank , balance ) )
}
pub fn get_token_supply (
& self ,
mint : & Pubkey ,
commitment : Option < CommitmentConfig > ,
2020-08-07 10:37:39 -07:00
) -> Result < RpcResponse < UiTokenAmount > > {
2020-07-28 22:00:48 -07:00
let bank = self . bank ( commitment ) ;
2020-08-28 14:54:57 -07:00
let mint_account = bank . get_account ( mint ) . ok_or_else ( | | {
Error ::invalid_params ( " Invalid param: could not find account " . to_string ( ) )
} ) ? ;
2022-01-25 20:32:21 -08:00
if ! is_known_spl_token_id ( mint_account . owner ( ) ) {
2020-07-28 22:00:48 -07:00
return Err ( Error ::invalid_params (
2021-11-21 05:27:03 -08:00
" Invalid param: not a Token mint " . to_string ( ) ,
2020-07-28 22:00:48 -07:00
) ) ;
}
2022-05-17 12:02:43 -07:00
let mint = StateWithExtensions ::< Mint > ::unpack ( mint_account . data ( ) ) . map_err ( | _ | {
2020-08-28 14:54:57 -07:00
Error ::invalid_params ( " Invalid param: mint could not be unpacked " . to_string ( ) )
} ) ? ;
2020-08-04 23:48:09 -07:00
2022-05-17 12:02:43 -07:00
let supply = token_amount_to_ui_amount ( mint . base . supply , mint . base . decimals ) ;
2020-07-28 22:00:48 -07:00
Ok ( new_response ( & bank , supply ) )
}
2020-08-02 09:23:44 -07:00
pub fn get_token_largest_accounts (
& self ,
mint : & Pubkey ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < Vec < RpcTokenAccountBalance > > > {
let bank = self . bank ( commitment ) ;
2020-08-04 23:48:09 -07:00
let ( mint_owner , decimals ) = get_mint_owner_and_decimals ( & bank , mint ) ? ;
2022-01-25 20:32:21 -08:00
if ! is_known_spl_token_id ( & mint_owner ) {
2020-08-02 09:23:44 -07:00
return Err ( Error ::invalid_params (
2021-11-21 05:27:03 -08:00
" Invalid param: not a Token mint " . to_string ( ) ,
2020-08-02 09:23:44 -07:00
) ) ;
}
2020-12-31 18:06:03 -08:00
let mut token_balances : Vec < RpcTokenAccountBalance > = self
2022-01-25 20:32:21 -08:00
. get_filtered_spl_token_accounts_by_mint ( & bank , & mint_owner , mint , vec! [ ] ) ?
2020-12-31 18:06:03 -08:00
. into_iter ( )
. map ( | ( address , account ) | {
2022-05-17 12:02:43 -07:00
let amount = StateWithExtensions ::< TokenAccount > ::unpack ( account . data ( ) )
. map ( | account | account . base . amount )
2020-12-31 18:06:03 -08:00
. unwrap_or ( 0 ) ;
let amount = token_amount_to_ui_amount ( amount , decimals ) ;
RpcTokenAccountBalance {
address : address . to_string ( ) ,
amount ,
}
} )
. collect ( ) ;
2020-08-04 23:48:09 -07:00
token_balances . sort_by ( | a , b | {
a . amount
. amount
. parse ::< u64 > ( )
. unwrap ( )
. cmp ( & b . amount . amount . parse ::< u64 > ( ) . unwrap ( ) )
. reverse ( )
} ) ;
2020-08-02 09:23:44 -07:00
token_balances . truncate ( NUM_LARGEST_ACCOUNTS ) ;
Ok ( new_response ( & bank , token_balances ) )
}
2020-07-28 22:00:48 -07:00
pub fn get_token_accounts_by_owner (
& self ,
owner : & Pubkey ,
token_account_filter : TokenAccountsFilter ,
2020-08-04 10:11:30 -07:00
config : Option < RpcAccountInfoConfig > ,
2020-07-28 22:00:48 -07:00
) -> Result < RpcResponse < Vec < RpcKeyedAccount > > > {
2022-05-16 23:46:02 -07:00
let RpcAccountInfoConfig {
encoding ,
data_slice : data_slice_config ,
commitment ,
min_context_slot ,
} = config . unwrap_or_default ( ) ;
let bank = self . get_bank_with_config ( RpcContextConfig {
commitment ,
min_context_slot ,
} ) ? ;
let encoding = encoding . unwrap_or ( UiAccountEncoding ::Binary ) ;
2022-01-25 20:32:21 -08:00
let ( token_program_id , mint ) = get_token_program_id_and_mint ( & bank , token_account_filter ) ? ;
2020-07-28 22:00:48 -07:00
2020-12-31 18:06:03 -08:00
let mut filters = vec! [ ] ;
2020-07-28 22:00:48 -07:00
if let Some ( mint ) = mint {
// Optional filter on Mint address
2022-07-06 21:39:03 -07:00
filters . push ( RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes (
0 ,
mint . to_bytes ( ) . into ( ) ,
) ) ) ;
2020-07-28 22:00:48 -07:00
}
2020-12-31 18:06:03 -08:00
2022-01-25 20:32:21 -08:00
let keyed_accounts = self . get_filtered_spl_token_accounts_by_owner (
& bank ,
& token_program_id ,
owner ,
filters ,
) ? ;
2020-08-07 10:37:39 -07:00
let accounts = if encoding = = UiAccountEncoding ::JsonParsed {
2020-12-31 18:06:03 -08:00
get_parsed_token_accounts ( bank . clone ( ) , keyed_accounts . into_iter ( ) ) . collect ( )
2020-08-07 10:37:39 -07:00
} else {
keyed_accounts
2020-12-31 18:06:03 -08:00
. into_iter ( )
2022-02-01 13:10:21 -08:00
. map ( | ( pubkey , account ) | {
Ok ( RpcKeyedAccount {
pubkey : pubkey . to_string ( ) ,
account : encode_account ( & account , & pubkey , encoding , data_slice_config ) ? ,
} )
2020-08-07 10:37:39 -07:00
} )
2022-02-01 13:10:21 -08:00
. collect ::< Result < Vec < _ > > > ( ) ?
2020-08-07 10:37:39 -07:00
} ;
2020-07-28 22:00:48 -07:00
Ok ( new_response ( & bank , accounts ) )
}
pub fn get_token_accounts_by_delegate (
& self ,
delegate : & Pubkey ,
token_account_filter : TokenAccountsFilter ,
2020-08-04 10:11:30 -07:00
config : Option < RpcAccountInfoConfig > ,
2020-07-28 22:00:48 -07:00
) -> Result < RpcResponse < Vec < RpcKeyedAccount > > > {
2022-05-16 23:46:02 -07:00
let RpcAccountInfoConfig {
encoding ,
data_slice : data_slice_config ,
commitment ,
min_context_slot ,
} = config . unwrap_or_default ( ) ;
let bank = self . get_bank_with_config ( RpcContextConfig {
commitment ,
min_context_slot ,
} ) ? ;
let encoding = encoding . unwrap_or ( UiAccountEncoding ::Binary ) ;
2020-07-28 22:00:48 -07:00
let ( token_program_id , mint ) = get_token_program_id_and_mint ( & bank , token_account_filter ) ? ;
let mut filters = vec! [
// Filter on Delegate is_some()
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes (
72 ,
bincode ::serialize ( & 1 u32 ) . unwrap ( ) ,
) ) ,
2020-07-28 22:00:48 -07:00
// Filter on Delegate address
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 76 , delegate . to_bytes ( ) . into ( ) ) ) ,
2020-07-28 22:00:48 -07:00
] ;
2020-12-31 18:06:03 -08:00
// Optional filter on Mint address, uses mint account index for scan
let keyed_accounts = if let Some ( mint ) = mint {
2022-01-25 20:32:21 -08:00
self . get_filtered_spl_token_accounts_by_mint ( & bank , & token_program_id , & mint , filters ) ?
2020-12-31 18:06:03 -08:00
} else {
// Filter on Token Account state
2022-05-17 12:02:43 -07:00
filters . push ( RpcFilterType ::TokenAccountState ) ;
2021-05-13 14:04:21 -07:00
self . get_filtered_program_accounts ( & bank , & token_program_id , filters ) ?
2020-12-31 18:06:03 -08:00
} ;
2020-08-07 10:37:39 -07:00
let accounts = if encoding = = UiAccountEncoding ::JsonParsed {
2020-12-31 18:06:03 -08:00
get_parsed_token_accounts ( bank . clone ( ) , keyed_accounts . into_iter ( ) ) . collect ( )
2020-08-07 10:37:39 -07:00
} else {
keyed_accounts
2020-12-31 18:06:03 -08:00
. into_iter ( )
2022-02-01 13:10:21 -08:00
. map ( | ( pubkey , account ) | {
Ok ( RpcKeyedAccount {
pubkey : pubkey . to_string ( ) ,
account : encode_account ( & account , & pubkey , encoding , data_slice_config ) ? ,
} )
2020-08-07 10:37:39 -07:00
} )
2022-02-01 13:10:21 -08:00
. collect ::< Result < Vec < _ > > > ( ) ?
2020-08-07 10:37:39 -07:00
} ;
2020-07-28 22:00:48 -07:00
Ok ( new_response ( & bank , accounts ) )
}
2020-12-31 18:06:03 -08:00
/// Use a set of filters to get an iterator of keyed program accounts from a bank
fn get_filtered_program_accounts (
& self ,
bank : & Arc < Bank > ,
program_id : & Pubkey ,
2021-10-14 11:43:27 -07:00
mut filters : Vec < RpcFilterType > ,
2021-06-14 21:04:01 -07:00
) -> RpcCustomResult < Vec < ( Pubkey , AccountSharedData ) > > {
2021-10-14 11:43:27 -07:00
optimize_filters ( & mut filters ) ;
2021-03-09 13:06:07 -08:00
let filter_closure = | account : & AccountSharedData | {
2022-04-20 18:18:12 -07:00
filters
. iter ( )
. all ( | filter_type | filter_type . allows ( account ) )
2020-12-31 18:06:03 -08:00
} ;
if self
. config
. account_indexes
. contains ( & AccountIndex ::ProgramId )
{
2021-05-13 14:04:21 -07:00
if ! self . config . account_indexes . include_key ( program_id ) {
return Err ( RpcCustomError ::KeyExcludedFromSecondaryIndex {
index_key : program_id . to_string ( ) ,
2021-06-14 21:04:01 -07:00
} ) ;
2021-05-13 14:04:21 -07:00
}
2021-06-14 21:04:01 -07:00
Ok ( bank
2021-11-17 11:10:29 -08:00
. get_filtered_indexed_accounts (
& IndexKey ::ProgramId ( * program_id ) ,
| account | {
// The program-id account index checks for Account owner on inclusion. However, due
// to the current AccountsDb implementation, an account may remain in storage as a
// zero-lamport AccountSharedData::Default() after being wiped and reinitialized in later
// updates. We include the redundant filters here to avoid returning these
// accounts.
account . owner ( ) = = program_id & & filter_closure ( account )
} ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
bank . byte_limit_for_scans ( ) ,
2021-11-17 11:10:29 -08:00
)
2021-06-14 21:04:01 -07:00
. map_err ( | e | RpcCustomError ::ScanError {
message : e . to_string ( ) ,
} ) ? )
2020-12-31 18:06:03 -08:00
} else {
2021-11-19 07:00:19 -08:00
// this path does not need to provide a mb limit because we only want to support secondary indexes
2021-06-14 21:04:01 -07:00
Ok ( bank
2021-11-19 07:00:19 -08:00
. get_filtered_program_accounts ( program_id , filter_closure , & ScanConfig ::default ( ) )
2021-06-14 21:04:01 -07:00
. map_err ( | e | RpcCustomError ::ScanError {
message : e . to_string ( ) ,
} ) ? )
2020-12-31 18:06:03 -08:00
}
}
/// Get an iterator of spl-token accounts by owner address
fn get_filtered_spl_token_accounts_by_owner (
& self ,
bank : & Arc < Bank > ,
2022-01-25 20:32:21 -08:00
program_id : & Pubkey ,
2020-12-31 18:06:03 -08:00
owner_key : & Pubkey ,
mut filters : Vec < RpcFilterType > ,
2021-06-14 21:04:01 -07:00
) -> RpcCustomResult < Vec < ( Pubkey , AccountSharedData ) > > {
2021-01-05 18:42:33 -08:00
// The by-owner accounts index checks for Token Account state and Owner address on
2021-02-18 23:42:09 -08:00
// inclusion. However, due to the current AccountsDb implementation, an account may remain
2021-03-09 13:06:07 -08:00
// in storage as a zero-lamport AccountSharedData::Default() after being wiped and reinitialized in
2021-01-05 18:42:33 -08:00
// later updates. We include the redundant filters here to avoid returning these accounts.
2020-12-31 18:06:03 -08:00
//
// Filter on Token Account state
2022-04-20 18:18:12 -07:00
filters . push ( RpcFilterType ::TokenAccountState ) ;
2020-12-31 18:06:03 -08:00
// Filter on Owner address
2022-07-06 21:39:03 -07:00
filters . push ( RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes (
SPL_TOKEN_ACCOUNT_OWNER_OFFSET ,
owner_key . to_bytes ( ) . into ( ) ,
) ) ) ;
2020-12-31 18:06:03 -08:00
if self
. config
. account_indexes
. contains ( & AccountIndex ::SplTokenOwner )
{
2021-05-13 14:04:21 -07:00
if ! self . config . account_indexes . include_key ( owner_key ) {
return Err ( RpcCustomError ::KeyExcludedFromSecondaryIndex {
index_key : owner_key . to_string ( ) ,
2021-06-14 21:04:01 -07:00
} ) ;
2021-05-13 14:04:21 -07:00
}
2021-06-14 21:04:01 -07:00
Ok ( bank
2021-11-17 11:10:29 -08:00
. get_filtered_indexed_accounts (
& IndexKey ::SplTokenOwner ( * owner_key ) ,
| account | {
2022-01-25 20:32:21 -08:00
account . owner ( ) = = program_id
2022-04-20 18:18:12 -07:00
& & filters
. iter ( )
. all ( | filter_type | filter_type . allows ( account ) )
2021-11-17 11:10:29 -08:00
} ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
bank . byte_limit_for_scans ( ) ,
2021-11-17 11:10:29 -08:00
)
2021-06-14 21:04:01 -07:00
. map_err ( | e | RpcCustomError ::ScanError {
message : e . to_string ( ) ,
} ) ? )
2020-12-31 18:06:03 -08:00
} else {
2022-01-25 20:32:21 -08:00
self . get_filtered_program_accounts ( bank , program_id , filters )
2020-12-31 18:06:03 -08:00
}
}
/// Get an iterator of spl-token accounts by mint address
fn get_filtered_spl_token_accounts_by_mint (
& self ,
bank : & Arc < Bank > ,
2022-01-25 20:32:21 -08:00
program_id : & Pubkey ,
2020-12-31 18:06:03 -08:00
mint_key : & Pubkey ,
mut filters : Vec < RpcFilterType > ,
2021-06-14 21:04:01 -07:00
) -> RpcCustomResult < Vec < ( Pubkey , AccountSharedData ) > > {
2020-12-31 18:06:03 -08:00
// The by-mint accounts index checks for Token Account state and Mint address on inclusion.
2021-02-18 23:42:09 -08:00
// However, due to the current AccountsDb implementation, an account may remain in storage
2021-03-09 13:06:07 -08:00
// as be zero-lamport AccountSharedData::Default() after being wiped and reinitialized in later
2021-01-05 18:42:33 -08:00
// updates. We include the redundant filters here to avoid returning these accounts.
2020-12-31 18:06:03 -08:00
//
// Filter on Token Account state
2022-04-20 18:18:12 -07:00
filters . push ( RpcFilterType ::TokenAccountState ) ;
2020-12-31 18:06:03 -08:00
// Filter on Mint address
2022-07-06 21:39:03 -07:00
filters . push ( RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes (
SPL_TOKEN_ACCOUNT_MINT_OFFSET ,
mint_key . to_bytes ( ) . into ( ) ,
) ) ) ;
2020-12-31 18:06:03 -08:00
if self
. config
. account_indexes
. contains ( & AccountIndex ::SplTokenMint )
{
2021-05-13 14:04:21 -07:00
if ! self . config . account_indexes . include_key ( mint_key ) {
return Err ( RpcCustomError ::KeyExcludedFromSecondaryIndex {
index_key : mint_key . to_string ( ) ,
2021-06-14 21:04:01 -07:00
} ) ;
2021-05-13 14:04:21 -07:00
}
2021-06-14 21:04:01 -07:00
Ok ( bank
2021-11-17 11:10:29 -08:00
. get_filtered_indexed_accounts (
& IndexKey ::SplTokenMint ( * mint_key ) ,
| account | {
2022-01-25 20:32:21 -08:00
account . owner ( ) = = program_id
2022-04-20 18:18:12 -07:00
& & filters
. iter ( )
. all ( | filter_type | filter_type . allows ( account ) )
2021-11-17 11:10:29 -08:00
} ,
2021-11-19 07:00:19 -08:00
& ScanConfig ::default ( ) ,
bank . byte_limit_for_scans ( ) ,
2021-11-17 11:10:29 -08:00
)
2021-06-14 21:04:01 -07:00
. map_err ( | e | RpcCustomError ::ScanError {
message : e . to_string ( ) ,
} ) ? )
2020-12-31 18:06:03 -08:00
} else {
2022-01-25 20:32:21 -08:00
self . get_filtered_program_accounts ( bank , program_id , filters )
2020-12-31 18:06:03 -08:00
}
}
2021-08-13 09:08:20 -07:00
2022-05-16 23:46:02 -07:00
fn get_latest_blockhash ( & self , config : RpcContextConfig ) -> Result < RpcResponse < RpcBlockhash > > {
let bank = self . get_bank_with_config ( config ) ? ;
2021-08-13 09:08:20 -07:00
let blockhash = bank . last_blockhash ( ) ;
let last_valid_block_height = bank
. get_blockhash_last_valid_block_height ( & blockhash )
. expect ( " bank blockhash queue should contain blockhash " ) ;
2022-05-16 23:46:02 -07:00
Ok ( new_response (
2021-08-13 09:08:20 -07:00
& bank ,
RpcBlockhash {
blockhash : blockhash . to_string ( ) ,
last_valid_block_height ,
} ,
2022-05-16 23:46:02 -07:00
) )
2021-08-13 09:08:20 -07:00
}
fn is_blockhash_valid (
& self ,
blockhash : & Hash ,
2022-05-16 23:46:02 -07:00
config : RpcContextConfig ,
) -> Result < RpcResponse < bool > > {
let bank = self . get_bank_with_config ( config ) ? ;
2021-08-13 09:08:20 -07:00
let is_valid = bank . is_blockhash_valid ( blockhash ) ;
2022-05-16 23:46:02 -07:00
Ok ( new_response ( & bank , is_valid ) )
2021-08-13 09:08:20 -07:00
}
2022-07-17 11:39:39 -07:00
fn get_stake_minimum_delegation ( & self , config : RpcContextConfig ) -> Result < RpcResponse < u64 > > {
let bank = self . get_bank_with_config ( config ) ? ;
let stake_minimum_delegation =
solana_stake_program ::get_minimum_delegation ( & bank . feature_set ) ;
Ok ( new_response ( & bank , stake_minimum_delegation ) )
}
2022-09-01 16:12:12 -07:00
fn get_recent_prioritization_fees (
& self ,
pubkeys : Vec < Pubkey > ,
) -> Result < Vec < RpcPrioritizationFee > > {
Ok ( self
. prioritization_fee_cache
. get_prioritization_fees ( & pubkeys )
. into_iter ( )
. map ( | ( slot , prioritization_fee ) | RpcPrioritizationFee {
slot ,
prioritization_fee ,
} )
. collect ( ) )
}
2019-02-17 09:29:08 -08:00
}
2018-10-25 16:58:40 -07:00
2022-02-24 13:09:25 -08:00
fn optimize_filters ( filters : & mut [ RpcFilterType ] ) {
2021-10-14 11:43:27 -07:00
filters . iter_mut ( ) . for_each ( | filter_type | {
if let RpcFilterType ::Memcmp ( compare ) = filter_type {
2023-01-26 13:50:15 -08:00
if let Err ( err ) = compare . convert_to_raw_bytes ( ) {
// All filters should have been previously verified
warn! ( " Invalid filter: bytes could not be decoded, {err} " ) ;
2021-10-14 11:43:27 -07:00
}
}
} )
}
2021-07-13 16:10:30 -07:00
fn verify_transaction (
2021-08-17 15:17:56 -07:00
transaction : & SanitizedTransaction ,
2021-08-30 00:58:45 -07:00
feature_set : & Arc < feature_set ::FeatureSet > ,
2021-07-13 16:10:30 -07:00
) -> Result < ( ) > {
2021-10-22 21:25:54 -07:00
#[ allow(clippy::question_mark) ]
2020-10-23 20:47:51 -07:00
if transaction . verify ( ) . is_err ( ) {
return Err ( RpcCustomError ::TransactionSignatureVerificationFailure . into ( ) ) ;
}
2021-08-30 00:58:45 -07:00
if let Err ( e ) = transaction . verify_precompiles ( feature_set ) {
2020-10-23 20:47:51 -07:00
return Err ( RpcCustomError ::TransactionPrecompileVerificationFailure ( e ) . into ( ) ) ;
}
Ok ( ( ) )
}
2020-07-03 00:46:29 -07:00
fn verify_filter ( input : & RpcFilterType ) -> Result < ( ) > {
input
. verify ( )
2022-12-06 06:30:06 -08:00
. map_err ( | e | Error ::invalid_params ( format! ( " Invalid param: {e:?} " ) ) )
2020-07-03 00:46:29 -07:00
}
2022-12-19 18:54:05 -08:00
pub fn verify_pubkey ( input : & str ) -> Result < Pubkey > {
2020-05-21 17:30:02 -07:00
input
. parse ( )
2022-12-06 06:30:06 -08:00
. map_err ( | e | Error ::invalid_params ( format! ( " Invalid param: {e:?} " ) ) )
2019-02-17 09:29:08 -08:00
}
2018-08-14 17:03:48 -07:00
2021-04-21 14:12:23 -07:00
fn verify_hash ( input : & str ) -> Result < Hash > {
2021-04-14 23:25:23 -07:00
input
. parse ( )
2022-12-06 06:30:06 -08:00
. map_err ( | e | Error ::invalid_params ( format! ( " Invalid param: {e:?} " ) ) )
2021-04-14 23:25:23 -07:00
}
2019-02-17 09:29:08 -08:00
fn verify_signature ( input : & str ) -> Result < Signature > {
2020-05-21 17:30:02 -07:00
input
. parse ( )
2022-12-06 06:30:06 -08:00
. map_err ( | e | Error ::invalid_params ( format! ( " Invalid param: {e:?} " ) ) )
2018-08-14 17:03:48 -07:00
}
2020-07-28 22:00:48 -07:00
fn verify_token_account_filter (
token_account_filter : RpcTokenAccountsFilter ,
) -> Result < TokenAccountsFilter > {
match token_account_filter {
RpcTokenAccountsFilter ::Mint ( mint_str ) = > {
2021-04-21 14:12:23 -07:00
let mint = verify_pubkey ( & mint_str ) ? ;
2020-07-28 22:00:48 -07:00
Ok ( TokenAccountsFilter ::Mint ( mint ) )
}
RpcTokenAccountsFilter ::ProgramId ( program_id_str ) = > {
2021-04-21 14:12:23 -07:00
let program_id = verify_pubkey ( & program_id_str ) ? ;
2020-07-28 22:00:48 -07:00
Ok ( TokenAccountsFilter ::ProgramId ( program_id ) )
}
}
}
2021-07-26 11:32:17 -07:00
fn verify_and_parse_signatures_for_address_params (
address : String ,
before : Option < String > ,
until : Option < String > ,
limit : Option < usize > ,
) -> Result < ( Pubkey , Option < Signature > , Option < Signature > , usize ) > {
let address = verify_pubkey ( & address ) ? ;
let before = before
. map ( | ref before | verify_signature ( before ) )
. transpose ( ) ? ;
let until = until . map ( | ref until | verify_signature ( until ) ) . transpose ( ) ? ;
let limit = limit . unwrap_or ( MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT ) ;
if limit = = 0 | | limit > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Invalid limit; max {MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT} "
2021-07-26 11:32:17 -07:00
) ) ) ;
}
Ok ( ( address , before , until , limit ) )
}
2021-12-17 15:03:09 -08:00
pub ( crate ) fn check_is_at_least_confirmed ( commitment : CommitmentConfig ) -> Result < ( ) > {
2021-03-26 15:47:35 -07:00
if ! commitment . is_at_least_confirmed ( ) {
return Err ( Error ::invalid_params (
" Method does not support commitment below `confirmed` " ,
) ) ;
}
Ok ( ( ) )
}
2020-09-03 10:35:06 -07:00
fn get_encoded_account (
bank : & Arc < Bank > ,
pubkey : & Pubkey ,
encoding : UiAccountEncoding ,
data_slice : Option < UiDataSliceConfig > ,
) -> Result < Option < UiAccount > > {
2021-07-22 20:56:27 -07:00
match bank . get_account ( pubkey ) {
Some ( account ) = > {
2022-01-25 20:32:21 -08:00
let response = if is_known_spl_token_id ( account . owner ( ) )
2021-07-22 20:56:27 -07:00
& & encoding = = UiAccountEncoding ::JsonParsed
{
get_parsed_token_account ( bank . clone ( ) , pubkey , account )
} else {
encode_account ( & account , pubkey , encoding , data_slice ) ?
} ;
Ok ( Some ( response ) )
2020-09-03 10:35:06 -07:00
}
2021-07-22 20:56:27 -07:00
None = > Ok ( None ) ,
}
}
fn encode_account < T : ReadableAccount > (
account : & T ,
pubkey : & Pubkey ,
encoding : UiAccountEncoding ,
data_slice : Option < UiDataSliceConfig > ,
) -> Result < UiAccount > {
if ( encoding = = UiAccountEncoding ::Binary | | encoding = = UiAccountEncoding ::Base58 )
2021-08-20 13:30:59 -07:00
& & account . data ( ) . len ( ) > MAX_BASE58_BYTES
2021-07-22 20:56:27 -07:00
{
2022-12-06 06:30:06 -08:00
let message = format! ( " Encoded binary (base 58) data should be less than {MAX_BASE58_BYTES} bytes, please use Base64 encoding. " ) ;
2021-07-22 20:56:27 -07:00
Err ( error ::Error {
code : error ::ErrorCode ::InvalidRequest ,
message ,
data : None ,
} )
} else {
Ok ( UiAccount ::encode (
pubkey , account , encoding , None , data_slice ,
) )
2020-09-03 10:35:06 -07:00
}
}
2021-10-26 14:44:24 -07:00
/// Analyze custom filters to determine if the result will be a subset of spl-token accounts by
/// owner.
/// NOTE: `optimize_filters()` should almost always be called before using this method because of
/// the strict match on `MemcmpEncodedBytes::Bytes`.
2020-12-31 18:06:03 -08:00
fn get_spl_token_owner_filter ( program_id : & Pubkey , filters : & [ RpcFilterType ] ) -> Option < Pubkey > {
2022-01-25 20:32:21 -08:00
if ! is_known_spl_token_id ( program_id ) {
2020-12-31 18:06:03 -08:00
return None ;
}
let mut data_size_filter : Option < u64 > = None ;
2022-05-17 12:02:43 -07:00
let mut memcmp_filter : Option < & [ u8 ] > = None ;
2020-12-31 18:06:03 -08:00
let mut owner_key : Option < Pubkey > = None ;
2021-10-26 14:44:24 -07:00
let mut incorrect_owner_len : Option < usize > = None ;
2022-05-17 12:02:43 -07:00
let mut token_account_state_filter = false ;
let account_packed_len = TokenAccount ::get_packed_len ( ) ;
2020-12-31 18:06:03 -08:00
for filter in filters {
match filter {
RpcFilterType ::DataSize ( size ) = > data_size_filter = Some ( * size ) ,
2023-01-26 13:50:15 -08:00
#[ allow(deprecated) ]
2020-12-31 18:06:03 -08:00
RpcFilterType ::Memcmp ( Memcmp {
2022-05-17 12:02:43 -07:00
offset ,
bytes : MemcmpEncodedBytes ::Bytes ( bytes ) ,
..
} ) if * offset = = account_packed_len & & * program_id = = inline_spl_token_2022 ::id ( ) = > {
memcmp_filter = Some ( bytes )
}
2023-01-26 13:50:15 -08:00
#[ allow(deprecated) ]
2022-05-17 12:02:43 -07:00
RpcFilterType ::Memcmp ( Memcmp {
offset ,
2021-10-26 14:44:24 -07:00
bytes : MemcmpEncodedBytes ::Bytes ( bytes ) ,
2020-12-31 18:06:03 -08:00
..
2022-05-17 12:02:43 -07:00
} ) if * offset = = SPL_TOKEN_ACCOUNT_OWNER_OFFSET = > {
2021-10-26 14:44:24 -07:00
if bytes . len ( ) = = PUBKEY_BYTES {
2023-01-21 10:06:27 -08:00
owner_key = Pubkey ::try_from ( & bytes [ .. ] ) . ok ( ) ;
2021-10-26 14:44:24 -07:00
} else {
incorrect_owner_len = Some ( bytes . len ( ) ) ;
2020-12-31 18:06:03 -08:00
}
}
2022-05-17 12:02:43 -07:00
RpcFilterType ::TokenAccountState = > token_account_state_filter = true ,
2020-12-31 18:06:03 -08:00
_ = > { }
}
}
2022-05-17 12:02:43 -07:00
if data_size_filter = = Some ( account_packed_len as u64 )
| | memcmp_filter = = Some ( & [ ACCOUNTTYPE_ACCOUNT ] )
| | token_account_state_filter
{
2021-10-26 14:44:24 -07:00
if let Some ( incorrect_owner_len ) = incorrect_owner_len {
info! (
" Incorrect num bytes ({:?}) provided for spl_token_owner_filter " ,
incorrect_owner_len
) ;
}
2020-12-31 18:06:03 -08:00
owner_key
} else {
2021-10-26 14:44:24 -07:00
debug! ( " spl_token program filters do not match by-owner index requisites " ) ;
2020-12-31 18:06:03 -08:00
None
}
2020-07-28 22:00:48 -07:00
}
2021-10-26 14:44:24 -07:00
/// Analyze custom filters to determine if the result will be a subset of spl-token accounts by
/// mint.
/// NOTE: `optimize_filters()` should almost always be called before using this method because of
/// the strict match on `MemcmpEncodedBytes::Bytes`.
2021-02-09 14:49:13 -08:00
fn get_spl_token_mint_filter ( program_id : & Pubkey , filters : & [ RpcFilterType ] ) -> Option < Pubkey > {
2022-01-25 20:32:21 -08:00
if ! is_known_spl_token_id ( program_id ) {
2021-02-09 14:49:13 -08:00
return None ;
}
let mut data_size_filter : Option < u64 > = None ;
2022-05-17 12:02:43 -07:00
let mut memcmp_filter : Option < & [ u8 ] > = None ;
2021-02-09 14:49:13 -08:00
let mut mint : Option < Pubkey > = None ;
2021-10-26 14:44:24 -07:00
let mut incorrect_mint_len : Option < usize > = None ;
2022-05-17 12:02:43 -07:00
let mut token_account_state_filter = false ;
let account_packed_len = TokenAccount ::get_packed_len ( ) ;
2021-02-09 14:49:13 -08:00
for filter in filters {
match filter {
RpcFilterType ::DataSize ( size ) = > data_size_filter = Some ( * size ) ,
2023-01-26 13:50:15 -08:00
#[ allow(deprecated) ]
2021-02-09 14:49:13 -08:00
RpcFilterType ::Memcmp ( Memcmp {
2022-05-17 12:02:43 -07:00
offset ,
2021-10-26 14:44:24 -07:00
bytes : MemcmpEncodedBytes ::Bytes ( bytes ) ,
2021-02-09 14:49:13 -08:00
..
2022-05-17 12:02:43 -07:00
} ) if * offset = = account_packed_len & & * program_id = = inline_spl_token_2022 ::id ( ) = > {
memcmp_filter = Some ( bytes )
}
2023-01-26 13:50:15 -08:00
#[ allow(deprecated) ]
2022-05-17 12:02:43 -07:00
RpcFilterType ::Memcmp ( Memcmp {
offset ,
bytes : MemcmpEncodedBytes ::Bytes ( bytes ) ,
..
} ) if * offset = = SPL_TOKEN_ACCOUNT_MINT_OFFSET = > {
2021-10-26 14:44:24 -07:00
if bytes . len ( ) = = PUBKEY_BYTES {
2023-01-21 10:06:27 -08:00
mint = Pubkey ::try_from ( & bytes [ .. ] ) . ok ( ) ;
2021-10-26 14:44:24 -07:00
} else {
incorrect_mint_len = Some ( bytes . len ( ) ) ;
2021-02-09 14:49:13 -08:00
}
}
2022-05-17 12:02:43 -07:00
RpcFilterType ::TokenAccountState = > token_account_state_filter = true ,
2021-02-09 14:49:13 -08:00
_ = > { }
}
}
2022-05-17 12:02:43 -07:00
if data_size_filter = = Some ( account_packed_len as u64 )
| | memcmp_filter = = Some ( & [ ACCOUNTTYPE_ACCOUNT ] )
| | token_account_state_filter
{
2021-10-26 14:44:24 -07:00
if let Some ( incorrect_mint_len ) = incorrect_mint_len {
info! (
" Incorrect num bytes ({:?}) provided for spl_token_mint_filter " ,
incorrect_mint_len
) ;
}
2021-02-09 14:49:13 -08:00
mint
} else {
2021-10-26 14:44:24 -07:00
debug! ( " spl_token program filters do not match by-mint index requisites " ) ;
2021-02-09 14:49:13 -08:00
None
}
}
2020-07-28 22:00:48 -07:00
/// Analyze a passed Pubkey that may be a Token program id or Mint address to determine the program
/// id and optional Mint
fn get_token_program_id_and_mint (
bank : & Arc < Bank > ,
token_account_filter : TokenAccountsFilter ,
) -> Result < ( Pubkey , Option < Pubkey > ) > {
match token_account_filter {
TokenAccountsFilter ::Mint ( mint ) = > {
2021-06-18 06:34:46 -07:00
let ( mint_owner , _ ) = get_mint_owner_and_decimals ( bank , & mint ) ? ;
2022-01-25 20:32:21 -08:00
if ! is_known_spl_token_id ( & mint_owner ) {
2020-07-28 22:00:48 -07:00
return Err ( Error ::invalid_params (
2021-11-21 05:27:03 -08:00
" Invalid param: not a Token mint " . to_string ( ) ,
2020-07-28 22:00:48 -07:00
) ) ;
}
2020-08-04 23:48:09 -07:00
Ok ( ( mint_owner , Some ( mint ) ) )
2020-07-28 22:00:48 -07:00
}
TokenAccountsFilter ::ProgramId ( program_id ) = > {
2022-01-25 20:32:21 -08:00
if is_known_spl_token_id ( & program_id ) {
2020-07-28 22:00:48 -07:00
Ok ( ( program_id , None ) )
} else {
Err ( Error ::invalid_params (
" Invalid param: unrecognized Token program id " . to_string ( ) ,
) )
}
}
}
}
2020-07-29 19:05:41 -07:00
fn _send_transaction (
meta : JsonRpcRequestProcessor ,
2021-08-17 15:17:56 -07:00
signature : Signature ,
2020-07-29 19:05:41 -07:00
wire_transaction : Vec < u8 > ,
2021-08-11 00:04:00 -07:00
last_valid_block_height : u64 ,
2020-12-29 08:48:43 -08:00
durable_nonce_info : Option < ( Pubkey , Hash ) > ,
2021-08-24 21:44:13 -07:00
max_retries : Option < usize > ,
2020-07-29 19:05:41 -07:00
) -> Result < String > {
2020-12-29 08:48:43 -08:00
let transaction_info = TransactionInfo ::new (
signature ,
wire_transaction ,
2021-08-11 00:04:00 -07:00
last_valid_block_height ,
2020-12-29 08:48:43 -08:00
durable_nonce_info ,
2021-08-24 21:44:13 -07:00
max_retries ,
2022-04-21 12:43:08 -07:00
None ,
2020-12-29 08:48:43 -08:00
) ;
2020-07-29 19:05:41 -07:00
meta . transaction_sender
. lock ( )
. unwrap ( )
. send ( transaction_info )
. unwrap_or_else ( | err | warn! ( " Failed to enqueue transaction: {} " , err ) ) ;
Ok ( signature . to_string ( ) )
}
2021-11-12 10:57:55 -08:00
// Minimal RPC interface that known validators are expected to provide
2021-02-26 21:42:09 -08:00
pub mod rpc_minimal {
use super ::* ;
#[ rpc ]
pub trait Minimal {
type Metadata ;
#[ rpc(meta, name = " getBalance " ) ]
fn get_balance (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < RpcResponse < u64 > > ;
#[ rpc(meta, name = " getEpochInfo " ) ]
fn get_epoch_info (
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < EpochInfo > ;
2022-02-14 20:29:26 -08:00
#[ rpc(meta, name = " getGenesisHash " ) ]
fn get_genesis_hash ( & self , meta : Self ::Metadata ) -> Result < String > ;
2021-02-26 21:42:09 -08:00
#[ rpc(meta, name = " getHealth " ) ]
fn get_health ( & self , meta : Self ::Metadata ) -> Result < String > ;
#[ rpc(meta, name = " getIdentity " ) ]
fn get_identity ( & self , meta : Self ::Metadata ) -> Result < RpcIdentity > ;
#[ rpc(meta, name = " getSlot " ) ]
2022-05-16 23:46:02 -07:00
fn get_slot ( & self , meta : Self ::Metadata , config : Option < RpcContextConfig > ) -> Result < Slot > ;
2021-02-26 21:42:09 -08:00
2021-05-26 00:26:19 -07:00
#[ rpc(meta, name = " getBlockHeight " ) ]
fn get_block_height (
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-05-26 00:26:19 -07:00
) -> Result < u64 > ;
2021-09-02 13:25:42 -07:00
#[ rpc(meta, name = " getHighestSnapshotSlot " ) ]
fn get_highest_snapshot_slot ( & self , meta : Self ::Metadata ) -> Result < RpcSnapshotSlotInfo > ;
2021-02-26 21:42:09 -08:00
#[ rpc(meta, name = " getTransactionCount " ) ]
fn get_transaction_count (
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < u64 > ;
#[ rpc(meta, name = " getVersion " ) ]
fn get_version ( & self , meta : Self ::Metadata ) -> Result < RpcVersionInfo > ;
// TODO: Refactor `solana-validator wait-for-restart-window` to not require this method, so
// it can be removed from rpc_minimal
#[ rpc(meta, name = " getVoteAccounts " ) ]
fn get_vote_accounts (
& self ,
meta : Self ::Metadata ,
2021-04-26 18:27:35 -07:00
config : Option < RpcGetVoteAccountsConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < RpcVoteAccountStatus > ;
// TODO: Refactor `solana-validator wait-for-restart-window` to not require this method, so
// it can be removed from rpc_minimal
#[ rpc(meta, name = " getLeaderSchedule " ) ]
fn get_leader_schedule (
& self ,
meta : Self ::Metadata ,
2021-04-22 12:27:30 -07:00
options : Option < RpcLeaderScheduleConfigWrapper > ,
2021-04-21 14:13:41 -07:00
config : Option < RpcLeaderScheduleConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < Option < RpcLeaderSchedule > > ;
}
pub struct MinimalImpl ;
impl Minimal for MinimalImpl {
type Metadata = JsonRpcRequestProcessor ;
fn get_balance (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < RpcResponse < u64 > > {
debug! ( " get_balance rpc request received: {:?} " , pubkey_str ) ;
2021-04-21 14:12:23 -07:00
let pubkey = verify_pubkey ( & pubkey_str ) ? ;
2022-05-16 23:46:02 -07:00
meta . get_balance ( & pubkey , config . unwrap_or_default ( ) )
2021-02-26 21:42:09 -08:00
}
2018-09-26 17:12:40 -07:00
2021-02-26 21:42:09 -08:00
fn get_epoch_info (
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < EpochInfo > {
debug! ( " get_epoch_info rpc request received " ) ;
2022-05-16 23:46:02 -07:00
let bank = meta . get_bank_with_config ( config . unwrap_or_default ( ) ) ? ;
2021-02-26 21:42:09 -08:00
Ok ( bank . get_epoch_info ( ) )
}
2019-02-26 12:25:46 -08:00
2022-02-14 20:29:26 -08:00
fn get_genesis_hash ( & self , meta : Self ::Metadata ) -> Result < String > {
debug! ( " get_genesis_hash rpc request received " ) ;
Ok ( meta . genesis_hash . to_string ( ) )
}
2021-02-26 21:42:09 -08:00
fn get_health ( & self , meta : Self ::Metadata ) -> Result < String > {
match meta . health . check ( ) {
RpcHealthStatus ::Ok = > Ok ( " ok " . to_string ( ) ) ,
2021-03-04 21:18:08 -08:00
RpcHealthStatus ::Unknown = > Err ( RpcCustomError ::NodeUnhealthy {
num_slots_behind : None ,
}
. into ( ) ) ,
2021-02-26 21:42:09 -08:00
RpcHealthStatus ::Behind { num_slots } = > Err ( RpcCustomError ::NodeUnhealthy {
num_slots_behind : Some ( num_slots ) ,
}
. into ( ) ) ,
}
}
2020-12-07 09:22:35 -08:00
2021-02-26 21:42:09 -08:00
fn get_identity ( & self , meta : Self ::Metadata ) -> Result < RpcIdentity > {
debug! ( " get_identity rpc request received " ) ;
Ok ( RpcIdentity {
2021-06-22 12:50:35 -07:00
identity : meta . cluster_info . id ( ) . to_string ( ) ,
2021-02-26 21:42:09 -08:00
} )
2020-09-03 10:35:06 -07:00
}
2021-02-26 21:42:09 -08:00
2022-05-16 23:46:02 -07:00
fn get_slot ( & self , meta : Self ::Metadata , config : Option < RpcContextConfig > ) -> Result < Slot > {
2021-02-26 21:42:09 -08:00
debug! ( " get_slot rpc request received " ) ;
2022-05-16 23:46:02 -07:00
meta . get_slot ( config . unwrap_or_default ( ) )
2020-09-03 10:35:06 -07:00
}
2021-05-26 00:26:19 -07:00
fn get_block_height (
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-05-26 00:26:19 -07:00
) -> Result < u64 > {
debug! ( " get_block_height rpc request received " ) ;
2022-05-16 23:46:02 -07:00
meta . get_block_height ( config . unwrap_or_default ( ) )
2021-05-26 00:26:19 -07:00
}
2021-09-02 13:25:42 -07:00
fn get_highest_snapshot_slot ( & self , meta : Self ::Metadata ) -> Result < RpcSnapshotSlotInfo > {
debug! ( " get_highest_snapshot_slot rpc request received " ) ;
2021-02-26 21:42:09 -08:00
2021-09-02 13:25:42 -07:00
if meta . snapshot_config . is_none ( ) {
return Err ( RpcCustomError ::NoSnapshot . into ( ) ) ;
}
2022-05-10 13:37:41 -07:00
let ( full_snapshot_archives_dir , incremental_snapshot_archives_dir ) = meta
2021-09-02 13:25:42 -07:00
. snapshot_config
2022-05-10 13:37:41 -07:00
. map ( | snapshot_config | {
(
snapshot_config . full_snapshot_archives_dir ,
snapshot_config . incremental_snapshot_archives_dir ,
)
} )
2021-09-02 13:25:42 -07:00
. unwrap ( ) ;
let full_snapshot_slot =
2022-11-09 11:39:38 -08:00
snapshot_utils ::get_highest_full_snapshot_archive_slot ( full_snapshot_archives_dir )
2021-09-02 13:25:42 -07:00
. ok_or ( RpcCustomError ::NoSnapshot ) ? ;
let incremental_snapshot_slot =
snapshot_utils ::get_highest_incremental_snapshot_archive_slot (
2022-11-09 11:39:38 -08:00
incremental_snapshot_archives_dir ,
2021-09-02 13:25:42 -07:00
full_snapshot_slot ,
) ;
Ok ( RpcSnapshotSlotInfo {
full : full_snapshot_slot ,
incremental : incremental_snapshot_slot ,
} )
2020-09-08 09:23:16 -07:00
}
2019-09-26 10:57:13 -07:00
2021-02-26 21:42:09 -08:00
fn get_transaction_count (
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < u64 > {
debug! ( " get_transaction_count rpc request received " ) ;
2022-05-16 23:46:02 -07:00
meta . get_transaction_count ( config . unwrap_or_default ( ) )
2021-02-22 22:54:35 -08:00
}
2021-02-26 21:42:09 -08:00
fn get_version ( & self , _ : Self ::Metadata ) -> Result < RpcVersionInfo > {
debug! ( " get_version rpc request received " ) ;
let version = solana_version ::Version ::default ( ) ;
Ok ( RpcVersionInfo {
solana_core : version . to_string ( ) ,
feature_set : Some ( version . feature_set ) ,
} )
2020-07-03 00:46:29 -07:00
}
2019-06-29 09:59:07 -07:00
2021-02-26 21:42:09 -08:00
// TODO: Refactor `solana-validator wait-for-restart-window` to not require this method, so
// it can be removed from rpc_minimal
fn get_vote_accounts (
& self ,
meta : Self ::Metadata ,
2021-04-26 18:27:35 -07:00
config : Option < RpcGetVoteAccountsConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < RpcVoteAccountStatus > {
debug! ( " get_vote_accounts rpc request received " ) ;
2021-04-26 18:27:35 -07:00
meta . get_vote_accounts ( config )
2021-02-26 21:42:09 -08:00
}
2020-05-29 11:50:25 -07:00
2021-02-26 21:42:09 -08:00
// TODO: Refactor `solana-validator wait-for-restart-window` to not require this method, so
// it can be removed from rpc_minimal
fn get_leader_schedule (
& self ,
meta : Self ::Metadata ,
2021-04-22 12:27:30 -07:00
options : Option < RpcLeaderScheduleConfigWrapper > ,
2021-04-21 14:13:41 -07:00
config : Option < RpcLeaderScheduleConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < Option < RpcLeaderSchedule > > {
2021-04-22 12:27:30 -07:00
let ( slot , maybe_config ) = options . map ( | options | options . unzip ( ) ) . unwrap_or_default ( ) ;
let config = maybe_config . or ( config ) . unwrap_or_default ( ) ;
2021-04-21 14:13:41 -07:00
if let Some ( ref identity ) = config . identity {
let _ = verify_pubkey ( identity ) ? ;
}
let bank = meta . bank ( config . commitment ) ;
2021-02-26 21:42:09 -08:00
let slot = slot . unwrap_or_else ( | | bank . slot ( ) ) ;
let epoch = bank . epoch_schedule ( ) . get_epoch ( slot ) ;
debug! ( " get_leader_schedule rpc request received: {:?} " , slot ) ;
2021-03-23 10:48:54 -07:00
Ok ( meta
. leader_schedule_cache
. get_epoch_leader_schedule ( epoch )
. map ( | leader_schedule | {
2021-04-21 14:13:41 -07:00
let mut schedule_by_identity =
solana_ledger ::leader_schedule_utils ::leader_schedule_by_identity (
leader_schedule . get_slot_leaders ( ) . iter ( ) . enumerate ( ) ,
) ;
if let Some ( identity ) = config . identity {
schedule_by_identity . retain ( | k , _ | * k = = identity ) ;
}
schedule_by_identity
2021-03-23 10:48:54 -07:00
} ) )
2021-02-26 21:42:09 -08:00
}
2019-10-22 13:41:18 -07:00
}
2021-02-26 21:42:09 -08:00
}
2019-10-22 13:41:18 -07:00
2021-07-21 13:40:33 -07:00
// RPC interface that only depends on immediate Bank data
2022-04-06 15:52:19 -07:00
// Expected to be provided by API nodes
2021-07-21 13:40:33 -07:00
pub mod rpc_bank {
2021-02-26 21:42:09 -08:00
use super ::* ;
#[ rpc ]
2021-07-21 13:40:33 -07:00
pub trait BankData {
2021-02-26 21:42:09 -08:00
type Metadata ;
2021-07-21 13:40:33 -07:00
#[ rpc(meta, name = " getMinimumBalanceForRentExemption " ) ]
fn get_minimum_balance_for_rent_exemption (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
2021-07-21 13:40:33 -07:00
data_len : usize ,
commitment : Option < CommitmentConfig > ,
) -> Result < u64 > ;
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
#[ rpc(meta, name = " getInflationGovernor " ) ]
fn get_inflation_governor (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
2021-07-21 13:40:33 -07:00
commitment : Option < CommitmentConfig > ,
) -> Result < RpcInflationGovernor > ;
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
#[ rpc(meta, name = " getInflationRate " ) ]
fn get_inflation_rate ( & self , meta : Self ::Metadata ) -> Result < RpcInflationRate > ;
#[ rpc(meta, name = " getEpochSchedule " ) ]
fn get_epoch_schedule ( & self , meta : Self ::Metadata ) -> Result < EpochSchedule > ;
#[ rpc(meta, name = " getSlotLeader " ) ]
fn get_slot_leader (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-07-21 13:40:33 -07:00
) -> Result < String > ;
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
#[ rpc(meta, name = " getSlotLeaders " ) ]
fn get_slot_leaders (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
limit : u64 ,
) -> Result < Vec < String > > ;
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
#[ rpc(meta, name = " getBlockProduction " ) ]
fn get_block_production (
& self ,
meta : Self ::Metadata ,
config : Option < RpcBlockProductionConfig > ,
) -> Result < RpcResponse < RpcBlockProduction > > ;
}
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
pub struct BankDataImpl ;
impl BankData for BankDataImpl {
type Metadata = JsonRpcRequestProcessor ;
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
fn get_minimum_balance_for_rent_exemption (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
2021-07-21 13:40:33 -07:00
data_len : usize ,
commitment : Option < CommitmentConfig > ,
) -> Result < u64 > {
debug! (
" get_minimum_balance_for_rent_exemption rpc request received: {:?} " ,
data_len
) ;
if data_len as u64 > system_instruction ::MAX_PERMITTED_DATA_LENGTH {
return Err ( Error ::invalid_request ( ) ) ;
}
Ok ( meta . get_minimum_balance_for_rent_exemption ( data_len , commitment ) )
}
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
fn get_inflation_governor (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
2021-07-21 13:40:33 -07:00
commitment : Option < CommitmentConfig > ,
) -> Result < RpcInflationGovernor > {
debug! ( " get_inflation_governor rpc request received " ) ;
Ok ( meta . get_inflation_governor ( commitment ) )
}
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
fn get_inflation_rate ( & self , meta : Self ::Metadata ) -> Result < RpcInflationRate > {
debug! ( " get_inflation_rate rpc request received " ) ;
Ok ( meta . get_inflation_rate ( ) )
}
fn get_epoch_schedule ( & self , meta : Self ::Metadata ) -> Result < EpochSchedule > {
debug! ( " get_epoch_schedule rpc request received " ) ;
Ok ( meta . get_epoch_schedule ( ) )
}
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
fn get_slot_leader (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-07-21 13:40:33 -07:00
) -> Result < String > {
debug! ( " get_slot_leader rpc request received " ) ;
2022-05-16 23:46:02 -07:00
meta . get_slot_leader ( config . unwrap_or_default ( ) )
2021-07-21 13:40:33 -07:00
}
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
fn get_slot_leaders (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
limit : u64 ,
) -> Result < Vec < String > > {
debug! (
" get_slot_leaders rpc request received (start: {} limit: {}) " ,
start_slot , limit
) ;
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
let limit = limit as usize ;
if limit > MAX_GET_SLOT_LEADERS {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Invalid limit; max {MAX_GET_SLOT_LEADERS} "
2021-07-21 13:40:33 -07:00
) ) ) ;
}
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
Ok ( meta
. get_slot_leaders ( None , start_slot , limit ) ?
. into_iter ( )
. map ( | identity | identity . to_string ( ) )
. collect ( ) )
}
fn get_block_production (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
2021-07-21 13:40:33 -07:00
config : Option < RpcBlockProductionConfig > ,
) -> Result < RpcResponse < RpcBlockProduction > > {
debug! ( " get_block_production rpc request received " ) ;
let config = config . unwrap_or_default ( ) ;
let filter_by_identity = if let Some ( ref identity ) = config . identity {
Some ( verify_pubkey ( identity ) ? )
} else {
None
} ;
let bank = meta . bank ( config . commitment ) ;
let ( first_slot , last_slot ) = match config . range {
None = > (
bank . epoch_schedule ( ) . get_first_slot_in_epoch ( bank . epoch ( ) ) ,
bank . slot ( ) ,
) ,
Some ( range ) = > {
let first_slot = range . first_slot ;
let last_slot = range . last_slot . unwrap_or_else ( | | bank . slot ( ) ) ;
if last_slot < first_slot {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" lastSlot, {last_slot}, cannot be less than firstSlot, {first_slot} "
2021-07-21 13:40:33 -07:00
) ) ) ;
}
( first_slot , last_slot )
}
} ;
let slot_history = bank . get_slot_history ( ) ;
if first_slot < slot_history . oldest ( ) {
return Err ( Error ::invalid_params ( format! (
" firstSlot, {}, is too small; min {} " ,
first_slot ,
slot_history . oldest ( )
) ) ) ;
}
if last_slot > slot_history . newest ( ) {
return Err ( Error ::invalid_params ( format! (
" lastSlot, {}, is too large; max {} " ,
last_slot ,
slot_history . newest ( )
) ) ) ;
}
let slot_leaders = meta . get_slot_leaders (
config . commitment ,
first_slot ,
last_slot . saturating_sub ( first_slot ) as usize + 1 , // +1 because last_slot is inclusive
) ? ;
let mut block_production : HashMap < _ , ( usize , usize ) > = HashMap ::new ( ) ;
let mut slot = first_slot ;
for identity in slot_leaders {
if let Some ( ref filter_by_identity ) = filter_by_identity {
if identity ! = * filter_by_identity {
slot + = 1 ;
continue ;
}
}
let mut entry = block_production . entry ( identity ) . or_default ( ) ;
if slot_history . check ( slot ) = = solana_sdk ::slot_history ::Check ::Found {
entry . 1 + = 1 ; // Increment blocks_produced
}
entry . 0 + = 1 ; // Increment leader_slots
slot + = 1 ;
}
Ok ( new_response (
& bank ,
RpcBlockProduction {
by_identity : block_production
. into_iter ( )
. map ( | ( k , v ) | ( k . to_string ( ) , v ) )
. collect ( ) ,
range : RpcBlockProductionRange {
first_slot ,
last_slot ,
} ,
} ,
) )
}
}
}
// RPC interface that depends on AccountsDB
2022-11-29 09:08:19 -08:00
// Expected to be provided by API nodes
2021-07-21 13:40:33 -07:00
pub mod rpc_accounts {
use super ::* ;
#[ rpc ]
pub trait AccountsData {
type Metadata ;
#[ rpc(meta, name = " getAccountInfo " ) ]
fn get_account_info (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Option < UiAccount > > > ;
#[ rpc(meta, name = " getMultipleAccounts " ) ]
fn get_multiple_accounts (
& self ,
meta : Self ::Metadata ,
pubkey_strs : Vec < String > ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Vec < Option < UiAccount > > > > ;
#[ rpc(meta, name = " getBlockCommitment " ) ]
fn get_block_commitment (
& self ,
meta : Self ::Metadata ,
block : Slot ,
) -> Result < RpcBlockCommitment < BlockCommitmentArray > > ;
#[ rpc(meta, name = " getStakeActivation " ) ]
fn get_stake_activation (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
config : Option < RpcEpochConfig > ,
) -> Result < RpcStakeActivation > ;
// SPL Token-specific RPC endpoints
// See https://github.com/solana-labs/solana-program-library/releases/tag/token-v2.0.0 for
// program details
#[ rpc(meta, name = " getTokenAccountBalance " ) ]
fn get_token_account_balance (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < UiTokenAmount > > ;
#[ rpc(meta, name = " getTokenSupply " ) ]
fn get_token_supply (
& self ,
meta : Self ::Metadata ,
mint_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < UiTokenAmount > > ;
}
pub struct AccountsDataImpl ;
impl AccountsData for AccountsDataImpl {
type Metadata = JsonRpcRequestProcessor ;
fn get_account_info (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Option < UiAccount > > > {
debug! ( " get_account_info rpc request received: {:?} " , pubkey_str ) ;
let pubkey = verify_pubkey ( & pubkey_str ) ? ;
meta . get_account_info ( & pubkey , config )
}
fn get_multiple_accounts (
& self ,
meta : Self ::Metadata ,
pubkey_strs : Vec < String > ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Vec < Option < UiAccount > > > > {
debug! (
" get_multiple_accounts rpc request received: {:?} " ,
pubkey_strs . len ( )
) ;
let max_multiple_accounts = meta
. config
. max_multiple_accounts
. unwrap_or ( MAX_MULTIPLE_ACCOUNTS ) ;
if pubkey_strs . len ( ) > max_multiple_accounts {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Too many inputs provided; max {max_multiple_accounts} "
2021-07-21 13:40:33 -07:00
) ) ) ;
}
2021-09-16 12:40:01 -07:00
let pubkeys = pubkey_strs
. into_iter ( )
. map ( | pubkey_str | verify_pubkey ( & pubkey_str ) )
. collect ::< Result < Vec < _ > > > ( ) ? ;
2021-07-21 13:40:33 -07:00
meta . get_multiple_accounts ( pubkeys , config )
}
2022-11-29 09:08:19 -08:00
fn get_block_commitment (
& self ,
meta : Self ::Metadata ,
block : Slot ,
) -> Result < RpcBlockCommitment < BlockCommitmentArray > > {
debug! ( " get_block_commitment rpc request received " ) ;
Ok ( meta . get_block_commitment ( block ) )
}
fn get_stake_activation (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
config : Option < RpcEpochConfig > ,
) -> Result < RpcStakeActivation > {
debug! (
" get_stake_activation rpc request received: {:?} " ,
pubkey_str
) ;
let pubkey = verify_pubkey ( & pubkey_str ) ? ;
meta . get_stake_activation ( & pubkey , config )
}
fn get_token_account_balance (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < UiTokenAmount > > {
debug! (
" get_token_account_balance rpc request received: {:?} " ,
pubkey_str
) ;
let pubkey = verify_pubkey ( & pubkey_str ) ? ;
meta . get_token_account_balance ( & pubkey , commitment )
}
fn get_token_supply (
& self ,
meta : Self ::Metadata ,
mint_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < UiTokenAmount > > {
debug! ( " get_token_supply rpc request received: {:?} " , mint_str ) ;
let mint = verify_pubkey ( & mint_str ) ? ;
meta . get_token_supply ( & mint , commitment )
}
}
}
// RPC interface that depends on AccountsDB and requires accounts scan
// Expected to be provided by API nodes for now, but collected for easy separation and removal in
// the future.
pub mod rpc_accounts_scan {
use super ::* ;
#[ rpc ]
pub trait AccountsScan {
type Metadata ;
#[ rpc(meta, name = " getProgramAccounts " ) ]
fn get_program_accounts (
& self ,
meta : Self ::Metadata ,
program_id_str : String ,
config : Option < RpcProgramAccountsConfig > ,
) -> Result < OptionalContext < Vec < RpcKeyedAccount > > > ;
#[ rpc(meta, name = " getLargestAccounts " ) ]
fn get_largest_accounts (
& self ,
meta : Self ::Metadata ,
config : Option < RpcLargestAccountsConfig > ,
) -> Result < RpcResponse < Vec < RpcAccountBalance > > > ;
#[ rpc(meta, name = " getSupply " ) ]
fn get_supply (
& self ,
meta : Self ::Metadata ,
config : Option < RpcSupplyConfig > ,
) -> Result < RpcResponse < RpcSupply > > ;
// SPL Token-specific RPC endpoints
// See https://github.com/solana-labs/solana-program-library/releases/tag/token-v2.0.0 for
// program details
#[ rpc(meta, name = " getTokenLargestAccounts " ) ]
fn get_token_largest_accounts (
& self ,
meta : Self ::Metadata ,
mint_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < Vec < RpcTokenAccountBalance > > > ;
#[ rpc(meta, name = " getTokenAccountsByOwner " ) ]
fn get_token_accounts_by_owner (
& self ,
meta : Self ::Metadata ,
owner_str : String ,
token_account_filter : RpcTokenAccountsFilter ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Vec < RpcKeyedAccount > > > ;
#[ rpc(meta, name = " getTokenAccountsByDelegate " ) ]
fn get_token_accounts_by_delegate (
& self ,
meta : Self ::Metadata ,
delegate_str : String ,
token_account_filter : RpcTokenAccountsFilter ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Vec < RpcKeyedAccount > > > ;
}
pub struct AccountsScanImpl ;
impl AccountsScan for AccountsScanImpl {
type Metadata = JsonRpcRequestProcessor ;
2021-07-21 13:40:33 -07:00
fn get_program_accounts (
& self ,
meta : Self ::Metadata ,
program_id_str : String ,
config : Option < RpcProgramAccountsConfig > ,
) -> Result < OptionalContext < Vec < RpcKeyedAccount > > > {
debug! (
" get_program_accounts rpc request received: {:?} " ,
program_id_str
) ;
let program_id = verify_pubkey ( & program_id_str ) ? ;
let ( config , filters , with_context ) = if let Some ( config ) = config {
(
Some ( config . account_config ) ,
config . filters . unwrap_or_default ( ) ,
config . with_context . unwrap_or_default ( ) ,
)
} else {
( None , vec! [ ] , false )
} ;
if filters . len ( ) > MAX_GET_PROGRAM_ACCOUNT_FILTERS {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Too many filters provided; max {MAX_GET_PROGRAM_ACCOUNT_FILTERS} "
2021-07-21 13:40:33 -07:00
) ) ) ;
}
for filter in & filters {
verify_filter ( filter ) ? ;
}
meta . get_program_accounts ( & program_id , config , filters , with_context )
}
fn get_largest_accounts (
& self ,
meta : Self ::Metadata ,
config : Option < RpcLargestAccountsConfig > ,
) -> Result < RpcResponse < Vec < RpcAccountBalance > > > {
debug! ( " get_largest_accounts rpc request received " ) ;
Ok ( meta . get_largest_accounts ( config ) ? )
}
fn get_supply (
& self ,
meta : Self ::Metadata ,
2021-08-17 16:32:58 -07:00
config : Option < RpcSupplyConfig > ,
2021-07-21 13:40:33 -07:00
) -> Result < RpcResponse < RpcSupply > > {
debug! ( " get_supply rpc request received " ) ;
2021-08-17 16:32:58 -07:00
Ok ( meta . get_supply ( config ) ? )
2021-07-21 13:40:33 -07:00
}
fn get_token_largest_accounts (
& self ,
meta : Self ::Metadata ,
mint_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < Vec < RpcTokenAccountBalance > > > {
debug! (
" get_token_largest_accounts rpc request received: {:?} " ,
mint_str
) ;
let mint = verify_pubkey ( & mint_str ) ? ;
meta . get_token_largest_accounts ( & mint , commitment )
}
fn get_token_accounts_by_owner (
& self ,
meta : Self ::Metadata ,
owner_str : String ,
token_account_filter : RpcTokenAccountsFilter ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Vec < RpcKeyedAccount > > > {
debug! (
" get_token_accounts_by_owner rpc request received: {:?} " ,
owner_str
) ;
let owner = verify_pubkey ( & owner_str ) ? ;
let token_account_filter = verify_token_account_filter ( token_account_filter ) ? ;
meta . get_token_accounts_by_owner ( & owner , token_account_filter , config )
}
fn get_token_accounts_by_delegate (
& self ,
meta : Self ::Metadata ,
delegate_str : String ,
token_account_filter : RpcTokenAccountsFilter ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Vec < RpcKeyedAccount > > > {
debug! (
" get_token_accounts_by_delegate rpc request received: {:?} " ,
delegate_str
) ;
let delegate = verify_pubkey ( & delegate_str ) ? ;
let token_account_filter = verify_token_account_filter ( token_account_filter ) ? ;
meta . get_token_accounts_by_delegate ( & delegate , token_account_filter , config )
}
}
}
// Full RPC interface that an API node is expected to provide
// (rpc_minimal should also be provided by an API node)
pub mod rpc_full {
2022-10-04 09:00:34 -07:00
use {
super ::* ,
solana_sdk ::message ::{ SanitizedVersionedMessage , VersionedMessage } ,
} ;
2021-07-21 13:40:33 -07:00
#[ rpc ]
pub trait Full {
type Metadata ;
#[ rpc(meta, name = " getInflationReward " ) ]
fn get_inflation_reward (
& self ,
meta : Self ::Metadata ,
address_strs : Vec < String > ,
config : Option < RpcEpochConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Option < RpcInflationReward > > > > ;
2021-07-21 13:40:33 -07:00
#[ rpc(meta, name = " getClusterNodes " ) ]
fn get_cluster_nodes ( & self , meta : Self ::Metadata ) -> Result < Vec < RpcContactInfo > > ;
#[ rpc(meta, name = " getRecentPerformanceSamples " ) ]
fn get_recent_performance_samples (
& self ,
meta : Self ::Metadata ,
limit : Option < usize > ,
) -> Result < Vec < RpcPerfSample > > ;
#[ rpc(meta, name = " getSignatureStatuses " ) ]
fn get_signature_statuses (
& self ,
meta : Self ::Metadata ,
signature_strs : Vec < String > ,
config : Option < RpcSignatureStatusConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < RpcResponse < Vec < Option < TransactionStatus > > > > > ;
2021-07-21 13:40:33 -07:00
#[ rpc(meta, name = " getMaxRetransmitSlot " ) ]
fn get_max_retransmit_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > ;
2021-02-26 21:42:09 -08:00
2021-07-21 13:40:33 -07:00
#[ rpc(meta, name = " getMaxShredInsertSlot " ) ]
fn get_max_shred_insert_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > ;
2021-02-26 21:42:09 -08:00
#[ rpc(meta, name = " requestAirdrop " ) ]
fn request_airdrop (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
lamports : u64 ,
2021-04-14 23:25:23 -07:00
config : Option < RpcRequestAirdropConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < String > ;
#[ rpc(meta, name = " sendTransaction " ) ]
fn send_transaction (
& self ,
meta : Self ::Metadata ,
data : String ,
config : Option < RpcSendTransactionConfig > ,
) -> Result < String > ;
#[ rpc(meta, name = " simulateTransaction " ) ]
fn simulate_transaction (
& self ,
meta : Self ::Metadata ,
data : String ,
config : Option < RpcSimulateTransactionConfig > ,
) -> Result < RpcResponse < RpcSimulateTransactionResult > > ;
#[ rpc(meta, name = " minimumLedgerSlot " ) ]
fn minimum_ledger_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > ;
2021-04-13 00:50:15 -07:00
#[ rpc(meta, name = " getBlock " ) ]
fn get_block (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
slot : Slot ,
2021-04-15 16:00:14 -07:00
config : Option < RpcEncodingConfigWrapper < RpcBlockConfig > > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Option < UiConfirmedBlock > > > ;
2021-02-26 21:42:09 -08:00
#[ rpc(meta, name = " getBlockTime " ) ]
2021-07-26 11:32:17 -07:00
fn get_block_time (
& self ,
meta : Self ::Metadata ,
slot : Slot ,
) -> BoxFuture < Result < Option < UnixTimestamp > > > ;
2021-02-26 21:42:09 -08:00
2021-04-13 00:50:15 -07:00
#[ rpc(meta, name = " getBlocks " ) ]
fn get_blocks (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
2021-04-15 16:00:14 -07:00
config : Option < RpcBlocksConfigWrapper > ,
2021-03-29 11:41:31 -07:00
commitment : Option < CommitmentConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Slot > > > ;
2021-02-26 21:42:09 -08:00
2021-04-13 00:50:15 -07:00
#[ rpc(meta, name = " getBlocksWithLimit " ) ]
fn get_blocks_with_limit (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
limit : usize ,
2021-03-29 11:41:31 -07:00
commitment : Option < CommitmentConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Slot > > > ;
2021-02-26 21:42:09 -08:00
2021-04-13 00:50:15 -07:00
#[ rpc(meta, name = " getTransaction " ) ]
fn get_transaction (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
signature_str : String ,
2021-04-15 16:00:14 -07:00
config : Option < RpcEncodingConfigWrapper < RpcTransactionConfig > > ,
2022-01-03 07:45:18 -08:00
) -> BoxFuture < Result < Option < EncodedConfirmedTransactionWithStatusMeta > > > ;
2021-02-26 21:42:09 -08:00
2021-04-13 00:50:15 -07:00
#[ rpc(meta, name = " getSignaturesForAddress " ) ]
fn get_signatures_for_address (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
address : String ,
2021-04-15 16:00:14 -07:00
config : Option < RpcSignaturesForAddressConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < RpcConfirmedTransactionStatusWithSignature > > > ;
2021-02-26 21:42:09 -08:00
#[ rpc(meta, name = " getFirstAvailableBlock " ) ]
2021-07-26 11:32:17 -07:00
fn get_first_available_block ( & self , meta : Self ::Metadata ) -> BoxFuture < Result < Slot > > ;
2021-08-13 09:08:20 -07:00
#[ rpc(meta, name = " getLatestBlockhash " ) ]
fn get_latest_blockhash (
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-08-13 09:08:20 -07:00
) -> Result < RpcResponse < RpcBlockhash > > ;
#[ rpc(meta, name = " isBlockhashValid " ) ]
fn is_blockhash_valid (
& self ,
meta : Self ::Metadata ,
blockhash : String ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-08-13 09:08:20 -07:00
) -> Result < RpcResponse < bool > > ;
#[ rpc(meta, name = " getFeeForMessage " ) ]
fn get_fee_for_message (
& self ,
meta : Self ::Metadata ,
data : String ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-08-13 09:08:20 -07:00
) -> Result < RpcResponse < Option < u64 > > > ;
2022-07-17 11:39:39 -07:00
#[ rpc(meta, name = " getStakeMinimumDelegation " ) ]
fn get_stake_minimum_delegation (
& self ,
meta : Self ::Metadata ,
config : Option < RpcContextConfig > ,
) -> Result < RpcResponse < u64 > > ;
2022-09-01 16:12:12 -07:00
#[ rpc(meta, name = " getRecentPrioritizationFees " ) ]
fn get_recent_prioritization_fees (
& self ,
meta : Self ::Metadata ,
pubkey_strs : Option < Vec < String > > ,
) -> Result < Vec < RpcPrioritizationFee > > ;
2021-02-26 21:42:09 -08:00
}
pub struct FullImpl ;
impl Full for FullImpl {
type Metadata = JsonRpcRequestProcessor ;
fn get_recent_performance_samples (
& self ,
meta : Self ::Metadata ,
limit : Option < usize > ,
) -> Result < Vec < RpcPerfSample > > {
debug! ( " get_recent_performance_samples request received " ) ;
2019-12-18 11:42:58 -08:00
2021-02-26 21:42:09 -08:00
let limit = limit . unwrap_or ( PERFORMANCE_SAMPLES_LIMIT ) ;
2020-07-28 17:28:51 -07:00
2021-02-26 21:42:09 -08:00
if limit > PERFORMANCE_SAMPLES_LIMIT {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Invalid limit; max {PERFORMANCE_SAMPLES_LIMIT} "
2021-02-26 21:42:09 -08:00
) ) ) ;
}
2019-12-18 11:42:58 -08:00
2021-02-26 21:42:09 -08:00
Ok ( meta
. blockstore
. get_recent_perf_samples ( limit )
. map_err ( | err | {
warn! ( " get_recent_performance_samples failed: {:?} " , err ) ;
Error ::invalid_request ( )
} ) ?
2023-01-12 19:14:04 -08:00
. into_iter ( )
. map ( | ( slot , sample ) | rpc_perf_sample_from_perf_sample ( slot , sample ) )
2021-02-26 21:42:09 -08:00
. collect ( ) )
}
2021-02-24 08:38:29 -08:00
2021-02-26 21:42:09 -08:00
fn get_cluster_nodes ( & self , meta : Self ::Metadata ) -> Result < Vec < RpcContactInfo > > {
debug! ( " get_cluster_nodes rpc request received " ) ;
let cluster_info = & meta . cluster_info ;
2021-07-23 08:25:03 -07:00
let socket_addr_space = cluster_info . socket_addr_space ( ) ;
let valid_address_or_none = | addr : & SocketAddr | -> Option < SocketAddr > {
if ContactInfo ::is_valid_address ( addr , socket_addr_space ) {
2021-02-26 21:42:09 -08:00
Some ( * addr )
} else {
None
}
2021-07-23 08:25:03 -07:00
} ;
2021-02-26 21:42:09 -08:00
let my_shred_version = cluster_info . my_shred_version ( ) ;
Ok ( cluster_info
. all_peers ( )
. iter ( )
. filter_map ( | ( contact_info , _ ) | {
if my_shred_version = = contact_info . shred_version
2021-07-23 08:25:03 -07:00
& & ContactInfo ::is_valid_address ( & contact_info . gossip , socket_addr_space )
2021-02-26 21:42:09 -08:00
{
let ( version , feature_set ) = if let Some ( version ) =
2021-07-21 13:40:33 -07:00
cluster_info . get_node_version ( & contact_info . id )
{
( Some ( version . to_string ( ) ) , Some ( version . feature_set ) )
} else {
( None , None )
} ;
Some ( RpcContactInfo {
pubkey : contact_info . id . to_string ( ) ,
gossip : Some ( contact_info . gossip ) ,
tpu : valid_address_or_none ( & contact_info . tpu ) ,
rpc : valid_address_or_none ( & contact_info . rpc ) ,
2023-01-08 21:25:56 -08:00
pubsub : valid_address_or_none ( & contact_info . rpc_pubsub ) ,
2021-07-21 13:40:33 -07:00
version ,
feature_set ,
shred_version : Some ( my_shred_version ) ,
} )
} else {
None // Exclude spy nodes
}
} )
. collect ( ) )
2021-02-26 21:42:09 -08:00
}
2021-02-23 13:06:33 -08:00
2021-02-26 21:42:09 -08:00
fn get_signature_statuses (
& self ,
meta : Self ::Metadata ,
signature_strs : Vec < String > ,
config : Option < RpcSignatureStatusConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < RpcResponse < Vec < Option < TransactionStatus > > > > > {
2021-02-26 21:42:09 -08:00
debug! (
" get_signature_statuses rpc request received: {:?} " ,
signature_strs . len ( )
) ;
if signature_strs . len ( ) > MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS {
2021-07-26 11:32:17 -07:00
return Box ::pin ( future ::err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Too many inputs provided; max {MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS} "
2021-07-26 11:32:17 -07:00
) ) ) ) ;
2021-02-26 21:42:09 -08:00
}
let mut signatures : Vec < Signature > = vec! [ ] ;
for signature_str in signature_strs {
2021-07-26 11:32:17 -07:00
match verify_signature ( & signature_str ) {
Ok ( signature ) = > {
signatures . push ( signature ) ;
}
Err ( err ) = > return Box ::pin ( future ::err ( err ) ) ,
}
2021-02-26 21:42:09 -08:00
}
2021-07-26 11:32:17 -07:00
Box ::pin ( async move { meta . get_signature_statuses ( signatures , config ) . await } )
2021-02-26 21:42:09 -08:00
}
2020-05-04 16:46:10 -07:00
2021-02-26 21:42:09 -08:00
fn get_max_retransmit_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > {
debug! ( " get_max_retransmit_slot rpc request received " ) ;
Ok ( meta . get_max_retransmit_slot ( ) )
}
2020-05-09 11:05:29 -07:00
2021-02-26 21:42:09 -08:00
fn get_max_shred_insert_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > {
debug! ( " get_max_shred_insert_slot rpc request received " ) ;
Ok ( meta . get_max_shred_insert_slot ( ) )
}
2019-03-06 09:26:12 -08:00
2021-02-26 21:42:09 -08:00
fn request_airdrop (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
lamports : u64 ,
2021-04-14 23:25:23 -07:00
config : Option < RpcRequestAirdropConfig > ,
2021-02-26 21:42:09 -08:00
) -> Result < String > {
debug! ( " request_airdrop rpc request received " ) ;
trace! (
2021-04-14 23:25:23 -07:00
" request_airdrop id={} lamports={} config: {:?} " ,
2021-02-26 21:42:09 -08:00
pubkey_str ,
lamports ,
2021-04-14 23:25:23 -07:00
& config
2021-02-26 21:42:09 -08:00
) ;
2018-11-14 18:57:34 -08:00
2021-02-26 21:42:09 -08:00
let faucet_addr = meta . config . faucet_addr . ok_or_else ( Error ::invalid_request ) ? ;
2021-04-21 14:12:23 -07:00
let pubkey = verify_pubkey ( & pubkey_str ) ? ;
2018-10-15 10:01:40 -07:00
2021-04-14 23:25:23 -07:00
let config = config . unwrap_or_default ( ) ;
let bank = meta . bank ( config . commitment ) ;
2019-02-26 12:25:46 -08:00
2021-04-14 23:25:23 -07:00
let blockhash = if let Some ( blockhash ) = config . recent_blockhash {
2021-04-21 14:12:23 -07:00
verify_hash ( & blockhash ) ?
2021-04-14 23:25:23 -07:00
} else {
2021-08-13 09:08:20 -07:00
bank . confirmed_last_blockhash ( )
2021-02-26 21:42:09 -08:00
} ;
2021-08-11 00:04:00 -07:00
let last_valid_block_height = bank
. get_blockhash_last_valid_block_height ( & blockhash )
. unwrap_or ( 0 ) ;
2020-12-17 14:37:22 -08:00
2021-02-26 21:42:09 -08:00
let transaction =
request_airdrop_transaction ( & faucet_addr , & pubkey , lamports , blockhash ) . map_err (
| err | {
info! ( " request_airdrop_transaction failed: {:?} " , err ) ;
Error ::internal_error ( )
} ,
) ? ;
2020-12-17 14:37:22 -08:00
2021-02-26 21:42:09 -08:00
let wire_transaction = serialize ( & transaction ) . map_err ( | err | {
info! ( " request_airdrop: serialize error: {:?} " , err ) ;
Error ::internal_error ( )
} ) ? ;
2020-05-29 23:16:35 -07:00
2021-08-17 15:17:56 -07:00
let signature = if ! transaction . signatures . is_empty ( ) {
transaction . signatures [ 0 ]
} else {
return Err ( RpcCustomError ::TransactionSignatureVerificationFailure . into ( ) ) ;
} ;
2021-08-11 00:04:00 -07:00
_send_transaction (
meta ,
2021-08-17 15:17:56 -07:00
signature ,
2021-08-11 00:04:00 -07:00
wire_transaction ,
last_valid_block_height ,
None ,
2021-08-24 21:44:13 -07:00
None ,
2021-08-11 00:04:00 -07:00
)
2020-12-29 08:48:43 -08:00
}
2021-02-26 21:42:09 -08:00
fn send_transaction (
& self ,
meta : Self ::Metadata ,
data : String ,
config : Option < RpcSendTransactionConfig > ,
) -> Result < String > {
debug! ( " send_transaction rpc request received " ) ;
2022-05-16 23:46:02 -07:00
let RpcSendTransactionConfig {
skip_preflight ,
preflight_commitment ,
encoding ,
max_retries ,
min_context_slot ,
} = config . unwrap_or_default ( ) ;
let tx_encoding = encoding . unwrap_or ( UiTransactionEncoding ::Base58 ) ;
2022-03-09 00:09:08 -08:00
let binary_encoding = tx_encoding . into_binary_encoding ( ) . ok_or_else ( | | {
Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" unsupported encoding: {tx_encoding}. Supported encodings: base58, base64 "
2022-03-09 00:09:08 -08:00
) )
} ) ? ;
2021-08-17 15:17:56 -07:00
let ( wire_transaction , unsanitized_tx ) =
2022-03-09 00:09:08 -08:00
decode_and_deserialize ::< VersionedTransaction > ( data , binary_encoding ) ? ;
2021-02-26 21:42:09 -08:00
2022-05-16 23:46:02 -07:00
let preflight_commitment =
preflight_commitment . map ( | commitment | CommitmentConfig { commitment } ) ;
let preflight_bank = & * meta . get_bank_with_config ( RpcContextConfig {
commitment : preflight_commitment ,
min_context_slot ,
} ) ? ;
2022-03-07 23:20:34 -08:00
let transaction = sanitize_transaction ( unsanitized_tx , preflight_bank ) ? ;
2021-08-17 15:17:56 -07:00
let signature = * transaction . signature ( ) ;
2021-02-26 21:42:09 -08:00
2021-08-11 00:04:00 -07:00
let mut last_valid_block_height = preflight_bank
2021-08-17 15:17:56 -07:00
. get_blockhash_last_valid_block_height ( transaction . message ( ) . recent_blockhash ( ) )
2021-02-26 21:42:09 -08:00
. unwrap_or ( 0 ) ;
2021-08-17 15:17:56 -07:00
let durable_nonce_info = transaction
2022-07-07 07:45:19 -07:00
. get_durable_nonce ( )
2021-08-17 15:17:56 -07:00
. map ( | & pubkey | ( pubkey , * transaction . message ( ) . recent_blockhash ( ) ) ) ;
2021-02-26 21:42:09 -08:00
if durable_nonce_info . is_some ( ) {
2021-08-11 00:04:00 -07:00
// While it uses a defined constant, this last_valid_block_height value is chosen arbitrarily.
2021-02-26 21:42:09 -08:00
// It provides a fallback timeout for durable-nonce transaction retries in case of
// malicious packing of the retry queue. Durable-nonce transactions are otherwise
// retried until the nonce is advanced.
2021-08-11 00:04:00 -07:00
last_valid_block_height =
preflight_bank . block_height ( ) + MAX_RECENT_BLOCKHASHES as u64 ;
2020-09-27 22:29:00 -07:00
}
2022-05-16 23:46:02 -07:00
if ! skip_preflight {
2022-08-22 18:01:03 -07:00
verify_transaction ( & transaction , & preflight_bank . feature_set ) ? ;
2021-02-26 21:42:09 -08:00
match meta . health . check ( ) {
RpcHealthStatus ::Ok = > ( ) ,
2021-03-04 21:18:08 -08:00
RpcHealthStatus ::Unknown = > {
2021-06-22 18:54:52 -07:00
inc_new_counter_info! ( " rpc-send-tx_health-unknown " , 1 ) ;
2021-03-04 21:18:08 -08:00
return Err ( RpcCustomError ::NodeUnhealthy {
num_slots_behind : None ,
}
. into ( ) ) ;
}
2021-02-26 21:42:09 -08:00
RpcHealthStatus ::Behind { num_slots } = > {
2021-06-22 18:54:52 -07:00
inc_new_counter_info! ( " rpc-send-tx_health-behind " , 1 ) ;
2021-02-26 21:42:09 -08:00
return Err ( RpcCustomError ::NodeUnhealthy {
num_slots_behind : Some ( num_slots ) ,
}
. into ( ) ) ;
2021-01-17 20:23:14 -08:00
}
2021-01-14 21:45:11 -08:00
}
2021-07-16 14:58:15 -07:00
if let TransactionSimulationResult {
result : Err ( err ) ,
logs ,
post_simulation_accounts : _ ,
units_consumed ,
2022-03-22 15:17:05 -07:00
return_data ,
2021-08-17 15:17:56 -07:00
} = preflight_bank . simulate_transaction ( transaction )
2021-07-16 14:58:15 -07:00
{
2021-06-22 18:54:52 -07:00
match err {
TransactionError ::BlockhashNotFound = > {
inc_new_counter_info! ( " rpc-send-tx_err-blockhash-not-found " , 1 ) ;
}
_ = > {
inc_new_counter_info! ( " rpc-send-tx_err-other " , 1 ) ;
}
}
2021-02-26 21:42:09 -08:00
return Err ( RpcCustomError ::SendTransactionPreflightFailure {
2022-12-06 06:30:06 -08:00
message : format ! ( " Transaction simulation failed: {err} " ) ,
2021-02-26 21:42:09 -08:00
result : RpcSimulateTransactionResult {
err : Some ( err ) ,
logs : Some ( logs ) ,
2021-05-25 16:44:18 -07:00
accounts : None ,
2021-07-16 14:58:15 -07:00
units_consumed : Some ( units_consumed ) ,
2022-04-14 22:42:08 -07:00
return_data : return_data . map ( | return_data | return_data . into ( ) ) ,
2021-02-26 21:42:09 -08:00
} ,
}
. into ( ) ) ;
2020-05-29 23:16:35 -07:00
}
}
2019-02-26 12:25:46 -08:00
2021-02-26 21:42:09 -08:00
_send_transaction (
meta ,
2021-08-17 15:17:56 -07:00
signature ,
2021-02-26 21:42:09 -08:00
wire_transaction ,
2021-08-11 00:04:00 -07:00
last_valid_block_height ,
2021-02-26 21:42:09 -08:00
durable_nonce_info ,
2022-05-16 23:46:02 -07:00
max_retries ,
2021-02-26 21:42:09 -08:00
)
2020-10-23 20:47:51 -07:00
}
2020-05-19 12:08:19 -07:00
2021-02-26 21:42:09 -08:00
fn simulate_transaction (
& self ,
meta : Self ::Metadata ,
data : String ,
config : Option < RpcSimulateTransactionConfig > ,
) -> Result < RpcResponse < RpcSimulateTransactionResult > > {
debug! ( " simulate_transaction rpc request received " ) ;
2022-05-16 23:46:02 -07:00
let RpcSimulateTransactionConfig {
sig_verify ,
replace_recent_blockhash ,
commitment ,
encoding ,
accounts : config_accounts ,
min_context_slot ,
} = config . unwrap_or_default ( ) ;
let tx_encoding = encoding . unwrap_or ( UiTransactionEncoding ::Base58 ) ;
2022-03-09 00:09:08 -08:00
let binary_encoding = tx_encoding . into_binary_encoding ( ) . ok_or_else ( | | {
Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" unsupported encoding: {tx_encoding}. Supported encodings: base58, base64 "
2022-03-09 00:09:08 -08:00
) )
} ) ? ;
2021-08-17 15:17:56 -07:00
let ( _ , mut unsanitized_tx ) =
2022-03-09 00:09:08 -08:00
decode_and_deserialize ::< VersionedTransaction > ( data , binary_encoding ) ? ;
2021-02-26 21:42:09 -08:00
2022-05-16 23:46:02 -07:00
let bank = & * meta . get_bank_with_config ( RpcContextConfig {
commitment ,
min_context_slot ,
} ) ? ;
if replace_recent_blockhash {
if sig_verify {
2021-05-25 14:04:17 -07:00
return Err ( Error ::invalid_params (
" sigVerify may not be used with replaceRecentBlockhash " ,
) ) ;
}
2021-08-17 15:17:56 -07:00
unsanitized_tx
. message
. set_recent_blockhash ( bank . last_blockhash ( ) ) ;
2021-02-26 21:42:09 -08:00
}
2021-08-17 15:17:56 -07:00
2022-03-07 23:20:34 -08:00
let transaction = sanitize_transaction ( unsanitized_tx , bank ) ? ;
2022-05-16 23:46:02 -07:00
if sig_verify {
2021-08-30 00:58:45 -07:00
verify_transaction ( & transaction , & bank . feature_set ) ? ;
2021-05-25 13:01:21 -07:00
}
2022-02-05 04:00:31 -08:00
let number_of_accounts = transaction . message ( ) . account_keys ( ) . len ( ) ;
2021-08-17 15:17:56 -07:00
2021-07-16 14:58:15 -07:00
let TransactionSimulationResult {
result ,
logs ,
post_simulation_accounts ,
units_consumed ,
2022-03-22 15:17:05 -07:00
return_data ,
2021-08-17 15:17:56 -07:00
} = bank . simulate_transaction ( transaction ) ;
2021-05-25 16:44:18 -07:00
2022-05-16 23:46:02 -07:00
let accounts = if let Some ( config_accounts ) = config_accounts {
2021-05-25 16:44:18 -07:00
let accounts_encoding = config_accounts
. encoding
. unwrap_or ( UiAccountEncoding ::Base64 ) ;
if accounts_encoding = = UiAccountEncoding ::Binary
| | accounts_encoding = = UiAccountEncoding ::Base58
{
return Err ( Error ::invalid_params ( " base58 encoding not supported " ) ) ;
}
2021-12-08 10:42:13 -08:00
if config_accounts . addresses . len ( ) > number_of_accounts {
2021-05-25 16:44:18 -07:00
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Too many accounts provided; max {number_of_accounts} "
2021-05-25 16:44:18 -07:00
) ) ) ;
}
2021-12-08 10:42:13 -08:00
if result . is_err ( ) {
Some ( vec! [ None ; config_accounts . addresses . len ( ) ] )
} else {
2022-02-01 13:10:21 -08:00
Some (
config_accounts
. addresses
. iter ( )
. map ( | address_str | {
let address = verify_pubkey ( address_str ) ? ;
post_simulation_accounts
. iter ( )
. find ( | ( key , _account ) | key = = & address )
. map ( | ( pubkey , account ) | {
encode_account ( account , pubkey , accounts_encoding , None )
} )
. transpose ( )
} )
. collect ::< Result < Vec < _ > > > ( ) ? ,
)
2021-05-25 16:44:18 -07:00
}
} else {
None
} ;
2020-03-04 14:44:21 -08:00
2021-02-26 21:42:09 -08:00
Ok ( new_response (
2022-02-21 13:15:37 -08:00
bank ,
2021-02-26 21:42:09 -08:00
RpcSimulateTransactionResult {
err : result . err ( ) ,
logs : Some ( logs ) ,
2021-05-25 16:44:18 -07:00
accounts ,
2021-07-16 14:58:15 -07:00
units_consumed : Some ( units_consumed ) ,
2022-04-14 22:42:08 -07:00
return_data : return_data . map ( | return_data | return_data . into ( ) ) ,
2021-02-26 21:42:09 -08:00
} ,
) )
}
2019-08-10 22:54:46 -07:00
2021-02-26 21:42:09 -08:00
fn minimum_ledger_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > {
debug! ( " minimum_ledger_slot rpc request received " ) ;
meta . minimum_ledger_slot ( )
}
2019-11-25 23:40:36 -08:00
2021-04-13 00:50:15 -07:00
fn get_block (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
slot : Slot ,
2021-04-15 16:00:14 -07:00
config : Option < RpcEncodingConfigWrapper < RpcBlockConfig > > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Option < UiConfirmedBlock > > > {
2021-04-13 00:50:15 -07:00
debug! ( " get_block rpc request received: {:?} " , slot ) ;
2021-07-26 11:32:17 -07:00
Box ::pin ( async move { meta . get_block ( slot , config ) . await } )
2021-02-26 21:42:09 -08:00
}
2019-12-18 15:51:47 -08:00
2021-04-13 00:50:15 -07:00
fn get_blocks (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
2021-04-15 16:00:14 -07:00
config : Option < RpcBlocksConfigWrapper > ,
2021-03-29 11:41:31 -07:00
commitment : Option < CommitmentConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Slot > > > {
2021-03-29 11:41:31 -07:00
let ( end_slot , maybe_commitment ) =
config . map ( | config | config . unzip ( ) ) . unwrap_or_default ( ) ;
2021-02-26 21:42:09 -08:00
debug! (
2021-04-13 00:50:15 -07:00
" get_blocks rpc request received: {}-{:?} " ,
2021-02-26 21:42:09 -08:00
start_slot , end_slot
) ;
2021-07-26 11:32:17 -07:00
Box ::pin ( async move {
meta . get_blocks ( start_slot , end_slot , commitment . or ( maybe_commitment ) )
. await
} )
2021-02-26 21:42:09 -08:00
}
2020-09-30 13:47:12 -07:00
2021-04-13 00:50:15 -07:00
fn get_blocks_with_limit (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
limit : usize ,
2021-03-29 11:41:31 -07:00
commitment : Option < CommitmentConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Slot > > > {
2021-02-26 21:42:09 -08:00
debug! (
2021-04-13 00:50:15 -07:00
" get_blocks_with_limit rpc request received: {}-{} " ,
2021-02-26 21:42:09 -08:00
start_slot , limit ,
) ;
2021-07-26 11:32:17 -07:00
Box ::pin ( async move {
meta . get_blocks_with_limit ( start_slot , limit , commitment )
. await
} )
2021-02-26 21:42:09 -08:00
}
2020-04-08 23:57:30 -07:00
2021-02-26 21:42:09 -08:00
fn get_block_time (
& self ,
meta : Self ::Metadata ,
slot : Slot ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Option < UnixTimestamp > > > {
Box ::pin ( async move { meta . get_block_time ( slot ) . await } )
2021-02-26 21:42:09 -08:00
}
2020-04-09 20:21:31 -07:00
2021-04-13 00:50:15 -07:00
fn get_transaction (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
signature_str : String ,
2021-04-15 16:00:14 -07:00
config : Option < RpcEncodingConfigWrapper < RpcTransactionConfig > > ,
2022-01-03 07:45:18 -08:00
) -> BoxFuture < Result < Option < EncodedConfirmedTransactionWithStatusMeta > > > {
2021-04-13 00:50:15 -07:00
debug! ( " get_transaction rpc request received: {:?} " , signature_str ) ;
2021-07-26 11:32:17 -07:00
let signature = verify_signature ( & signature_str ) ;
if let Err ( err ) = signature {
return Box ::pin ( future ::err ( err ) ) ;
}
Box ::pin ( async move { meta . get_transaction ( signature . unwrap ( ) , config ) . await } )
2020-04-09 20:21:31 -07:00
}
2021-02-26 21:42:09 -08:00
2021-04-13 00:50:15 -07:00
fn get_signatures_for_address (
2021-02-26 21:42:09 -08:00
& self ,
meta : Self ::Metadata ,
address : String ,
2021-04-15 16:00:14 -07:00
config : Option < RpcSignaturesForAddressConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < RpcConfirmedTransactionStatusWithSignature > > > {
2022-05-16 23:46:02 -07:00
let RpcSignaturesForAddressConfig {
before ,
until ,
limit ,
commitment ,
min_context_slot ,
} = config . unwrap_or_default ( ) ;
let verification =
verify_and_parse_signatures_for_address_params ( address , before , until , limit ) ;
2020-07-27 11:42:49 -07:00
2021-07-26 11:32:17 -07:00
match verification {
Err ( err ) = > Box ::pin ( future ::err ( err ) ) ,
Ok ( ( address , before , until , limit ) ) = > Box ::pin ( async move {
2022-05-16 23:46:02 -07:00
meta . get_signatures_for_address (
address ,
before ,
until ,
limit ,
RpcContextConfig {
commitment ,
min_context_slot ,
} ,
)
. await
2021-07-26 11:32:17 -07:00
} ) ,
}
2020-07-27 11:42:49 -07:00
}
2021-07-26 11:32:17 -07:00
fn get_first_available_block ( & self , meta : Self ::Metadata ) -> BoxFuture < Result < Slot > > {
2021-02-26 21:42:09 -08:00
debug! ( " get_first_available_block rpc request received " ) ;
2021-07-26 11:32:17 -07:00
Box ::pin ( async move { Ok ( meta . get_first_available_block ( ) . await ) } )
2021-02-26 21:42:09 -08:00
}
2020-07-06 12:28:40 -07:00
2021-04-06 18:10:53 -07:00
fn get_inflation_reward (
& self ,
meta : Self ::Metadata ,
address_strs : Vec < String > ,
config : Option < RpcEpochConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Option < RpcInflationReward > > > > {
2021-04-06 18:10:53 -07:00
debug! (
" get_inflation_reward rpc request received: {:?} " ,
address_strs . len ( )
) ;
let mut addresses : Vec < Pubkey > = vec! [ ] ;
for address_str in address_strs {
2021-07-26 11:32:17 -07:00
match verify_pubkey ( & address_str ) {
Ok ( pubkey ) = > {
addresses . push ( pubkey ) ;
}
Err ( err ) = > return Box ::pin ( future ::err ( err ) ) ,
}
2021-04-06 18:10:53 -07:00
}
2021-07-26 11:32:17 -07:00
Box ::pin ( async move { meta . get_inflation_reward ( addresses , config ) . await } )
2021-04-06 18:10:53 -07:00
}
2021-08-13 09:08:20 -07:00
fn get_latest_blockhash (
& self ,
meta : Self ::Metadata ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-08-13 09:08:20 -07:00
) -> Result < RpcResponse < RpcBlockhash > > {
debug! ( " get_latest_blockhash rpc request received " ) ;
2022-05-16 23:46:02 -07:00
meta . get_latest_blockhash ( config . unwrap_or_default ( ) )
2021-08-13 09:08:20 -07:00
}
fn is_blockhash_valid (
& self ,
meta : Self ::Metadata ,
blockhash : String ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-08-13 09:08:20 -07:00
) -> Result < RpcResponse < bool > > {
2022-12-06 06:30:06 -08:00
let blockhash =
Hash ::from_str ( & blockhash ) . map_err ( | e | Error ::invalid_params ( format! ( " {e:?} " ) ) ) ? ;
2022-05-16 23:46:02 -07:00
meta . is_blockhash_valid ( & blockhash , config . unwrap_or_default ( ) )
2021-08-13 09:08:20 -07:00
}
fn get_fee_for_message (
& self ,
meta : Self ::Metadata ,
data : String ,
2022-05-16 23:46:02 -07:00
config : Option < RpcContextConfig > ,
2021-08-13 09:08:20 -07:00
) -> Result < RpcResponse < Option < u64 > > > {
debug! ( " get_fee_for_message rpc request received " ) ;
2022-10-04 09:00:34 -07:00
let ( _ , message ) = decode_and_deserialize ::< VersionedMessage > (
data ,
TransactionBinaryEncoding ::Base64 ,
) ? ;
let bank = & * meta . get_bank_with_config ( config . unwrap_or_default ( ) ) ? ;
let sanitized_versioned_message = SanitizedVersionedMessage ::try_from ( message )
. map_err ( | err | {
2022-12-06 06:30:06 -08:00
Error ::invalid_params ( format! ( " invalid transaction message: {err} " ) )
2022-10-04 09:00:34 -07:00
} ) ? ;
let sanitized_message = SanitizedMessage ::try_new ( sanitized_versioned_message , bank )
. map_err ( | err | {
2022-12-06 06:30:06 -08:00
Error ::invalid_params ( format! ( " invalid transaction message: {err} " ) )
2022-10-04 09:00:34 -07:00
} ) ? ;
let fee = bank . get_fee_for_message ( & sanitized_message ) ;
Ok ( new_response ( bank , fee ) )
2021-08-13 09:08:20 -07:00
}
2022-07-17 11:39:39 -07:00
fn get_stake_minimum_delegation (
& self ,
meta : Self ::Metadata ,
config : Option < RpcContextConfig > ,
) -> Result < RpcResponse < u64 > > {
debug! ( " get_stake_minimum_delegation rpc request received " ) ;
meta . get_stake_minimum_delegation ( config . unwrap_or_default ( ) )
}
2022-09-01 16:12:12 -07:00
fn get_recent_prioritization_fees (
& self ,
meta : Self ::Metadata ,
pubkey_strs : Option < Vec < String > > ,
) -> Result < Vec < RpcPrioritizationFee > > {
let pubkey_strs = pubkey_strs . unwrap_or_default ( ) ;
debug! (
" get_recent_prioritization_fees rpc request received: {:?} pubkeys " ,
pubkey_strs . len ( )
) ;
if pubkey_strs . len ( ) > MAX_TX_ACCOUNT_LOCKS {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Too many inputs provided; max {MAX_TX_ACCOUNT_LOCKS} "
2022-09-01 16:12:12 -07:00
) ) ) ;
}
let pubkeys = pubkey_strs
. into_iter ( )
. map ( | pubkey_str | verify_pubkey ( & pubkey_str ) )
. collect ::< Result < Vec < _ > > > ( ) ? ;
meta . get_recent_prioritization_fees ( pubkeys )
}
2021-08-13 09:08:20 -07:00
}
}
2023-01-12 19:14:04 -08:00
fn rpc_perf_sample_from_perf_sample ( slot : u64 , sample : PerfSample ) -> RpcPerfSample {
match sample {
PerfSample ::V1 ( PerfSampleV1 {
num_transactions ,
num_slots ,
sample_period_secs ,
} ) = > RpcPerfSample {
slot ,
num_transactions ,
2023-01-18 00:22:47 -08:00
num_non_vote_transactions : None ,
2023-01-12 19:14:04 -08:00
num_slots ,
sample_period_secs ,
} ,
PerfSample ::V2 ( PerfSampleV2 {
num_transactions ,
2023-01-18 00:22:47 -08:00
num_non_vote_transactions ,
2023-01-12 19:14:04 -08:00
num_slots ,
sample_period_secs ,
} ) = > RpcPerfSample {
slot ,
num_transactions ,
2023-01-18 00:22:47 -08:00
num_non_vote_transactions : Some ( num_non_vote_transactions ) ,
2023-01-12 19:14:04 -08:00
num_slots ,
sample_period_secs ,
} ,
}
}
2021-08-13 09:08:20 -07:00
// RPC methods deprecated in v1.8
2021-11-01 19:04:29 -07:00
pub mod rpc_deprecated_v1_9 {
2021-08-13 09:08:20 -07:00
#![ allow(deprecated) ]
use super ::* ;
#[ rpc ]
2021-11-01 19:04:29 -07:00
pub trait DeprecatedV1_9 {
2021-08-13 09:08:20 -07:00
type Metadata ;
#[ rpc(meta, name = " getRecentBlockhash " ) ]
fn get_recent_blockhash (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < RpcBlockhashFeeCalculator > > ;
#[ rpc(meta, name = " getFees " ) ]
fn get_fees (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < RpcFees > > ;
#[ rpc(meta, name = " getFeeCalculatorForBlockhash " ) ]
fn get_fee_calculator_for_blockhash (
& self ,
meta : Self ::Metadata ,
blockhash : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < Option < RpcFeeCalculator > > > ;
#[ rpc(meta, name = " getFeeRateGovernor " ) ]
fn get_fee_rate_governor (
& self ,
meta : Self ::Metadata ,
) -> Result < RpcResponse < RpcFeeRateGovernor > > ;
2021-09-02 13:25:42 -07:00
#[ rpc(meta, name = " getSnapshotSlot " ) ]
fn get_snapshot_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > ;
2021-08-13 09:08:20 -07:00
}
2021-11-01 19:04:29 -07:00
pub struct DeprecatedV1_9Impl ;
impl DeprecatedV1_9 for DeprecatedV1_9Impl {
2021-08-13 09:08:20 -07:00
type Metadata = JsonRpcRequestProcessor ;
fn get_recent_blockhash (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < RpcBlockhashFeeCalculator > > {
debug! ( " get_recent_blockhash rpc request received " ) ;
2022-05-16 23:46:02 -07:00
meta . get_recent_blockhash ( commitment )
2021-08-13 09:08:20 -07:00
}
fn get_fees (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < RpcFees > > {
debug! ( " get_fees rpc request received " ) ;
2022-05-16 23:46:02 -07:00
meta . get_fees ( commitment )
2021-08-13 09:08:20 -07:00
}
fn get_fee_calculator_for_blockhash (
& self ,
meta : Self ::Metadata ,
blockhash : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < Option < RpcFeeCalculator > > > {
debug! ( " get_fee_calculator_for_blockhash rpc request received " ) ;
2022-12-06 06:30:06 -08:00
let blockhash =
Hash ::from_str ( & blockhash ) . map_err ( | e | Error ::invalid_params ( format! ( " {e:?} " ) ) ) ? ;
2022-05-16 23:46:02 -07:00
meta . get_fee_calculator_for_blockhash ( & blockhash , commitment )
2021-08-13 09:08:20 -07:00
}
fn get_fee_rate_governor (
& self ,
meta : Self ::Metadata ,
) -> Result < RpcResponse < RpcFeeRateGovernor > > {
debug! ( " get_fee_rate_governor rpc request received " ) ;
Ok ( meta . get_fee_rate_governor ( ) )
}
2021-09-02 13:25:42 -07:00
fn get_snapshot_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > {
debug! ( " get_snapshot_slot rpc request received " ) ;
meta . snapshot_config
. and_then ( | snapshot_config | {
snapshot_utils ::get_highest_full_snapshot_archive_slot (
2022-11-09 11:39:38 -08:00
snapshot_config . full_snapshot_archives_dir ,
2021-09-02 13:25:42 -07:00
)
} )
. ok_or_else ( | | RpcCustomError ::NoSnapshot . into ( ) )
}
2020-07-28 22:00:48 -07:00
}
2019-11-11 10:18:34 -08:00
}
2021-08-13 09:08:20 -07:00
// RPC methods deprecated in v1.7
2021-04-13 00:50:15 -07:00
pub mod rpc_deprecated_v1_7 {
2021-04-15 16:00:14 -07:00
#![ allow(deprecated) ]
2021-04-13 00:50:15 -07:00
use super ::* ;
#[ rpc ]
pub trait DeprecatedV1_7 {
type Metadata ;
// DEPRECATED
#[ rpc(meta, name = " getConfirmedBlock " ) ]
fn get_confirmed_block (
& self ,
meta : Self ::Metadata ,
slot : Slot ,
config : Option < RpcEncodingConfigWrapper < RpcConfirmedBlockConfig > > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Option < UiConfirmedBlock > > > ;
2021-04-13 00:50:15 -07:00
// DEPRECATED
#[ rpc(meta, name = " getConfirmedBlocks " ) ]
fn get_confirmed_blocks (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
config : Option < RpcConfirmedBlocksConfigWrapper > ,
commitment : Option < CommitmentConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Slot > > > ;
2021-04-13 00:50:15 -07:00
// DEPRECATED
#[ rpc(meta, name = " getConfirmedBlocksWithLimit " ) ]
fn get_confirmed_blocks_with_limit (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
limit : usize ,
commitment : Option < CommitmentConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Slot > > > ;
2021-04-13 00:50:15 -07:00
// DEPRECATED
#[ rpc(meta, name = " getConfirmedTransaction " ) ]
fn get_confirmed_transaction (
& self ,
meta : Self ::Metadata ,
signature_str : String ,
config : Option < RpcEncodingConfigWrapper < RpcConfirmedTransactionConfig > > ,
2022-01-03 07:45:18 -08:00
) -> BoxFuture < Result < Option < EncodedConfirmedTransactionWithStatusMeta > > > ;
2021-04-13 00:50:15 -07:00
// DEPRECATED
#[ rpc(meta, name = " getConfirmedSignaturesForAddress2 " ) ]
fn get_confirmed_signatures_for_address2 (
& self ,
meta : Self ::Metadata ,
address : String ,
config : Option < RpcGetConfirmedSignaturesForAddress2Config > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < RpcConfirmedTransactionStatusWithSignature > > > ;
2021-04-13 00:50:15 -07:00
}
pub struct DeprecatedV1_7Impl ;
impl DeprecatedV1_7 for DeprecatedV1_7Impl {
type Metadata = JsonRpcRequestProcessor ;
fn get_confirmed_block (
& self ,
meta : Self ::Metadata ,
slot : Slot ,
config : Option < RpcEncodingConfigWrapper < RpcConfirmedBlockConfig > > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Option < UiConfirmedBlock > > > {
2021-04-13 00:50:15 -07:00
debug! ( " get_confirmed_block rpc request received: {:?} " , slot ) ;
2021-07-26 11:32:17 -07:00
Box ::pin ( async move {
meta . get_block ( slot , config . map ( | config | config . convert ( ) ) )
. await
} )
2021-04-13 00:50:15 -07:00
}
fn get_confirmed_blocks (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
config : Option < RpcConfirmedBlocksConfigWrapper > ,
commitment : Option < CommitmentConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Slot > > > {
2021-04-13 00:50:15 -07:00
let ( end_slot , maybe_commitment ) =
config . map ( | config | config . unzip ( ) ) . unwrap_or_default ( ) ;
debug! (
" get_confirmed_blocks rpc request received: {}-{:?} " ,
start_slot , end_slot
) ;
2021-07-26 11:32:17 -07:00
Box ::pin ( async move {
meta . get_blocks ( start_slot , end_slot , commitment . or ( maybe_commitment ) )
. await
} )
2021-04-13 00:50:15 -07:00
}
fn get_confirmed_blocks_with_limit (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
limit : usize ,
commitment : Option < CommitmentConfig > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < Slot > > > {
2021-04-13 00:50:15 -07:00
debug! (
" get_confirmed_blocks_with_limit rpc request received: {}-{} " ,
start_slot , limit ,
) ;
2021-07-26 11:32:17 -07:00
Box ::pin ( async move {
meta . get_blocks_with_limit ( start_slot , limit , commitment )
. await
} )
2021-04-13 00:50:15 -07:00
}
fn get_confirmed_transaction (
& self ,
meta : Self ::Metadata ,
signature_str : String ,
config : Option < RpcEncodingConfigWrapper < RpcConfirmedTransactionConfig > > ,
2022-01-03 07:45:18 -08:00
) -> BoxFuture < Result < Option < EncodedConfirmedTransactionWithStatusMeta > > > {
2021-04-13 00:50:15 -07:00
debug! (
" get_confirmed_transaction rpc request received: {:?} " ,
signature_str
) ;
2021-07-26 11:32:17 -07:00
let signature = verify_signature ( & signature_str ) ;
if let Err ( err ) = signature {
return Box ::pin ( future ::err ( err ) ) ;
}
Box ::pin ( async move {
meta . get_transaction ( signature . unwrap ( ) , config . map ( | config | config . convert ( ) ) )
. await
} )
2021-04-13 00:50:15 -07:00
}
fn get_confirmed_signatures_for_address2 (
& self ,
meta : Self ::Metadata ,
address : String ,
config : Option < RpcGetConfirmedSignaturesForAddress2Config > ,
2021-07-26 11:32:17 -07:00
) -> BoxFuture < Result < Vec < RpcConfirmedTransactionStatusWithSignature > > > {
2021-04-13 00:50:15 -07:00
let config = config . unwrap_or_default ( ) ;
2021-07-26 11:32:17 -07:00
let commitment = config . commitment ;
let verification = verify_and_parse_signatures_for_address_params (
address ,
config . before ,
config . until ,
config . limit ,
) ;
2021-04-13 00:50:15 -07:00
2021-07-26 11:32:17 -07:00
match verification {
Err ( err ) = > Box ::pin ( future ::err ( err ) ) ,
Ok ( ( address , before , until , limit ) ) = > Box ::pin ( async move {
2022-05-16 23:46:02 -07:00
meta . get_signatures_for_address (
address ,
before ,
until ,
limit ,
RpcContextConfig {
commitment ,
min_context_slot : None ,
} ,
)
. await
2021-07-26 11:32:17 -07:00
} ) ,
}
2021-04-13 00:50:15 -07:00
}
}
}
2021-04-12 19:33:40 -07:00
// Obsolete RPC methods, collected for easy deactivation and removal
pub mod rpc_obsolete_v1_7 {
use super ::* ;
#[ rpc ]
pub trait ObsoleteV1_7 {
type Metadata ;
// DEPRECATED
#[ rpc(meta, name = " confirmTransaction " ) ]
fn confirm_transaction (
& self ,
meta : Self ::Metadata ,
signature_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < bool > > ;
// DEPRECATED
#[ rpc(meta, name = " getSignatureStatus " ) ]
fn get_signature_status (
& self ,
meta : Self ::Metadata ,
signature_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < Option < transaction ::Result < ( ) > > > ;
// DEPRECATED (used by Trust Wallet)
#[ rpc(meta, name = " getSignatureConfirmation " ) ]
fn get_signature_confirmation (
& self ,
meta : Self ::Metadata ,
signature_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < Option < RpcSignatureConfirmation > > ;
// DEPRECATED
#[ rpc(meta, name = " getTotalSupply " ) ]
fn get_total_supply (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < u64 > ;
// DEPRECATED
#[ rpc(meta, name = " getConfirmedSignaturesForAddress " ) ]
fn get_confirmed_signatures_for_address (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
start_slot : Slot ,
end_slot : Slot ,
) -> Result < Vec < String > > ;
}
pub struct ObsoleteV1_7Impl ;
impl ObsoleteV1_7 for ObsoleteV1_7Impl {
type Metadata = JsonRpcRequestProcessor ;
fn confirm_transaction (
& self ,
meta : Self ::Metadata ,
id : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < bool > > {
debug! ( " confirm_transaction rpc request received: {:?} " , id ) ;
let signature = verify_signature ( & id ) ? ;
2022-05-16 23:46:02 -07:00
meta . confirm_transaction ( & signature , commitment )
2021-04-12 19:33:40 -07:00
}
fn get_signature_status (
& self ,
meta : Self ::Metadata ,
signature_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < Option < transaction ::Result < ( ) > > > {
debug! (
" get_signature_status rpc request received: {:?} " ,
signature_str
) ;
let signature = verify_signature ( & signature_str ) ? ;
2022-05-16 23:46:02 -07:00
meta . get_signature_status ( signature , commitment )
2021-04-12 19:33:40 -07:00
}
fn get_signature_confirmation (
& self ,
meta : Self ::Metadata ,
signature_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < Option < RpcSignatureConfirmation > > {
debug! (
" get_signature_confirmation rpc request received: {:?} " ,
signature_str
) ;
let signature = verify_signature ( & signature_str ) ? ;
2022-05-16 23:46:02 -07:00
meta . get_signature_confirmation_status ( signature , commitment )
2021-04-12 19:33:40 -07:00
}
fn get_total_supply (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < u64 > {
debug! ( " get_total_supply rpc request received " ) ;
2022-05-16 23:46:02 -07:00
meta . get_total_supply ( commitment )
2021-04-12 19:33:40 -07:00
}
fn get_confirmed_signatures_for_address (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
start_slot : Slot ,
end_slot : Slot ,
) -> Result < Vec < String > > {
debug! (
" get_confirmed_signatures_for_address rpc request received: {:?} {:?}-{:?} " ,
pubkey_str , start_slot , end_slot
) ;
2021-04-21 14:12:23 -07:00
let pubkey = verify_pubkey ( & pubkey_str ) ? ;
2021-04-12 19:33:40 -07:00
if end_slot < start_slot {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" start_slot {start_slot} must be less than or equal to end_slot {end_slot} "
2021-04-12 19:33:40 -07:00
) ) ) ;
}
if end_slot - start_slot > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE {
return Err ( Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" Slot range too large; max {MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE} "
2021-04-12 19:33:40 -07:00
) ) ) ;
}
Ok ( meta
. get_confirmed_signatures_for_address ( pubkey , start_slot , end_slot )
. iter ( )
. map ( | signature | signature . to_string ( ) )
. collect ( ) )
}
}
}
2021-08-13 09:08:20 -07:00
const MAX_BASE58_SIZE : usize = 1683 ; // Golden, bump if PACKET_DATA_SIZE changes
const MAX_BASE64_SIZE : usize = 1644 ; // Golden, bump if PACKET_DATA_SIZE changes
fn decode_and_deserialize < T > (
encoded : String ,
2022-03-09 00:09:08 -08:00
encoding : TransactionBinaryEncoding ,
2021-08-13 09:08:20 -07:00
) -> Result < ( Vec < u8 > , T ) >
where
2021-08-17 15:17:56 -07:00
T : serde ::de ::DeserializeOwned ,
2021-08-13 09:08:20 -07:00
{
let wire_output = match encoding {
2022-03-09 00:09:08 -08:00
TransactionBinaryEncoding ::Base58 = > {
2020-10-13 12:33:38 -07:00
inc_new_counter_info! ( " rpc-base58_encoded_tx " , 1 ) ;
2021-08-13 09:08:20 -07:00
if encoded . len ( ) > MAX_BASE58_SIZE {
2020-10-05 21:47:47 -07:00
return Err ( Error ::invalid_params ( format! (
2022-10-24 04:19:34 -07:00
" base58 encoded {} too large: {} bytes (max: encoded/raw {}/{}) " ,
2021-08-13 09:08:20 -07:00
type_name ::< T > ( ) ,
encoded . len ( ) ,
MAX_BASE58_SIZE ,
2020-10-05 21:47:47 -07:00
PACKET_DATA_SIZE ,
) ) ) ;
}
2021-08-13 09:08:20 -07:00
bs58 ::decode ( encoded )
2020-10-05 21:47:47 -07:00
. into_vec ( )
2022-12-06 06:30:06 -08:00
. map_err ( | e | Error ::invalid_params ( format! ( " invalid base58 encoding: {e:?} " ) ) ) ?
2020-10-05 21:47:47 -07:00
}
2022-03-09 00:09:08 -08:00
TransactionBinaryEncoding ::Base64 = > {
2020-10-13 12:33:38 -07:00
inc_new_counter_info! ( " rpc-base64_encoded_tx " , 1 ) ;
2021-08-13 09:08:20 -07:00
if encoded . len ( ) > MAX_BASE64_SIZE {
2020-10-05 21:47:47 -07:00
return Err ( Error ::invalid_params ( format! (
2022-10-24 04:19:34 -07:00
" base64 encoded {} too large: {} bytes (max: encoded/raw {}/{}) " ,
2021-08-13 09:08:20 -07:00
type_name ::< T > ( ) ,
encoded . len ( ) ,
MAX_BASE64_SIZE ,
2020-10-05 21:47:47 -07:00
PACKET_DATA_SIZE ,
) ) ) ;
}
2022-10-24 04:19:34 -07:00
base64 ::decode ( encoded )
2022-12-06 06:30:06 -08:00
. map_err ( | e | Error ::invalid_params ( format! ( " invalid base64 encoding: {e:?} " ) ) ) ?
2020-10-05 21:47:47 -07:00
}
} ;
2021-08-13 09:08:20 -07:00
if wire_output . len ( ) > PACKET_DATA_SIZE {
2022-10-24 04:19:34 -07:00
return Err ( Error ::invalid_params ( format! (
" decoded {} too large: {} bytes (max: {} bytes) " ,
2021-08-13 09:08:20 -07:00
type_name ::< T > ( ) ,
wire_output . len ( ) ,
2020-05-19 12:08:19 -07:00
PACKET_DATA_SIZE
2022-10-24 04:19:34 -07:00
) ) ) ;
2020-05-19 12:08:19 -07:00
}
2020-07-08 17:08:05 -07:00
bincode ::options ( )
. with_limit ( PACKET_DATA_SIZE as u64 )
. with_fixint_encoding ( )
. allow_trailing_bytes ( )
2021-08-13 09:08:20 -07:00
. deserialize_from ( & wire_output [ .. ] )
2020-05-19 12:08:19 -07:00
. map_err ( | err | {
2022-10-24 04:19:34 -07:00
Error ::invalid_params ( format! (
" failed to deserialize {}: {} " ,
type_name ::< T > ( ) ,
& err . to_string ( )
) )
2020-05-19 12:08:19 -07:00
} )
2021-08-13 09:08:20 -07:00
. map ( | output | ( wire_output , output ) )
2020-05-19 12:08:19 -07:00
}
2022-03-07 23:20:34 -08:00
fn sanitize_transaction (
transaction : VersionedTransaction ,
2022-03-14 21:02:22 -07:00
address_loader : impl AddressLoader ,
2022-03-07 23:20:34 -08:00
) -> Result < SanitizedTransaction > {
2022-05-06 12:19:50 -07:00
SanitizedTransaction ::try_create (
transaction ,
MessageHash ::Compute ,
None ,
address_loader ,
true , // require_static_program_ids
)
2022-12-06 06:30:06 -08:00
. map_err ( | err | Error ::invalid_params ( format! ( " invalid transaction: {err} " ) ) )
2021-08-17 15:17:56 -07:00
}
2022-12-19 18:54:05 -08:00
pub fn create_validator_exit ( exit : & Arc < AtomicBool > ) -> Arc < RwLock < Exit > > {
2021-06-03 20:06:13 -07:00
let mut validator_exit = Exit ::default ( ) ;
2020-06-16 22:30:59 -07:00
let exit_ = exit . clone ( ) ;
validator_exit . register_exit ( Box ::new ( move | | exit_ . store ( true , Ordering ::Relaxed ) ) ) ;
2021-03-01 13:20:04 -08:00
Arc ::new ( RwLock ::new ( validator_exit ) )
2020-06-16 22:30:59 -07:00
}
2022-03-07 23:20:34 -08:00
pub fn create_test_transaction_entries (
2021-06-04 08:23:06 -07:00
keypairs : Vec < & Keypair > ,
bank : Arc < Bank > ,
2022-03-07 23:20:34 -08:00
) -> ( Vec < Entry > , Vec < Signature > ) {
2021-06-04 08:23:06 -07:00
let mint_keypair = keypairs [ 0 ] ;
let keypair1 = keypairs [ 1 ] ;
let keypair2 = keypairs [ 2 ] ;
let keypair3 = keypairs [ 3 ] ;
2021-08-13 09:08:20 -07:00
let blockhash = bank . confirmed_last_blockhash ( ) ;
2022-01-11 10:32:25 -08:00
let rent_exempt_amount = bank . get_minimum_balance_for_rent_exemption ( 0 ) ;
2021-06-04 08:23:06 -07:00
2022-03-07 23:20:34 -08:00
let mut signatures = Vec ::new ( ) ;
2021-06-04 08:23:06 -07:00
// Generate transactions for processing
// Successful transaction
2022-01-11 10:32:25 -08:00
let success_tx = solana_sdk ::system_transaction ::transfer (
mint_keypair ,
& keypair1 . pubkey ( ) ,
rent_exempt_amount ,
blockhash ,
) ;
2022-03-07 23:20:34 -08:00
signatures . push ( success_tx . signatures [ 0 ] ) ;
2021-07-14 05:16:29 -07:00
let entry_1 = solana_entry ::entry ::next_entry ( & blockhash , 1 , vec! [ success_tx ] ) ;
2021-06-04 08:23:06 -07:00
// Failed transaction, InstructionError
2022-01-11 10:32:25 -08:00
let ix_error_tx = solana_sdk ::system_transaction ::transfer (
keypair2 ,
& keypair3 . pubkey ( ) ,
2 * rent_exempt_amount ,
blockhash ,
) ;
2022-03-07 23:20:34 -08:00
signatures . push ( ix_error_tx . signatures [ 0 ] ) ;
2021-07-14 05:16:29 -07:00
let entry_2 = solana_entry ::entry ::next_entry ( & entry_1 . hash , 1 , vec! [ ix_error_tx ] ) ;
2022-03-07 23:20:34 -08:00
( vec! [ entry_1 , entry_2 ] , signatures )
}
2021-06-04 08:23:06 -07:00
2022-03-07 23:20:34 -08:00
pub fn populate_blockstore_for_tests (
entries : Vec < Entry > ,
bank : Arc < Bank > ,
blockstore : Arc < Blockstore > ,
max_complete_transaction_status_slot : Arc < AtomicU64 > ,
) {
let slot = bank . slot ( ) ;
let parent_slot = bank . parent_slot ( ) ;
2022-09-15 14:51:41 -07:00
let shreds = solana_ledger ::blockstore ::entries_to_test_shreds (
& entries ,
slot ,
parent_slot ,
true ,
0 ,
true , // merkle_variant
) ;
2021-06-04 08:23:06 -07:00
blockstore . insert_shreds ( shreds , None , false ) . unwrap ( ) ;
2021-07-01 20:02:40 -07:00
blockstore . set_roots ( std ::iter ::once ( & slot ) ) . unwrap ( ) ;
2021-06-04 08:23:06 -07:00
2022-01-11 02:44:46 -08:00
let ( transaction_status_sender , transaction_status_receiver ) = unbounded ( ) ;
let ( replay_vote_sender , _replay_vote_receiver ) = unbounded ( ) ;
2021-06-04 08:23:06 -07:00
let transaction_status_service =
crate ::transaction_status_service ::TransactionStatusService ::new (
transaction_status_receiver ,
max_complete_transaction_status_slot ,
2021-11-23 09:55:53 -08:00
true ,
None ,
2021-06-04 08:23:06 -07:00
blockstore ,
2022-02-11 20:29:07 -08:00
false ,
2021-06-04 08:23:06 -07:00
& Arc ::new ( AtomicBool ::new ( false ) ) ,
) ;
// Check that process_entries successfully writes can_commit transactions statuses, and
// that they are matched properly by get_rooted_block
2022-02-09 21:28:18 -08:00
assert_eq! (
solana_ledger ::blockstore_processor ::process_entries_for_tests (
& bank ,
entries ,
true ,
Some (
& solana_ledger ::blockstore_processor ::TransactionStatusSender {
sender : transaction_status_sender ,
} ,
) ,
Some ( & replay_vote_sender ) ,
2021-06-04 08:23:06 -07:00
) ,
2022-02-09 21:28:18 -08:00
Ok ( ( ) )
2021-06-04 08:23:06 -07:00
) ;
transaction_status_service . join ( ) . unwrap ( ) ;
}
2018-08-13 10:24:39 -07:00
#[ cfg(test) ]
2019-08-20 23:59:31 -07:00
pub mod tests {
2021-06-04 08:23:06 -07:00
use {
2021-08-13 09:08:20 -07:00
super ::{
2022-11-29 09:08:19 -08:00
rpc_accounts ::* , rpc_accounts_scan ::* , rpc_bank ::* , rpc_deprecated_v1_9 ::* ,
rpc_full ::* , rpc_minimal ::* , * ,
2021-08-13 09:08:20 -07:00
} ,
2021-06-04 08:23:06 -07:00
crate ::{
optimistically_confirmed_bank_tracker ::{
BankNotification , OptimisticallyConfirmedBankTracker ,
} ,
rpc_subscriptions ::RpcSubscriptions ,
2021-05-18 23:54:28 -07:00
} ,
2021-06-04 08:23:06 -07:00
bincode ::deserialize ,
jsonrpc_core ::{ futures , ErrorCode , MetaIoHandler , Output , Response , Value } ,
jsonrpc_core_client ::transports ::local ,
2022-03-04 02:20:11 -08:00
serde ::de ::DeserializeOwned ,
2022-03-07 23:20:34 -08:00
solana_address_lookup_table_program ::state ::{ AddressLookupTable , LookupTableMeta } ,
solana_entry ::entry ::next_versioned_entry ,
2023-01-08 08:00:55 -08:00
solana_gossip ::socketaddr ,
2021-06-04 08:23:06 -07:00
solana_ledger ::{
2023-01-12 19:14:04 -08:00
blockstore_meta ::PerfSampleV2 ,
2021-06-04 08:23:06 -07:00
blockstore_processor ::fill_blockstore_slot_with_ticks ,
genesis_utils ::{ create_genesis_config , GenesisConfigInfo } ,
} ,
2022-08-24 09:47:02 -07:00
solana_rpc_client_api ::{
custom_error ::{
JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE ,
JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE ,
JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION ,
} ,
filter ::{ Memcmp , MemcmpEncodedBytes } ,
} ,
2021-06-04 08:23:06 -07:00
solana_runtime ::{
2022-11-16 19:39:11 -08:00
accounts_background_service ::AbsRequestSender , bank ::BankTestConfig ,
commitment ::BlockCommitment , inline_spl_token ,
non_circulating_supply ::non_circulating_accounts ,
2021-06-04 08:23:06 -07:00
} ,
solana_sdk ::{
2022-03-04 02:20:11 -08:00
account ::{ Account , WritableAccount } ,
2021-06-04 08:23:06 -07:00
clock ::MAX_RECENT_BLOCKHASHES ,
2022-09-01 16:12:12 -07:00
compute_budget ::ComputeBudgetInstruction ,
2022-10-04 09:00:34 -07:00
fee_calculator ::{ FeeRateGovernor , DEFAULT_BURN_PERCENT } ,
2021-06-04 08:23:06 -07:00
hash ::{ hash , Hash } ,
instruction ::InstructionError ,
2022-10-04 09:00:34 -07:00
message ::{
v0 ::{ self , MessageAddressTableLookup } ,
Message , MessageHeader , VersionedMessage ,
} ,
2022-06-03 07:36:27 -07:00
nonce ::{ self , state ::DurableNonce } ,
rpc_port ,
2021-06-04 08:23:06 -07:00
signature ::{ Keypair , Signer } ,
2022-03-07 23:20:34 -08:00
slot_hashes ::SlotHashes ,
2021-06-04 08:23:06 -07:00
system_program , system_transaction ,
timing ::slot_duration_from_slots_per_year ,
2022-03-07 23:20:34 -08:00
transaction ::{
2022-03-14 21:02:22 -07:00
self , SimpleAddressLoader , Transaction , TransactionError , TransactionVersion ,
2022-03-07 23:20:34 -08:00
} ,
2021-06-04 08:23:06 -07:00
} ,
solana_transaction_status ::{
EncodedConfirmedBlock , EncodedTransaction , EncodedTransactionWithStatusMeta ,
2022-03-04 02:20:11 -08:00
TransactionDetails ,
2021-06-04 08:23:06 -07:00
} ,
solana_vote_program ::{
vote_instruction ,
2022-08-03 23:12:59 -07:00
vote_state ::{ self , Vote , VoteInit , VoteStateVersions , MAX_LOCKOUT_HISTORY } ,
2021-06-04 08:23:06 -07:00
} ,
2022-05-17 12:02:43 -07:00
spl_token_2022 ::{
extension ::{
immutable_owner ::ImmutableOwner , memo_transfer ::MemoTransfer ,
mint_close_authority ::MintCloseAuthority , ExtensionType , StateWithExtensionsMut ,
} ,
pod ::OptionalNonZeroPubkey ,
2021-06-04 08:23:06 -07:00
solana_program ::{ program_option ::COption , pubkey ::Pubkey as SplTokenPubkey } ,
2021-12-03 09:00:31 -08:00
state ::{ AccountState as TokenAccountState , Mint } ,
2021-06-04 08:23:06 -07:00
} ,
2022-03-07 23:20:34 -08:00
std ::{ borrow ::Cow , collections ::HashMap } ,
2020-07-30 14:52:28 -07:00
} ;
2018-08-13 10:24:39 -07:00
2022-10-04 09:00:34 -07:00
const TEST_MINT_LAMPORTS : u64 = 1_000_000_000 ;
const TEST_SIGNATURE_FEE : u64 = 5_000 ;
2020-06-09 08:43:16 -07:00
const TEST_SLOTS_PER_EPOCH : u64 = DELINQUENT_VALIDATOR_SLOT_DISTANCE + 1 ;
2019-06-21 21:00:26 -07:00
2023-01-24 08:57:55 -08:00
pub ( crate ) fn new_test_cluster_info ( ) -> ClusterInfo {
let keypair = Arc ::new ( Keypair ::new ( ) ) ;
let contact_info = ContactInfo {
id : keypair . pubkey ( ) ,
.. ContactInfo ::default ( )
} ;
ClusterInfo ::new ( contact_info , keypair , SocketAddrSpace ::Unspecified )
}
2022-03-04 02:20:11 -08:00
fn create_test_request ( method : & str , params : Option < serde_json ::Value > ) -> serde_json ::Value {
json! ( {
" jsonrpc " : " 2.0 " ,
" id " : 1 u64 ,
" method " : method ,
" params " : params ,
} )
}
fn parse_success_result < T : DeserializeOwned > ( response : Response ) -> T {
if let Response ::Single ( output ) = response {
match output {
Output ::Success ( success ) = > serde_json ::from_value ( success . result ) . unwrap ( ) ,
Output ::Failure ( failure ) = > {
2022-12-06 06:30:06 -08:00
panic! ( " Expected success but received: {failure:?} " ) ;
2022-03-04 02:20:11 -08:00
}
}
} else {
panic! ( " Expected single response " ) ;
}
}
fn parse_failure_response ( response : Response ) -> ( i64 , String ) {
if let Response ::Single ( output ) = response {
match output {
Output ::Success ( success ) = > {
2022-12-06 06:30:06 -08:00
panic! ( " Expected failure but received: {success:?} " ) ;
2022-03-04 02:20:11 -08:00
}
Output ::Failure ( failure ) = > ( failure . error . code . code ( ) , failure . error . message ) ,
}
} else {
panic! ( " Expected single response " ) ;
}
}
2019-10-14 15:24:10 -07:00
struct RpcHandler {
2020-06-07 20:54:03 -07:00
io : MetaIoHandler < JsonRpcRequestProcessor > ,
meta : JsonRpcRequestProcessor ,
2022-03-04 02:20:11 -08:00
identity : Pubkey ,
mint_keypair : Keypair ,
2020-07-23 18:50:42 -07:00
leader_vote_keypair : Arc < Keypair > ,
2022-03-04 02:20:11 -08:00
blockstore : Arc < Blockstore > ,
bank_forks : Arc < RwLock < BankForks > > ,
max_slots : Arc < MaxSlots > ,
max_complete_transaction_status_slot : Arc < AtomicU64 > ,
2019-11-04 15:44:27 -08:00
block_commitment_cache : Arc < RwLock < BlockCommitmentCache > > ,
2019-10-14 15:24:10 -07:00
}
2022-03-04 02:20:11 -08:00
impl RpcHandler {
fn start ( ) -> Self {
2022-11-16 19:39:11 -08:00
Self ::start_with_config ( JsonRpcConfig {
enable_rpc_transaction_history : true ,
.. JsonRpcConfig ::default ( )
} )
}
fn start_with_config ( config : JsonRpcConfig ) -> Self {
let ( bank_forks , mint_keypair , leader_vote_keypair ) =
new_bank_forks_with_config ( BankTestConfig {
secondary_indexes : config . account_indexes . clone ( ) ,
} ) ;
2022-03-04 02:20:11 -08:00
let ledger_path = get_tmp_ledger_path! ( ) ;
let blockstore = Arc ::new ( Blockstore ::open ( & ledger_path ) . unwrap ( ) ) ;
let bank = bank_forks . read ( ) . unwrap ( ) . working_bank ( ) ;
let leader_pubkey = * bank . collector_id ( ) ;
let block_commitment_cache = Arc ::new ( RwLock ::new ( BlockCommitmentCache ::default ( ) ) ) ;
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
let validator_exit = create_validator_exit ( & exit ) ;
2023-01-24 08:57:55 -08:00
let cluster_info = Arc ::new ( new_test_cluster_info ( ) ) ;
let identity = cluster_info . id ( ) ;
2023-02-01 05:07:42 -08:00
cluster_info . insert_info ( ContactInfo ::new_with_socketaddr (
2022-03-04 02:20:11 -08:00
& leader_pubkey ,
& socketaddr! ( " 127.0.0.1:1234 " ) ,
) ) ;
let max_slots = Arc ::new ( MaxSlots ::default ( ) ) ;
// note that this means that slot 0 will always be considered complete
let max_complete_transaction_status_slot = Arc ::new ( AtomicU64 ::new ( 0 ) ) ;
let meta = JsonRpcRequestProcessor ::new (
2022-11-16 19:39:11 -08:00
config ,
2022-03-04 02:20:11 -08:00
None ,
bank_forks . clone ( ) ,
block_commitment_cache . clone ( ) ,
blockstore . clone ( ) ,
validator_exit ,
RpcHealth ::stub ( ) ,
cluster_info ,
Hash ::default ( ) ,
None ,
OptimisticallyConfirmedBank ::locked_from_bank_forks_root ( & bank_forks ) ,
Arc ::new ( RwLock ::new ( LargestAccountsCache ::new ( 30 ) ) ) ,
max_slots . clone ( ) ,
Arc ::new ( LeaderScheduleCache ::new_from_bank ( & bank ) ) ,
max_complete_transaction_status_slot . clone ( ) ,
2022-09-01 16:12:12 -07:00
Arc ::new ( PrioritizationFeeCache ::default ( ) ) ,
2022-03-04 02:20:11 -08:00
)
. 0 ;
let mut io = MetaIoHandler ::default ( ) ;
io . extend_with ( rpc_minimal ::MinimalImpl . to_delegate ( ) ) ;
io . extend_with ( rpc_bank ::BankDataImpl . to_delegate ( ) ) ;
io . extend_with ( rpc_accounts ::AccountsDataImpl . to_delegate ( ) ) ;
2022-11-29 09:08:19 -08:00
io . extend_with ( rpc_accounts_scan ::AccountsScanImpl . to_delegate ( ) ) ;
2022-03-04 02:20:11 -08:00
io . extend_with ( rpc_full ::FullImpl . to_delegate ( ) ) ;
io . extend_with ( rpc_deprecated_v1_9 ::DeprecatedV1_9Impl . to_delegate ( ) ) ;
Self {
io ,
meta ,
identity ,
mint_keypair ,
leader_vote_keypair ,
bank_forks ,
blockstore ,
max_slots ,
max_complete_transaction_status_slot ,
block_commitment_cache ,
}
}
2021-01-11 15:27:30 -08:00
2022-03-04 02:20:11 -08:00
fn handle_request_sync ( & self , req : serde_json ::Value ) -> Response {
let response = & self
. io
. handle_request_sync ( & req . to_string ( ) , self . meta . clone ( ) )
. expect ( " no response " ) ;
serde_json ::from_str ( response ) . expect ( " failed to deserialize response " )
}
2019-11-25 11:08:03 -08:00
2022-03-07 23:20:34 -08:00
fn overwrite_working_bank_entries ( & self , entries : Vec < Entry > ) {
populate_blockstore_for_tests (
entries ,
self . working_bank ( ) ,
self . blockstore . clone ( ) ,
self . max_complete_transaction_status_slot . clone ( ) ,
) ;
}
2022-03-04 02:20:11 -08:00
fn create_test_transactions_and_populate_blockstore ( & self ) -> Vec < Signature > {
let mint_keypair = & self . mint_keypair ;
let keypair1 = Keypair ::new ( ) ;
let keypair2 = Keypair ::new ( ) ;
let keypair3 = Keypair ::new ( ) ;
2022-03-07 23:20:34 -08:00
let bank = self . working_bank ( ) ;
2022-03-04 02:20:11 -08:00
let rent_exempt_amount = bank . get_minimum_balance_for_rent_exemption ( 0 ) ;
2022-10-04 09:00:34 -07:00
bank . transfer (
rent_exempt_amount + TEST_SIGNATURE_FEE ,
mint_keypair ,
& keypair2 . pubkey ( ) ,
)
. unwrap ( ) ;
2022-03-07 23:20:34 -08:00
let ( entries , signatures ) = create_test_transaction_entries (
2022-03-04 02:20:11 -08:00
vec! [ & self . mint_keypair , & keypair1 , & keypair2 , & keypair3 ] ,
bank ,
2022-03-07 23:20:34 -08:00
) ;
self . overwrite_working_bank_entries ( entries ) ;
signatures
}
fn create_test_versioned_transactions_and_populate_blockstore (
& self ,
address_table_key : Option < Pubkey > ,
) -> Vec < Signature > {
let address_table_key =
address_table_key . unwrap_or_else ( | | self . store_address_lookup_table ( ) ) ;
let bank = self . working_bank ( ) ;
let recent_blockhash = bank . confirmed_last_blockhash ( ) ;
let legacy_message = VersionedMessage ::Legacy ( Message {
header : MessageHeader {
num_required_signatures : 1 ,
num_readonly_signed_accounts : 0 ,
num_readonly_unsigned_accounts : 0 ,
} ,
recent_blockhash ,
account_keys : vec ! [ self . mint_keypair . pubkey ( ) ] ,
instructions : vec ! [ ] ,
} ) ;
let version_0_message = VersionedMessage ::V0 ( v0 ::Message {
header : MessageHeader {
num_required_signatures : 1 ,
num_readonly_signed_accounts : 0 ,
num_readonly_unsigned_accounts : 0 ,
} ,
recent_blockhash ,
account_keys : vec ! [ self . mint_keypair . pubkey ( ) ] ,
address_table_lookups : vec ! [ MessageAddressTableLookup {
account_key : address_table_key ,
writable_indexes : vec ! [ 0 ] ,
readonly_indexes : vec ! [ ] ,
} ] ,
instructions : vec ! [ ] ,
} ) ;
let mut signatures = Vec ::new ( ) ;
let legacy_tx =
VersionedTransaction ::try_new ( legacy_message , & [ & self . mint_keypair ] ) . unwrap ( ) ;
signatures . push ( legacy_tx . signatures [ 0 ] ) ;
let version_0_tx =
VersionedTransaction ::try_new ( version_0_message , & [ & self . mint_keypair ] ) . unwrap ( ) ;
signatures . push ( version_0_tx . signatures [ 0 ] ) ;
let entry1 = next_versioned_entry ( & recent_blockhash , 1 , vec! [ legacy_tx ] ) ;
let entry2 = next_versioned_entry ( & entry1 . hash , 1 , vec! [ version_0_tx ] ) ;
let entries = vec! [ entry1 , entry2 ] ;
self . overwrite_working_bank_entries ( entries ) ;
signatures
}
fn store_address_lookup_table ( & self ) -> Pubkey {
let bank = self . working_bank ( ) ;
let address_table_pubkey = Pubkey ::new_unique ( ) ;
let address_table_account = {
let address_table_state = AddressLookupTable {
meta : LookupTableMeta {
// ensure that active address length is 1 at slot 0
last_extended_slot_start_index : 1 ,
.. LookupTableMeta ::default ( )
} ,
addresses : Cow ::Owned ( vec! [ Pubkey ::new_unique ( ) ] ) ,
} ;
let address_table_data = address_table_state . serialize_for_tests ( ) . unwrap ( ) ;
let min_balance_lamports =
bank . get_minimum_balance_for_rent_exemption ( address_table_data . len ( ) ) ;
AccountSharedData ::create (
min_balance_lamports ,
address_table_data ,
solana_address_lookup_table_program ::id ( ) ,
false ,
0 ,
)
} ;
bank . store_account ( & address_table_pubkey , & address_table_account ) ;
address_table_pubkey
2022-03-04 02:20:11 -08:00
}
2019-10-14 15:24:10 -07:00
2022-03-04 02:20:11 -08:00
fn add_roots_to_blockstore ( & self , mut roots : Vec < Slot > ) {
roots . retain ( | & slot | slot > 0 ) ;
if roots . is_empty ( ) {
return ;
}
2020-03-30 10:29:30 -07:00
2022-03-04 02:20:11 -08:00
let mut parent_bank = self . bank_forks . read ( ) . unwrap ( ) . working_bank ( ) ;
2019-12-18 15:51:47 -08:00
for ( i , root ) in roots . iter ( ) . enumerate ( ) {
let new_bank =
Bank ::new_from_parent ( & parent_bank , parent_bank . collector_id ( ) , * root ) ;
2022-03-04 02:20:11 -08:00
parent_bank = self . bank_forks . write ( ) . unwrap ( ) . insert ( new_bank ) ;
2020-04-28 10:20:43 -07:00
let parent = if i > 0 { roots [ i - 1 ] } else { 0 } ;
2022-03-04 02:20:11 -08:00
fill_blockstore_slot_with_ticks (
& self . blockstore ,
5 ,
* root ,
parent ,
Hash ::default ( ) ,
) ;
2019-12-18 15:51:47 -08:00
}
2022-03-04 02:20:11 -08:00
self . blockstore . set_roots ( roots . iter ( ) ) . unwrap ( ) ;
2019-12-18 15:51:47 -08:00
let new_bank = Bank ::new_from_parent (
& parent_bank ,
parent_bank . collector_id ( ) ,
roots . iter ( ) . max ( ) . unwrap ( ) + 1 ,
) ;
2022-03-04 02:20:11 -08:00
self . bank_forks . write ( ) . unwrap ( ) . insert ( new_bank ) ;
2020-04-28 10:20:43 -07:00
for root in roots . iter ( ) {
2022-03-04 02:20:11 -08:00
self . bank_forks . write ( ) . unwrap ( ) . set_root (
* root ,
& AbsRequestSender ::default ( ) ,
Some ( 0 ) ,
2021-03-09 13:06:07 -08:00
) ;
2022-03-04 02:20:11 -08:00
let block_time = self
. bank_forks
2020-10-26 12:23:45 -07:00
. read ( )
. unwrap ( )
. get ( * root )
. unwrap ( )
. clock ( )
. unix_timestamp ;
2022-03-04 02:20:11 -08:00
self . blockstore . cache_block_time ( * root , block_time ) . unwrap ( ) ;
2020-04-28 10:20:43 -07:00
}
2019-12-18 15:51:47 -08:00
}
2022-03-04 02:20:11 -08:00
fn advance_bank_to_confirmed_slot ( & self , slot : Slot ) -> Arc < Bank > {
let parent_bank = self . working_bank ( ) ;
let bank = self
. bank_forks
. write ( )
. unwrap ( )
. insert ( Bank ::new_from_parent (
& parent_bank ,
& Pubkey ::default ( ) ,
slot ,
) ) ;
2020-09-22 12:26:32 -07:00
2022-07-11 04:33:15 -07:00
let new_block_commitment = BlockCommitmentCache ::new (
2022-03-04 02:20:11 -08:00
HashMap ::new ( ) ,
0 ,
CommitmentSlots ::new_from_slot ( self . bank_forks . read ( ) . unwrap ( ) . highest_slot ( ) ) ,
) ;
2022-07-11 04:33:15 -07:00
* self . block_commitment_cache . write ( ) . unwrap ( ) = new_block_commitment ;
2022-03-04 02:20:11 -08:00
bank
}
2021-02-23 13:06:33 -08:00
2022-03-04 02:20:11 -08:00
fn store_vote_account ( & self , vote_pubkey : & Pubkey , vote_state : VoteState ) {
let bank = self . working_bank ( ) ;
let versioned = VoteStateVersions ::new_current ( vote_state ) ;
let space = VoteState ::size_of ( ) ;
let balance = bank . get_minimum_balance_for_rent_exemption ( space ) ;
let mut vote_account =
AccountSharedData ::new ( balance , space , & solana_vote_program ::id ( ) ) ;
2022-08-03 23:12:59 -07:00
vote_state ::to ( & versioned , & mut vote_account ) . unwrap ( ) ;
2022-03-04 02:20:11 -08:00
bank . store_account ( vote_pubkey , & vote_account ) ;
}
2018-08-13 10:24:39 -07:00
2022-09-01 16:12:12 -07:00
fn update_prioritization_fee_cache ( & self , transactions : Vec < Transaction > ) {
let bank = self . working_bank ( ) ;
let prioritization_fee_cache = & self . meta . prioritization_fee_cache ;
let transactions : Vec < _ > = transactions
. into_iter ( )
. map ( | tx | SanitizedTransaction ::try_from_legacy_transaction ( tx ) . unwrap ( ) )
. collect ( ) ;
prioritization_fee_cache . update ( bank , transactions . iter ( ) ) ;
}
fn get_prioritization_fee_cache ( & self ) -> & PrioritizationFeeCache {
& self . meta . prioritization_fee_cache
}
2022-03-04 02:20:11 -08:00
fn working_bank ( & self ) -> Arc < Bank > {
self . bank_forks . read ( ) . unwrap ( ) . working_bank ( )
}
2020-06-05 21:23:13 -07:00
2022-03-04 02:20:11 -08:00
fn leader_pubkey ( & self ) -> Pubkey {
* self . working_bank ( ) . collector_id ( )
2019-10-14 15:24:10 -07:00
}
2018-10-15 10:01:40 -07:00
}
#[ test ]
fn test_rpc_request_processor_new ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-06-16 22:30:59 -07:00
let genesis = create_genesis_config ( 100 ) ;
2021-08-05 06:42:38 -07:00
let bank = Arc ::new ( Bank ::new_for_tests ( & genesis . genesis_config ) ) ;
2020-06-16 22:30:59 -07:00
bank . transfer ( 20 , & genesis . mint_keypair , & bob_pubkey )
. unwrap ( ) ;
2022-06-08 04:57:12 -07:00
let connection_cache = Arc ::new ( ConnectionCache ::default ( ) ) ;
let request_processor = JsonRpcRequestProcessor ::new_from_bank (
& bank ,
SocketAddrSpace ::Unspecified ,
connection_cache ,
) ;
2022-05-16 23:46:02 -07:00
assert_eq! (
request_processor
. get_transaction_count ( RpcContextConfig ::default ( ) )
. unwrap ( ) ,
1
) ;
2018-10-15 10:01:40 -07:00
}
#[ test ]
fn test_rpc_get_balance ( ) {
2020-06-16 22:30:59 -07:00
let genesis = create_genesis_config ( 20 ) ;
let mint_pubkey = genesis . mint_keypair . pubkey ( ) ;
2021-08-05 06:42:38 -07:00
let bank = Arc ::new ( Bank ::new_for_tests ( & genesis . genesis_config ) ) ;
2022-06-08 04:57:12 -07:00
let connection_cache = Arc ::new ( ConnectionCache ::default ( ) ) ;
let meta = JsonRpcRequestProcessor ::new_from_bank (
& bank ,
SocketAddrSpace ::Unspecified ,
connection_cache ,
) ;
2020-06-16 22:30:59 -07:00
let mut io = MetaIoHandler ::default ( ) ;
2021-02-26 21:42:09 -08:00
io . extend_with ( rpc_minimal ::MinimalImpl . to_delegate ( ) ) ;
2018-08-14 17:03:48 -07:00
2018-08-13 10:24:39 -07:00
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["{mint_pubkey}"]}}"#
2018-08-13 10:24:39 -07:00
) ;
2018-10-15 10:01:40 -07:00
let res = io . handle_request_sync ( & req , meta ) ;
2019-11-12 11:49:41 -08:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2019-11-12 11:49:41 -08:00
" value " :20 ,
} ,
" id " : 1 ,
} ) ;
let result = serde_json ::from_str ::< Value > ( & res . expect ( " actual response " ) )
2018-08-13 10:24:39 -07:00
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2018-10-15 10:01:40 -07:00
}
2020-06-11 15:51:25 -07:00
#[ test ]
fn test_rpc_get_balance_via_client ( ) {
2020-06-16 22:30:59 -07:00
let genesis = create_genesis_config ( 20 ) ;
let mint_pubkey = genesis . mint_keypair . pubkey ( ) ;
2021-08-05 06:42:38 -07:00
let bank = Arc ::new ( Bank ::new_for_tests ( & genesis . genesis_config ) ) ;
2022-06-08 04:57:12 -07:00
let connection_cache = Arc ::new ( ConnectionCache ::default ( ) ) ;
let meta = JsonRpcRequestProcessor ::new_from_bank (
& bank ,
SocketAddrSpace ::Unspecified ,
connection_cache ,
) ;
2020-06-16 22:30:59 -07:00
let mut io = MetaIoHandler ::default ( ) ;
2021-02-26 21:42:09 -08:00
io . extend_with ( rpc_minimal ::MinimalImpl . to_delegate ( ) ) ;
2020-06-16 22:30:59 -07:00
2021-02-26 21:42:09 -08:00
async fn use_client ( client : rpc_minimal ::gen_client ::Client , mint_pubkey : Pubkey ) -> u64 {
2020-06-11 15:51:25 -07:00
client
2020-06-16 22:30:59 -07:00
. get_balance ( mint_pubkey . to_string ( ) , None )
2021-02-02 18:53:08 -08:00
. await
. unwrap ( )
. value
}
let fut = async {
let ( client , server ) =
2021-02-26 21:42:09 -08:00
local ::connect_with_metadata ::< rpc_minimal ::gen_client ::Client , _ , _ > ( & io , meta ) ;
2021-02-02 18:53:08 -08:00
let client = use_client ( client , mint_pubkey ) ;
futures ::join! ( client , server )
2020-06-11 15:51:25 -07:00
} ;
2021-02-02 18:53:08 -08:00
let ( response , _ ) = futures ::executor ::block_on ( fut ) ;
assert_eq! ( response , 20 ) ;
2020-06-11 15:51:25 -07:00
}
2019-04-23 14:46:41 -07:00
#[ test ]
fn test_rpc_get_cluster_nodes ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let request = create_test_request ( " getClusterNodes " , None ) ;
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = json! ( [ {
" pubkey " : rpc . leader_pubkey ( ) . to_string ( ) ,
" gossip " : " 127.0.0.1:1235 " ,
" shredVersion " : 0 u16 ,
" tpu " : " 127.0.0.1:1234 " ,
" rpc " : format ! ( " 127.0.0.1:{} " , rpc_port ::DEFAULT_RPC_PORT ) ,
2023-01-08 21:25:56 -08:00
" pubsub " : format ! ( " 127.0.0.1:{} " , rpc_port ::DEFAULT_RPC_PUBSUB_PORT ) ,
2022-03-04 02:20:11 -08:00
" version " : null ,
" featureSet " : null ,
} ] ) ;
assert_eq! ( result , expected ) ;
2019-04-23 14:46:41 -07:00
}
2020-09-22 12:26:32 -07:00
#[ test ]
fn test_rpc_get_recent_performance_samples ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let slot = 0 ;
let num_slots = 1 ;
let num_transactions = 4 ;
2023-01-12 19:14:04 -08:00
let num_non_vote_transactions = 1 ;
2022-03-04 02:20:11 -08:00
let sample_period_secs = 60 ;
rpc . blockstore
. write_perf_sample (
slot ,
2023-01-12 19:14:04 -08:00
& PerfSampleV2 {
2022-03-04 02:20:11 -08:00
num_slots ,
num_transactions ,
2023-01-12 19:14:04 -08:00
num_non_vote_transactions ,
2022-03-04 02:20:11 -08:00
sample_period_secs ,
} ,
)
. expect ( " write to blockstore " ) ;
2020-09-22 12:26:32 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getRecentPerformanceSamples " , None ) ;
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = json! ( [ {
" slot " : slot ,
" numSlots " : num_slots ,
" numTransactions " : num_transactions ,
2023-01-18 00:22:47 -08:00
" numNonVoteTransactions " : num_non_vote_transactions ,
2022-03-04 02:20:11 -08:00
" samplePeriodSecs " : sample_period_secs ,
} ] ) ;
assert_eq! ( result , expected ) ;
2020-09-22 12:26:32 -07:00
}
#[ test ]
fn test_rpc_get_recent_performance_samples_invalid_limit ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let request = create_test_request ( " getRecentPerformanceSamples " , Some ( json! ( [ 10_000 ] ) ) ) ;
let response = parse_failure_response ( rpc . handle_request_sync ( request ) ) ;
let expected = (
ErrorCode ::InvalidParams . code ( ) ,
String ::from ( " Invalid limit; max 720 " ) ,
) ;
assert_eq! ( response , expected ) ;
2020-09-22 12:26:32 -07:00
}
2019-04-23 14:46:41 -07:00
#[ test ]
fn test_rpc_get_slot_leader ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let request = create_test_request ( " getSlotLeader " , None ) ;
let result : String = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = rpc . leader_pubkey ( ) . to_string ( ) ;
assert_eq! ( result , expected ) ;
2019-04-23 14:46:41 -07:00
}
2018-10-15 10:01:40 -07:00
#[ test ]
fn test_rpc_get_tx_count ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-06-16 22:30:59 -07:00
let genesis = create_genesis_config ( 10 ) ;
2021-08-05 06:42:38 -07:00
let bank = Arc ::new ( Bank ::new_for_tests ( & genesis . genesis_config ) ) ;
2020-06-16 22:30:59 -07:00
// Add 4 transactions
bank . transfer ( 1 , & genesis . mint_keypair , & bob_pubkey )
. unwrap ( ) ;
bank . transfer ( 2 , & genesis . mint_keypair , & bob_pubkey )
. unwrap ( ) ;
bank . transfer ( 3 , & genesis . mint_keypair , & bob_pubkey )
. unwrap ( ) ;
bank . transfer ( 4 , & genesis . mint_keypair , & bob_pubkey )
. unwrap ( ) ;
2022-06-08 04:57:12 -07:00
let connection_cache = Arc ::new ( ConnectionCache ::default ( ) ) ;
let meta = JsonRpcRequestProcessor ::new_from_bank (
& bank ,
SocketAddrSpace ::Unspecified ,
connection_cache ,
) ;
2020-06-16 22:30:59 -07:00
let mut io = MetaIoHandler ::default ( ) ;
2021-02-26 21:42:09 -08:00
io . extend_with ( rpc_minimal ::MinimalImpl . to_delegate ( ) ) ;
2018-08-13 10:24:39 -07:00
2020-05-15 09:35:43 -07:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}"# ;
2021-06-18 06:34:46 -07:00
let res = io . handle_request_sync ( req , meta ) ;
2020-05-15 09:35:43 -07:00
let expected = r # "{"jsonrpc":"2.0","result":4,"id":1}"# ;
2018-08-14 17:03:48 -07:00
let expected : Response =
2021-06-18 06:34:46 -07:00
serde_json ::from_str ( expected ) . expect ( " expected response deserialization " ) ;
2018-08-14 17:03:48 -07:00
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
2020-01-21 12:05:04 -08:00
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-01-21 12:05:04 -08:00
}
#[ test ]
fn test_rpc_minimum_ledger_slot ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
// populate blockstore so that a minimum slot can be detected
rpc . create_test_transactions_and_populate_blockstore ( ) ;
let request = create_test_request ( " minimumLedgerSlot " , None ) ;
let result : Slot = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( 0 , result ) ;
2018-10-15 10:01:40 -07:00
}
2020-05-12 20:05:05 -07:00
#[ test ]
fn test_get_supply ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let request = create_test_request ( " getSupply " , None ) ;
let result = {
let mut result : RpcResponse < RpcSupply > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
result . value . non_circulating_accounts . sort ( ) ;
result . value
} ;
let expected = {
let mut non_circulating_accounts : Vec < String > = non_circulating_accounts ( )
. iter ( )
. map ( | pubkey | pubkey . to_string ( ) )
. collect ( ) ;
non_circulating_accounts . sort ( ) ;
let total_capitalization = rpc . working_bank ( ) . capitalization ( ) ;
RpcSupply {
non_circulating : 0 ,
circulating : total_capitalization ,
total : total_capitalization ,
non_circulating_accounts ,
}
} ;
assert_eq! ( result , expected ) ;
2020-05-12 20:05:05 -07:00
}
2021-08-17 16:32:58 -07:00
#[ test ]
fn test_get_supply_exclude_account_list ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let request = create_test_request (
" getSupply " ,
Some ( json! ( [ { " excludeNonCirculatingAccountsList " : true } ] ) ) ,
) ;
let result : RpcResponse < RpcSupply > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = {
let total_capitalization = rpc . working_bank ( ) . capitalization ( ) ;
RpcSupply {
non_circulating : 0 ,
circulating : total_capitalization ,
total : total_capitalization ,
non_circulating_accounts : vec ! [ ] ,
}
} ;
assert_eq! ( result . value , expected ) ;
2021-08-17 16:32:58 -07:00
}
2020-05-04 16:46:10 -07:00
#[ test ]
fn test_get_largest_accounts ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
// make a non-circulating account one of the largest accounts
let non_circulating_key = & non_circulating_accounts ( ) [ 0 ] ;
let bank = rpc . working_bank ( ) ;
bank . process_transaction ( & system_transaction ::transfer (
& rpc . mint_keypair ,
non_circulating_key ,
500_000 ,
bank . confirmed_last_blockhash ( ) ,
) )
. expect ( " process transaction " ) ;
let request = create_test_request ( " getLargestAccounts " , None ) ;
let largest_accounts_result : RpcResponse < Vec < RpcAccountBalance > > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( largest_accounts_result . value . len ( ) , 20 ) ;
// Get mint balance
let request = create_test_request (
" getBalance " ,
Some ( json! ( [ rpc . mint_keypair . pubkey ( ) . to_string ( ) ] ) ) ,
) ;
let mint_balance_result : RpcResponse < u64 > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert! ( largest_accounts_result . value . contains ( & RpcAccountBalance {
address : rpc . mint_keypair . pubkey ( ) . to_string ( ) ,
lamports : mint_balance_result . value ,
2020-05-04 16:46:10 -07:00
} ) ) ;
2022-03-04 02:20:11 -08:00
// Get non-circulating account balance
let request =
create_test_request ( " getBalance " , Some ( json! ( [ non_circulating_key . to_string ( ) ] ) ) ) ;
let non_circulating_balance_result : RpcResponse < u64 > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert! ( largest_accounts_result . value . contains ( & RpcAccountBalance {
address : non_circulating_key . to_string ( ) ,
lamports : non_circulating_balance_result . value ,
2020-05-04 16:46:10 -07:00
} ) ) ;
2020-05-12 20:05:05 -07:00
// Test Circulating/NonCirculating Filter
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getLargestAccounts " ,
Some ( json! ( [ { " filter " :" circulating " } ] ) ) ,
) ;
let largest_accounts_result : RpcResponse < Vec < RpcAccountBalance > > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( largest_accounts_result . value . len ( ) , 20 ) ;
assert! ( ! largest_accounts_result . value . contains ( & RpcAccountBalance {
address : non_circulating_key . to_string ( ) ,
lamports : non_circulating_balance_result . value ,
} ) ) ;
let request = create_test_request (
" getLargestAccounts " ,
Some ( json! ( [ { " filter " :" nonCirculating " } ] ) ) ,
) ;
let largest_accounts_result : RpcResponse < Vec < RpcAccountBalance > > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( largest_accounts_result . value . len ( ) , 1 ) ;
assert! ( largest_accounts_result . value . contains ( & RpcAccountBalance {
address : non_circulating_key . to_string ( ) ,
lamports : non_circulating_balance_result . value ,
} ) ) ;
2020-05-04 16:46:10 -07:00
}
2019-09-26 10:57:13 -07:00
#[ test ]
fn test_rpc_get_minimum_balance_for_rent_exemption ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
2019-09-26 10:57:13 -07:00
let data_len = 50 ;
2022-03-04 02:20:11 -08:00
let request =
create_test_request ( " getMinimumBalanceForRentExemption " , Some ( json! ( [ data_len ] ) ) ) ;
let result : u64 = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = rpc
. working_bank ( )
. get_minimum_balance_for_rent_exemption ( data_len ) ;
assert_eq! ( result , expected ) ;
2019-09-26 10:57:13 -07:00
}
2019-08-27 15:17:03 -07:00
#[ test ]
fn test_rpc_get_inflation ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let request = create_test_request ( " getInflationGovernor " , None ) ;
let result : RpcInflationGovernor = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected : RpcInflationGovernor = bank . inflation ( ) . into ( ) ;
assert_eq! ( result , expected ) ;
// Query inflation rate for current epoch
let request = create_test_request ( " getInflationRate " , None ) ;
let result : RpcInflationRate = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
2020-07-01 15:43:25 -07:00
let inflation = bank . inflation ( ) ;
let epoch = bank . epoch ( ) ;
2020-12-10 23:42:39 -08:00
let slot_in_year = bank . slot_in_year_for_inflation ( ) ;
2022-03-04 02:20:11 -08:00
let expected = RpcInflationRate {
2020-12-10 23:42:39 -08:00
total : inflation . total ( slot_in_year ) ,
validator : inflation . validator ( slot_in_year ) ,
foundation : inflation . foundation ( slot_in_year ) ,
2020-05-29 11:50:25 -07:00
epoch ,
} ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2019-08-27 15:17:03 -07:00
}
2019-10-22 13:41:18 -07:00
#[ test ]
fn test_rpc_get_epoch_schedule ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let request = create_test_request ( " getEpochSchedule " , None ) ;
let result : EpochSchedule = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = bank . epoch_schedule ( ) ;
assert_eq! ( expected , & result ) ;
2019-10-22 13:41:18 -07:00
}
2019-12-17 15:26:31 -08:00
#[ test ]
fn test_rpc_get_leader_schedule ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
2019-12-18 11:42:58 -08:00
2022-03-04 02:20:11 -08:00
for params in [
None ,
Some ( json! ( [ 0 u64 ] ) ) ,
Some ( json! ( [ null , { " identity " : rpc . leader_pubkey ( ) . to_string ( ) } ] ) ) ,
Some ( json! ( [ { " identity " : rpc . leader_pubkey ( ) . to_string ( ) } ] ) ) ,
] {
let request = create_test_request ( " getLeaderSchedule " , params ) ;
let result : Option < RpcLeaderSchedule > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = Some ( HashMap ::from_iter ( std ::iter ::once ( (
rpc . leader_pubkey ( ) . to_string ( ) ,
Vec ::from_iter ( 0 ..= 128 ) ,
) ) ) ) ;
assert_eq! ( result , expected ) ;
}
let request = create_test_request ( " getLeaderSchedule " , Some ( json! ( [ 42424242 ] ) ) ) ;
let result : Option < RpcLeaderSchedule > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected : Option < RpcLeaderSchedule > = None ;
assert_eq! ( result , expected ) ;
let request = create_test_request (
" getLeaderSchedule " ,
Some ( json! ( [ { " identity " : Pubkey ::new_unique ( ) . to_string ( ) } ] ) ) ,
) ;
let result : Option < RpcLeaderSchedule > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = Some ( HashMap ::default ( ) ) ;
assert_eq! ( result , expected ) ;
2019-12-17 15:26:31 -08:00
}
2022-03-04 02:20:11 -08:00
#[ test ]
fn test_rpc_get_slot_leaders ( ) {
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
// Test that slot leaders will be returned across epochs
let query_start = 0 ;
let query_limit = 2 * bank . epoch_schedule ( ) . slots_per_epoch ;
2021-03-23 10:48:54 -07:00
2022-03-04 02:20:11 -08:00
let request =
create_test_request ( " getSlotLeaders " , Some ( json! ( [ query_start , query_limit ] ) ) ) ;
let result : Vec < String > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result . len ( ) , query_limit as usize ) ;
2021-03-23 10:48:54 -07:00
// Test that invalid limit returns an error
let query_start = 0 ;
let query_limit = 5001 ;
2022-03-04 02:20:11 -08:00
let request =
create_test_request ( " getSlotLeaders " , Some ( json! ( [ query_start , query_limit ] ) ) ) ;
let response = parse_failure_response ( rpc . handle_request_sync ( request ) ) ;
let expected = (
ErrorCode ::InvalidParams . code ( ) ,
String ::from ( " Invalid limit; max 5000 " ) ,
2021-03-23 10:48:54 -07:00
) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( response , expected ) ;
2021-03-23 10:48:54 -07:00
// Test that invalid epoch returns an error
let query_start = 2 * bank . epoch_schedule ( ) . slots_per_epoch ;
let query_limit = 10 ;
2022-03-04 02:20:11 -08:00
let request =
create_test_request ( " getSlotLeaders " , Some ( json! ( [ query_start , query_limit ] ) ) ) ;
let response = parse_failure_response ( rpc . handle_request_sync ( request ) ) ;
let expected = (
ErrorCode ::InvalidParams . code ( ) ,
String ::from ( " Invalid slot range: leader schedule for epoch 2 is unavailable " ) ,
2021-03-23 10:48:54 -07:00
) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( response , expected ) ;
2021-03-23 10:48:54 -07:00
}
2018-10-15 10:01:40 -07:00
#[ test ]
fn test_rpc_get_account_info ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
2018-09-20 13:20:37 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getAccountInfo " ,
Some ( json! ( [ rpc . mint_keypair . pubkey ( ) . to_string ( ) ] ) ) ,
2018-09-20 13:20:37 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
2019-11-12 11:49:41 -08:00
let expected = json! ( {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2022-03-04 02:20:11 -08:00
" value " :{
" owner " : " 11111111111111111111111111111111 " ,
2022-10-04 09:00:34 -07:00
" lamports " : TEST_MINT_LAMPORTS ,
2022-03-04 02:20:11 -08:00
" data " : " " ,
" executable " : false ,
2022-10-17 10:56:04 -07:00
" rentEpoch " : 0 ,
" space " : 0 ,
2020-08-15 17:56:09 -07:00
} ,
2019-11-12 11:49:41 -08:00
} ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-08-10 15:35:29 -07:00
2022-03-04 02:20:11 -08:00
let pubkey = Pubkey ::new_unique ( ) ;
let address = pubkey . to_string ( ) ;
2020-08-10 15:35:29 -07:00
let data = vec! [ 1 , 2 , 3 , 4 , 5 ] ;
2022-03-04 02:20:11 -08:00
let account = AccountSharedData ::create ( 42 , data . clone ( ) , Pubkey ::default ( ) , false , 0 ) ;
bank . store_account ( & pubkey , & account ) ;
2020-08-10 15:35:29 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getAccountInfo " ,
Some ( json! ( [ address , { " encoding " : " base64 " } ] ) ) ,
2020-08-15 17:56:09 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = json! ( [ base64 ::encode ( & data ) , " base64 " ] ) ;
assert_eq! ( result [ " value " ] [ " data " ] , expected ) ;
2022-10-17 10:56:04 -07:00
assert_eq! ( result [ " value " ] [ " space " ] , 5 ) ;
2020-08-10 15:35:29 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getAccountInfo " ,
Some ( json! ( [ address , { " encoding " : " base64 " , " dataSlice " : { " length " : 2 , " offset " : 1 } } ] ) ) ,
2020-08-10 15:35:29 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = json! ( [ base64 ::encode ( & data [ 1 .. 3 ] ) , " base64 " ] ) ;
assert_eq! ( result [ " value " ] [ " data " ] , expected ) ;
2022-10-17 10:56:04 -07:00
assert_eq! ( result [ " value " ] [ " space " ] , 5 ) ;
2020-08-10 15:35:29 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getAccountInfo " ,
Some ( json! ( [ address , { " encoding " : " binary " , " dataSlice " : { " length " : 2 , " offset " : 1 } } ] ) ) ,
2020-08-10 15:35:29 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = bs58 ::encode ( & data [ 1 .. 3 ] ) . into_string ( ) ;
assert_eq! ( result [ " value " ] [ " data " ] , expected ) ;
2022-10-17 10:56:04 -07:00
assert_eq! ( result [ " value " ] [ " space " ] , 5 ) ;
2020-08-10 15:35:29 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getAccountInfo " ,
Some (
json! ( [ address , { " encoding " : " jsonParsed " , " dataSlice " : { " length " : 2 , " offset " : 1 } } ] ) ,
) ,
2020-08-10 15:35:29 -07:00
) ;
2022-10-19 01:49:12 -07:00
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = json! ( [ base64 ::encode ( & data [ 1 .. 3 ] ) , " base64 " ] ) ;
assert_eq! (
result [ " value " ] [ " data " ] , expected ,
" should use data slice if parsing fails "
2022-03-04 02:20:11 -08:00
) ;
2018-10-15 10:01:40 -07:00
}
2018-09-20 13:20:37 -07:00
2020-09-03 10:35:06 -07:00
#[ test ]
fn test_rpc_get_multiple_accounts ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
2022-01-11 10:32:25 -08:00
2022-03-04 02:20:11 -08:00
let non_existent_pubkey = Pubkey ::new_unique ( ) ;
let pubkey = Pubkey ::new_unique ( ) ;
let address = pubkey . to_string ( ) ;
2020-09-03 10:35:06 -07:00
let data = vec! [ 1 , 2 , 3 , 4 , 5 ] ;
2022-03-04 02:20:11 -08:00
let account = AccountSharedData ::create ( 42 , data . clone ( ) , Pubkey ::default ( ) , false , 0 ) ;
bank . store_account ( & pubkey , & account ) ;
// Test 3 accounts, one empty, one non-existent, and one with data
let request = create_test_request (
" getMultipleAccounts " ,
Some ( json! ( [ [
rpc . mint_keypair . pubkey ( ) . to_string ( ) ,
non_existent_pubkey . to_string ( ) ,
address ,
] ] ) ) ,
2020-09-03 10:35:06 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : RpcResponse < Value > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = json! ( [
{
" owner " : " 11111111111111111111111111111111 " ,
2022-10-04 09:00:34 -07:00
" lamports " : TEST_MINT_LAMPORTS ,
2022-03-04 02:20:11 -08:00
" data " : [ " " , " base64 " ] ,
" executable " : false ,
2022-10-17 10:56:04 -07:00
" rentEpoch " : 0 ,
" space " : 0 ,
2020-09-03 10:35:06 -07:00
} ,
2022-03-04 02:20:11 -08:00
null ,
{
" owner " : " 11111111111111111111111111111111 " ,
" lamports " : 42 ,
" data " : [ base64 ::encode ( & data ) , " base64 " ] ,
" executable " : false ,
2022-10-17 10:56:04 -07:00
" rentEpoch " : 0 ,
" space " : 5 ,
2022-03-04 02:20:11 -08:00
}
] ) ;
assert_eq! ( result . value , expected ) ;
2020-09-03 10:35:06 -07:00
// Test config settings still work with multiple accounts
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getMultipleAccounts " ,
Some ( json! ( [
[
rpc . mint_keypair . pubkey ( ) . to_string ( ) ,
non_existent_pubkey . to_string ( ) ,
address ,
] ,
{ " encoding " : " base58 " } ,
] ) ) ,
2020-09-03 10:35:06 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : RpcResponse < Value > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = json! ( [
{
" owner " : " 11111111111111111111111111111111 " ,
2022-10-04 09:00:34 -07:00
" lamports " : TEST_MINT_LAMPORTS ,
2022-03-04 02:20:11 -08:00
" data " : [ " " , " base58 " ] ,
" executable " : false ,
2022-10-17 10:56:04 -07:00
" rentEpoch " : 0 ,
" space " : 0 ,
2022-03-04 02:20:11 -08:00
} ,
null ,
{
" owner " : " 11111111111111111111111111111111 " ,
" lamports " : 42 ,
" data " : [ bs58 ::encode ( & data ) . into_string ( ) , " base58 " ] ,
" executable " : false ,
2022-10-17 10:56:04 -07:00
" rentEpoch " : 0 ,
" space " : 5 ,
2022-03-04 02:20:11 -08:00
}
] ) ;
assert_eq! ( result . value , expected ) ;
let request = create_test_request (
" getMultipleAccounts " ,
Some ( json! ( [
[
rpc . mint_keypair . pubkey ( ) . to_string ( ) ,
non_existent_pubkey . to_string ( ) ,
address ,
] ,
{ " encoding " : " jsonParsed " , " dataSlice " : { " length " : 2 , " offset " : 1 } } ,
] ) ) ,
2020-09-03 10:35:06 -07:00
) ;
2022-10-19 01:49:12 -07:00
let result : RpcResponse < Value > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = json! ( [
{
" owner " : " 11111111111111111111111111111111 " ,
" lamports " : TEST_MINT_LAMPORTS ,
" data " : [ " " , " base64 " ] ,
" executable " : false ,
2022-10-19 09:25:50 -07:00
" rentEpoch " : 0 ,
" space " : 0 ,
2022-10-19 01:49:12 -07:00
} ,
null ,
{
" owner " : " 11111111111111111111111111111111 " ,
" lamports " : 42 ,
" data " : [ base64 ::encode ( & data [ 1 .. 3 ] ) , " base64 " ] ,
" executable " : false ,
2022-10-19 09:25:50 -07:00
" rentEpoch " : 0 ,
" space " : 5 ,
2022-10-19 01:49:12 -07:00
}
] ) ;
assert_eq! (
result . value , expected ,
" should use data slice if parsing fails "
2020-09-03 10:35:06 -07:00
) ;
}
2019-06-29 09:59:07 -07:00
#[ test ]
fn test_rpc_get_program_accounts ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let new_program_id = Pubkey ::new_unique ( ) ;
let new_program_account_key = Pubkey ::new_unique ( ) ;
let new_program_account = AccountSharedData ::new ( 42 , 0 , & new_program_id ) ;
bank . store_account ( & new_program_account_key , & new_program_account ) ;
let request = create_test_request (
" getProgramAccounts " ,
Some ( json! ( [ new_program_id . to_string ( ) ] ) ) ,
) ;
let result : Vec < RpcKeyedAccount > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected_value = vec! [ RpcKeyedAccount {
pubkey : new_program_account_key . to_string ( ) ,
account : UiAccount ::encode (
& new_program_account_key ,
& new_program_account ,
UiAccountEncoding ::Binary ,
None ,
None ,
) ,
} ] ;
assert_eq! ( result , expected_value ) ;
2020-07-03 00:46:29 -07:00
2021-05-22 00:12:21 -07:00
// Test returns context
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getProgramAccounts " ,
Some ( json! ( [
new_program_id . to_string ( ) ,
{ " withContext " : true } ,
] ) ) ,
) ;
let result : RpcResponse < Vec < RpcKeyedAccount > > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = RpcResponse {
2022-05-11 21:17:21 -07:00
context : RpcResponseContext ::new ( 0 ) ,
2022-03-04 02:20:11 -08:00
value : expected_value ,
} ;
assert_eq! ( result , expected ) ;
2021-05-22 00:12:21 -07:00
2020-07-03 00:46:29 -07:00
// Set up nonce accounts to test filters
2022-03-04 02:20:11 -08:00
let nonce_authorities = ( 0 .. 2 )
. map ( | _ | {
let pubkey = Pubkey ::new_unique ( ) ;
let authority = Pubkey ::new_unique ( ) ;
let account = AccountSharedData ::new_data (
42 ,
2022-07-06 05:03:13 -07:00
& nonce ::state ::Versions ::new ( nonce ::State ::new_initialized (
& authority ,
DurableNonce ::default ( ) ,
1000 ,
) ) ,
2022-03-04 02:20:11 -08:00
& system_program ::id ( ) ,
)
. unwrap ( ) ;
bank . store_account ( & pubkey , & account ) ;
authority
} )
. collect ::< Vec < _ > > ( ) ;
2020-07-03 00:46:29 -07:00
// Test memcmp filter; filter on Initialized state
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getProgramAccounts " ,
Some ( json! ( [
system_program ::id ( ) . to_string ( ) ,
{ " filters " : [ {
" memcmp " : {
" offset " : 4 ,
" bytes " : bs58 ::encode ( vec! [ 1 , 0 , 0 , 0 ] ) . into_string ( ) ,
} ,
} ] } ,
] ) ) ,
) ;
let result : Vec < RpcKeyedAccount > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result . len ( ) , 2 ) ;
let request = create_test_request (
" getProgramAccounts " ,
Some ( json! ( [
system_program ::id ( ) . to_string ( ) ,
{ " filters " : [ {
" memcmp " : {
2022-06-09 08:28:37 -07:00
" offset " : 4 ,
" bytes " : bs58 ::encode ( vec! [ 0 , 0 , 0 , 0 ] ) . into_string ( ) ,
2022-03-04 02:20:11 -08:00
} ,
} ] } ,
] ) ) ,
2020-07-03 00:46:29 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : Vec < RpcKeyedAccount > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result . len ( ) , 0 ) ;
2020-07-03 00:46:29 -07:00
// Test dataSize filter
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getProgramAccounts " ,
Some ( json! ( [
system_program ::id ( ) . to_string ( ) ,
{ " filters " : [ { " dataSize " : nonce ::State ::size ( ) } ] } ,
] ) ) ,
) ;
let result : Vec < RpcKeyedAccount > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result . len ( ) , 2 ) ;
let request = create_test_request (
" getProgramAccounts " ,
Some ( json! ( [
system_program ::id ( ) . to_string ( ) ,
{ " filters " : [ { " dataSize " : 1 } ] } ,
] ) ) ,
) ;
let result : Vec < RpcKeyedAccount > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result . len ( ) , 0 ) ;
2020-07-03 00:46:29 -07:00
// Test multiple filters
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getProgramAccounts " ,
Some ( json! ( [
system_program ::id ( ) . to_string ( ) ,
{ " filters " : [ {
" memcmp " : {
" offset " : 4 ,
" bytes " : bs58 ::encode ( vec! [ 1 , 0 , 0 , 0 ] ) . into_string ( ) ,
} ,
} , {
" memcmp " : {
" offset " : 8 ,
" bytes " : nonce_authorities [ 0 ] . to_string ( ) ,
} ,
} ] } , // Filter on Initialized and Nonce authority
] ) ) ,
) ;
let result : Vec < RpcKeyedAccount > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result . len ( ) , 1 ) ;
let request = create_test_request (
" getProgramAccounts " ,
Some ( json! ( [
system_program ::id ( ) . to_string ( ) ,
{ " filters " : [ {
" memcmp " : {
" offset " : 4 ,
" bytes " : bs58 ::encode ( vec! [ 1 , 0 , 0 , 0 ] ) . into_string ( ) ,
} ,
} , {
" dataSize " : 1 ,
} ] } , // Filter on Initialized and non-matching data size
] ) ) ,
) ;
let result : Vec < RpcKeyedAccount > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result . len ( ) , 0 ) ;
2019-06-29 09:59:07 -07:00
}
2020-05-19 12:08:19 -07:00
#[ test ]
fn test_rpc_simulate_transaction ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let rent_exempt_amount = bank . get_minimum_balance_for_rent_exemption ( 0 ) ;
let recent_blockhash = bank . confirmed_last_blockhash ( ) ;
2020-05-19 12:08:19 -07:00
let RpcHandler {
2022-03-04 02:20:11 -08:00
ref meta , ref io , ..
} = rpc ;
2020-05-19 12:08:19 -07:00
2021-05-25 16:44:18 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2022-03-04 02:20:11 -08:00
let mut tx = system_transaction ::transfer (
& rpc . mint_keypair ,
& bob_pubkey ,
rent_exempt_amount ,
recent_blockhash ,
) ;
2020-05-19 12:08:19 -07:00
let tx_serialized_encoded = bs58 ::encode ( serialize ( & tx ) . unwrap ( ) ) . into_string ( ) ;
tx . signatures [ 0 ] = Signature ::default ( ) ;
let tx_badsig_serialized_encoded = bs58 ::encode ( serialize ( & tx ) . unwrap ( ) ) . into_string ( ) ;
2021-05-25 14:04:17 -07:00
tx . message . recent_blockhash = Hash ::default ( ) ;
let tx_invalid_recent_blockhash = bs58 ::encode ( serialize ( & tx ) . unwrap ( ) ) . into_string ( ) ;
2020-05-19 12:08:19 -07:00
2022-03-04 02:20:11 -08:00
// Simulation bank must be frozen
bank . freeze ( ) ;
2020-05-19 12:08:19 -07:00
// Good signature with sigVerify=true
let req = format! (
2021-05-25 16:44:18 -07:00
r #" {{ " jsonrpc " : " 2.0 " ,
" id " :1 ,
" method " :" simulateTransaction " ,
" params " :[
" {} " ,
{ {
" sigVerify " : true ,
" accounts " : { {
" encoding " : " jsonParsed " ,
" addresses " : [ " {} " , " {} " ]
} }
} }
]
} } " #,
2020-05-19 12:08:19 -07:00
tx_serialized_encoded ,
2021-05-25 16:44:18 -07:00
solana_sdk ::pubkey ::new_rand ( ) ,
bob_pubkey ,
2020-05-19 12:08:19 -07:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2021-05-25 16:44:18 -07:00
" value " :{
" accounts " : [
null ,
{
" data " : [ " " , " base64 " ] ,
" executable " : false ,
" owner " : " 11111111111111111111111111111111 " ,
2022-01-11 10:32:25 -08:00
" lamports " : rent_exempt_amount ,
2023-01-06 14:21:10 -08:00
" rentEpoch " : u64 ::MAX ,
2022-10-17 10:56:04 -07:00
" space " : 0 ,
2021-05-25 16:44:18 -07:00
}
] ,
" err " :null ,
" logs " :[
" Program 11111111111111111111111111111111 invoke [1] " ,
" Program 11111111111111111111111111111111 success "
2021-07-16 14:58:15 -07:00
] ,
2022-03-22 15:17:05 -07:00
" returnData " :null ,
2021-07-16 14:58:15 -07:00
" unitsConsumed " :0
2021-05-25 16:44:18 -07:00
}
2020-05-19 12:08:19 -07:00
} ,
" id " : 1 ,
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-05-19 12:08:19 -07:00
2021-05-25 16:44:18 -07:00
// Too many input accounts...
let req = format! (
r #" {{ " jsonrpc " : " 2.0 " ,
" id " :1 ,
" method " :" simulateTransaction " ,
" params " :[
2022-12-06 06:30:06 -08:00
" {tx_serialized_encoded} " ,
2021-05-25 16:44:18 -07:00
{ {
" sigVerify " : true ,
" accounts " : { {
" addresses " : [
" 11111111111111111111111111111111 " ,
" 11111111111111111111111111111111 " ,
" 11111111111111111111111111111111 " ,
" 11111111111111111111111111111111 "
]
} }
} }
]
} } " #,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " :" 2.0 " ,
" error " : {
" code " : error ::ErrorCode ::InvalidParams . code ( ) ,
" message " : " Too many accounts provided; max 3 "
} ,
" id " :1
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2021-05-25 16:44:18 -07:00
2020-05-19 12:08:19 -07:00
// Bad signature with sigVerify=true
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_badsig_serialized_encoded}", {{"sigVerify": true}}]}}"# ,
2020-05-19 12:08:19 -07:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
2020-10-23 20:47:51 -07:00
" jsonrpc " :" 2.0 " ,
" error " : {
" code " : - 32003 ,
" message " : " Transaction signature verification failure "
2020-05-19 12:08:19 -07:00
} ,
2020-10-23 20:47:51 -07:00
" id " :1
2020-05-19 12:08:19 -07:00
} ) ;
2020-10-23 20:47:51 -07:00
2020-05-19 12:08:19 -07:00
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-05-19 12:08:19 -07:00
// Bad signature with sigVerify=false
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_serialized_encoded}", {{"sigVerify": false}}]}}"# ,
2020-05-19 12:08:19 -07:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2021-07-16 14:58:15 -07:00
" value " :{
" accounts " :null ,
" err " :null ,
" logs " :[
" Program 11111111111111111111111111111111 invoke [1] " ,
" Program 11111111111111111111111111111111 success "
] ,
2022-03-22 15:17:05 -07:00
" returnData " :null ,
2021-07-16 14:58:15 -07:00
" unitsConsumed " :0
}
2020-05-19 12:08:19 -07:00
} ,
" id " : 1 ,
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-05-19 12:08:19 -07:00
// Bad signature with default sigVerify setting (false)
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_serialized_encoded}"]}}"# ,
2020-05-19 12:08:19 -07:00
) ;
2021-05-25 14:04:17 -07:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2021-07-16 14:58:15 -07:00
" value " :{
" accounts " :null ,
" err " :null ,
" logs " :[
" Program 11111111111111111111111111111111 invoke [1] " ,
" Program 11111111111111111111111111111111 success "
] ,
2022-03-22 15:17:05 -07:00
" returnData " :null ,
2021-07-16 14:58:15 -07:00
" unitsConsumed " :0
}
2021-05-25 14:04:17 -07:00
} ,
" id " : 1 ,
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2021-05-25 14:04:17 -07:00
// Enabled both sigVerify=true and replaceRecentBlockhash=true
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}", {}]}}"# ,
tx_serialized_encoded ,
json! ( {
" sigVerify " : true ,
" replaceRecentBlockhash " : true ,
} )
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " :" 2.0 " ,
" error " : {
" code " : ErrorCode ::InvalidParams ,
" message " : " sigVerify may not be used with replaceRecentBlockhash "
} ,
" id " :1
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2021-05-25 14:04:17 -07:00
// Bad recent blockhash with replaceRecentBlockhash=false
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_invalid_recent_blockhash}", {{"replaceRecentBlockhash": false}}]}}"# ,
2021-05-25 14:04:17 -07:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " :" 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2021-07-16 14:58:15 -07:00
" value " :{
" err " :" BlockhashNotFound " ,
" accounts " :null ,
" logs " :[ ] ,
2022-03-22 15:17:05 -07:00
" returnData " :null ,
2021-07-16 14:58:15 -07:00
" unitsConsumed " :0
}
2021-05-25 14:04:17 -07:00
} ,
" id " :1
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2021-05-25 14:04:17 -07:00
// Bad recent blockhash with replaceRecentBlockhash=true
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_invalid_recent_blockhash}", {{"replaceRecentBlockhash": true}}]}}"# ,
2021-05-25 14:04:17 -07:00
) ;
2022-03-04 02:20:11 -08:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2020-05-19 12:08:19 -07:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2021-07-16 14:58:15 -07:00
" value " :{
" accounts " :null ,
" err " :null ,
" logs " :[
" Program 11111111111111111111111111111111 invoke [1] " ,
" Program 11111111111111111111111111111111 success "
] ,
2022-03-22 15:17:05 -07:00
" returnData " :null ,
2021-07-16 14:58:15 -07:00
" unitsConsumed " :0
}
2020-05-19 12:08:19 -07:00
} ,
" id " : 1 ,
} ) ;
2021-05-25 14:04:17 -07:00
2020-05-19 12:08:19 -07:00
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-05-19 12:08:19 -07:00
}
#[ test ]
2022-03-04 02:20:11 -08:00
#[ should_panic(expected = " simulation bank must be frozen " ) ]
2020-05-19 12:08:19 -07:00
fn test_rpc_simulate_transaction_panic_on_unfrozen_bank ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let recent_blockhash = bank . confirmed_last_blockhash ( ) ;
2020-05-19 12:08:19 -07:00
let RpcHandler {
meta ,
2022-03-04 02:20:11 -08:00
io ,
mint_keypair ,
2020-05-19 12:08:19 -07:00
..
2022-03-04 02:20:11 -08:00
} = rpc ;
2020-05-19 12:08:19 -07:00
2022-03-04 02:20:11 -08:00
let bob_pubkey = Pubkey ::new_unique ( ) ;
let tx = system_transaction ::transfer ( & mint_keypair , & bob_pubkey , 1234 , recent_blockhash ) ;
2020-05-19 12:08:19 -07:00
let tx_serialized_encoded = bs58 ::encode ( serialize ( & tx ) . unwrap ( ) ) . into_string ( ) ;
assert! ( ! bank . is_frozen ( ) ) ;
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{tx_serialized_encoded}", {{"sigVerify": true}}]}}"# ,
2020-05-19 12:08:19 -07:00
) ;
// should panic because `bank` is not frozen
2020-05-29 00:26:06 -07:00
let _ = io . handle_request_sync ( & req , meta ) ;
2020-05-19 12:08:19 -07:00
}
2020-04-01 11:30:58 -07:00
#[ test ]
fn test_rpc_get_signature_statuses ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let recent_blockhash = bank . confirmed_last_blockhash ( ) ;
let confirmed_block_signatures = rpc . create_test_transactions_and_populate_blockstore ( ) ;
2019-10-14 15:24:10 -07:00
let RpcHandler {
2021-05-26 12:27:41 -07:00
mut meta ,
2022-03-04 02:20:11 -08:00
io ,
mint_keypair ,
2019-10-14 15:24:10 -07:00
..
2022-03-04 02:20:11 -08:00
} = rpc ;
2018-08-15 09:37:02 -07:00
2018-10-15 10:01:40 -07:00
let req = format! (
2020-04-01 11:30:58 -07:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"# ,
2020-03-23 10:25:39 -07:00
confirmed_block_signatures [ 0 ]
2018-10-15 10:01:40 -07:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2020-03-23 10:25:39 -07:00
let expected_res : transaction ::Result < ( ) > = Ok ( ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
2020-03-26 18:21:01 -07:00
let result : Option < TransactionStatus > =
serde_json ::from_value ( json [ " result " ] [ " value " ] [ 0 ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
2020-03-30 16:53:25 -07:00
let result = result . as_ref ( ) . unwrap ( ) ;
assert_eq! ( expected_res , result . status ) ;
2020-04-22 11:22:09 -07:00
assert_eq! ( None , result . confirmations ) ;
2018-08-13 10:24:39 -07:00
2018-10-15 10:01:40 -07:00
// Test getSignatureStatus request on unprocessed tx
2022-03-04 02:20:11 -08:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2022-01-11 10:32:25 -08:00
let tx = system_transaction ::transfer (
2022-03-04 02:20:11 -08:00
& mint_keypair ,
2022-01-11 10:32:25 -08:00
& bob_pubkey ,
bank . get_minimum_balance_for_rent_exemption ( 0 ) + 10 ,
2022-03-04 02:20:11 -08:00
recent_blockhash ,
2022-01-11 10:32:25 -08:00
) ;
2018-10-15 10:01:40 -07:00
let req = format! (
2020-04-01 11:30:58 -07:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"# ,
2018-10-26 14:43:34 -07:00
tx . signatures [ 0 ]
2018-10-15 10:01:40 -07:00
) ;
2019-04-05 18:07:30 -07:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2020-03-23 10:25:39 -07:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
2020-03-26 18:21:01 -07:00
let result : Option < TransactionStatus > =
serde_json ::from_value ( json [ " result " ] [ " value " ] [ 0 ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert! ( result . is_none ( ) ) ;
2019-04-05 18:07:30 -07:00
// Test getSignatureStatus request on a TransactionError
let req = format! (
2020-04-01 11:30:58 -07:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"# ,
2020-03-23 10:25:39 -07:00
confirmed_block_signatures [ 1 ]
2019-04-05 18:07:30 -07:00
) ;
2021-05-26 12:27:41 -07:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2020-03-23 10:25:39 -07:00
let expected_res : transaction ::Result < ( ) > = Err ( TransactionError ::InstructionError (
0 ,
2020-04-01 09:01:11 -07:00
InstructionError ::Custom ( 1 ) ,
2019-04-05 18:07:30 -07:00
) ) ;
2020-03-23 10:25:39 -07:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
2020-03-26 18:21:01 -07:00
let result : Option < TransactionStatus > =
serde_json ::from_value ( json [ " result " ] [ " value " ] [ 0 ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected_res , result . as_ref ( ) . unwrap ( ) . status ) ;
2021-05-26 12:27:41 -07:00
// disable rpc-tx-history, but attempt historical query
meta . config . enable_rpc_transaction_history = false ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"], {{"searchTransactionHistory": true}}]}}"# ,
confirmed_block_signatures [ 1 ]
) ;
let res = io . handle_request_sync ( & req , meta ) ;
assert_eq! (
res ,
Some (
r # "{"jsonrpc":"2.0","error":{"code":-32011,"message":"Transaction history is not available from this node"},"id":1}"# . to_string ( ) ,
)
) ;
2018-10-15 10:01:40 -07:00
}
#[ test ]
2019-03-02 10:25:16 -08:00
fn test_rpc_get_recent_blockhash ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let recent_blockhash = bank . confirmed_last_blockhash ( ) ;
let RpcHandler { meta , io , .. } = rpc ;
2018-10-15 10:01:40 -07:00
2020-05-15 09:35:43 -07:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getRecentBlockhash"}"# ;
2021-06-18 06:34:46 -07:00
let res = io . handle_request_sync ( req , meta ) ;
2019-06-10 22:18:32 -07:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
2019-11-12 11:49:41 -08:00
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
" value " :{
" blockhash " : recent_blockhash . to_string ( ) ,
" feeCalculator " : {
2022-10-04 09:00:34 -07:00
" lamportsPerSignature " : TEST_SIGNATURE_FEE ,
2022-05-11 21:17:21 -07:00
}
} ,
} ,
2020-02-28 12:27:01 -08:00
" id " : 1
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-05-26 12:06:21 -07:00
}
#[ test ]
fn test_rpc_get_fees ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let recent_blockhash = bank . confirmed_last_blockhash ( ) ;
let RpcHandler { meta , io , .. } = rpc ;
2020-05-26 12:06:21 -07:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getFees"}"# ;
2021-06-18 06:34:46 -07:00
let res = io . handle_request_sync ( req , meta ) ;
2020-05-26 12:06:21 -07:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2022-03-04 02:20:11 -08:00
" value " : {
" blockhash " : recent_blockhash . to_string ( ) ,
" feeCalculator " : {
2022-10-04 09:00:34 -07:00
" lamportsPerSignature " : TEST_SIGNATURE_FEE ,
2022-03-04 02:20:11 -08:00
} ,
" lastValidSlot " : MAX_RECENT_BLOCKHASHES ,
" lastValidBlockHeight " : MAX_RECENT_BLOCKHASHES ,
2020-05-26 12:06:21 -07:00
} ,
2022-03-04 02:20:11 -08:00
} ,
2020-05-26 12:06:21 -07:00
" id " : 1
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-02-28 12:27:01 -08:00
}
2020-03-06 16:01:31 -08:00
#[ test ]
fn test_rpc_get_fee_calculator_for_blockhash ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let recent_blockhash = bank . confirmed_last_blockhash ( ) ;
let RpcHandler { meta , io , .. } = rpc ;
2020-03-06 16:01:31 -08:00
2021-10-22 14:32:40 -07:00
let lamports_per_signature = bank . get_lamports_per_signature ( ) ;
let fee_calculator = RpcFeeCalculator {
fee_calculator : FeeCalculator ::new ( lamports_per_signature ) ,
} ;
2020-03-06 16:01:31 -08:00
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getFeeCalculatorForBlockhash","params":["{recent_blockhash:?}"]}}"#
2020-03-06 16:01:31 -08:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2020-03-06 16:01:31 -08:00
" value " :fee_calculator ,
} ,
" id " : 1
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-03-06 16:01:31 -08:00
// Expired (non-existent) blockhash
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getFeeCalculatorForBlockhash","params":["{:?}"]}}"# ,
Hash ::default ( )
) ;
2020-05-15 09:35:43 -07:00
let res = io . handle_request_sync ( & req , meta ) ;
2020-03-06 16:01:31 -08:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
2020-03-06 16:01:31 -08:00
" value " :Value ::Null ,
} ,
" id " : 1
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2020-03-06 16:01:31 -08:00
}
2020-02-28 12:27:01 -08:00
#[ test ]
fn test_rpc_get_fee_rate_governor ( ) {
2022-03-04 02:20:11 -08:00
let RpcHandler { meta , io , .. } = RpcHandler ::start ( ) ;
2020-02-28 12:27:01 -08:00
2020-05-15 09:35:43 -07:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getFeeRateGovernor"}"# ;
2021-06-18 06:34:46 -07:00
let res = io . handle_request_sync ( req , meta ) ;
2020-02-28 12:27:01 -08:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2022-05-11 21:17:21 -07:00
" context " : { " slot " : 0 , " apiVersion " : RpcApiVersion ::default ( ) } ,
" value " :{
" feeRateGovernor " : {
" burnPercent " : DEFAULT_BURN_PERCENT ,
2022-10-04 09:00:34 -07:00
" maxLamportsPerSignature " : TEST_SIGNATURE_FEE ,
" minLamportsPerSignature " : TEST_SIGNATURE_FEE ,
" targetLamportsPerSignature " : TEST_SIGNATURE_FEE ,
2022-05-11 21:17:21 -07:00
" targetSignaturesPerSlot " : 0
}
} ,
} ,
2019-06-10 22:18:32 -07:00
" id " : 1
} ) ;
2018-10-15 10:01:40 -07:00
let expected : Response =
2019-06-10 22:18:32 -07:00
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
2018-08-13 10:24:39 -07:00
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2018-08-13 10:24:39 -07:00
}
2018-10-15 10:01:40 -07:00
2018-08-13 10:24:39 -07:00
#[ test ]
2018-11-01 10:30:56 -07:00
fn test_rpc_fail_request_airdrop ( ) {
2022-03-04 02:20:11 -08:00
let RpcHandler { meta , io , .. } = RpcHandler ::start ( ) ;
2018-10-15 10:01:40 -07:00
2019-12-16 13:05:17 -08:00
// Expect internal error because no faucet is available
2022-03-04 02:20:11 -08:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2018-10-15 10:01:40 -07:00
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"requestAirdrop","params":["{bob_pubkey}", 50]}}"#
2018-10-15 10:01:40 -07:00
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let expected =
2019-03-06 09:26:12 -08:00
r # "{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":1}"# ;
2018-10-15 10:01:40 -07:00
let expected : Response =
serde_json ::from_str ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2018-10-15 10:01:40 -07:00
}
#[ test ]
fn test_rpc_send_bad_tx ( ) {
2020-09-28 19:43:05 -07:00
let genesis = create_genesis_config ( 100 ) ;
2021-08-05 06:42:38 -07:00
let bank = Arc ::new ( Bank ::new_for_tests ( & genesis . genesis_config ) ) ;
2022-06-08 04:57:12 -07:00
let connection_cache = Arc ::new ( ConnectionCache ::default ( ) ) ;
let meta = JsonRpcRequestProcessor ::new_from_bank (
& bank ,
SocketAddrSpace ::Unspecified ,
connection_cache ,
) ;
2018-08-15 09:37:02 -07:00
2018-08-13 10:24:39 -07:00
let mut io = MetaIoHandler ::default ( ) ;
2021-02-26 21:42:09 -08:00
io . extend_with ( rpc_full ::FullImpl . to_delegate ( ) ) ;
2018-08-13 10:24:39 -07:00
2020-01-21 21:16:07 -08:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["37u9WtQpcm6ULa3Vmu7ySnANv"]}"# ;
2020-05-15 09:35:43 -07:00
let res = io . handle_request_sync ( req , meta ) ;
2020-05-21 17:30:02 -07:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let error = & json [ " error " ] ;
assert_eq! ( error [ " code " ] , ErrorCode ::InvalidParams . code ( ) ) ;
2018-08-13 10:24:39 -07:00
}
2018-10-15 10:01:40 -07:00
2020-06-01 13:53:37 -07:00
#[ test ]
fn test_rpc_send_transaction_preflight ( ) {
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
let validator_exit = create_validator_exit ( & exit ) ;
let ledger_path = get_tmp_ledger_path! ( ) ;
let blockstore = Arc ::new ( Blockstore ::open ( & ledger_path ) . unwrap ( ) ) ;
2020-06-25 21:06:58 -07:00
let block_commitment_cache = Arc ::new ( RwLock ::new ( BlockCommitmentCache ::default ( ) ) ) ;
2020-08-04 20:49:37 -07:00
let ( bank_forks , mint_keypair , .. ) = new_bank_forks ( ) ;
2020-06-01 13:53:37 -07:00
let health = RpcHealth ::stub ( ) ;
// Freeze bank 0 to prevent a panic in `run_transaction_simulation()`
bank_forks . write ( ) . unwrap ( ) . get ( 0 ) . unwrap ( ) . freeze ( ) ;
let mut io = MetaIoHandler ::default ( ) ;
2021-02-26 21:42:09 -08:00
io . extend_with ( rpc_full ::FullImpl . to_delegate ( ) ) ;
2023-01-24 08:57:55 -08:00
let cluster_info = Arc ::new ( {
let keypair = Arc ::new ( Keypair ::new ( ) ) ;
2023-02-01 05:07:42 -08:00
let contact_info =
ContactInfo ::new_with_socketaddr ( & keypair . pubkey ( ) , & socketaddr! ( " 127.0.0.1:1234 " ) ) ;
2023-01-24 08:57:55 -08:00
ClusterInfo ::new ( contact_info , keypair , SocketAddrSpace ::Unspecified )
} ) ;
2020-07-08 18:13:42 -07:00
let tpu_address = cluster_info . my_contact_info ( ) . tpu ;
2020-07-10 18:14:41 -07:00
let ( meta , receiver ) = JsonRpcRequestProcessor ::new (
2020-06-07 20:54:03 -07:00
JsonRpcConfig ::default ( ) ,
2021-01-14 21:45:11 -08:00
None ,
2020-06-05 21:23:13 -07:00
bank_forks . clone ( ) ,
2020-06-07 20:54:03 -07:00
block_commitment_cache ,
blockstore ,
validator_exit ,
health . clone ( ) ,
2020-07-08 18:13:42 -07:00
cluster_info ,
2020-06-07 20:54:03 -07:00
Hash ::default ( ) ,
2020-07-23 09:54:57 -07:00
None ,
2020-09-28 19:43:05 -07:00
OptimisticallyConfirmedBank ::locked_from_bank_forks_root ( & bank_forks ) ,
2021-02-11 11:32:46 -08:00
Arc ::new ( RwLock ::new ( LargestAccountsCache ::new ( 30 ) ) ) ,
2021-02-23 13:06:33 -08:00
Arc ::new ( MaxSlots ::default ( ) ) ,
2021-03-23 10:48:54 -07:00
Arc ::new ( LeaderScheduleCache ::default ( ) ) ,
2021-03-26 15:47:35 -07:00
Arc ::new ( AtomicU64 ::default ( ) ) ,
2022-09-01 16:12:12 -07:00
Arc ::new ( PrioritizationFeeCache ::default ( ) ) ,
2020-06-07 20:54:03 -07:00
) ;
2022-06-08 04:57:12 -07:00
let connection_cache = Arc ::new ( ConnectionCache ::default ( ) ) ;
2021-08-23 15:32:15 -07:00
SendTransactionService ::new ::< NullTpuInfo > (
tpu_address ,
& bank_forks ,
None ,
receiver ,
2022-06-08 04:57:12 -07:00
& connection_cache ,
2021-08-23 15:32:15 -07:00
1000 ,
1 ,
) ;
2020-06-01 13:53:37 -07:00
2020-10-19 12:23:14 -07:00
let mut bad_transaction = system_transaction ::transfer (
& mint_keypair ,
& solana_sdk ::pubkey ::new_rand ( ) ,
42 ,
Hash ::default ( ) ,
) ;
2020-06-01 13:53:37 -07:00
// sendTransaction will fail because the blockhash is invalid
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"# ,
bs58 ::encode ( serialize ( & bad_transaction ) . unwrap ( ) ) . into_string ( )
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
assert_eq! (
res ,
Some (
2022-03-22 15:17:05 -07:00
r # "{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found","data":{"accounts":null,"err":"BlockhashNotFound","logs":[],"returnData":null,"unitsConsumed":0}},"id":1}"# . to_string ( ) ,
2020-06-01 13:53:37 -07:00
)
) ;
2020-08-04 19:46:25 -07:00
// sendTransaction will fail due to insanity
2020-09-15 18:23:21 -07:00
bad_transaction . message . instructions [ 0 ] . program_id_index = 0 u8 ;
2020-07-29 19:03:30 -07:00
let recent_blockhash = bank_forks . read ( ) . unwrap ( ) . root_bank ( ) . last_blockhash ( ) ;
2020-08-04 20:49:37 -07:00
bad_transaction . sign ( & [ & mint_keypair ] , recent_blockhash ) ;
2020-08-04 19:46:25 -07:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"# ,
bs58 ::encode ( serialize ( & bad_transaction ) . unwrap ( ) ) . into_string ( )
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
assert_eq! (
res ,
Some (
2021-08-17 15:17:56 -07:00
r # "{"jsonrpc":"2.0","error":{"code":-32602,"message":"invalid transaction: Transaction failed to sanitize accounts offsets correctly"},"id":1}"# . to_string ( ) ,
2020-08-04 19:46:25 -07:00
)
) ;
2020-10-19 12:23:14 -07:00
let mut bad_transaction = system_transaction ::transfer (
& mint_keypair ,
& solana_sdk ::pubkey ::new_rand ( ) ,
42 ,
recent_blockhash ,
) ;
2020-07-29 19:03:30 -07:00
2020-06-01 13:53:37 -07:00
// sendTransaction will fail due to poor node health
2021-01-14 21:45:11 -08:00
health . stub_set_health_status ( Some ( RpcHealthStatus ::Behind { num_slots : 42 } ) ) ;
2020-06-01 13:53:37 -07:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"# ,
bs58 ::encode ( serialize ( & bad_transaction ) . unwrap ( ) ) . into_string ( )
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
assert_eq! (
res ,
Some (
2021-01-17 20:23:14 -08:00
r # "{"jsonrpc":"2.0","error":{"code":-32005,"message":"Node is behind by 42 slots","data":{"numSlotsBehind":42}},"id":1}"# . to_string ( ) ,
2020-06-01 13:53:37 -07:00
)
) ;
health . stub_set_health_status ( None ) ;
// sendTransaction will fail due to invalid signature
bad_transaction . signatures [ 0 ] = Signature ::default ( ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"# ,
bs58 ::encode ( serialize ( & bad_transaction ) . unwrap ( ) ) . into_string ( )
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
assert_eq! (
res ,
Some (
2020-09-15 22:30:04 -07:00
r # "{"jsonrpc":"2.0","error":{"code":-32003,"message":"Transaction signature verification failure"},"id":1}"# . to_string ( ) ,
2020-06-01 13:53:37 -07:00
)
) ;
// sendTransaction will now succeed because skipPreflight=true even though it's a bad
// transaction
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}", {{"skipPreflight": true}}]}}"# ,
bs58 ::encode ( serialize ( & bad_transaction ) . unwrap ( ) ) . into_string ( )
) ;
2020-07-29 19:03:30 -07:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2020-06-01 13:53:37 -07:00
assert_eq! (
res ,
Some (
r # "{"jsonrpc":"2.0","result":"1111111111111111111111111111111111111111111111111111111111111111","id":1}"# . to_string ( ) ,
)
) ;
2020-07-29 19:03:30 -07:00
2021-01-20 18:11:58 -08:00
// sendTransaction will fail due to sanitization failure
2020-07-29 19:03:30 -07:00
bad_transaction . signatures . clear ( ) ;
let req = format! (
2021-01-20 18:11:58 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["{}"]}}"# ,
2020-07-29 19:03:30 -07:00
bs58 ::encode ( serialize ( & bad_transaction ) . unwrap ( ) ) . into_string ( )
) ;
let res = io . handle_request_sync ( & req , meta ) ;
assert_eq! (
res ,
Some (
2021-08-17 15:17:56 -07:00
r # "{"jsonrpc":"2.0","error":{"code":-32602,"message":"invalid transaction: Transaction failed to sanitize accounts offsets correctly"},"id":1}"# . to_string ( ) ,
2020-07-29 19:03:30 -07:00
)
) ;
2020-06-01 13:53:37 -07:00
}
2020-07-03 00:46:29 -07:00
#[ test ]
fn test_rpc_verify_filter ( ) {
2023-01-26 13:50:15 -08:00
let filter = RpcFilterType ::Memcmp ( Memcmp ::new (
0 , // offset
MemcmpEncodedBytes ::Base58 ( " 13LeFbG6m2EP1fqCj9k66fcXsoTHMMtgr7c78AivUrYD " . to_string ( ) ) , // encoded bytes
) ) ;
2020-07-03 00:46:29 -07:00
assert_eq! ( verify_filter ( & filter ) , Ok ( ( ) ) ) ;
// Invalid base-58
2023-01-26 13:50:15 -08:00
let filter = RpcFilterType ::Memcmp ( Memcmp ::new (
0 , // offset
MemcmpEncodedBytes ::Base58 ( " III " . to_string ( ) ) , // encoded bytes
) ) ;
2020-07-03 00:46:29 -07:00
assert! ( verify_filter ( & filter ) . is_err ( ) ) ;
}
2018-10-15 10:01:40 -07:00
#[ test ]
fn test_rpc_verify_pubkey ( ) {
2020-10-19 12:12:08 -07:00
let pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2021-04-21 14:12:23 -07:00
assert_eq! ( verify_pubkey ( & pubkey . to_string ( ) ) . unwrap ( ) , pubkey ) ;
2018-10-15 10:01:40 -07:00
let bad_pubkey = " a1b2c3d4 " ;
assert_eq! (
2022-01-21 16:01:22 -08:00
verify_pubkey ( bad_pubkey ) ,
2020-07-03 00:46:29 -07:00
Err ( Error ::invalid_params ( " Invalid param: WrongSize " ) )
2018-10-15 10:01:40 -07:00
) ;
}
#[ test ]
fn test_rpc_verify_signature ( ) {
2020-10-19 12:23:14 -07:00
let tx = system_transaction ::transfer (
& Keypair ::new ( ) ,
& solana_sdk ::pubkey ::new_rand ( ) ,
20 ,
hash ( & [ 0 ] ) ,
) ;
2018-10-15 10:01:40 -07:00
assert_eq! (
2018-10-26 14:43:34 -07:00
verify_signature ( & tx . signatures [ 0 ] . to_string ( ) ) . unwrap ( ) ,
tx . signatures [ 0 ]
2018-10-15 10:01:40 -07:00
) ;
let bad_signature = " a1b2c3d4 " ;
assert_eq! (
2022-01-21 16:01:22 -08:00
verify_signature ( bad_signature ) ,
2020-07-03 00:46:29 -07:00
Err ( Error ::invalid_params ( " Invalid param: WrongSize " ) )
2018-10-15 10:01:40 -07:00
) ;
}
2019-03-03 22:01:09 -08:00
2020-07-23 18:50:42 -07:00
fn new_bank_forks ( ) -> ( Arc < RwLock < BankForks > > , Keypair , Arc < Keypair > ) {
2022-11-16 19:39:11 -08:00
new_bank_forks_with_config ( BankTestConfig ::default ( ) )
}
fn new_bank_forks_with_config (
config : BankTestConfig ,
) -> ( Arc < RwLock < BankForks > > , Keypair , Arc < Keypair > ) {
2019-11-08 20:56:57 -08:00
let GenesisConfigInfo {
mut genesis_config ,
2019-05-22 20:39:00 -07:00
mint_keypair ,
2019-12-11 22:04:54 -08:00
voting_keypair ,
2021-12-29 10:34:31 -08:00
..
2019-11-08 20:56:57 -08:00
} = create_genesis_config ( TEST_MINT_LAMPORTS ) ;
2019-09-26 10:57:13 -07:00
2019-11-08 20:56:57 -08:00
genesis_config . rent . lamports_per_byte_year = 50 ;
genesis_config . rent . exemption_threshold = 2.0 ;
2019-12-11 22:04:54 -08:00
genesis_config . epoch_schedule =
EpochSchedule ::custom ( TEST_SLOTS_PER_EPOCH , TEST_SLOTS_PER_EPOCH , false ) ;
2022-10-04 09:00:34 -07:00
genesis_config . fee_rate_governor = FeeRateGovernor ::new ( TEST_SIGNATURE_FEE , 0 ) ;
2019-09-26 10:57:13 -07:00
2022-11-16 19:39:11 -08:00
let bank = Bank ::new_for_tests_with_config ( & genesis_config , config ) ;
2019-03-18 14:18:43 -07:00
(
2020-06-12 10:04:17 -07:00
Arc ::new ( RwLock ::new ( BankForks ::new ( bank ) ) ) ,
2019-05-22 20:39:00 -07:00
mint_keypair ,
2020-08-19 22:04:38 -07:00
Arc ::new ( voting_keypair ) ,
2019-03-18 14:18:43 -07:00
)
}
2020-03-04 14:44:21 -08:00
#[ test ]
fn test_rpc_get_identity ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let request = create_test_request ( " getIdentity " , None ) ;
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected : Value = json! ( { " identity " : rpc . identity . to_string ( ) } ) ;
assert_eq! ( result , expected ) ;
2021-02-23 13:06:33 -08:00
}
#[ test ]
fn test_rpc_get_max_slots ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
rpc . max_slots . retransmit . store ( 42 , Ordering ::Relaxed ) ;
rpc . max_slots . shred_insert . store ( 43 , Ordering ::Relaxed ) ;
let request = create_test_request ( " getMaxRetransmitSlot " , None ) ;
let result : Slot = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result , 42 ) ;
let request = create_test_request ( " getMaxShredInsertSlot " , None ) ;
let result : Slot = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result , 43 ) ;
2021-02-23 13:06:33 -08:00
}
2019-08-07 19:06:27 -07:00
#[ test ]
fn test_rpc_get_version ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let request = create_test_request ( " getVersion " , None ) ;
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = {
let version = solana_version ::Version ::default ( ) ;
json! ( {
2020-09-21 19:54:43 -07:00
" solana-core " : version . to_string ( ) ,
" feature-set " : version . feature_set ,
2022-03-04 02:20:11 -08:00
} )
} ;
assert_eq! ( result , expected ) ;
2019-08-07 19:06:27 -07:00
}
2019-10-14 15:24:10 -07:00
#[ test ]
2019-11-04 15:44:27 -08:00
fn test_rpc_processor_get_block_commitment ( ) {
2019-10-14 15:24:10 -07:00
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
let validator_exit = create_validator_exit ( & exit ) ;
2020-03-30 10:29:30 -07:00
let bank_forks = new_bank_forks ( ) . 0 ;
2020-04-22 11:22:09 -07:00
let ledger_path = get_tmp_ledger_path! ( ) ;
let blockstore = Arc ::new ( Blockstore ::open ( & ledger_path ) . unwrap ( ) ) ;
2020-03-30 10:29:30 -07:00
2020-04-20 22:25:49 -07:00
let commitment_slot0 = BlockCommitment ::new ( [ 8 ; MAX_LOCKOUT_HISTORY + 1 ] ) ;
let commitment_slot1 = BlockCommitment ::new ( [ 9 ; MAX_LOCKOUT_HISTORY + 1 ] ) ;
2019-11-04 15:44:27 -08:00
let mut block_commitment : HashMap < u64 , BlockCommitment > = HashMap ::new ( ) ;
block_commitment
. entry ( 0 )
2020-05-15 09:35:43 -07:00
. or_insert_with ( | | commitment_slot0 . clone ( ) ) ;
2019-11-04 15:44:27 -08:00
block_commitment
. entry ( 1 )
2020-05-15 09:35:43 -07:00
. or_insert_with ( | | commitment_slot1 . clone ( ) ) ;
2020-03-30 10:29:30 -07:00
let block_commitment_cache = Arc ::new ( RwLock ::new ( BlockCommitmentCache ::new (
block_commitment ,
42 ,
2020-08-12 20:51:15 -07:00
CommitmentSlots ::new_from_slot ( bank_forks . read ( ) . unwrap ( ) . highest_slot ( ) ) ,
2020-03-30 10:29:30 -07:00
) ) ) ;
2019-10-14 15:24:10 -07:00
2023-01-24 08:57:55 -08:00
let cluster_info = Arc ::new ( new_test_cluster_info ( ) ) ;
2020-07-08 18:13:42 -07:00
let tpu_address = cluster_info . my_contact_info ( ) . tpu ;
2020-07-10 18:14:41 -07:00
let ( request_processor , receiver ) = JsonRpcRequestProcessor ::new (
2021-02-26 21:42:09 -08:00
JsonRpcConfig ::default ( ) ,
2021-01-14 21:45:11 -08:00
None ,
2020-06-05 21:23:13 -07:00
bank_forks . clone ( ) ,
2019-11-04 15:44:27 -08:00
block_commitment_cache ,
2020-04-22 11:22:09 -07:00
blockstore ,
2019-12-19 23:27:54 -08:00
validator_exit ,
2020-05-30 00:39:24 -07:00
RpcHealth ::stub ( ) ,
2020-07-08 18:13:42 -07:00
cluster_info ,
2020-06-07 20:54:03 -07:00
Hash ::default ( ) ,
2020-07-23 09:54:57 -07:00
None ,
2020-09-28 19:43:05 -07:00
OptimisticallyConfirmedBank ::locked_from_bank_forks_root ( & bank_forks ) ,
2021-02-11 11:32:46 -08:00
Arc ::new ( RwLock ::new ( LargestAccountsCache ::new ( 30 ) ) ) ,
2021-02-23 13:06:33 -08:00
Arc ::new ( MaxSlots ::default ( ) ) ,
2021-03-23 10:48:54 -07:00
Arc ::new ( LeaderScheduleCache ::default ( ) ) ,
2021-03-26 15:47:35 -07:00
Arc ::new ( AtomicU64 ::default ( ) ) ,
2022-09-01 16:12:12 -07:00
Arc ::new ( PrioritizationFeeCache ::default ( ) ) ,
2019-10-14 15:24:10 -07:00
) ;
2022-06-08 04:57:12 -07:00
let connection_cache = Arc ::new ( ConnectionCache ::default ( ) ) ;
2021-08-23 15:32:15 -07:00
SendTransactionService ::new ::< NullTpuInfo > (
tpu_address ,
& bank_forks ,
None ,
receiver ,
2022-06-08 04:57:12 -07:00
& connection_cache ,
2021-08-23 15:32:15 -07:00
1000 ,
1 ,
) ;
2019-10-14 15:24:10 -07:00
assert_eq! (
2019-11-04 15:44:27 -08:00
request_processor . get_block_commitment ( 0 ) ,
2020-01-14 23:25:45 -08:00
RpcBlockCommitment {
2020-01-21 19:17:33 -08:00
commitment : Some ( commitment_slot0 . commitment ) ,
2020-01-14 23:25:45 -08:00
total_stake : 42 ,
}
2019-10-14 15:24:10 -07:00
) ;
assert_eq! (
2019-11-04 15:44:27 -08:00
request_processor . get_block_commitment ( 1 ) ,
2020-01-14 23:25:45 -08:00
RpcBlockCommitment {
2020-01-21 19:17:33 -08:00
commitment : Some ( commitment_slot1 . commitment ) ,
2020-01-14 23:25:45 -08:00
total_stake : 42 ,
}
) ;
assert_eq! (
request_processor . get_block_commitment ( 2 ) ,
RpcBlockCommitment {
commitment : None ,
total_stake : 42 ,
}
2019-10-14 15:24:10 -07:00
) ;
}
#[ test ]
2019-11-04 15:44:27 -08:00
fn test_rpc_get_block_commitment ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let expected_total_stake = 42 ;
let mut block_0_commitment = BlockCommitment ::default ( ) ;
block_0_commitment . increase_confirmation_stake ( 2 , 9 ) ;
let _ = std ::mem ::replace (
& mut * rpc . block_commitment_cache . write ( ) . unwrap ( ) ,
BlockCommitmentCache ::new (
HashMap ::from_iter ( std ::iter ::once ( ( 0 , block_0_commitment . clone ( ) ) ) ) ,
expected_total_stake ,
CommitmentSlots ::new_from_slot ( 0 ) ,
) ,
) ;
2019-10-14 15:24:10 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlockCommitment " , Some ( json! ( [ 0 u64 ] ) ) ) ;
let result : RpcBlockCommitment < _ > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = RpcBlockCommitment {
commitment : Some ( block_0_commitment . commitment ) ,
total_stake : expected_total_stake ,
2020-01-14 23:25:45 -08:00
} ;
2022-03-04 02:20:11 -08:00
assert_eq! ( result , expected ) ;
2019-10-14 15:24:10 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlockCommitment " , Some ( json! ( [ 1 u64 ] ) ) ) ;
let result : Value = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = json! ( {
" commitment " : null ,
" totalStake " : expected_total_stake ,
} ) ;
assert_eq! ( result , expected ) ;
2019-10-14 15:24:10 -07:00
}
2019-11-25 11:08:03 -08:00
2022-03-07 23:20:34 -08:00
#[ test ]
fn test_get_block_with_versioned_tx ( ) {
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
// Slot hashes is necessary for processing versioned txs.
bank . set_sysvar_for_tests ( & SlotHashes ::default ( ) ) ;
// Add both legacy and version #0 transactions to the block
rpc . create_test_versioned_transactions_and_populate_blockstore ( None ) ;
let request = create_test_request (
" getBlock " ,
Some ( json! ( [
0 u64 ,
{ " maxSupportedTransactionVersion " : 0 } ,
] ) ) ,
) ;
let result : Option < EncodedConfirmedBlock > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let confirmed_block = result . unwrap ( ) ;
assert_eq! ( confirmed_block . transactions . len ( ) , 2 ) ;
assert_eq! (
confirmed_block . transactions [ 0 ] . version ,
Some ( TransactionVersion ::LEGACY )
) ;
assert_eq! (
confirmed_block . transactions [ 1 ] . version ,
Some ( TransactionVersion ::Number ( 0 ) )
) ;
let request = create_test_request ( " getBlock " , Some ( json! ( [ 0 u64 , ] ) ) ) ;
let response = parse_failure_response ( rpc . handle_request_sync ( request ) ) ;
let expected = (
JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION ,
2022-10-06 02:12:56 -07:00
String ::from (
" Transaction version (0) is not supported by the requesting client. \
Please try the request again with the following configuration parameter : \
\ " maxSupportedTransactionVersion \" : 0 " ,
) ,
2022-03-07 23:20:34 -08:00
) ;
assert_eq! ( response , expected ) ;
}
2019-11-25 11:08:03 -08:00
#[ test ]
2021-04-13 00:50:15 -07:00
fn test_get_block ( ) {
2022-03-04 02:20:11 -08:00
let mut rpc = RpcHandler ::start ( ) ;
let confirmed_block_signatures = rpc . create_test_transactions_and_populate_blockstore ( ) ;
2019-11-25 11:08:03 -08:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlock " , Some ( json! ( [ 0 u64 ] ) ) ) ;
let result : Option < EncodedConfirmedBlock > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let confirmed_block = result . unwrap ( ) ;
2022-02-09 21:28:18 -08:00
assert_eq! ( confirmed_block . transactions . len ( ) , 2 ) ;
2021-03-18 10:58:20 -07:00
assert_eq! ( confirmed_block . rewards , vec! [ ] ) ;
2020-01-12 21:34:30 -08:00
2022-03-07 23:20:34 -08:00
for EncodedTransactionWithStatusMeta {
transaction ,
meta ,
version ,
} in confirmed_block . transactions . into_iter ( )
2020-01-14 23:25:45 -08:00
{
2022-03-07 23:20:34 -08:00
assert_eq! (
version , None ,
" requests which don't set max_supported_transaction_version shouldn't receive a version "
) ;
2020-03-26 13:29:30 -07:00
if let EncodedTransaction ::Json ( transaction ) = transaction {
2020-01-12 21:34:30 -08:00
if transaction . signatures [ 0 ] = = confirmed_block_signatures [ 0 ] . to_string ( ) {
2020-04-04 16:13:26 -07:00
let meta = meta . unwrap ( ) ;
assert_eq! ( meta . status , Ok ( ( ) ) ) ;
assert_eq! ( meta . err , None ) ;
2020-01-12 21:34:30 -08:00
} else if transaction . signatures [ 0 ] = = confirmed_block_signatures [ 1 ] . to_string ( ) {
2020-04-04 16:13:26 -07:00
let meta = meta . unwrap ( ) ;
2020-01-12 21:34:30 -08:00
assert_eq! (
2020-04-04 16:13:26 -07:00
meta . err ,
Some ( TransactionError ::InstructionError (
0 ,
InstructionError ::Custom ( 1 )
) )
) ;
assert_eq! (
meta . status ,
2020-01-12 21:34:30 -08:00
Err ( TransactionError ::InstructionError (
0 ,
2020-04-01 09:01:11 -07:00
InstructionError ::Custom ( 1 )
2020-01-12 21:34:30 -08:00
) )
) ;
} else {
2020-01-14 23:25:45 -08:00
assert_eq! ( meta , None ) ;
2020-01-12 21:34:30 -08:00
}
}
}
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlock " , Some ( json! ( [ 0 u64 , " binary " ] ) ) ) ;
let result : Option < EncodedConfirmedBlock > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let confirmed_block = result . unwrap ( ) ;
2022-02-09 21:28:18 -08:00
assert_eq! ( confirmed_block . transactions . len ( ) , 2 ) ;
2021-03-18 10:58:20 -07:00
assert_eq! ( confirmed_block . rewards , vec! [ ] ) ;
2019-11-25 11:08:03 -08:00
2022-03-07 23:20:34 -08:00
for EncodedTransactionWithStatusMeta {
transaction ,
meta ,
version ,
} in confirmed_block . transactions . into_iter ( )
2020-01-14 23:25:45 -08:00
{
2022-03-07 23:20:34 -08:00
assert_eq! (
version , None ,
" requests which don't set max_supported_transaction_version shouldn't receive a version "
) ;
2020-08-15 17:56:09 -07:00
if let EncodedTransaction ::LegacyBinary ( transaction ) = transaction {
2020-01-12 21:34:30 -08:00
let decoded_transaction : Transaction =
deserialize ( & bs58 ::decode ( & transaction ) . into_vec ( ) . unwrap ( ) ) . unwrap ( ) ;
if decoded_transaction . signatures [ 0 ] = = confirmed_block_signatures [ 0 ] {
2020-04-04 16:13:26 -07:00
let meta = meta . unwrap ( ) ;
assert_eq! ( meta . status , Ok ( ( ) ) ) ;
assert_eq! ( meta . err , None ) ;
2020-01-12 21:34:30 -08:00
} else if decoded_transaction . signatures [ 0 ] = = confirmed_block_signatures [ 1 ] {
2020-04-04 16:13:26 -07:00
let meta = meta . unwrap ( ) ;
assert_eq! (
meta . err ,
Some ( TransactionError ::InstructionError (
0 ,
InstructionError ::Custom ( 1 )
) )
) ;
2020-01-12 21:34:30 -08:00
assert_eq! (
2020-04-04 16:13:26 -07:00
meta . status ,
2020-01-12 21:34:30 -08:00
Err ( TransactionError ::InstructionError (
0 ,
2020-04-01 09:01:11 -07:00
InstructionError ::Custom ( 1 )
2020-01-12 21:34:30 -08:00
) )
) ;
} else {
2020-01-14 23:25:45 -08:00
assert_eq! ( meta , None ) ;
2020-01-12 21:34:30 -08:00
}
2019-11-25 11:08:03 -08:00
}
}
2021-05-26 12:27:41 -07:00
// disable rpc-tx-history
2022-03-04 02:20:11 -08:00
rpc . meta . config . enable_rpc_transaction_history = false ;
let request = create_test_request ( " getBlock " , Some ( json! ( [ 0 u64 ] ) ) ) ;
let response = parse_failure_response ( rpc . handle_request_sync ( request ) ) ;
let expected = (
JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE ,
String ::from ( " Transaction history is not available from this node " ) ,
2021-05-26 12:27:41 -07:00
) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( response , expected ) ;
2019-11-25 11:08:03 -08:00
}
2019-11-25 23:40:36 -08:00
2021-03-18 10:58:20 -07:00
#[ test ]
2021-04-13 00:50:15 -07:00
fn test_get_block_config ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let confirmed_block_signatures = rpc . create_test_transactions_and_populate_blockstore ( ) ;
let request = create_test_request (
" getBlock " ,
Some ( json! ( [
0 u64 ,
RpcBlockConfig {
encoding : None ,
transaction_details : Some ( TransactionDetails ::Signatures ) ,
rewards : Some ( false ) ,
commitment : None ,
2022-03-07 23:20:34 -08:00
max_supported_transaction_version : None ,
2022-03-04 02:20:11 -08:00
} ,
] ) ) ,
2021-03-18 10:58:20 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : Option < UiConfirmedBlock > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let confirmed_block = result . unwrap ( ) ;
2021-03-18 10:58:20 -07:00
assert! ( confirmed_block . transactions . is_none ( ) ) ;
assert! ( confirmed_block . rewards . is_none ( ) ) ;
for ( i , signature ) in confirmed_block . signatures . unwrap ( ) [ .. 2 ] . iter ( ) . enumerate ( ) {
assert_eq! ( * signature , confirmed_block_signatures [ i ] . to_string ( ) ) ;
}
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getBlock " ,
Some ( json! ( [
0 u64 ,
RpcBlockConfig {
encoding : None ,
transaction_details : Some ( TransactionDetails ::None ) ,
rewards : Some ( true ) ,
commitment : None ,
2022-03-07 23:20:34 -08:00
max_supported_transaction_version : None ,
2022-03-04 02:20:11 -08:00
} ,
] ) ) ,
2021-03-18 10:58:20 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : Option < UiConfirmedBlock > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let confirmed_block = result . unwrap ( ) ;
2021-03-18 10:58:20 -07:00
assert! ( confirmed_block . transactions . is_none ( ) ) ;
assert! ( confirmed_block . signatures . is_none ( ) ) ;
assert_eq! ( confirmed_block . rewards . unwrap ( ) , vec! [ ] ) ;
}
2021-05-07 12:43:43 -07:00
#[ test ]
fn test_get_block_production ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
rpc . add_roots_to_blockstore ( vec! [ 0 , 1 , 3 , 4 , 8 ] ) ;
rpc . block_commitment_cache
2021-05-07 12:43:43 -07:00
. write ( )
. unwrap ( )
. set_highest_confirmed_root ( 8 ) ;
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlockProduction " , Some ( json! ( [ ] ) ) ) ;
let result : RpcResponse < RpcBlockProduction > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = RpcBlockProduction {
by_identity : HashMap ::from_iter ( std ::iter ::once ( (
rpc . leader_pubkey ( ) . to_string ( ) ,
( 9 , 5 ) ,
) ) ) ,
range : RpcBlockProductionRange {
2021-05-07 12:43:43 -07:00
first_slot : 0 ,
2022-03-04 02:20:11 -08:00
last_slot : 8 ,
} ,
} ;
assert_eq! ( result . value , expected ) ;
let request = create_test_request (
" getBlockProduction " ,
Some ( json! ( [ {
" identity " : rpc . leader_pubkey ( ) . to_string ( )
} ] ) ) ,
) ;
let result : RpcResponse < RpcBlockProduction > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result . value , expected ) ;
let request = create_test_request (
" getBlockProduction " ,
Some ( json! ( [ {
" identity " : Pubkey ::new_unique ( ) . to_string ( ) ,
" range " : {
" firstSlot " : 0 u64 ,
" lastSlot " : 4 u64 ,
} ,
} ] ) ) ,
2021-05-07 12:43:43 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : RpcResponse < RpcBlockProduction > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = RpcBlockProduction {
by_identity : HashMap ::new ( ) ,
range : RpcBlockProductionRange {
2021-05-07 12:43:43 -07:00
first_slot : 0 ,
2022-03-04 02:20:11 -08:00
last_slot : 4 ,
} ,
} ;
assert_eq! ( result . value , expected ) ;
2021-05-07 12:43:43 -07:00
}
2019-12-18 15:51:47 -08:00
#[ test ]
2021-04-13 00:50:15 -07:00
fn test_get_blocks ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
2022-04-27 23:36:19 -07:00
let _ = rpc . create_test_transactions_and_populate_blockstore ( ) ;
2022-03-04 02:20:11 -08:00
rpc . add_roots_to_blockstore ( vec! [ 0 , 1 , 3 , 4 , 8 ] ) ;
rpc . block_commitment_cache
2020-04-28 10:20:43 -07:00
. write ( )
. unwrap ( )
2020-07-07 16:59:46 -07:00
. set_highest_confirmed_root ( 8 ) ;
2019-12-18 15:51:47 -08:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocks " , Some ( json! ( [ 0 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
2022-04-27 23:36:19 -07:00
assert_eq! ( result , vec! [ 0 , 1 , 3 , 4 , 8 ] ) ;
2019-12-18 15:51:47 -08:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocks " , Some ( json! ( [ 2 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result , vec! [ 3 , 4 , 8 ] ) ;
2019-12-18 15:51:47 -08:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocks " , Some ( json! ( [ 0 u64 , 4 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
2022-04-27 23:36:19 -07:00
assert_eq! ( result , vec! [ 0 , 1 , 3 , 4 ] ) ;
2019-12-18 15:51:47 -08:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocks " , Some ( json! ( [ 0 u64 , 7 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
2022-04-27 23:36:19 -07:00
assert_eq! ( result , vec! [ 0 , 1 , 3 , 4 ] ) ;
2019-12-18 15:51:47 -08:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocks " , Some ( json! ( [ 9 u64 , 11 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result , Vec ::< Slot > ::new ( ) ) ;
2020-07-06 08:37:04 -07:00
2022-03-04 02:20:11 -08:00
rpc . block_commitment_cache
2020-07-06 08:37:04 -07:00
. write ( )
. unwrap ( )
2020-07-10 12:57:32 -07:00
. set_highest_confirmed_root ( std ::u64 ::MAX ) ;
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getBlocks " ,
Some ( json! ( [ 0 u64 , MAX_GET_CONFIRMED_BLOCKS_RANGE ] ) ) ,
2020-07-06 08:37:04 -07:00
) ;
2022-03-04 02:20:11 -08:00
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
2022-04-27 23:36:19 -07:00
assert_eq! ( result , vec! [ 0 , 1 , 3 , 4 , 8 ] ) ;
2020-07-06 08:37:04 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request (
" getBlocks " ,
Some ( json! ( [ 0 u64 , MAX_GET_CONFIRMED_BLOCKS_RANGE + 1 ] ) ) ,
2020-07-06 08:37:04 -07:00
) ;
2022-03-04 02:20:11 -08:00
let response = parse_failure_response ( rpc . handle_request_sync ( request ) ) ;
let expected = (
ErrorCode ::InvalidParams . code ( ) ,
String ::from ( " Slot range too large; max 500000 " ) ,
2020-07-06 08:37:04 -07:00
) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( response , expected ) ;
2019-12-18 15:51:47 -08:00
}
2020-09-30 13:47:12 -07:00
#[ test ]
2021-04-13 00:50:15 -07:00
fn test_get_blocks_with_limit ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
rpc . add_roots_to_blockstore ( vec! [ 0 , 1 , 3 , 4 , 8 ] ) ;
rpc . block_commitment_cache
2020-09-30 13:47:12 -07:00
. write ( )
. unwrap ( )
. set_highest_confirmed_root ( 8 ) ;
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocksWithLimit " , Some ( json! ( [ 0 u64 , 500_001 u64 ] ) ) ) ;
let response = parse_failure_response ( rpc . handle_request_sync ( request ) ) ;
let expected = (
ErrorCode ::InvalidParams . code ( ) ,
String ::from ( " Limit too large; max 500000 " ) ,
2020-09-30 13:47:12 -07:00
) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( response , expected ) ;
2020-09-30 13:47:12 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocksWithLimit " , Some ( json! ( [ 0 u64 , 0 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result , Vec ::< Slot > ::new ( ) ) ;
2020-09-30 13:47:12 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocksWithLimit " , Some ( json! ( [ 2 u64 , 2 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result , vec! [ 3 , 4 ] ) ;
2020-09-30 13:47:12 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocksWithLimit " , Some ( json! ( [ 2 u64 , 3 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result , vec! [ 3 , 4 , 8 ] ) ;
2020-09-30 13:47:12 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocksWithLimit " , Some ( json! ( [ 2 u64 , 500_000 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result , vec! [ 3 , 4 , 8 ] ) ;
2020-09-30 13:47:12 -07:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlocksWithLimit " , Some ( json! ( [ 9 u64 , 500_000 u64 ] ) ) ) ;
let result : Vec < Slot > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( result , Vec ::< Slot > ::new ( ) ) ;
2020-09-30 13:47:12 -07:00
}
2019-11-25 23:40:36 -08:00
#[ test ]
fn test_get_block_time ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
rpc . add_roots_to_blockstore ( vec! [ 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ) ;
let base_timestamp = rpc
. bank_forks
2020-10-26 12:23:45 -07:00
. read ( )
. unwrap ( )
. get ( 0 )
. unwrap ( )
. unix_timestamp_from_genesis ( ) ;
2022-03-04 02:20:11 -08:00
rpc . block_commitment_cache
2020-05-04 18:39:27 -07:00
. write ( )
. unwrap ( )
2020-07-07 16:59:46 -07:00
. set_highest_confirmed_root ( 7 ) ;
2019-11-25 23:40:36 -08:00
2022-03-04 02:20:11 -08:00
let slot_duration = slot_duration_from_slots_per_year ( rpc . working_bank ( ) . slots_per_year ( ) ) ;
2019-11-25 23:40:36 -08:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlockTime " , Some ( json! ( [ 2 u64 ] ) ) ) ;
let result : Option < UnixTimestamp > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = Some ( base_timestamp ) ;
assert_eq! ( result , expected ) ;
2019-11-25 23:40:36 -08:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlockTime " , Some ( json! ( [ 7 u64 ] ) ) ) ;
let result : Option < UnixTimestamp > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let expected = Some ( base_timestamp + ( 7 * slot_duration ) . as_secs ( ) as i64 ) ;
assert_eq! ( result , expected ) ;
2019-12-06 23:12:25 -08:00
2022-03-04 02:20:11 -08:00
let request = create_test_request ( " getBlockTime " , Some ( json! ( [ 12345 u64 ] ) ) ) ;
let response = parse_failure_response ( rpc . handle_request_sync ( request ) ) ;
let expected = (
JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE ,
String ::from ( " Block not available for slot 12345 " ) ,
2020-07-20 16:03:40 -07:00
) ;
2022-03-04 02:20:11 -08:00
assert_eq! ( response , expected ) ;
2020-07-20 16:03:40 -07:00
}
2019-12-06 23:12:25 -08:00
#[ test ]
fn test_get_vote_accounts ( ) {
2022-03-04 02:20:11 -08:00
let rpc = RpcHandler ::start ( ) ;
let mut bank = rpc . working_bank ( ) ;
2019-12-06 23:12:25 -08:00
let RpcHandler {
2022-03-04 02:20:11 -08:00
ref io ,
ref meta ,
ref mint_keypair ,
ref leader_vote_keypair ,
2019-12-06 23:12:25 -08:00
..
2022-03-04 02:20:11 -08:00
} = rpc ;
2019-12-06 23:12:25 -08:00
assert_eq! ( bank . vote_accounts ( ) . len ( ) , 1 ) ;
2019-12-14 00:53:45 -08:00
// Create a vote account with no stake.
let alice_vote_keypair = Keypair ::new ( ) ;
2022-03-04 02:20:11 -08:00
let alice_vote_state = VoteState ::new (
2019-12-06 23:12:25 -08:00
& VoteInit {
2022-03-04 02:20:11 -08:00
node_pubkey : mint_keypair . pubkey ( ) ,
2019-12-14 00:53:45 -08:00
authorized_voter : alice_vote_keypair . pubkey ( ) ,
authorized_withdrawer : alice_vote_keypair . pubkey ( ) ,
2019-12-06 23:12:25 -08:00
commission : 0 ,
} ,
2022-03-04 02:20:11 -08:00
& bank . get_sysvar_cache_for_tests ( ) . get_clock ( ) . unwrap ( ) ,
2019-12-06 23:12:25 -08:00
) ;
2022-03-04 02:20:11 -08:00
rpc . store_vote_account ( & alice_vote_keypair . pubkey ( ) , alice_vote_state ) ;
2019-12-06 23:12:25 -08:00
assert_eq! ( bank . vote_accounts ( ) . len ( ) , 2 ) ;
2020-01-22 08:22:09 -08:00
// Check getVoteAccounts: the bootstrap validator vote account will be delinquent as it has
2019-12-14 00:53:45 -08:00
// stake but has never voted, and the vote account with no stake should not be present.
{
2020-05-15 09:35:43 -07:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts"}"# ;
2021-06-18 06:34:46 -07:00
let res = io . handle_request_sync ( req , meta . clone ( ) ) ;
2019-12-14 00:53:45 -08:00
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let vote_account_status : RpcVoteAccountStatus =
serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert! ( vote_account_status . current . is_empty ( ) ) ;
assert_eq! ( vote_account_status . delinquent . len ( ) , 1 ) ;
for vote_account_info in vote_account_status . delinquent {
assert_ne! ( vote_account_info . activated_stake , 0 ) ;
}
}
2021-04-20 00:31:38 -07:00
let mut advance_bank = | | {
2019-12-11 22:04:54 -08:00
bank . freeze ( ) ;
2019-12-14 00:53:45 -08:00
// Votes
2020-04-24 12:03:46 -07:00
let instructions = [
2019-12-14 00:53:45 -08:00
vote_instruction ::vote (
& leader_vote_keypair . pubkey ( ) ,
& leader_vote_keypair . pubkey ( ) ,
Vote {
slots : vec ! [ bank . slot ( ) ] ,
hash : bank . hash ( ) ,
timestamp : None ,
} ,
) ,
vote_instruction ::vote (
& alice_vote_keypair . pubkey ( ) ,
& alice_vote_keypair . pubkey ( ) ,
Vote {
slots : vec ! [ bank . slot ( ) ] ,
hash : bank . hash ( ) ,
timestamp : None ,
} ,
) ,
] ;
2019-12-11 22:04:54 -08:00
2022-03-04 02:20:11 -08:00
bank = rpc . advance_bank_to_confirmed_slot ( bank . slot ( ) + 1 ) ;
2019-12-11 22:04:54 -08:00
let transaction = Transaction ::new_signed_with_payer (
2020-04-24 12:03:46 -07:00
& instructions ,
2022-03-04 02:20:11 -08:00
Some ( & rpc . mint_keypair . pubkey ( ) ) ,
& [ & rpc . mint_keypair , leader_vote_keypair , & alice_vote_keypair ] ,
2019-12-11 22:04:54 -08:00
bank . last_blockhash ( ) ,
) ;
bank . process_transaction ( & transaction )
. expect ( " process transaction " ) ;
2021-04-20 00:31:38 -07:00
} ;
// Advance bank to the next epoch
for _ in 0 .. TEST_SLOTS_PER_EPOCH {
advance_bank ( ) ;
2019-12-11 22:04:54 -08:00
}
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"# ,
2021-01-26 11:23:07 -08:00
json! ( [ CommitmentConfig ::processed ( ) ] )
2019-12-11 22:04:54 -08:00
) ;
2019-12-06 23:12:25 -08:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let vote_account_status : RpcVoteAccountStatus =
serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
2019-12-11 22:04:54 -08:00
// The vote account with no stake should not be present.
assert! ( vote_account_status . delinquent . is_empty ( ) ) ;
2019-12-14 00:53:45 -08:00
// Both accounts should be active and have voting history.
assert_eq! ( vote_account_status . current . len ( ) , 2 ) ;
let leader_info = vote_account_status
. current
. iter ( )
. find ( | x | x . vote_pubkey = = leader_vote_keypair . pubkey ( ) . to_string ( ) )
. unwrap ( ) ;
2019-12-11 22:04:54 -08:00
assert_ne! ( leader_info . activated_stake , 0 ) ;
// Subtract one because the last vote always carries over to the next epoch
let expected_credits = TEST_SLOTS_PER_EPOCH - MAX_LOCKOUT_HISTORY as u64 - 1 ;
2020-01-21 19:08:40 -08:00
assert_eq! (
leader_info . epoch_credits ,
vec! [
( 0 , expected_credits , 0 ) ,
( 1 , expected_credits + 1 , expected_credits ) // one vote in current epoch
]
) ;
2019-12-14 00:53:45 -08:00
2021-04-26 18:27:35 -07:00
// Filter request based on the leader:
{
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"# ,
json! ( [ RpcGetVoteAccountsConfig {
vote_pubkey : Some ( leader_vote_keypair . pubkey ( ) . to_string ( ) ) ,
2021-07-02 22:51:41 -07:00
commitment : Some ( CommitmentConfig ::processed ( ) ) ,
.. RpcGetVoteAccountsConfig ::default ( )
2021-04-26 18:27:35 -07:00
} ] )
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let vote_account_status : RpcVoteAccountStatus =
serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( vote_account_status . current . len ( ) , 1 ) ;
assert_eq! ( vote_account_status . delinquent . len ( ) , 0 ) ;
for vote_account_info in vote_account_status . current {
assert_eq! (
vote_account_info . vote_pubkey ,
leader_vote_keypair . pubkey ( ) . to_string ( )
) ;
}
}
2022-09-26 16:28:29 -07:00
// Overflow the epoch credits history and ensure only `MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY`
2021-04-20 00:31:38 -07:00
// results are returned
2022-09-26 16:28:29 -07:00
for _ in
0 .. ( TEST_SLOTS_PER_EPOCH * ( MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY ) as u64 )
{
2021-04-20 00:31:38 -07:00
advance_bank ( ) ;
}
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"# ,
json! ( [ CommitmentConfig ::processed ( ) ] )
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let vote_account_status : RpcVoteAccountStatus =
serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert! ( vote_account_status . delinquent . is_empty ( ) ) ;
assert! ( ! vote_account_status
. current
. iter ( )
2022-09-26 16:28:29 -07:00
. any ( | x | x . epoch_credits . len ( ) ! = MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY ) ) ;
2021-04-20 00:31:38 -07:00
2019-12-14 00:53:45 -08:00
// Advance bank with no voting
2022-03-04 02:20:11 -08:00
rpc . advance_bank_to_confirmed_slot ( bank . slot ( ) + TEST_SLOTS_PER_EPOCH ) ;
2019-12-14 00:53:45 -08:00
// The leader vote account should now be delinquent, and the other vote account disappears
// because it's inactive with no stake
{
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"# ,
2021-01-26 11:23:07 -08:00
json! ( [ CommitmentConfig ::processed ( ) ] )
2019-12-14 00:53:45 -08:00
) ;
2022-03-04 02:20:11 -08:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2019-12-14 00:53:45 -08:00
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let vote_account_status : RpcVoteAccountStatus =
serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert! ( vote_account_status . current . is_empty ( ) ) ;
assert_eq! ( vote_account_status . delinquent . len ( ) , 1 ) ;
for vote_account_info in vote_account_status . delinquent {
assert_eq! (
vote_account_info . vote_pubkey ,
2022-03-04 02:20:11 -08:00
rpc . leader_vote_keypair . pubkey ( ) . to_string ( )
2019-12-14 00:53:45 -08:00
) ;
}
}
2019-12-06 23:12:25 -08:00
}
2020-06-25 21:06:58 -07:00
#[ test ]
2021-03-26 15:47:35 -07:00
fn test_is_finalized ( ) {
2021-08-05 09:53:29 -07:00
let bank = Arc ::new ( Bank ::default_for_tests ( ) ) ;
2020-06-25 21:06:58 -07:00
let ledger_path = get_tmp_ledger_path! ( ) ;
let blockstore = Arc ::new ( Blockstore ::open ( & ledger_path ) . unwrap ( ) ) ;
2021-07-01 20:02:40 -07:00
blockstore . set_roots ( vec! [ 0 , 1 ] . iter ( ) ) . unwrap ( ) ;
2020-06-25 21:06:58 -07:00
// Build BlockCommitmentCache with rooted slots
let mut cache0 = BlockCommitment ::default ( ) ;
cache0 . increase_rooted_stake ( 50 ) ;
let mut cache1 = BlockCommitment ::default ( ) ;
cache1 . increase_rooted_stake ( 40 ) ;
let mut cache2 = BlockCommitment ::default ( ) ;
cache2 . increase_rooted_stake ( 20 ) ;
let mut block_commitment = HashMap ::new ( ) ;
block_commitment . entry ( 1 ) . or_insert ( cache0 ) ;
block_commitment . entry ( 2 ) . or_insert ( cache1 ) ;
block_commitment . entry ( 3 ) . or_insert ( cache2 ) ;
2020-07-07 16:59:46 -07:00
let highest_confirmed_root = 1 ;
2020-07-07 19:13:30 -07:00
let block_commitment_cache = BlockCommitmentCache ::new (
block_commitment ,
50 ,
2020-07-17 10:54:49 -07:00
CommitmentSlots {
2020-07-17 08:24:51 -07:00
slot : bank . slot ( ) ,
highest_confirmed_root ,
2020-08-12 20:51:15 -07:00
.. CommitmentSlots ::default ( )
2020-07-17 08:24:51 -07:00
} ,
2020-07-07 19:13:30 -07:00
) ;
2020-06-25 21:06:58 -07:00
2021-03-26 15:47:35 -07:00
assert! ( is_finalized ( & block_commitment_cache , & bank , & blockstore , 0 ) ) ;
assert! ( is_finalized ( & block_commitment_cache , & bank , & blockstore , 1 ) ) ;
assert! ( ! is_finalized (
2020-06-25 21:06:58 -07:00
& block_commitment_cache ,
2020-07-07 19:13:30 -07:00
& bank ,
2020-06-25 21:06:58 -07:00
& blockstore ,
2
) ) ;
2021-03-26 15:47:35 -07:00
assert! ( ! is_finalized (
2020-06-25 21:06:58 -07:00
& block_commitment_cache ,
2020-07-07 19:13:30 -07:00
& bank ,
2020-06-25 21:06:58 -07:00
& blockstore ,
3
) ) ;
}
2020-07-28 22:00:48 -07:00
#[ test ]
fn test_token_rpcs ( ) {
2022-05-17 12:02:43 -07:00
for program_id in solana_account_decoder ::parse_token ::spl_token_ids ( ) {
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let RpcHandler { io , meta , .. } = rpc ;
let mint = SplTokenPubkey ::new ( & [ 2 ; 32 ] ) ;
let owner = SplTokenPubkey ::new ( & [ 3 ; 32 ] ) ;
let delegate = SplTokenPubkey ::new ( & [ 4 ; 32 ] ) ;
let token_account_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
let token_with_different_mint_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
let new_mint = SplTokenPubkey ::new ( & [ 5 ; 32 ] ) ;
if program_id = = inline_spl_token_2022 ::id ( ) {
// Add the token account
let account_base = TokenAccount {
mint ,
owner ,
delegate : COption ::Some ( delegate ) ,
amount : 420 ,
state : TokenAccountState ::Initialized ,
is_native : COption ::None ,
delegated_amount : 30 ,
close_authority : COption ::Some ( owner ) ,
} ;
let account_size = ExtensionType ::get_account_len ::< TokenAccount > ( & [
ExtensionType ::ImmutableOwner ,
ExtensionType ::MemoTransfer ,
] ) ;
let mut account_data = vec! [ 0 ; account_size ] ;
let mut account_state =
StateWithExtensionsMut ::< TokenAccount > ::unpack_uninitialized ( & mut account_data )
. unwrap ( ) ;
account_state . base = account_base ;
account_state . pack_base ( ) ;
account_state . init_account_type ( ) . unwrap ( ) ;
2022-07-25 14:39:13 -07:00
account_state
. init_extension ::< ImmutableOwner > ( true )
. unwrap ( ) ;
let mut memo_transfer = account_state . init_extension ::< MemoTransfer > ( true ) . unwrap ( ) ;
2022-05-17 12:02:43 -07:00
memo_transfer . require_incoming_transfer_memos = true . into ( ) ;
let token_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : account_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & token_account_pubkey , & token_account ) ;
// Add the mint
let mint_size =
ExtensionType ::get_account_len ::< Mint > ( & [ ExtensionType ::MintCloseAuthority ] ) ;
let mint_base = Mint {
mint_authority : COption ::Some ( owner ) ,
supply : 500 ,
decimals : 2 ,
is_initialized : true ,
freeze_authority : COption ::Some ( owner ) ,
} ;
let mut mint_data = vec! [ 0 ; mint_size ] ;
let mut mint_state =
StateWithExtensionsMut ::< Mint > ::unpack_uninitialized ( & mut mint_data ) . unwrap ( ) ;
mint_state . base = mint_base ;
mint_state . pack_base ( ) ;
mint_state . init_account_type ( ) . unwrap ( ) ;
2022-07-25 14:39:13 -07:00
let mut mint_close_authority = mint_state
. init_extension ::< MintCloseAuthority > ( true )
. unwrap ( ) ;
2022-05-17 12:02:43 -07:00
mint_close_authority . close_authority =
OptionalNonZeroPubkey ::try_from ( Some ( owner ) ) . unwrap ( ) ;
let mint_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : mint_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & Pubkey ::from_str ( & mint . to_string ( ) ) . unwrap ( ) , & mint_account ) ;
// Add another token account with the same owner, delegate, and mint
let other_token_account_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
bank . store_account ( & other_token_account_pubkey , & token_account ) ;
// Add another token account with the same owner and delegate but different mint
let mut account_data = vec! [ 0 ; TokenAccount ::get_packed_len ( ) ] ;
let token_account = TokenAccount {
mint : new_mint ,
owner ,
delegate : COption ::Some ( delegate ) ,
amount : 42 ,
state : TokenAccountState ::Initialized ,
is_native : COption ::None ,
delegated_amount : 30 ,
close_authority : COption ::Some ( owner ) ,
} ;
TokenAccount ::pack ( token_account , & mut account_data ) . unwrap ( ) ;
let token_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : account_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & token_with_different_mint_pubkey , & token_account ) ;
} else {
// Add the token account
let mut account_data = vec! [ 0 ; TokenAccount ::get_packed_len ( ) ] ;
let token_account = TokenAccount {
mint ,
owner ,
delegate : COption ::Some ( delegate ) ,
amount : 420 ,
state : TokenAccountState ::Initialized ,
is_native : COption ::None ,
delegated_amount : 30 ,
close_authority : COption ::Some ( owner ) ,
} ;
TokenAccount ::pack ( token_account , & mut account_data ) . unwrap ( ) ;
let token_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : account_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & token_account_pubkey , & token_account ) ;
// Add the mint
let mut mint_data = vec! [ 0 ; Mint ::get_packed_len ( ) ] ;
let mint_state = Mint {
mint_authority : COption ::Some ( owner ) ,
supply : 500 ,
decimals : 2 ,
is_initialized : true ,
freeze_authority : COption ::Some ( owner ) ,
} ;
Mint ::pack ( mint_state , & mut mint_data ) . unwrap ( ) ;
let mint_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : mint_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & Pubkey ::from_str ( & mint . to_string ( ) ) . unwrap ( ) , & mint_account ) ;
// Add another token account with the same owner, delegate, and mint
let other_token_account_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
bank . store_account ( & other_token_account_pubkey , & token_account ) ;
// Add another token account with the same owner and delegate but different mint
let mut account_data = vec! [ 0 ; TokenAccount ::get_packed_len ( ) ] ;
let token_account = TokenAccount {
mint : new_mint ,
owner ,
delegate : COption ::Some ( delegate ) ,
amount : 42 ,
state : TokenAccountState ::Initialized ,
is_native : COption ::None ,
delegated_amount : 30 ,
close_authority : COption ::Some ( owner ) ,
} ;
TokenAccount ::pack ( token_account , & mut account_data ) . unwrap ( ) ;
let token_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : account_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & token_with_different_mint_pubkey , & token_account ) ;
}
2020-07-28 22:00:48 -07:00
2022-05-17 12:02:43 -07:00
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenAccountBalance","params":["{token_account_pubkey}"]}}"# ,
2022-05-17 12:02:43 -07:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let balance : UiTokenAmount =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
let error = f64 ::EPSILON ;
assert! ( ( balance . ui_amount . unwrap ( ) - 4.2 ) . abs ( ) < error ) ;
assert_eq! ( balance . amount , 420. to_string ( ) ) ;
assert_eq! ( balance . decimals , 2 ) ;
assert_eq! ( balance . ui_amount_string , " 4.2 " . to_string ( ) ) ;
// Test non-existent token account
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenAccountBalance","params":["{}"]}}"# ,
solana_sdk ::pubkey ::new_rand ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
2020-08-28 14:54:57 -07:00
2022-05-17 12:02:43 -07:00
// Test get token supply, pulls supply from mint
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenSupply","params":["{mint}"]}}"# ,
2022-05-17 12:02:43 -07:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let supply : UiTokenAmount =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
let error = f64 ::EPSILON ;
assert! ( ( supply . ui_amount . unwrap ( ) - 5.0 ) . abs ( ) < error ) ;
assert_eq! ( supply . amount , 500. to_string ( ) ) ;
assert_eq! ( supply . decimals , 2 ) ;
assert_eq! ( supply . ui_amount_string , " 5 " . to_string ( ) ) ;
// Test non-existent mint address
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenSupply","params":["{}"]}}"# ,
solana_sdk ::pubkey ::new_rand ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
2020-07-28 22:00:48 -07:00
2022-05-17 12:02:43 -07:00
// Test getTokenAccountsByOwner with Token program id returns all accounts, regardless of Mint address
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
2022-12-06 06:30:06 -08:00
" params " :[ " {owner} " , { { " programId " : " {program_id} " } } , { { " encoding " :" base64 " } } ]
2022-05-17 12:02:43 -07:00
} } " #,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let accounts : Vec < RpcKeyedAccount > =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( accounts . len ( ) , 3 ) ;
2020-07-28 22:00:48 -07:00
2022-05-17 12:02:43 -07:00
// Test getTokenAccountsByOwner with jsonParsed encoding doesn't return accounts with invalid mints
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
2022-12-06 06:30:06 -08:00
" params " :[ " {owner} " , { { " programId " : " {program_id} " } } , { { " encoding " : " jsonParsed " } } ]
2022-05-17 12:02:43 -07:00
} } " #,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let accounts : Vec < RpcKeyedAccount > =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( accounts . len ( ) , 2 ) ;
2020-08-26 10:39:42 -07:00
2022-05-17 12:02:43 -07:00
// Test getProgramAccounts with jsonParsed encoding returns mints, but doesn't return accounts with invalid mints
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getProgramAccounts " ,
2022-12-06 06:30:06 -08:00
" params " :[ " {program_id} " , { { " encoding " : " jsonParsed " } } ]
2022-05-17 12:02:43 -07:00
} } " #,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let accounts : Vec < RpcKeyedAccount > =
serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
if program_id = = inline_spl_token ::id ( ) {
// native mint is included for token-v3
assert_eq! ( accounts . len ( ) , 4 ) ;
} else {
assert_eq! ( accounts . len ( ) , 3 ) ;
}
2020-08-29 11:38:27 -07:00
2022-05-17 12:02:43 -07:00
// Test returns only mint accounts
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 , " method " :" getTokenAccountsByOwner " ,
2022-12-06 06:30:06 -08:00
" params " :[ " {owner} " , { { " mint " : " {mint} " } } , { { " encoding " :" base64 " } } ]
2022-05-17 12:02:43 -07:00
} } " #,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let accounts : Vec < RpcKeyedAccount > =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( accounts . len ( ) , 2 ) ;
2020-07-28 22:00:48 -07:00
2022-05-17 12:02:43 -07:00
// Test non-existent Mint/program id
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
owner ,
solana_sdk ::pubkey ::new_rand ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
" params " :[ " {} " , { { " mint " : " {} " } } ]
} } " #,
owner ,
solana_sdk ::pubkey ::new_rand ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
2020-07-28 22:00:48 -07:00
2022-05-17 12:02:43 -07:00
// Test non-existent Owner
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
solana_sdk ::pubkey ::new_rand ( ) ,
program_id ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let accounts : Vec < RpcKeyedAccount > =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
assert! ( accounts . is_empty ( ) ) ;
2020-07-28 22:00:48 -07:00
2022-05-17 12:02:43 -07:00
// Test getTokenAccountsByDelegate with Token program id returns all accounts, regardless of Mint address
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByDelegate " ,
2022-12-06 06:30:06 -08:00
" params " :[ " {delegate} " , { { " programId " : " {program_id} " } } , { { " encoding " :" base64 " } } ]
2022-05-17 12:02:43 -07:00
} } " #,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let accounts : Vec < RpcKeyedAccount > =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( accounts . len ( ) , 3 ) ;
2020-07-28 22:00:48 -07:00
2022-05-17 12:02:43 -07:00
// Test returns only mint accounts
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 , " method " :
" getTokenAccountsByDelegate " ,
2022-12-06 06:30:06 -08:00
" params " :[ " {delegate} " , { { " mint " : " {mint} " } } , { { " encoding " :" base64 " } } ]
2022-05-17 12:02:43 -07:00
} } " #,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let accounts : Vec < RpcKeyedAccount > =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( accounts . len ( ) , 2 ) ;
2020-07-28 22:00:48 -07:00
2022-05-17 12:02:43 -07:00
// Test non-existent Mint/program id
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByDelegate " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
delegate ,
solana_sdk ::pubkey ::new_rand ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByDelegate " ,
" params " :[ " {} " , { { " mint " : " {} " } } ]
} } " #,
delegate ,
solana_sdk ::pubkey ::new_rand ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
2020-07-28 22:00:48 -07:00
2022-05-17 12:02:43 -07:00
// Test non-existent Delegate
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByDelegate " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
solana_sdk ::pubkey ::new_rand ( ) ,
program_id ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let accounts : Vec < RpcKeyedAccount > =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
assert! ( accounts . is_empty ( ) ) ;
// Add new_mint, and another token account on new_mint with different balance
let mut mint_data = vec! [ 0 ; Mint ::get_packed_len ( ) ] ;
let mint_state = Mint {
mint_authority : COption ::Some ( owner ) ,
supply : 500 ,
decimals : 2 ,
is_initialized : true ,
freeze_authority : COption ::Some ( owner ) ,
} ;
Mint ::pack ( mint_state , & mut mint_data ) . unwrap ( ) ;
let mint_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : mint_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account (
& Pubkey ::from_str ( & new_mint . to_string ( ) ) . unwrap ( ) ,
& mint_account ,
) ;
let mut account_data = vec! [ 0 ; TokenAccount ::get_packed_len ( ) ] ;
let token_account = TokenAccount {
mint : new_mint ,
owner ,
delegate : COption ::Some ( delegate ) ,
amount : 10 ,
state : TokenAccountState ::Initialized ,
is_native : COption ::None ,
delegated_amount : 30 ,
close_authority : COption ::Some ( owner ) ,
} ;
TokenAccount ::pack ( token_account , & mut account_data ) . unwrap ( ) ;
let token_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : account_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
let token_with_smaller_balance = solana_sdk ::pubkey ::new_rand ( ) ;
bank . store_account ( & token_with_smaller_balance , & token_account ) ;
2020-08-02 09:23:44 -07:00
2022-05-17 12:02:43 -07:00
// Test largest token accounts
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenLargestAccounts","params":["{new_mint}"]}}"# ,
2022-05-17 12:02:43 -07:00
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let largest_accounts : Vec < RpcTokenAccountBalance > =
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! (
largest_accounts ,
vec! [
RpcTokenAccountBalance {
address : token_with_different_mint_pubkey . to_string ( ) ,
amount : UiTokenAmount {
ui_amount : Some ( 0.42 ) ,
decimals : 2 ,
amount : " 42 " . to_string ( ) ,
ui_amount_string : " 0.42 " . to_string ( ) ,
}
} ,
RpcTokenAccountBalance {
address : token_with_smaller_balance . to_string ( ) ,
amount : UiTokenAmount {
ui_amount : Some ( 0.1 ) ,
decimals : 2 ,
amount : " 10 " . to_string ( ) ,
ui_amount_string : " 0.1 " . to_string ( ) ,
}
2020-08-04 23:48:09 -07:00
}
2022-05-17 12:02:43 -07:00
]
) ;
}
2020-07-28 22:00:48 -07:00
}
2020-08-10 13:35:36 -07:00
#[ test ]
fn test_token_parsing ( ) {
2022-05-17 12:02:43 -07:00
for program_id in solana_account_decoder ::parse_token ::spl_token_ids ( ) {
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let RpcHandler { io , meta , .. } = rpc ;
let mint = SplTokenPubkey ::new ( & [ 2 ; 32 ] ) ;
let owner = SplTokenPubkey ::new ( & [ 3 ; 32 ] ) ;
let delegate = SplTokenPubkey ::new ( & [ 4 ; 32 ] ) ;
let token_account_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
let ( program_name , account_size , mint_size ) = if program_id
= = inline_spl_token_2022 ::id ( )
{
let account_base = TokenAccount {
mint ,
owner ,
delegate : COption ::Some ( delegate ) ,
amount : 420 ,
state : TokenAccountState ::Initialized ,
is_native : COption ::Some ( 10 ) ,
delegated_amount : 30 ,
close_authority : COption ::Some ( owner ) ,
} ;
let account_size = ExtensionType ::get_account_len ::< TokenAccount > ( & [
ExtensionType ::ImmutableOwner ,
ExtensionType ::MemoTransfer ,
] ) ;
let mut account_data = vec! [ 0 ; account_size ] ;
let mut account_state =
StateWithExtensionsMut ::< TokenAccount > ::unpack_uninitialized ( & mut account_data )
. unwrap ( ) ;
account_state . base = account_base ;
account_state . pack_base ( ) ;
account_state . init_account_type ( ) . unwrap ( ) ;
2022-07-25 14:39:13 -07:00
account_state
. init_extension ::< ImmutableOwner > ( true )
. unwrap ( ) ;
let mut memo_transfer = account_state . init_extension ::< MemoTransfer > ( true ) . unwrap ( ) ;
2022-05-17 12:02:43 -07:00
memo_transfer . require_incoming_transfer_memos = true . into ( ) ;
let token_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : account_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & token_account_pubkey , & token_account ) ;
let mint_size =
ExtensionType ::get_account_len ::< Mint > ( & [ ExtensionType ::MintCloseAuthority ] ) ;
let mint_base = Mint {
mint_authority : COption ::Some ( owner ) ,
supply : 500 ,
decimals : 2 ,
is_initialized : true ,
freeze_authority : COption ::Some ( owner ) ,
} ;
let mut mint_data = vec! [ 0 ; mint_size ] ;
let mut mint_state =
StateWithExtensionsMut ::< Mint > ::unpack_uninitialized ( & mut mint_data ) . unwrap ( ) ;
mint_state . base = mint_base ;
mint_state . pack_base ( ) ;
mint_state . init_account_type ( ) . unwrap ( ) ;
2022-07-25 14:39:13 -07:00
let mut mint_close_authority = mint_state
. init_extension ::< MintCloseAuthority > ( true )
. unwrap ( ) ;
2022-05-17 12:02:43 -07:00
mint_close_authority . close_authority =
OptionalNonZeroPubkey ::try_from ( Some ( owner ) ) . unwrap ( ) ;
let mint_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : mint_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & Pubkey ::from_str ( & mint . to_string ( ) ) . unwrap ( ) , & mint_account ) ;
( " spl-token-2022 " , account_size , mint_size )
} else {
let account_size = TokenAccount ::get_packed_len ( ) ;
let mut account_data = vec! [ 0 ; account_size ] ;
let token_account = TokenAccount {
mint ,
owner ,
delegate : COption ::Some ( delegate ) ,
amount : 420 ,
state : TokenAccountState ::Initialized ,
is_native : COption ::Some ( 10 ) ,
delegated_amount : 30 ,
close_authority : COption ::Some ( owner ) ,
} ;
TokenAccount ::pack ( token_account , & mut account_data ) . unwrap ( ) ;
let token_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : account_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & token_account_pubkey , & token_account ) ;
// Add the mint
let mint_size = Mint ::get_packed_len ( ) ;
let mut mint_data = vec! [ 0 ; mint_size ] ;
let mint_state = Mint {
mint_authority : COption ::Some ( owner ) ,
supply : 500 ,
decimals : 2 ,
is_initialized : true ,
freeze_authority : COption ::Some ( owner ) ,
} ;
Mint ::pack ( mint_state , & mut mint_data ) . unwrap ( ) ;
let mint_account = AccountSharedData ::from ( Account {
lamports : 111 ,
data : mint_data . to_vec ( ) ,
owner : program_id ,
.. Account ::default ( )
} ) ;
bank . store_account ( & Pubkey ::from_str ( & mint . to_string ( ) ) . unwrap ( ) , & mint_account ) ;
( " spl-token " , account_size , mint_size )
} ;
2020-08-10 13:35:36 -07:00
2022-05-17 12:02:43 -07:00
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{token_account_pubkey}", {{"encoding": "jsonParsed"}}]}}"# ,
2022-05-17 12:02:43 -07:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let mut expected_value = json! ( {
" program " : program_name ,
" space " : account_size ,
2020-08-10 13:35:36 -07:00
" parsed " : {
" type " : " account " ,
" info " : {
" mint " : mint . to_string ( ) ,
" owner " : owner . to_string ( ) ,
" tokenAmount " : {
2021-02-25 13:53:40 -08:00
" uiAmount " : 4.2 ,
2020-08-10 13:35:36 -07:00
" decimals " : 2 ,
" amount " : " 420 " ,
2021-03-02 21:51:41 -08:00
" uiAmountString " : " 4.2 " ,
2020-08-10 13:35:36 -07:00
} ,
" delegate " : delegate . to_string ( ) ,
2020-08-28 14:54:57 -07:00
" state " : " initialized " ,
" isNative " : true ,
" rentExemptReserve " : {
2021-02-25 13:53:40 -08:00
" uiAmount " : 0.1 ,
2020-08-28 14:54:57 -07:00
" decimals " : 2 ,
" amount " : " 10 " ,
2021-03-02 21:51:41 -08:00
" uiAmountString " : " 0.1 " ,
2020-08-28 14:54:57 -07:00
} ,
2020-08-10 13:35:36 -07:00
" delegatedAmount " : {
2021-02-25 13:53:40 -08:00
" uiAmount " : 0.3 ,
2020-08-10 13:35:36 -07:00
" decimals " : 2 ,
" amount " : " 30 " ,
2021-03-02 21:51:41 -08:00
" uiAmountString " : " 0.3 " ,
2020-08-10 13:35:36 -07:00
} ,
2020-08-28 14:54:57 -07:00
" closeAuthority " : owner . to_string ( ) ,
2020-08-10 13:35:36 -07:00
}
}
2022-05-17 12:02:43 -07:00
} ) ;
if program_id = = inline_spl_token_2022 ::id ( ) {
expected_value [ " parsed " ] [ " info " ] [ " extensions " ] = json! ( [
{
" extension " : " immutableOwner "
} ,
{
" extension " : " memoTransfer " ,
" state " : {
" requireIncomingTransferMemos " : true
}
} ,
] ) ;
}
assert_eq! ( result [ " result " ] [ " value " ] [ " data " ] , expected_value ) ;
2020-08-10 13:35:36 -07:00
2022-05-17 12:02:43 -07:00
// Test Mint
let req = format! (
2022-12-06 06:30:06 -08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{mint}", {{"encoding": "jsonParsed"}}]}}"# ,
2022-05-17 12:02:43 -07:00
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let mut expected_value = json! ( {
" program " : program_name ,
" space " : mint_size ,
2020-08-10 13:35:36 -07:00
" parsed " : {
" type " : " mint " ,
" info " : {
2020-08-28 14:54:57 -07:00
" mintAuthority " : owner . to_string ( ) ,
2020-08-10 13:35:36 -07:00
" decimals " : 2 ,
2020-08-28 14:54:57 -07:00
" supply " : " 500 " . to_string ( ) ,
2020-08-10 13:35:36 -07:00
" isInitialized " : true ,
2020-08-28 14:54:57 -07:00
" freezeAuthority " : owner . to_string ( ) ,
2020-08-10 13:35:36 -07:00
}
}
2022-05-17 12:02:43 -07:00
} ) ;
if program_id = = inline_spl_token_2022 ::id ( ) {
expected_value [ " parsed " ] [ " info " ] [ " extensions " ] = json! ( [
{
" extension " : " mintCloseAuthority " ,
" state " : {
" closeAuthority " : owner . to_string ( ) ,
}
}
] ) ;
}
assert_eq! ( result [ " result " ] [ " value " ] [ " data " ] , expected_value , ) ;
}
2020-08-10 13:35:36 -07:00
}
2020-09-28 19:43:05 -07:00
2020-12-31 18:06:03 -08:00
#[ test ]
fn test_get_spl_token_owner_filter ( ) {
2022-05-17 12:02:43 -07:00
// Filtering on token-v3 length
2020-12-31 18:06:03 -08:00
let owner = Pubkey ::new_unique ( ) ;
assert_eq! (
get_spl_token_owner_filter (
& Pubkey ::from_str ( " TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 32 , owner . to_bytes ( ) . to_vec ( ) ) ) ,
2020-12-31 18:06:03 -08:00
RpcFilterType ::DataSize ( 165 )
] ,
)
. unwrap ( ) ,
owner
) ;
2022-05-17 12:02:43 -07:00
// Filtering on token-2022 account type
assert_eq! (
get_spl_token_owner_filter (
& Pubkey ::from_str ( " TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 32 , owner . to_bytes ( ) . to_vec ( ) ) ) ,
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 165 , vec! [ ACCOUNTTYPE_ACCOUNT ] ) ) ,
2022-05-17 12:02:43 -07:00
] ,
)
. unwrap ( ) ,
owner
) ;
// Filtering on token account state
assert_eq! (
get_spl_token_owner_filter (
& Pubkey ::from_str ( " TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 32 , owner . to_bytes ( ) . to_vec ( ) ) ) ,
2022-05-17 12:02:43 -07:00
RpcFilterType ::TokenAccountState ,
] ,
)
. unwrap ( ) ,
owner
) ;
// Can't filter on account type for token-v3
assert! ( get_spl_token_owner_filter (
& Pubkey ::from_str ( " TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 32 , owner . to_bytes ( ) . to_vec ( ) ) ) ,
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 165 , vec! [ ACCOUNTTYPE_ACCOUNT ] ) ) ,
2022-05-17 12:02:43 -07:00
] ,
)
. is_none ( ) ) ;
2020-12-31 18:06:03 -08:00
// Filtering on mint instead of owner
assert! ( get_spl_token_owner_filter (
& Pubkey ::from_str ( " TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 0 , owner . to_bytes ( ) . to_vec ( ) ) ) ,
2020-12-31 18:06:03 -08:00
RpcFilterType ::DataSize ( 165 )
] ,
)
. is_none ( ) ) ;
// Wrong program id
assert! ( get_spl_token_owner_filter (
& Pubkey ::new_unique ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 32 , owner . to_bytes ( ) . to_vec ( ) ) ) ,
2020-12-31 18:06:03 -08:00
RpcFilterType ::DataSize ( 165 )
] ,
)
. is_none ( ) ) ;
2022-05-17 12:02:43 -07:00
assert! ( get_spl_token_owner_filter (
& Pubkey ::new_unique ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 32 , owner . to_bytes ( ) . to_vec ( ) ) ) ,
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 165 , vec! [ ACCOUNTTYPE_ACCOUNT ] ) ) ,
2022-05-17 12:02:43 -07:00
] ,
)
. is_none ( ) ) ;
}
#[ test ]
fn test_get_spl_token_mint_filter ( ) {
// Filtering on token-v3 length
let mint = Pubkey ::new_unique ( ) ;
assert_eq! (
get_spl_token_mint_filter (
& Pubkey ::from_str ( " TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 0 , mint . to_bytes ( ) . to_vec ( ) ) ) ,
2022-05-17 12:02:43 -07:00
RpcFilterType ::DataSize ( 165 )
] ,
)
. unwrap ( ) ,
mint
) ;
// Filtering on token-2022 account type
assert_eq! (
get_spl_token_mint_filter (
& Pubkey ::from_str ( " TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 0 , mint . to_bytes ( ) . to_vec ( ) ) ) ,
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 165 , vec! [ ACCOUNTTYPE_ACCOUNT ] ) ) ,
2022-05-17 12:02:43 -07:00
] ,
)
. unwrap ( ) ,
mint
) ;
// Filtering on token account state
assert_eq! (
get_spl_token_mint_filter (
& Pubkey ::from_str ( " TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 0 , mint . to_bytes ( ) . to_vec ( ) ) ) ,
2022-05-17 12:02:43 -07:00
RpcFilterType ::TokenAccountState ,
] ,
)
. unwrap ( ) ,
mint
) ;
// Can't filter on account type for token-v3
assert! ( get_spl_token_mint_filter (
& Pubkey ::from_str ( " TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 0 , mint . to_bytes ( ) . to_vec ( ) ) ) ,
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 165 , vec! [ ACCOUNTTYPE_ACCOUNT ] ) ) ,
2022-05-17 12:02:43 -07:00
] ,
)
. is_none ( ) ) ;
// Filtering on owner instead of mint
assert! ( get_spl_token_mint_filter (
& Pubkey ::from_str ( " TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA " ) . unwrap ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 32 , mint . to_bytes ( ) . to_vec ( ) ) ) ,
2022-05-17 12:02:43 -07:00
RpcFilterType ::DataSize ( 165 )
] ,
)
. is_none ( ) ) ;
// Wrong program id
assert! ( get_spl_token_mint_filter (
& Pubkey ::new_unique ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 0 , mint . to_bytes ( ) . to_vec ( ) ) ) ,
2022-05-17 12:02:43 -07:00
RpcFilterType ::DataSize ( 165 )
] ,
)
. is_none ( ) ) ;
assert! ( get_spl_token_mint_filter (
& Pubkey ::new_unique ( ) ,
& [
2022-07-06 21:39:03 -07:00
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 0 , mint . to_bytes ( ) . to_vec ( ) ) ) ,
RpcFilterType ::Memcmp ( Memcmp ::new_raw_bytes ( 165 , vec! [ ACCOUNTTYPE_ACCOUNT ] ) ) ,
2022-05-17 12:02:43 -07:00
] ,
)
. is_none ( ) ) ;
2020-12-31 18:06:03 -08:00
}
2020-09-28 19:43:05 -07:00
#[ test ]
fn test_rpc_single_gossip ( ) {
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
let validator_exit = create_validator_exit ( & exit ) ;
let ledger_path = get_tmp_ledger_path! ( ) ;
let blockstore = Arc ::new ( Blockstore ::open ( & ledger_path ) . unwrap ( ) ) ;
let block_commitment_cache = Arc ::new ( RwLock ::new ( BlockCommitmentCache ::default ( ) ) ) ;
2023-01-24 08:57:55 -08:00
let cluster_info = Arc ::new ( new_test_cluster_info ( ) ) ;
2020-09-28 19:43:05 -07:00
let GenesisConfigInfo { genesis_config , .. } = create_genesis_config ( 100 ) ;
2021-08-05 06:42:38 -07:00
let bank = Bank ::new_for_tests ( & genesis_config ) ;
2020-09-28 19:43:05 -07:00
let bank_forks = Arc ::new ( RwLock ::new ( BankForks ::new ( bank ) ) ) ;
2022-04-28 11:51:00 -07:00
let bank0 = bank_forks . read ( ) . unwrap ( ) . get ( 0 ) . unwrap ( ) ;
2020-09-28 19:43:05 -07:00
let bank1 = Bank ::new_from_parent ( & bank0 , & Pubkey ::default ( ) , 1 ) ;
bank_forks . write ( ) . unwrap ( ) . insert ( bank1 ) ;
2022-04-28 11:51:00 -07:00
let bank1 = bank_forks . read ( ) . unwrap ( ) . get ( 1 ) . unwrap ( ) ;
2020-09-28 19:43:05 -07:00
let bank2 = Bank ::new_from_parent ( & bank1 , & Pubkey ::default ( ) , 2 ) ;
bank_forks . write ( ) . unwrap ( ) . insert ( bank2 ) ;
2022-04-28 11:51:00 -07:00
let bank2 = bank_forks . read ( ) . unwrap ( ) . get ( 2 ) . unwrap ( ) ;
2020-09-28 19:43:05 -07:00
let bank3 = Bank ::new_from_parent ( & bank2 , & Pubkey ::default ( ) , 3 ) ;
bank_forks . write ( ) . unwrap ( ) . insert ( bank3 ) ;
let optimistically_confirmed_bank =
OptimisticallyConfirmedBank ::locked_from_bank_forks_root ( & bank_forks ) ;
let mut pending_optimistically_confirmed_banks = HashSet ::new ( ) ;
2021-12-17 15:03:09 -08:00
let max_complete_transaction_status_slot = Arc ::new ( AtomicU64 ::default ( ) ) ;
2021-09-17 12:40:14 -07:00
let subscriptions = Arc ::new ( RpcSubscriptions ::new_for_tests (
2020-09-28 19:43:05 -07:00
& exit ,
2021-12-17 15:03:09 -08:00
max_complete_transaction_status_slot ,
2020-09-28 19:43:05 -07:00
bank_forks . clone ( ) ,
block_commitment_cache . clone ( ) ,
optimistically_confirmed_bank . clone ( ) ,
) ) ;
let ( meta , _receiver ) = JsonRpcRequestProcessor ::new (
JsonRpcConfig ::default ( ) ,
2021-01-14 21:45:11 -08:00
None ,
2020-09-28 19:43:05 -07:00
bank_forks . clone ( ) ,
block_commitment_cache ,
blockstore ,
validator_exit ,
RpcHealth ::stub ( ) ,
cluster_info ,
Hash ::default ( ) ,
None ,
optimistically_confirmed_bank . clone ( ) ,
2021-02-11 11:32:46 -08:00
Arc ::new ( RwLock ::new ( LargestAccountsCache ::new ( 30 ) ) ) ,
2021-02-23 13:06:33 -08:00
Arc ::new ( MaxSlots ::default ( ) ) ,
2021-03-23 10:48:54 -07:00
Arc ::new ( LeaderScheduleCache ::default ( ) ) ,
2021-03-26 15:47:35 -07:00
Arc ::new ( AtomicU64 ::default ( ) ) ,
2022-09-01 16:12:12 -07:00
Arc ::new ( PrioritizationFeeCache ::default ( ) ) ,
2020-09-28 19:43:05 -07:00
) ;
let mut io = MetaIoHandler ::default ( ) ;
2021-02-26 21:42:09 -08:00
io . extend_with ( rpc_minimal ::MinimalImpl . to_delegate ( ) ) ;
io . extend_with ( rpc_full ::FullImpl . to_delegate ( ) ) ;
2020-09-28 19:43:05 -07:00
2021-01-26 11:23:07 -08:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment":"confirmed"}]}"# ;
2020-09-28 19:43:05 -07:00
let res = io . handle_request_sync ( req , meta . clone ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let slot : Slot = serde_json ::from_value ( json [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( slot , 0 ) ;
2021-08-10 16:44:45 -07:00
let mut highest_confirmed_slot : Slot = 0 ;
let mut last_notified_confirmed_slot : Slot = 0 ;
2020-09-28 19:43:05 -07:00
OptimisticallyConfirmedBankTracker ::process_notification (
BankNotification ::OptimisticallyConfirmed ( 2 ) ,
& bank_forks ,
& optimistically_confirmed_bank ,
& subscriptions ,
& mut pending_optimistically_confirmed_banks ,
2021-08-10 16:44:45 -07:00
& mut last_notified_confirmed_slot ,
& mut highest_confirmed_slot ,
2021-09-01 14:10:16 -07:00
& None ,
2020-09-28 19:43:05 -07:00
) ;
2021-01-26 11:23:07 -08:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"# ;
2021-06-18 06:34:46 -07:00
let res = io . handle_request_sync ( req , meta . clone ( ) ) ;
2020-09-28 19:43:05 -07:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let slot : Slot = serde_json ::from_value ( json [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( slot , 2 ) ;
// Test rollback does not appear to happen, even if slots are notified out of order
OptimisticallyConfirmedBankTracker ::process_notification (
BankNotification ::OptimisticallyConfirmed ( 1 ) ,
& bank_forks ,
& optimistically_confirmed_bank ,
& subscriptions ,
& mut pending_optimistically_confirmed_banks ,
2021-08-10 16:44:45 -07:00
& mut last_notified_confirmed_slot ,
& mut highest_confirmed_slot ,
2021-09-01 14:10:16 -07:00
& None ,
2020-09-28 19:43:05 -07:00
) ;
2021-01-26 11:23:07 -08:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"# ;
2021-06-18 06:34:46 -07:00
let res = io . handle_request_sync ( req , meta . clone ( ) ) ;
2020-09-28 19:43:05 -07:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let slot : Slot = serde_json ::from_value ( json [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( slot , 2 ) ;
// Test bank will only be cached when frozen
OptimisticallyConfirmedBankTracker ::process_notification (
BankNotification ::OptimisticallyConfirmed ( 3 ) ,
& bank_forks ,
& optimistically_confirmed_bank ,
& subscriptions ,
& mut pending_optimistically_confirmed_banks ,
2021-08-10 16:44:45 -07:00
& mut last_notified_confirmed_slot ,
& mut highest_confirmed_slot ,
2021-09-01 14:10:16 -07:00
& None ,
2020-09-28 19:43:05 -07:00
) ;
2021-01-26 11:23:07 -08:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"# ;
2021-06-18 06:34:46 -07:00
let res = io . handle_request_sync ( req , meta . clone ( ) ) ;
2020-09-28 19:43:05 -07:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let slot : Slot = serde_json ::from_value ( json [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( slot , 2 ) ;
// Test freezing an optimistically confirmed bank will update cache
2022-04-28 11:51:00 -07:00
let bank3 = bank_forks . read ( ) . unwrap ( ) . get ( 3 ) . unwrap ( ) ;
2020-09-28 19:43:05 -07:00
OptimisticallyConfirmedBankTracker ::process_notification (
BankNotification ::Frozen ( bank3 ) ,
& bank_forks ,
& optimistically_confirmed_bank ,
& subscriptions ,
& mut pending_optimistically_confirmed_banks ,
2021-08-10 16:44:45 -07:00
& mut last_notified_confirmed_slot ,
& mut highest_confirmed_slot ,
2021-09-01 14:10:16 -07:00
& None ,
2020-09-28 19:43:05 -07:00
) ;
2021-01-26 11:23:07 -08:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"# ;
2021-06-18 06:34:46 -07:00
let res = io . handle_request_sync ( req , meta ) ;
2020-09-28 19:43:05 -07:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let slot : Slot = serde_json ::from_value ( json [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( slot , 3 ) ;
}
2020-10-05 20:21:33 -07:00
#[ test ]
fn test_worst_case_encoded_tx_goldens ( ) {
let ff_tx = vec! [ 0xff u8 ; PACKET_DATA_SIZE ] ;
2020-10-05 21:47:47 -07:00
let tx58 = bs58 ::encode ( & ff_tx ) . into_string ( ) ;
2021-08-13 09:08:20 -07:00
assert_eq! ( tx58 . len ( ) , MAX_BASE58_SIZE ) ;
2020-10-05 21:47:47 -07:00
let tx64 = base64 ::encode ( & ff_tx ) ;
2021-08-13 09:08:20 -07:00
assert_eq! ( tx64 . len ( ) , MAX_BASE64_SIZE ) ;
2020-10-05 21:47:47 -07:00
}
#[ test ]
2021-08-13 09:08:20 -07:00
fn test_decode_and_deserialize_too_large_payloads_fail ( ) {
2020-10-05 21:47:47 -07:00
// +2 because +1 still fits in base64 encoded worst-case
let too_big = PACKET_DATA_SIZE + 2 ;
let tx_ser = vec! [ 0xff u8 ; too_big ] ;
2022-10-24 04:19:34 -07:00
2020-10-05 21:47:47 -07:00
let tx58 = bs58 ::encode ( & tx_ser ) . into_string ( ) ;
let tx58_len = tx58 . len ( ) ;
assert_eq! (
2022-03-09 00:09:08 -08:00
decode_and_deserialize ::< Transaction > ( tx58 , TransactionBinaryEncoding ::Base58 )
. unwrap_err ( ) ,
2022-10-24 04:19:34 -07:00
Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" base58 encoded solana_sdk::transaction::Transaction too large: {tx58_len} bytes (max: encoded/raw {MAX_BASE58_SIZE}/{PACKET_DATA_SIZE}) " ,
2022-10-24 04:19:34 -07:00
)
) ) ;
2020-10-05 21:47:47 -07:00
let tx64 = base64 ::encode ( & tx_ser ) ;
let tx64_len = tx64 . len ( ) ;
assert_eq! (
2022-03-09 00:09:08 -08:00
decode_and_deserialize ::< Transaction > ( tx64 , TransactionBinaryEncoding ::Base64 )
. unwrap_err ( ) ,
2022-10-24 04:19:34 -07:00
Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" base64 encoded solana_sdk::transaction::Transaction too large: {tx64_len} bytes (max: encoded/raw {MAX_BASE64_SIZE}/{PACKET_DATA_SIZE}) " ,
2022-10-24 04:19:34 -07:00
)
) ) ;
2020-10-05 21:47:47 -07:00
let too_big = PACKET_DATA_SIZE + 1 ;
let tx_ser = vec! [ 0x00 u8 ; too_big ] ;
let tx58 = bs58 ::encode ( & tx_ser ) . into_string ( ) ;
assert_eq! (
2022-03-09 00:09:08 -08:00
decode_and_deserialize ::< Transaction > ( tx58 , TransactionBinaryEncoding ::Base58 )
. unwrap_err ( ) ,
2022-10-24 04:19:34 -07:00
Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" decoded solana_sdk::transaction::Transaction too large: {too_big} bytes (max: {PACKET_DATA_SIZE} bytes) "
2022-10-24 04:19:34 -07:00
) )
2020-10-05 21:47:47 -07:00
) ;
2022-10-24 04:19:34 -07:00
2020-10-05 21:47:47 -07:00
let tx64 = base64 ::encode ( & tx_ser ) ;
assert_eq! (
2022-03-09 00:09:08 -08:00
decode_and_deserialize ::< Transaction > ( tx64 , TransactionBinaryEncoding ::Base64 )
. unwrap_err ( ) ,
2022-10-24 04:19:34 -07:00
Error ::invalid_params ( format! (
2022-12-06 06:30:06 -08:00
" decoded solana_sdk::transaction::Transaction too large: {too_big} bytes (max: {PACKET_DATA_SIZE} bytes) "
2022-10-24 04:19:34 -07:00
) )
) ;
let tx_ser = vec! [ 0xff u8 ; PACKET_DATA_SIZE - 2 ] ;
let mut tx64 = base64 ::encode ( & tx_ser ) ;
assert_eq! (
decode_and_deserialize ::< Transaction > ( tx64 . clone ( ) , TransactionBinaryEncoding ::Base64 )
. unwrap_err ( ) ,
Error ::invalid_params (
" failed to deserialize solana_sdk::transaction::Transaction: invalid value: \
continue signal on byte - three , expected a terminal signal on or before byte - three "
. to_string ( )
)
) ;
tx64 . push ( '!' ) ;
assert_eq! (
decode_and_deserialize ::< Transaction > ( tx64 , TransactionBinaryEncoding ::Base64 )
. unwrap_err ( ) ,
Error ::invalid_params ( " invalid base64 encoding: InvalidByte(1640, 33) " . to_string ( ) )
) ;
let mut tx58 = bs58 ::encode ( & tx_ser ) . into_string ( ) ;
assert_eq! (
decode_and_deserialize ::< Transaction > ( tx58 . clone ( ) , TransactionBinaryEncoding ::Base58 )
. unwrap_err ( ) ,
Error ::invalid_params (
" failed to deserialize solana_sdk::transaction::Transaction: invalid value: \
continue signal on byte - three , expected a terminal signal on or before byte - three "
. to_string ( )
)
) ;
tx58 . push ( '!' ) ;
assert_eq! (
decode_and_deserialize ::< Transaction > ( tx58 , TransactionBinaryEncoding ::Base58 )
. unwrap_err ( ) ,
Error ::invalid_params (
" invalid base58 encoding: InvalidCharacter { character: '!', index: 1680 } "
. to_string ( ) ,
)
2020-10-05 21:47:47 -07:00
) ;
2020-10-05 20:21:33 -07:00
}
2021-01-20 18:11:58 -08:00
#[ test ]
2021-08-17 15:17:56 -07:00
fn test_sanitize_unsanitary ( ) {
2021-01-20 18:11:58 -08:00
let unsanitary_tx58 = " ju9xZWuDBX4pRxX2oZkTjxU5jB4SSTgEGhX8bQ8PURNzyzqKMPPpNvWihx8zUe \
FfrbVNoAaEsNKZvGzAnTDy5bhNT9kt6KFCTBixpvrLCzg4M5UdFUQYrn1gdgjX \
pLHxcaShD81xBNaFDgnA2nkkdHnKtZt4hVSfKAmw3VRZbjrZ7L2fKZBx21CwsG \
hD6onjM2M3qZW5C8J6d1pj41MxKmZgPBSha3MyKkNLkAGFASK "
. to_string ( ) ;
2021-08-17 15:17:56 -07:00
let unsanitary_versioned_tx = decode_and_deserialize ::< VersionedTransaction > (
unsanitary_tx58 ,
2022-03-09 00:09:08 -08:00
TransactionBinaryEncoding ::Base58 ,
2021-08-17 15:17:56 -07:00
)
. unwrap ( )
. 1 ;
2021-08-13 09:08:20 -07:00
let expect58 = Error ::invalid_params (
2021-08-17 15:17:56 -07:00
" invalid transaction: Transaction failed to sanitize accounts offsets correctly "
. to_string ( ) ,
2021-08-13 09:08:20 -07:00
) ;
2021-01-20 18:11:58 -08:00
assert_eq! (
2022-03-14 21:02:22 -07:00
sanitize_transaction ( unsanitary_versioned_tx , SimpleAddressLoader ::Disabled )
. unwrap_err ( ) ,
2021-01-20 18:11:58 -08:00
expect58
) ;
}
2022-03-07 23:20:34 -08:00
#[ test ]
fn test_sanitize_unsupported_transaction_version ( ) {
let versioned_tx = VersionedTransaction {
signatures : vec ! [ Signature ::default ( ) ] ,
message : VersionedMessage ::V0 ( v0 ::Message {
header : MessageHeader {
num_required_signatures : 1 ,
.. MessageHeader ::default ( )
} ,
account_keys : vec ! [ Pubkey ::new_unique ( ) ] ,
.. v0 ::Message ::default ( )
} ) ,
} ;
assert_eq! (
2022-03-14 21:02:22 -07:00
sanitize_transaction ( versioned_tx , SimpleAddressLoader ::Disabled ) . unwrap_err ( ) ,
2022-03-07 23:20:34 -08:00
Error ::invalid_params (
2022-10-04 09:00:34 -07:00
" invalid transaction: Transaction version is unsupported " . to_string ( ) ,
2022-03-07 23:20:34 -08:00
)
) ;
}
2022-07-17 11:39:39 -07:00
#[ test ]
fn test_rpc_get_stake_minimum_delegation ( ) {
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
let expected_stake_minimum_delegation =
solana_stake_program ::get_minimum_delegation ( & bank . feature_set ) ;
let request = create_test_request ( " getStakeMinimumDelegation " , None ) ;
let response : RpcResponse < u64 > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
let actual_stake_minimum_delegation = response . value ;
assert_eq! (
actual_stake_minimum_delegation ,
expected_stake_minimum_delegation
) ;
}
2022-09-01 16:12:12 -07:00
2022-10-04 09:00:34 -07:00
#[ test ]
fn test_get_fee_for_message ( ) {
let rpc = RpcHandler ::start ( ) ;
let bank = rpc . working_bank ( ) ;
// Slot hashes is necessary for processing versioned txs.
bank . set_sysvar_for_tests ( & SlotHashes ::default ( ) ) ;
// Correct blockhash is needed because fees are specific to blockhashes
let recent_blockhash = bank . last_blockhash ( ) ;
{
let legacy_msg = VersionedMessage ::Legacy ( Message {
header : MessageHeader {
num_required_signatures : 1 ,
.. MessageHeader ::default ( )
} ,
recent_blockhash ,
account_keys : vec ! [ Pubkey ::new_unique ( ) ] ,
.. Message ::default ( )
} ) ;
let request = create_test_request (
" getFeeForMessage " ,
2022-11-09 11:39:38 -08:00
Some ( json! ( [ base64 ::encode ( serialize ( & legacy_msg ) . unwrap ( ) ) ] ) ) ,
2022-10-04 09:00:34 -07:00
) ;
let response : RpcResponse < u64 > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( response . value , TEST_SIGNATURE_FEE ) ;
}
{
let v0_msg = VersionedMessage ::V0 ( v0 ::Message {
header : MessageHeader {
num_required_signatures : 1 ,
.. MessageHeader ::default ( )
} ,
recent_blockhash ,
account_keys : vec ! [ Pubkey ::new_unique ( ) ] ,
.. v0 ::Message ::default ( )
} ) ;
let request = create_test_request (
" getFeeForMessage " ,
2022-11-09 11:39:38 -08:00
Some ( json! ( [ base64 ::encode ( serialize ( & v0_msg ) . unwrap ( ) ) ] ) ) ,
2022-10-04 09:00:34 -07:00
) ;
let response : RpcResponse < u64 > = parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_eq! ( response . value , TEST_SIGNATURE_FEE ) ;
}
}
2022-09-01 16:12:12 -07:00
#[ test ]
fn test_rpc_get_recent_prioritization_fees ( ) {
fn wait_for_cache_blocks ( cache : & PrioritizationFeeCache , num_blocks : usize ) {
while cache . available_block_count ( ) < num_blocks {
std ::thread ::sleep ( std ::time ::Duration ::from_millis ( 100 ) ) ;
}
}
fn assert_fee_vec_eq (
expected : & mut Vec < RpcPrioritizationFee > ,
actual : & mut Vec < RpcPrioritizationFee > ,
) {
expected . sort_by ( | a , b | a . slot . partial_cmp ( & b . slot ) . unwrap ( ) ) ;
actual . sort_by ( | a , b | a . slot . partial_cmp ( & b . slot ) . unwrap ( ) ) ;
assert_eq! ( expected , actual ) ;
}
let rpc = RpcHandler ::start ( ) ;
assert_eq! (
rpc . get_prioritization_fee_cache ( ) . available_block_count ( ) ,
0
) ;
let slot0 = rpc . working_bank ( ) . slot ( ) ;
let account0 = Pubkey ::new_unique ( ) ;
let account1 = Pubkey ::new_unique ( ) ;
let account2 = Pubkey ::new_unique ( ) ;
let price0 = 42 ;
let transactions = vec! [
Transaction ::new_unsigned ( Message ::new (
& [
system_instruction ::transfer ( & account0 , & account1 , 1 ) ,
ComputeBudgetInstruction ::set_compute_unit_price ( price0 ) ,
] ,
Some ( & account0 ) ,
) ) ,
Transaction ::new_unsigned ( Message ::new (
& [ system_instruction ::transfer ( & account0 , & account2 , 1 ) ] ,
Some ( & account0 ) ,
) ) ,
] ;
rpc . update_prioritization_fee_cache ( transactions ) ;
let cache = rpc . get_prioritization_fee_cache ( ) ;
cache . finalize_priority_fee ( slot0 ) ;
wait_for_cache_blocks ( cache , 1 ) ;
let request = create_test_request ( " getRecentPrioritizationFees " , None ) ;
let mut response : Vec < RpcPrioritizationFee > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_fee_vec_eq (
& mut response ,
& mut vec! [ RpcPrioritizationFee {
slot : slot0 ,
prioritization_fee : 0 ,
} ] ,
) ;
let request = create_test_request (
" getRecentPrioritizationFees " ,
Some ( json! ( [ [ account1 . to_string ( ) ] ] ) ) ,
) ;
let mut response : Vec < RpcPrioritizationFee > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_fee_vec_eq (
& mut response ,
& mut vec! [ RpcPrioritizationFee {
slot : slot0 ,
prioritization_fee : price0 ,
} ] ,
) ;
let request = create_test_request (
" getRecentPrioritizationFees " ,
Some ( json! ( [ [ account2 . to_string ( ) ] ] ) ) ,
) ;
let mut response : Vec < RpcPrioritizationFee > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_fee_vec_eq (
& mut response ,
& mut vec! [ RpcPrioritizationFee {
slot : slot0 ,
prioritization_fee : 0 ,
} ] ,
) ;
rpc . advance_bank_to_confirmed_slot ( 1 ) ;
let slot1 = rpc . working_bank ( ) . slot ( ) ;
let price1 = 11 ;
let transactions = vec! [
Transaction ::new_unsigned ( Message ::new (
& [
system_instruction ::transfer ( & account0 , & account2 , 1 ) ,
ComputeBudgetInstruction ::set_compute_unit_price ( price1 ) ,
] ,
Some ( & account0 ) ,
) ) ,
Transaction ::new_unsigned ( Message ::new (
& [ system_instruction ::transfer ( & account0 , & account1 , 1 ) ] ,
Some ( & account0 ) ,
) ) ,
] ;
rpc . update_prioritization_fee_cache ( transactions ) ;
let cache = rpc . get_prioritization_fee_cache ( ) ;
cache . finalize_priority_fee ( slot1 ) ;
wait_for_cache_blocks ( cache , 2 ) ;
let request = create_test_request ( " getRecentPrioritizationFees " , None ) ;
let mut response : Vec < RpcPrioritizationFee > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_fee_vec_eq (
& mut response ,
& mut vec! [
RpcPrioritizationFee {
slot : slot0 ,
prioritization_fee : 0 ,
} ,
RpcPrioritizationFee {
slot : slot1 ,
prioritization_fee : 0 ,
} ,
] ,
) ;
let request = create_test_request (
" getRecentPrioritizationFees " ,
Some ( json! ( [ [ account1 . to_string ( ) ] ] ) ) ,
) ;
let mut response : Vec < RpcPrioritizationFee > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_fee_vec_eq (
& mut response ,
& mut vec! [
RpcPrioritizationFee {
slot : slot0 ,
prioritization_fee : price0 ,
} ,
RpcPrioritizationFee {
slot : slot1 ,
prioritization_fee : 0 ,
} ,
] ,
) ;
let request = create_test_request (
" getRecentPrioritizationFees " ,
Some ( json! ( [ [ account2 . to_string ( ) ] ] ) ) ,
) ;
let mut response : Vec < RpcPrioritizationFee > =
parse_success_result ( rpc . handle_request_sync ( request ) ) ;
assert_fee_vec_eq (
& mut response ,
& mut vec! [
RpcPrioritizationFee {
slot : slot0 ,
prioritization_fee : 0 ,
} ,
RpcPrioritizationFee {
slot : slot1 ,
prioritization_fee : price1 ,
} ,
] ,
) ;
}
2018-08-13 10:24:39 -07:00
}