2018-08-16 08:46:07 -06:00
//! The `rpc` module implements the Solana RPC interface.
2018-08-10 17:05:23 -06:00
2019-10-14 16:24:10 -06:00
use crate ::{
2020-09-08 02:00:49 -07:00
cluster_info ::ClusterInfo ,
contact_info ::ContactInfo ,
2021-02-23 13:06:33 -08:00
max_slots ::MaxSlots ,
2020-09-08 02:00:49 -07:00
non_circulating_supply ::calculate_non_circulating_supply ,
2020-09-28 20:43:05 -06:00
optimistically_confirmed_bank_tracker ::OptimisticallyConfirmedBank ,
2020-09-08 02:00:49 -07:00
rpc_health ::* ,
send_transaction_service ::{ SendTransactionService , TransactionInfo } ,
validator ::ValidatorExit ,
2019-10-14 16:24:10 -06:00
} ;
2020-07-09 00:08:05 +00:00
use bincode ::{ config ::Options , serialize } ;
2020-08-08 22:40:13 -07:00
use jsonrpc_core ::{ types ::error , Error , Metadata , Result } ;
2019-02-04 17:41:03 -07:00
use jsonrpc_derive ::rpc ;
2020-08-05 00:48:09 -06:00
use solana_account_decoder ::{
2020-08-07 11:37:39 -06:00
parse_account_data ::AccountAdditionalData ,
parse_token ::{
2020-08-28 15:54:57 -06:00
get_token_account_mint , spl_token_id_v2_0 , spl_token_v2_0_native_mint ,
2020-08-07 11:37:39 -06:00
token_amount_to_ui_amount , UiTokenAmount ,
} ,
2020-09-03 11:35:06 -06:00
UiAccount , UiAccountData , UiAccountEncoding , UiDataSliceConfig ,
2020-08-05 00:48:09 -06:00
} ;
2020-04-20 22:01:09 -07:00
use solana_client ::{
2021-02-11 11:32:46 -08:00
rpc_cache ::LargestAccountsCache ,
2020-05-12 21:05:05 -06:00
rpc_config ::* ,
2020-10-12 17:47:06 -07:00
rpc_custom_error ::RpcCustomError ,
2020-07-28 23:00:48 -06:00
rpc_filter ::{ Memcmp , MemcmpEncodedBytes , RpcFilterType } ,
2020-04-20 22:01:09 -07:00
rpc_request ::{
2020-07-31 14:53:49 -06:00
TokenAccountsFilter , DELINQUENT_VALIDATOR_SLOT_DISTANCE , MAX_GET_CONFIRMED_BLOCKS_RANGE ,
2020-07-27 11:42:49 -07:00
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT ,
2021-02-22 22:54:35 -08:00
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE , MAX_GET_PROGRAM_ACCOUNT_FILTERS ,
2020-09-03 11:35:06 -06:00
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS , MAX_MULTIPLE_ACCOUNTS , NUM_LARGEST_ACCOUNTS ,
2020-04-20 22:01:09 -07:00
} ,
2020-06-11 16:51:25 -06:00
rpc_response ::Response as RpcResponse ,
2020-04-20 22:01:09 -07:00
rpc_response ::* ,
} ;
2019-12-16 14:05:17 -07:00
use solana_faucet ::faucet ::request_airdrop_transaction ;
2020-09-24 14:22:22 -07:00
use solana_ledger ::{ blockstore ::Blockstore , blockstore_db ::BlockstoreError , get_tmp_ledger_path } ;
2020-10-13 13:33:38 -06:00
use solana_metrics ::inc_new_counter_info ;
2020-03-17 23:30:23 -07:00
use solana_perf ::packet ::PACKET_DATA_SIZE ;
2020-06-17 09:27:03 -06:00
use solana_runtime ::{
2020-06-25 22:06:58 -06:00
accounts ::AccountAddressFilter ,
2020-12-31 18:06:03 -08:00
accounts_index ::{ AccountIndex , IndexKey } ,
2020-06-25 22:06:58 -06:00
bank ::Bank ,
2021-01-14 21:45:11 -08:00
bank_forks ::{ BankForks , SnapshotConfig } ,
2020-07-17 11:54:49 -06:00
commitment ::{ BlockCommitmentArray , BlockCommitmentCache , CommitmentSlots } ,
2020-12-31 18:06:03 -08:00
inline_spl_token_v2_0 ::{ SPL_TOKEN_ACCOUNT_MINT_OFFSET , SPL_TOKEN_ACCOUNT_OWNER_OFFSET } ,
2021-01-14 21:45:11 -08:00
snapshot_utils ::get_highest_snapshot_archive_path ,
2020-06-17 09:27:03 -06:00
} ;
2019-10-14 16:24:10 -06:00
use solana_sdk ::{
2021-03-09 16:31:33 -06:00
account ::{ AccountSharedData , ReadableAccount } ,
2020-07-06 13:28:40 -06:00
account_utils ::StateMut ,
2020-12-29 09:48:43 -07:00
clock ::{ Slot , UnixTimestamp , MAX_RECENT_BLOCKHASHES } ,
2019-11-06 14:15:00 -07:00
commitment_config ::{ CommitmentConfig , CommitmentLevel } ,
2020-05-20 16:42:46 -07:00
epoch_info ::EpochInfo ,
2019-10-22 16:41:18 -04:00
epoch_schedule ::EpochSchedule ,
2019-10-14 16:24:10 -06:00
hash ::Hash ,
pubkey ::Pubkey ,
2021-01-20 18:11:58 -08:00
sanitize ::Sanitize ,
2019-11-14 16:34:39 -07:00
signature ::Signature ,
2020-07-06 13:28:40 -06:00
stake_history ::StakeHistory ,
2020-09-08 09:23:16 -07:00
system_instruction ,
2020-10-28 22:01:07 -07:00
sysvar ::stake_history ,
2020-04-02 02:30:58 +08:00
transaction ::{ self , Transaction } ,
2019-10-14 16:24:10 -06:00
} ;
2020-07-06 13:28:40 -06:00
use solana_stake_program ::stake_state ::StakeState ;
2020-04-09 00:57:30 -06:00
use solana_transaction_status ::{
2021-01-15 09:05:05 -07:00
EncodedConfirmedBlock , EncodedConfirmedTransaction , TransactionConfirmationStatus ,
TransactionStatus , UiTransactionEncoding ,
2020-04-09 00:57:30 -06:00
} ;
2019-11-20 10:12:43 -08:00
use solana_vote_program ::vote_state ::{ VoteState , MAX_LOCKOUT_HISTORY } ;
2020-08-28 15:54:57 -06:00
use spl_token_v2_0 ::{
2020-11-04 11:18:20 -08:00
solana_program ::program_pack ::Pack ,
2020-08-28 15:54:57 -06:00
state ::{ Account as TokenAccount , Mint } ,
} ;
2019-10-14 16:24:10 -06:00
use std ::{
2020-05-04 19:39:27 -06:00
cmp ::{ max , min } ,
2020-05-04 17:46:10 -06:00
collections ::{ HashMap , HashSet } ,
2020-06-05 21:23:13 -07:00
net ::SocketAddr ,
2020-03-06 17:01:31 -07:00
str ::FromStr ,
2020-06-16 23:30:59 -06:00
sync ::{
atomic ::{ AtomicBool , Ordering } ,
2020-07-10 19:14:41 -06:00
mpsc ::{ channel , Receiver , Sender } ,
Arc , Mutex , RwLock ,
2020-06-16 23:30:59 -06:00
} ,
2021-01-19 22:57:16 +09:00
time ::Duration ,
2019-10-14 16:24:10 -06:00
} ;
2021-02-05 00:21:53 -07:00
use tokio ::runtime ::Runtime ;
2018-08-10 17:05:23 -06:00
2020-09-16 12:50:43 -06:00
pub const MAX_REQUEST_PAYLOAD_SIZE : usize = 50 * ( 1 < < 10 ) ; // 50kB
2020-09-22 12:26:32 -07:00
pub const PERFORMANCE_SAMPLES_LIMIT : usize = 720 ;
2020-09-16 12:50:43 -06:00
2020-07-03 17:39:14 -06:00
fn new_response < T > ( bank : & Bank , value : T ) -> RpcResponse < T > {
2019-11-12 14:49:41 -05:00
let context = RpcResponseContext { slot : bank . slot ( ) } ;
2020-07-03 17:39:14 -06:00
Response { context , value }
2019-11-12 14:49:41 -05:00
}
2020-06-25 22:06:58 -06:00
pub fn is_confirmed_rooted (
block_commitment_cache : & BlockCommitmentCache ,
2020-07-07 20:13:30 -06:00
bank : & Bank ,
2020-06-25 22:06:58 -06:00
blockstore : & Blockstore ,
slot : Slot ,
) -> bool {
2020-07-07 17:59:46 -06:00
slot < = block_commitment_cache . highest_confirmed_root ( )
2020-07-07 20:13:30 -06:00
& & ( blockstore . is_root ( slot ) | | bank . status_cache_ancestors ( ) . contains ( & slot ) )
2020-06-25 22:06:58 -06:00
}
2020-01-30 10:17:01 -07:00
#[ derive(Debug, Default, Clone) ]
2019-03-05 21:12:30 -08:00
pub struct JsonRpcConfig {
2020-03-23 11:25:39 -06:00
pub enable_rpc_transaction_history : bool ,
2021-02-01 14:00:51 -07:00
pub enable_cpi_and_log_storage : bool ,
2020-03-04 14:44:21 -08:00
pub identity_pubkey : Pubkey ,
2019-12-16 14:05:17 -07:00
pub faucet_addr : Option < SocketAddr > ,
2020-05-29 15:31:52 -07:00
pub health_check_slot_distance : u64 ,
2020-07-23 09:54:57 -07:00
pub enable_bigtable_ledger_storage : bool ,
2020-09-03 11:30:21 -07:00
pub enable_bigtable_ledger_upload : bool ,
2020-12-07 09:22:35 -08:00
pub max_multiple_accounts : Option < usize > ,
2020-12-31 18:06:03 -08:00
pub account_indexes : HashSet < AccountIndex > ,
2021-01-12 17:13:47 -08:00
pub rpc_threads : usize ,
2021-01-19 22:57:16 +09:00
pub rpc_bigtable_timeout : Option < Duration > ,
2021-02-26 21:42:09 -08:00
pub minimal_api : bool ,
2019-03-03 22:01:09 -08:00
}
2019-02-17 10:29:08 -07:00
#[ derive(Clone) ]
pub struct JsonRpcRequestProcessor {
2019-03-18 14:18:43 -07:00
bank_forks : Arc < RwLock < BankForks > > ,
2019-11-04 16:44:27 -07:00
block_commitment_cache : Arc < RwLock < BlockCommitmentCache > > ,
2020-01-13 14:13:52 -07: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-03-01 13:20:04 -08:00
validator_exit : Arc < RwLock < ValidatorExit > > ,
2020-05-30 00:39:24 -07:00
health : Arc < RpcHealth > ,
2020-06-07 21:54:03 -06:00
cluster_info : Arc < ClusterInfo > ,
genesis_hash : Hash ,
2020-07-10 19:14:41 -06:00
transaction_sender : Arc < Mutex < Sender < TransactionInfo > > > ,
2021-02-05 00:21:53 -07:00
runtime : Arc < Runtime > ,
2020-07-23 09:54:57 -07:00
bigtable_ledger_storage : Option < solana_storage_bigtable ::LedgerStorage > ,
2020-09-28 20:43:05 -06: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 > ,
2018-08-14 18:03:48 -06:00
}
2020-06-07 21:54:03 -06:00
impl Metadata for JsonRpcRequestProcessor { }
2018-08-14 18:03:48 -06:00
2019-02-17 10:29:08 -07:00
impl JsonRpcRequestProcessor {
2021-01-26 12:23:07 -07:00
#[ allow(deprecated) ]
2020-07-03 17:39:14 -06:00
fn bank ( & self , commitment : Option < CommitmentConfig > ) -> Arc < Bank > {
2019-11-06 14:15:00 -07:00
debug! ( " RPC commitment_config: {:?} " , commitment ) ;
let r_bank_forks = self . bank_forks . read ( ) . unwrap ( ) ;
2020-05-18 12:49:01 -06:00
2021-01-26 12:23:07 -07:00
let commitment = commitment . unwrap_or_default ( ) ;
2020-06-25 17:08:55 -06:00
2021-01-26 12:23:07 -07:00
if commitment . is_confirmed ( ) {
2020-09-28 20:43:05 -06:00
let bank = self
. optimistically_confirmed_bank
. read ( )
. unwrap ( )
. bank
. clone ( ) ;
debug! ( " RPC using optimistically confirmed slot: {:?} " , bank . slot ( ) ) ;
return bank ;
}
2020-07-20 17:03:40 -06:00
let slot = self
. block_commitment_cache
. read ( )
. unwrap ( )
2021-01-26 12:23:07 -07:00
. slot_with_commitment ( commitment . commitment ) ;
2020-07-20 17:03:40 -06:00
2021-01-26 12:23:07 -07:00
match commitment . commitment {
// Recent variant is deprecated
CommitmentLevel ::Recent | CommitmentLevel ::Processed = > {
2020-07-20 17:03:40 -06:00
debug! ( " RPC using the heaviest slot: {:?} " , slot ) ;
2020-05-18 12:49:01 -06:00
}
2021-01-26 12:23:07 -07:00
// Root variant is deprecated
2020-06-25 17:08:55 -06:00
CommitmentLevel ::Root = > {
2020-05-18 12:49:01 -06:00
debug! ( " RPC using node root: {:?} " , slot ) ;
}
2021-01-26 12:23:07 -07:00
// Single variant is deprecated
2020-09-28 20:43:05 -06:00
CommitmentLevel ::Single = > {
2020-05-18 12:49:01 -06:00
debug! ( " RPC using confirmed slot: {:?} " , slot ) ;
}
2021-01-26 12:23:07 -07:00
// Max variant is deprecated
CommitmentLevel ::Max | CommitmentLevel ::Finalized = > {
2020-07-03 17:39:14 -06:00
debug! ( " RPC using block: {:?} " , slot ) ;
2020-05-18 12:49:01 -06:00
}
2021-01-26 12:23:07 -07:00
CommitmentLevel ::SingleGossip | CommitmentLevel ::Confirmed = > unreachable! ( ) , // SingleGossip variant is deprecated
2020-07-03 17:39:14 -06:00
} ;
2020-07-20 17:03:40 -06:00
2020-07-23 18:57:15 -06:00
r_bank_forks . get ( slot ) . cloned ( ) . unwrap_or_else ( | | {
2020-11-18 20:36:10 -07:00
// We log a warning instead of returning an error, because all known error cases
2020-07-23 18:57:15 -06: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 20:36:10 -07:00
warn! (
2020-07-23 18:57:15 -06:00
" Bank with {:?} not found at slot: {:?} " ,
2021-01-26 12:23:07 -07:00
commitment . commitment , slot
2020-07-23 18:57:15 -06:00
) ;
2020-12-27 13:28:05 +00:00
r_bank_forks . root_bank ( )
2020-07-23 18:57:15 -06:00
} )
2019-02-20 21:23:44 -08:00
}
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 16:44:27 -07:00
block_commitment_cache : Arc < RwLock < BlockCommitmentCache > > ,
2020-01-13 14:13:52 -07:00
blockstore : Arc < Blockstore > ,
2021-03-01 13:20:04 -08:00
validator_exit : Arc < RwLock < ValidatorExit > > ,
2020-05-30 00:39:24 -07:00
health : Arc < RpcHealth > ,
2020-06-07 21:54:03 -06:00
cluster_info : Arc < ClusterInfo > ,
genesis_hash : Hash ,
2021-02-05 00:21:53 -07:00
runtime : Arc < Runtime > ,
2020-07-23 09:54:57 -07:00
bigtable_ledger_storage : Option < solana_storage_bigtable ::LedgerStorage > ,
2020-09-28 20:43:05 -06: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 > ,
2020-07-10 19:14:41 -06:00
) -> ( Self , Receiver < TransactionInfo > ) {
let ( sender , receiver ) = channel ( ) ;
(
Self {
config ,
2021-01-14 21:45:11 -08:00
snapshot_config ,
2020-07-10 19:14:41 -06:00
bank_forks ,
block_commitment_cache ,
blockstore ,
validator_exit ,
health ,
cluster_info ,
genesis_hash ,
transaction_sender : Arc ::new ( Mutex ::new ( sender ) ) ,
2021-02-05 00:21:53 -07:00
runtime ,
2020-07-23 09:54:57 -07:00
bigtable_ledger_storage ,
2020-09-28 20:43:05 -06: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 ,
2020-07-10 19:14:41 -06:00
} ,
receiver ,
)
2019-01-15 12:20:07 -08:00
}
2020-06-16 23:30:59 -06:00
// Useful for unit testing
pub fn new_from_bank ( bank : & Arc < Bank > ) -> Self {
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 ) ) ;
let cluster_info = Arc ::new ( ClusterInfo ::default ( ) ) ;
2020-07-08 19:13:42 -06:00
let tpu_address = cluster_info . my_contact_info ( ) . tpu ;
2020-07-10 19:14:41 -06:00
let ( sender , receiver ) = channel ( ) ;
2020-12-17 14:37:22 -08:00
SendTransactionService ::new ( tpu_address , & bank_forks , None , receiver , 1000 , 1 ) ;
2020-07-10 19:14:41 -06:00
2020-06-16 23:30:59 -06:00
Self {
config : JsonRpcConfig ::default ( ) ,
2021-01-14 21:45:11 -08:00
snapshot_config : None ,
2020-07-10 19:14:41 -06:00
bank_forks ,
2020-06-16 23:30:59 -06:00
block_commitment_cache : Arc ::new ( RwLock ::new ( BlockCommitmentCache ::new (
HashMap ::new ( ) ,
0 ,
2020-08-12 21:51:15 -06:00
CommitmentSlots ::new_from_slot ( bank . slot ( ) ) ,
2020-06-16 23:30:59 -06:00
) ) ) ,
blockstore ,
validator_exit : create_validator_exit ( & exit ) ,
health : Arc ::new ( RpcHealth ::new ( cluster_info . clone ( ) , None , 0 , exit . clone ( ) ) ) ,
2020-07-08 19:13:42 -06:00
cluster_info ,
2020-06-16 23:30:59 -06:00
genesis_hash ,
2020-07-10 19:14:41 -06:00
transaction_sender : Arc ::new ( Mutex ::new ( sender ) ) ,
2021-02-05 00:21:53 -07:00
runtime : Arc ::new ( Runtime ::new ( ) . expect ( " Runtime " ) ) ,
2020-07-23 09:54:57 -07:00
bigtable_ledger_storage : None ,
2020-09-28 20:43:05 -06: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 ( ) ) ,
2020-06-16 23:30:59 -06:00
}
}
2019-11-06 14:15:00 -07:00
pub fn get_account_info (
& self ,
2020-06-25 17:08:55 -06:00
pubkey : & Pubkey ,
2020-06-30 22:55:11 -06:00
config : Option < RpcAccountInfoConfig > ,
2020-08-08 22:40:13 -07:00
) -> Result < RpcResponse < Option < UiAccount > > > {
2020-06-30 22:55:11 -06:00
let config = config . unwrap_or_default ( ) ;
2020-07-03 17:39:14 -06:00
let bank = self . bank ( config . commitment ) ;
2020-06-30 22:55:11 -06:00
let encoding = config . encoding . unwrap_or ( UiAccountEncoding ::Binary ) ;
2020-08-10 16:35:29 -06:00
check_slice_and_encoding ( & encoding , config . data_slice . is_some ( ) ) ? ;
2020-08-08 22:40:13 -07:00
2020-09-03 11:35:06 -06:00
let response = get_encoded_account ( & bank , pubkey , encoding , config . 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 11:35:06 -06:00
pub fn get_multiple_accounts (
& self ,
pubkeys : Vec < Pubkey > ,
config : Option < RpcAccountInfoConfig > ,
) -> Result < RpcResponse < Vec < Option < UiAccount > > > > {
let mut accounts : Vec < Option < UiAccount > > = vec! [ ] ;
let config = config . unwrap_or_default ( ) ;
let bank = self . bank ( config . commitment ) ;
let encoding = config . encoding . unwrap_or ( UiAccountEncoding ::Base64 ) ;
check_slice_and_encoding ( & encoding , config . data_slice . is_some ( ) ) ? ;
for pubkey in pubkeys {
let response_account =
get_encoded_account ( & bank , & pubkey , encoding . clone ( ) , config . data_slice ) ? ;
accounts . push ( response_account )
}
2020-09-03 11:57:57 -06:00
Ok ( new_response ( & bank , accounts ) )
2020-09-03 11:35:06 -06:00
}
2019-11-06 14:15:00 -07:00
pub fn get_minimum_balance_for_rent_exemption (
& self ,
data_len : usize ,
commitment : Option < CommitmentConfig > ,
2020-07-03 17:39:14 -06:00
) -> u64 {
self . bank ( commitment )
. get_minimum_balance_for_rent_exemption ( data_len )
2019-09-26 23:27:13 +05:30
}
2019-11-06 14:15:00 -07:00
pub fn get_program_accounts (
& self ,
program_id : & Pubkey ,
2020-06-30 22:55:11 -06:00
config : Option < RpcAccountInfoConfig > ,
2020-07-03 01:46:29 -06:00
filters : Vec < RpcFilterType > ,
2020-08-10 16:35:29 -06:00
) -> Result < Vec < RpcKeyedAccount > > {
2020-06-30 22:55:11 -06:00
let config = config . unwrap_or_default ( ) ;
2020-07-03 17:39:14 -06:00
let bank = self . bank ( config . commitment ) ;
2020-06-30 22:55:11 -06:00
let encoding = config . encoding . unwrap_or ( UiAccountEncoding ::Binary ) ;
2020-08-10 16:35:29 -06:00
let data_slice_config = config . data_slice ;
check_slice_and_encoding ( & encoding , data_slice_config . is_some ( ) ) ? ;
2020-12-31 18:06:03 -08:00
let keyed_accounts = {
if let Some ( owner ) = get_spl_token_owner_filter ( program_id , & filters ) {
self . get_filtered_spl_token_accounts_by_owner ( & bank , & owner , filters )
2021-02-09 15:49:13 -07:00
} else if let Some ( mint ) = get_spl_token_mint_filter ( program_id , & filters ) {
self . get_filtered_spl_token_accounts_by_mint ( & bank , & mint , filters )
2020-12-31 18:06:03 -08:00
} else {
self . get_filtered_program_accounts ( & bank , program_id , filters )
}
} ;
2020-08-10 16:35:29 -06:00
let result =
2020-08-28 15:54:57 -06:00
if program_id = = & spl_token_id_v2_0 ( ) & & encoding = = UiAccountEncoding ::JsonParsed {
2020-12-31 18:06:03 -08:00
get_parsed_token_accounts ( bank , keyed_accounts . into_iter ( ) ) . collect ( )
2020-08-10 16:35:29 -06:00
} else {
keyed_accounts
2020-12-31 18:06:03 -08:00
. into_iter ( )
2020-08-10 16:35:29 -06:00
. map ( | ( pubkey , account ) | RpcKeyedAccount {
pubkey : pubkey . to_string ( ) ,
account : UiAccount ::encode (
& pubkey ,
account ,
encoding . clone ( ) ,
None ,
data_slice_config ,
) ,
} )
. collect ( )
} ;
Ok ( result )
2019-06-29 10:59:07 -06:00
}
2020-05-29 12:50:25 -06:00
pub fn get_inflation_governor (
& self ,
commitment : Option < CommitmentConfig > ,
2020-07-03 17:39:14 -06:00
) -> RpcInflationGovernor {
self . bank ( commitment ) . inflation ( ) . into ( )
2020-05-29 12:50:25 -06:00
}
2020-07-03 17:39:14 -06: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-11 16:42:39 +09:00
let slot_in_year = bank . slot_in_year_for_inflation ( ) ;
2020-05-29 12:50:25 -06:00
2020-07-03 17:39:14 -06:00
RpcInflationRate {
2020-12-11 16:42:39 +09:00
total : inflation . total ( slot_in_year ) ,
validator : inflation . validator ( slot_in_year ) ,
foundation : inflation . foundation ( slot_in_year ) ,
2020-05-29 12:50:25 -06:00
epoch ,
2020-07-03 17:39:14 -06:00
}
2019-08-27 18:17:03 -04:00
}
2020-07-03 17:39:14 -06:00
pub fn get_epoch_schedule ( & self ) -> EpochSchedule {
2019-11-08 23:56:57 -05:00
// Since epoch schedule data comes from the genesis config, any commitment level should be
2019-11-06 14:15:00 -07:00
// fine
2021-01-26 12:23:07 -07:00
let bank = self . bank ( Some ( CommitmentConfig ::finalized ( ) ) ) ;
2020-07-03 17:39:14 -06:00
* bank . epoch_schedule ( )
2019-10-22 16:41:18 -04:00
}
2019-11-12 14:49:41 -05:00
pub fn get_balance (
& self ,
2020-06-25 17:08:55 -06:00
pubkey : & Pubkey ,
2019-11-12 14:49:41 -05:00
commitment : Option < CommitmentConfig > ,
2020-07-03 17:39:14 -06:00
) -> RpcResponse < u64 > {
let bank = self . bank ( commitment ) ;
2020-06-25 17:08:55 -06:00
new_response ( & bank , bank . get_balance ( pubkey ) )
2019-02-17 10:29:08 -07:00
}
2019-02-26 12:25:46 -08:00
2019-11-06 14:15:00 -07:00
fn get_recent_blockhash (
& self ,
commitment : Option < CommitmentConfig > ,
2020-07-03 17:39:14 -06:00
) -> RpcResponse < RpcBlockhashFeeCalculator > {
let bank = self . bank ( commitment ) ;
2019-11-12 14:49:41 -05:00
let ( blockhash , fee_calculator ) = bank . confirmed_last_blockhash ( ) ;
2020-01-15 00:25:45 -07:00
new_response (
2020-06-25 17:08:55 -06:00
& bank ,
2020-01-15 00:25:45 -07:00
RpcBlockhashFeeCalculator {
blockhash : blockhash . to_string ( ) ,
fee_calculator ,
} ,
)
2019-11-12 14:49:41 -05:00
}
2020-07-03 17:39:14 -06:00
fn get_fees ( & self , commitment : Option < CommitmentConfig > ) -> RpcResponse < RpcFees > {
let bank = self . bank ( commitment ) ;
2020-05-26 13:06:21 -06:00
let ( blockhash , fee_calculator ) = bank . confirmed_last_blockhash ( ) ;
let last_valid_slot = bank
. get_blockhash_last_valid_slot ( & blockhash )
. expect ( " bank blockhash queue should contain blockhash " ) ;
new_response (
2020-06-25 17:08:55 -06:00
& bank ,
2020-05-26 13:06:21 -06:00
RpcFees {
blockhash : blockhash . to_string ( ) ,
fee_calculator ,
last_valid_slot ,
} ,
)
}
2020-03-06 17:01:31 -07:00
fn get_fee_calculator_for_blockhash (
& self ,
blockhash : & Hash ,
2020-05-26 17:23:58 -06:00
commitment : Option < CommitmentConfig > ,
2020-07-03 17:39:14 -06:00
) -> RpcResponse < Option < RpcFeeCalculator > > {
let bank = self . bank ( commitment ) ;
2020-03-06 17:01:31 -07:00
let fee_calculator = bank . get_fee_calculator ( blockhash ) ;
new_response (
2020-06-25 17:08:55 -06:00
& bank ,
2020-03-06 17:01:31 -07:00
fee_calculator . map ( | fee_calculator | RpcFeeCalculator { fee_calculator } ) ,
)
}
2020-07-03 17:39:14 -06:00
fn get_fee_rate_governor ( & self ) -> RpcResponse < RpcFeeRateGovernor > {
let bank = self . bank ( None ) ;
2020-02-28 13:27:01 -07:00
let fee_rate_governor = bank . get_fee_rate_governor ( ) ;
new_response (
2020-06-25 17:08:55 -06:00
& bank ,
2020-02-28 13:27:01 -07:00
RpcFeeRateGovernor {
fee_rate_governor : fee_rate_governor . clone ( ) ,
} ,
)
}
2019-11-12 14:49:41 -05:00
pub fn confirm_transaction (
& self ,
2020-06-25 17:08:55 -06:00
signature : & Signature ,
2019-11-12 14:49:41 -05:00
commitment : Option < CommitmentConfig > ,
2020-07-03 17:39:14 -06:00
) -> RpcResponse < bool > {
let bank = self . bank ( commitment ) ;
2020-06-25 17:08:55 -06:00
let status = bank . get_signature_status ( signature ) ;
match status {
Some ( status ) = > new_response ( & bank , status . is_ok ( ) ) ,
None = > new_response ( & bank , false ) ,
2019-11-12 14:49:41 -05:00
}
2019-02-17 10:29:08 -07:00
}
2019-02-26 12:25:46 -08:00
2020-04-20 23:25:49 -06:00
fn get_block_commitment ( & self , block : Slot ) -> RpcBlockCommitment < BlockCommitmentArray > {
2019-11-04 16:44:27 -07:00
let r_block_commitment = self . block_commitment_cache . read ( ) . unwrap ( ) ;
2020-01-15 00:25:45 -07:00
RpcBlockCommitment {
2020-01-21 20:17:33 -07:00
commitment : r_block_commitment
. get_block_commitment ( block )
. map ( | block_commitment | block_commitment . commitment ) ,
2020-01-15 00:25:45 -07:00
total_stake : r_block_commitment . total_stake ( ) ,
}
2019-10-14 16:24:10 -06:00
}
2021-01-14 21:45:11 -08:00
fn get_slot ( & self , commitment : Option < CommitmentConfig > ) -> Slot {
2020-07-03 17:39:14 -06:00
self . bank ( commitment ) . slot ( )
2019-06-12 16:43:05 -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 )
}
2020-07-03 17:39:14 -06:00
fn get_slot_leader ( & self , commitment : Option < CommitmentConfig > ) -> String {
self . bank ( commitment ) . collector_id ( ) . to_string ( )
2019-07-09 22:06:47 -07:00
}
2020-01-21 13:05:04 -07: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 ( ) )
}
}
}
2020-07-03 17:39:14 -06:00
fn get_transaction_count ( & self , commitment : Option < CommitmentConfig > ) -> u64 {
self . bank ( commitment ) . transaction_count ( ) as u64
2019-02-17 10:29:08 -07:00
}
2019-02-26 12:25:46 -08:00
2020-07-03 17:39:14 -06:00
fn get_total_supply ( & self , commitment : Option < CommitmentConfig > ) -> u64 {
self . bank ( commitment ) . capitalization ( )
2019-06-21 22:00:26 -06: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 17:46:10 -06:00
fn get_largest_accounts (
& self ,
2020-05-12 21:05:05 -06:00
config : Option < RpcLargestAccountsConfig > ,
2020-07-03 17:39:14 -06:00
) -> RpcResponse < Vec < RpcAccountBalance > > {
2020-05-12 21:05:05 -06:00
let config = config . unwrap_or_default ( ) ;
2020-07-03 17:39:14 -06: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 ) {
Response {
context : RpcResponseContext { slot } ,
value : accounts ,
}
2020-05-12 21:05:05 -06:00
} else {
2021-02-11 11:32:46 -08:00
let ( addresses , address_filter ) = if let Some ( filter ) = config . clone ( ) . filter {
let non_circulating_supply = calculate_non_circulating_supply ( & bank ) ;
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 )
2020-05-12 21:05:05 -06: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 ) ;
new_response ( & bank , accounts )
}
2020-05-04 17:46:10 -06:00
}
2020-07-03 17:39:14 -06:00
fn get_supply ( & self , commitment : Option < CommitmentConfig > ) -> RpcResponse < RpcSupply > {
let bank = self . bank ( commitment ) ;
2020-05-20 20:04:07 -07:00
let non_circulating_supply = calculate_non_circulating_supply ( & bank ) ;
2020-05-09 12:05:29 -06:00
let total_supply = bank . capitalization ( ) ;
new_response (
& bank ,
RpcSupply {
total : total_supply ,
circulating : total_supply - non_circulating_supply . lamports ,
non_circulating : non_circulating_supply . lamports ,
non_circulating_accounts : non_circulating_supply
. accounts
. iter ( )
. map ( | pubkey | pubkey . to_string ( ) )
. collect ( ) ,
} ,
)
}
2019-11-06 14:15:00 -07:00
fn get_vote_accounts (
& self ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcVoteAccountStatus > {
2020-07-03 17:39:14 -06:00
let bank = self . bank ( commitment ) ;
2019-08-16 17:02:19 -06: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 17:02:19 -06:00
. ok_or_else ( Error ::invalid_request ) ? ;
2020-11-30 17:18:33 +00:00
let default_vote_state = VoteState ::default ( ) ;
2019-08-16 17:02:19 -06:00
let ( current_vote_accounts , delinquent_vote_accounts ) : (
Vec < RpcVoteAccountInfo > ,
Vec < RpcVoteAccountInfo > ,
) = vote_accounts
2019-05-20 22:21:13 -07:00
. iter ( )
2019-08-16 17:02:19 -06:00
. map ( | ( pubkey , ( activated_stake , account ) ) | {
2020-11-30 17:18:33 +00:00
let vote_state = account . vote_state ( ) ;
let vote_state = vote_state . as_ref ( ) . unwrap_or ( & default_vote_state ) ;
2019-08-16 17:02:19 -06:00
let last_vote = if let Some ( vote ) = vote_state . votes . iter ( ) . last ( ) {
vote . slot
} else {
0
} ;
2019-06-12 14:12:08 -07:00
RpcVoteAccountInfo {
2019-08-16 17:02:19 -06:00
vote_pubkey : ( pubkey ) . to_string ( ) ,
2019-06-12 14:12:08 -07:00
node_pubkey : vote_state . node_pubkey . to_string ( ) ,
2019-08-16 17:02:19 -06:00
activated_stake : * activated_stake ,
2019-06-12 14:12:08 -07:00
commission : vote_state . commission ,
2019-10-07 12:24:26 +09:00
root_slot : vote_state . root_slot . unwrap_or ( 0 ) ,
2019-12-11 22:04:54 -08:00
epoch_credits : vote_state . epoch_credits ( ) . clone ( ) ,
2020-10-12 19:58:21 -07:00
epoch_vote_account : epoch_vote_accounts . contains_key ( pubkey ) ,
2019-08-16 17:02:19 -06:00
last_vote ,
2019-06-12 14:12:08 -07:00
}
} )
2019-08-16 17:02:19 -06:00
. partition ( | vote_account_info | {
2020-06-09 08:43:16 -07:00
if bank . slot ( ) > = DELINQUENT_VALIDATOR_SLOT_DISTANCE as u64 {
vote_account_info . last_vote
> bank . slot ( ) - DELINQUENT_VALIDATOR_SLOT_DISTANCE as u64
2019-09-26 19:40:18 -06:00
} else {
vote_account_info . last_vote > 0
}
2019-08-16 17:02:19 -06:00
} ) ;
2019-12-14 01:53:45 -07:00
let delinquent_staked_vote_accounts = delinquent_vote_accounts
. into_iter ( )
. filter ( | vote_account_info | vote_account_info . activated_stake > 0 )
. collect ::< Vec < _ > > ( ) ;
2019-08-16 17:02:19 -06:00
Ok ( RpcVoteAccountStatus {
current : current_vote_accounts ,
2019-12-14 01:53:45 -07:00
delinquent : delinquent_staked_vote_accounts ,
2019-08-16 17:02:19 -06:00
} )
2019-05-20 22:21:13 -07:00
}
2020-12-16 13:40:36 -07:00
fn check_blockstore_root < T > (
2020-11-25 15:59:38 -07:00
& self ,
result : & std ::result ::Result < T , BlockstoreError > ,
slot : Slot ,
) -> Result < ( ) >
where
T : std ::fmt ::Debug ,
{
if result . is_err ( ) {
2020-12-01 00:44:18 -07:00
let err = result . as_ref ( ) . unwrap_err ( ) ;
debug! (
2020-12-16 13:40:36 -07:00
" check_blockstore_root, slot: {:?}, max root: {:?}, err: {:?} " ,
2020-12-01 00:44:18 -07:00
slot ,
self . blockstore . max_root ( ) ,
err
) ;
if slot > = self . blockstore . max_root ( ) {
return Err ( RpcCustomError ::BlockNotAvailable { slot } . into ( ) ) ;
2020-11-25 15:59:38 -07:00
}
2020-12-16 13:40:36 -07:00
if self . blockstore . is_skipped ( slot ) {
return Err ( RpcCustomError ::SlotSkipped { slot } . into ( ) ) ;
}
2020-11-25 15:59:38 -07:00
}
Ok ( ( ) )
}
fn check_slot_cleaned_up < T > (
2020-05-11 15:47:40 -06:00
& self ,
result : & std ::result ::Result < T , BlockstoreError > ,
slot : Slot ,
) -> Result < ( ) >
where
T : std ::fmt ::Debug ,
{
if result . is_err ( ) {
if let BlockstoreError ::SlotCleanedUp = result . as_ref ( ) . unwrap_err ( ) {
return Err ( RpcCustomError ::BlockCleanedUp {
slot ,
first_available_block : self
. blockstore
. get_first_available_block ( )
. unwrap_or_default ( ) ,
}
. into ( ) ) ;
}
}
Ok ( ( ) )
}
2021-01-21 21:40:47 -07:00
fn check_bigtable_result < T > (
& self ,
result : & std ::result ::Result < T , solana_storage_bigtable ::Error > ,
) -> Result < ( ) >
where
T : std ::fmt ::Debug ,
{
if result . is_err ( ) {
let err = result . as_ref ( ) . unwrap_err ( ) ;
if let solana_storage_bigtable ::Error ::BlockNotFound ( slot ) = err {
return Err ( RpcCustomError ::LongTermStorageSlotSkipped { slot : * slot } . into ( ) ) ;
}
}
Ok ( ( ) )
}
2020-01-12 22:34:30 -07:00
pub fn get_confirmed_block (
& self ,
slot : Slot ,
2020-07-01 14:06:40 -06:00
encoding : Option < UiTransactionEncoding > ,
2020-09-24 13:10:29 +08:00
) -> Result < Option < EncodedConfirmedBlock > > {
2020-07-23 09:54:57 -07:00
let encoding = encoding . unwrap_or ( UiTransactionEncoding ::Json ) ;
2020-05-04 19:39:27 -06:00
if self . config . enable_rpc_transaction_history
& & slot
< = self
. block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 17:59:46 -06:00
. highest_confirmed_root ( )
2020-05-04 19:39:27 -06:00
{
2021-02-17 18:04:52 -07:00
let result = self . blockstore . get_confirmed_block ( slot , true ) ;
2020-12-16 13:40:36 -07:00
self . check_blockstore_root ( & result , slot ) ? ;
2020-07-23 09:54:57 -07:00
if result . is_err ( ) {
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-01-21 21:40:47 -07:00
let bigtable_result = self
2021-02-05 00:21:53 -07:00
. runtime
2021-01-21 21:40:47 -07:00
. block_on ( bigtable_ledger_storage . get_confirmed_block ( slot ) ) ;
self . check_bigtable_result ( & bigtable_result ) ? ;
return Ok ( bigtable_result
2020-09-24 13:10:29 +08:00
. ok ( )
. map ( | confirmed_block | confirmed_block . encode ( encoding ) ) ) ;
2020-07-23 09:54:57 -07:00
}
}
2020-11-25 15:59:38 -07:00
self . check_slot_cleaned_up ( & result , slot ) ? ;
2020-09-24 13:10:29 +08:00
Ok ( result
. ok ( )
. map ( | confirmed_block | confirmed_block . encode ( encoding ) ) )
2020-02-11 18:01:49 -07:00
} else {
2020-08-20 15:05:30 -06:00
Err ( RpcCustomError ::BlockNotAvailable { slot } . into ( ) )
2020-02-11 18:01:49 -07:00
}
2019-11-11 13:18:34 -05:00
}
2019-11-26 00:40:36 -07:00
2019-12-18 16:51:47 -07:00
pub fn get_confirmed_blocks (
& self ,
start_slot : Slot ,
end_slot : Option < Slot > ,
) -> Result < Vec < Slot > > {
2020-05-04 19:39:27 -06:00
let end_slot = min (
end_slot . unwrap_or ( std ::u64 ::MAX ) ,
self . block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 17:59:46 -06:00
. highest_confirmed_root ( ) ,
2020-05-04 19:39:27 -06:00
) ;
2019-12-18 16:51:47 -07: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! (
" Slot range too large; max {} " ,
MAX_GET_CONFIRMED_BLOCKS_RANGE
) ) ) ;
}
2020-07-23 09:54:57 -07:00
2020-09-30 13:47:12 -07:00
let lowest_blockstore_slot = self . blockstore . lowest_slot ( ) ;
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
// [start_slot..end_slot] can be fetched from BigTable.
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-01-23 11:55:15 -08:00
return self
2021-02-05 00:21:53 -07:00
. runtime
2020-07-23 09:54:57 -07:00
. block_on (
bigtable_ledger_storage
2021-01-18 19:14:10 -07:00
. 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
2020-07-23 09:54:57 -07:00
)
2021-01-18 19:14:10 -07:00
. map ( | mut bigtable_blocks | {
bigtable_blocks . retain ( | & slot | slot < = end_slot ) ;
bigtable_blocks
} )
2021-01-19 22:57:16 +09: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
}
}
2020-04-22 14:33:06 -06:00
Ok ( self
. blockstore
2020-09-30 13:47:12 -07:00
. rooted_slot_iterator ( max ( start_slot , lowest_blockstore_slot ) )
2020-04-22 14:33:06 -06:00
. map_err ( | _ | Error ::internal_error ( ) ) ?
. filter ( | & slot | slot < = end_slot )
. collect ( ) )
2019-12-18 16:51:47 -07:00
}
2020-09-30 13:47:12 -07:00
pub fn get_confirmed_blocks_with_limit (
& self ,
start_slot : Slot ,
limit : usize ,
) -> Result < Vec < Slot > > {
if limit > MAX_GET_CONFIRMED_BLOCKS_RANGE as usize {
return Err ( Error ::invalid_params ( format! (
" Limit too large; max {} " ,
MAX_GET_CONFIRMED_BLOCKS_RANGE
) ) ) ;
}
let lowest_blockstore_slot = self . blockstore . lowest_slot ( ) ;
if start_slot < lowest_blockstore_slot {
// If the starting slot is lower than what's available in blockstore assume the entire
// range can be fetched from BigTable.
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
return Ok ( self
2021-02-05 00:21:53 -07:00
. runtime
2020-09-30 13:47:12 -07:00
. block_on ( bigtable_ledger_storage . get_confirmed_blocks ( start_slot , limit ) )
. unwrap_or_else ( | _ | vec! [ ] ) ) ;
}
}
Ok ( self
. blockstore
. rooted_slot_iterator ( max ( start_slot , lowest_blockstore_slot ) )
. map_err ( | _ | Error ::internal_error ( ) ) ?
. take ( limit )
. collect ( ) )
}
2019-11-26 00:40:36 -07:00
pub fn get_block_time ( & self , slot : Slot ) -> Result < Option < UnixTimestamp > > {
2020-05-04 19:39:27 -06:00
if slot
< = self
. block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 17:59:46 -06:00
. highest_confirmed_root ( )
2020-05-04 19:39:27 -06:00
{
2020-09-09 09:33:14 -06:00
let result = self . blockstore . get_block_time ( slot ) ;
2020-12-16 13:40:36 -07: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 15:39:36 -06:00
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-01-21 21:40:47 -07:00
let bigtable_result = self
2021-02-05 00:21:53 -07:00
. runtime
2021-01-21 21:40:47 -07:00
. block_on ( bigtable_ledger_storage . get_confirmed_block ( slot ) ) ;
self . check_bigtable_result ( & bigtable_result ) ? ;
return Ok ( bigtable_result
2020-09-29 15:39:36 -06:00
. ok ( )
. and_then ( | confirmed_block | confirmed_block . block_time ) ) ;
}
}
2020-11-25 15:59:38 -07:00
self . check_slot_cleaned_up ( & result , slot ) ? ;
2020-05-11 15:47:40 -06:00
Ok ( result . ok ( ) . unwrap_or ( None ) )
2020-05-04 19:39:27 -06:00
} else {
2020-08-20 15:05:30 -06:00
Err ( RpcCustomError ::BlockNotAvailable { slot } . into ( ) )
2020-05-04 19:39:27 -06:00
}
2019-11-26 00:40:36 -07:00
}
2020-03-23 11:25:39 -06:00
2020-04-01 17:56:18 -06:00
pub fn get_signature_confirmation_status (
& self ,
signature : Signature ,
commitment : Option < CommitmentConfig > ,
) -> Option < RpcSignatureConfirmation > {
2020-07-03 17:39:14 -06:00
let bank = self . bank ( commitment ) ;
2020-06-25 17:08:55 -06:00
let transaction_status = self . get_transaction_status ( signature , & bank ) ? ;
let confirmations = transaction_status
. confirmations
. unwrap_or ( MAX_LOCKOUT_HISTORY + 1 ) ;
Some ( RpcSignatureConfirmation {
confirmations ,
status : transaction_status . status ,
} )
2020-04-01 17:56:18 -06:00
}
2020-03-23 11:25:39 -06:00
pub fn get_signature_status (
2020-04-02 02:30:58 +08:00
& self ,
signature : Signature ,
commitment : Option < CommitmentConfig > ,
) -> Option < transaction ::Result < ( ) > > {
2020-07-03 17:39:14 -06:00
let bank = self . bank ( commitment ) ;
2020-06-25 17:08:55 -06:00
let ( _ , status ) = bank . get_signature_status_slot ( & signature ) ? ;
Some ( status )
2020-04-02 02:30:58 +08:00
}
2020-04-06 04:04:54 -06:00
pub fn get_signature_statuses (
2020-03-23 11:25:39 -06:00
& self ,
signatures : Vec < Signature > ,
2020-04-06 04:04:54 -06:00
config : Option < RpcSignatureStatusConfig > ,
2020-06-11 16:51:25 -06:00
) -> Result < RpcResponse < Vec < Option < TransactionStatus > > > > {
2020-03-26 13:29:30 -07:00
let mut statuses : Vec < Option < TransactionStatus > > = vec! [ ] ;
2020-03-23 11:25:39 -06:00
2020-04-06 04:04:54 -06:00
let search_transaction_history = config
. map ( | x | x . search_transaction_history )
. unwrap_or ( false ) ;
2021-01-26 12:23:07 -07:00
let bank = self . bank ( Some ( CommitmentConfig ::processed ( ) ) ) ;
2020-03-23 11:25:39 -06:00
for signature in signatures {
2020-04-06 04:04:54 -06: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 {
self . blockstore
. get_transaction_status ( signature )
. map_err ( | _ | Error ::internal_error ( ) ) ?
2020-05-04 19:39:27 -06:00
. filter ( | ( slot , _status_meta ) | {
slot < = & self
. block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 17:59:46 -06:00
. highest_confirmed_root ( )
2020-05-04 19:39:27 -06:00
} )
2020-04-06 04:04:54 -06:00
. map ( | ( slot , status_meta ) | {
let err = status_meta . status . clone ( ) . err ( ) ;
TransactionStatus {
slot ,
status : status_meta . status ,
confirmations : None ,
err ,
2021-01-15 09:05:05 -07:00
confirmation_status : Some ( TransactionConfirmationStatus ::Finalized ) ,
2020-04-06 04:04:54 -06:00
}
} )
2020-07-23 09:54:57 -07:00
. or_else ( | | {
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
2021-02-05 00:21:53 -07:00
self . runtime
2020-07-23 09:54:57 -07:00
. block_on ( bigtable_ledger_storage . get_signature_status ( & signature ) )
. map ( Some )
. unwrap_or ( None )
} else {
None
}
} )
2020-04-06 04:04:54 -06:00
} else {
None
} ;
2020-03-23 11:25:39 -06:00
statuses . push ( status ) ;
}
2020-09-03 11:57:57 -06:00
Ok ( new_response ( & bank , statuses ) )
2020-03-23 11:25:39 -06:00
}
2020-04-01 17:56:18 -06:00
fn get_transaction_status (
& self ,
signature : Signature ,
bank : & Arc < Bank > ,
) -> Option < TransactionStatus > {
2020-06-25 17:08:55 -06:00
let ( slot , status ) = bank . get_signature_status_slot ( & signature ) ? ;
let r_block_commitment_cache = self . block_commitment_cache . read ( ) . unwrap ( ) ;
2021-01-26 12:23:07 -07:00
let optimistically_confirmed_bank = self . bank ( Some ( CommitmentConfig ::confirmed ( ) ) ) ;
2021-01-15 09:05:05 -07:00
let optimistically_confirmed =
optimistically_confirmed_bank . get_signature_status_slot ( & signature ) ;
2020-06-25 17:08:55 -06:00
let confirmations = if r_block_commitment_cache . root ( ) > = slot
2020-07-07 20:13:30 -06:00
& & is_confirmed_rooted ( & r_block_commitment_cache , bank , & self . blockstore , slot )
2020-06-25 17:08:55 -06: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 09:05:05 -07: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 17:08:55 -06:00
} )
2020-04-01 17:56:18 -06:00
}
2020-04-09 00:57:30 -06:00
pub fn get_confirmed_transaction (
& self ,
signature : Signature ,
2020-07-01 14:06:40 -06:00
encoding : Option < UiTransactionEncoding > ,
2020-09-24 13:10:29 +08:00
) -> Option < EncodedConfirmedTransaction > {
2020-07-23 09:54:57 -07:00
let encoding = encoding . unwrap_or ( UiTransactionEncoding ::Json ) ;
2020-04-09 00:57:30 -06:00
if self . config . enable_rpc_transaction_history {
2020-07-23 09:54:57 -07:00
match self
. blockstore
2020-09-24 13:10:29 +08:00
. get_confirmed_transaction ( signature )
2020-05-04 19:39:27 -06:00
. unwrap_or ( None )
2020-07-23 09:54:57 -07:00
{
Some ( confirmed_transaction ) = > {
if confirmed_transaction . slot
2020-05-04 19:39:27 -06:00
< = self
. block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 17:59:46 -06:00
. highest_confirmed_root ( )
2020-07-23 09:54:57 -07:00
{
2020-09-24 13:10:29 +08:00
return Some ( confirmed_transaction . encode ( encoding ) ) ;
2020-07-23 09:54:57 -07:00
}
}
None = > {
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
return self
2021-02-05 00:21:53 -07:00
. runtime
2020-09-24 13:10:29 +08:00
. block_on ( bigtable_ledger_storage . get_confirmed_transaction ( & signature ) )
. unwrap_or ( None )
. map ( | confirmed | confirmed . encode ( encoding ) ) ;
2020-07-23 09:54:57 -07:00
}
}
}
2020-04-09 00:57:30 -06:00
}
2020-07-23 09:54:57 -07:00
None
2020-04-09 00:57:30 -06:00
}
2020-04-09 21:21:31 -06:00
pub fn get_confirmed_signatures_for_address (
& self ,
pubkey : Pubkey ,
start_slot : Slot ,
end_slot : Slot ,
2020-07-03 17:39:14 -06:00
) -> Vec < Signature > {
2020-04-09 21:21:31 -06: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 19:39:27 -06:00
let end_slot = min (
end_slot ,
self . block_commitment_cache
. read ( )
. unwrap ( )
2020-07-07 17:59:46 -06:00
. highest_confirmed_root ( ) ,
2020-05-04 19:39:27 -06:00
) ;
2020-07-03 17:39:14 -06:00
self . blockstore
2020-04-09 21:21:31 -06:00
. get_confirmed_signatures_for_address ( pubkey , start_slot , end_slot )
2020-07-03 17:39:14 -06:00
. unwrap_or_else ( | _ | vec! [ ] )
2020-04-09 21:21:31 -06:00
} else {
2020-07-03 17:39:14 -06:00
vec! [ ]
2020-04-09 21:21:31 -06:00
}
}
2020-04-22 14:33:06 -06:00
2020-07-27 11:42:49 -07:00
pub fn get_confirmed_signatures_for_address2 (
& self ,
address : Pubkey ,
2020-07-30 09:54:06 -07:00
mut before : Option < Signature > ,
2020-08-15 10:42:17 -06:00
until : Option < Signature > ,
2020-07-30 09:54:06 -07:00
mut limit : usize ,
2020-07-27 11:42:49 -07:00
) -> Result < Vec < RpcConfirmedTransactionStatusWithSignature > > {
if self . config . enable_rpc_transaction_history {
let highest_confirmed_root = self
. block_commitment_cache
. read ( )
. unwrap ( )
. highest_confirmed_root ( ) ;
2020-07-30 09:54:06 -07:00
let mut results = self
2020-07-27 11:42:49 -07:00
. blockstore
. get_confirmed_signatures_for_address2 (
address ,
highest_confirmed_root ,
2020-08-05 11:30:21 -07:00
before ,
2020-08-15 10:42:17 -06:00
until ,
2020-07-27 11:42:49 -07:00
limit ,
)
. map_err ( | err | Error ::invalid_params ( format! ( " {} " , err ) ) ) ? ;
2020-07-30 09:54:06 -07:00
if results . len ( ) < limit {
if let Some ( bigtable_ledger_storage ) = & self . bigtable_ledger_storage {
if ! results . is_empty ( ) {
limit - = results . len ( ) ;
before = results . last ( ) . map ( | x | x . signature ) ;
}
2021-02-05 00:21:53 -07:00
let bigtable_results = self . runtime . block_on (
2020-08-12 17:57:05 -06:00
bigtable_ledger_storage . get_confirmed_signatures_for_address (
& address ,
before . as_ref ( ) ,
2020-08-15 10:42:17 -06:00
until . as_ref ( ) ,
2020-08-12 17:57:05 -06:00
limit ,
) ,
) ;
match bigtable_results {
2020-09-09 20:21:52 -07:00
Ok ( bigtable_results ) = > {
results . extend ( bigtable_results . into_iter ( ) . map ( | x | x . 0 ) ) ;
2020-08-12 17:57:05 -06:00
}
Err ( err ) = > {
warn! ( " {:?} " , err ) ;
}
}
2020-07-30 09:54:06 -07:00
}
}
2020-07-27 11:42:49 -07:00
Ok ( results . into_iter ( ) . map ( | x | x . into ( ) ) . collect ( ) )
} else {
Ok ( vec! [ ] )
}
}
2020-07-03 17:39:14 -06:00
pub fn get_first_available_block ( & self ) -> Slot {
2020-07-23 09:54:57 -07:00
let slot = self
. blockstore
2020-04-22 14:33:06 -06: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 {
let bigtable_slot = self
2021-02-05 00:21:53 -07:00
. runtime
2020-07-23 09:54:57 -07:00
. block_on ( bigtable_ledger_storage . get_first_available_block ( ) )
. unwrap_or ( None )
. unwrap_or ( slot ) ;
if bigtable_slot < slot {
return bigtable_slot ;
}
}
slot
2020-04-22 14:33:06 -06:00
}
2020-07-06 13:28:40 -06:00
pub fn get_stake_activation (
& self ,
pubkey : & Pubkey ,
config : Option < RpcStakeConfig > ,
) -> Result < RpcStakeActivation > {
let config = config . unwrap_or_default ( ) ;
let bank = self . bank ( config . commitment ) ;
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! (
" Invalid param: epoch {:?} is too far in the past " ,
epoch
) ) ) ;
}
if epoch > bank . epoch ( ) {
return Err ( Error ::invalid_params ( format! (
" Invalid param: epoch {:?} has not yet started " ,
epoch
) ) ) ;
}
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 ( ) ) ) ? ;
let delegation = stake_state . delegation ( ) . ok_or_else ( | | {
Error ::invalid_params ( " Invalid param: stake account has not been delegated " . to_string ( ) )
} ) ? ;
let stake_history_account = bank
. get_account ( & stake_history ::id ( ) )
. ok_or_else ( Error ::internal_error ) ? ;
let stake_history =
2021-03-09 15:06:07 -06: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 13:28:40 -06:00
2020-11-12 06:11:57 +09:00
let ( active , activating , deactivating ) = delegation . stake_activating_and_deactivating (
epoch ,
Some ( & stake_history ) ,
bank . stake_program_v2_enabled ( ) ,
) ;
2020-07-06 13:28:40 -06:00
let stake_activation_state = if deactivating > 0 {
StakeActivationState ::Deactivating
} else if activating > 0 {
StakeActivationState ::Activating
} else if active > 0 {
StakeActivationState ::Active
} else {
StakeActivationState ::Inactive
} ;
let inactive_stake = match stake_activation_state {
StakeActivationState ::Activating = > activating ,
StakeActivationState ::Active = > 0 ,
StakeActivationState ::Deactivating = > delegation . stake . saturating_sub ( active ) ,
StakeActivationState ::Inactive = > delegation . stake ,
} ;
Ok ( RpcStakeActivation {
state : stake_activation_state ,
active ,
inactive : inactive_stake ,
} )
}
2020-07-28 23:00:48 -06:00
pub fn get_token_account_balance (
& self ,
pubkey : & Pubkey ,
commitment : Option < CommitmentConfig > ,
2020-08-07 11:37:39 -06:00
) -> Result < RpcResponse < UiTokenAmount > > {
2020-07-28 23:00:48 -06: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 ( ) )
} ) ? ;
2020-08-28 15:54:57 -06:00
if account . owner ! = spl_token_id_v2_0 ( ) {
2020-07-28 23:00:48 -06:00
return Err ( Error ::invalid_params (
2020-08-28 15:54:57 -06:00
" Invalid param: not a v2.0 Token account " . to_string ( ) ,
2020-07-28 23:00:48 -06:00
) ) ;
}
2021-03-09 16:31:33 -06:00
let token_account = TokenAccount ::unpack ( & account . data ( ) ) . map_err ( | _ | {
2020-08-28 15:54:57 -06:00
Error ::invalid_params ( " Invalid param: not a v2.0 Token account " . to_string ( ) )
} ) ? ;
2020-08-05 00:48:09 -06:00
let mint = & Pubkey ::from_str ( & token_account . mint . to_string ( ) )
. expect ( " Token account mint should be convertible to Pubkey " ) ;
let ( _ , decimals ) = get_mint_owner_and_decimals ( & bank , & mint ) ? ;
let balance = token_amount_to_ui_amount ( token_account . amount , decimals ) ;
2020-07-28 23:00:48 -06:00
Ok ( new_response ( & bank , balance ) )
}
pub fn get_token_supply (
& self ,
mint : & Pubkey ,
commitment : Option < CommitmentConfig > ,
2020-08-07 11:37:39 -06:00
) -> Result < RpcResponse < UiTokenAmount > > {
2020-07-28 23:00:48 -06:00
let bank = self . bank ( commitment ) ;
2020-08-28 15:54:57 -06:00
let mint_account = bank . get_account ( mint ) . ok_or_else ( | | {
Error ::invalid_params ( " Invalid param: could not find account " . to_string ( ) )
} ) ? ;
if mint_account . owner ! = spl_token_id_v2_0 ( ) {
2020-07-28 23:00:48 -06:00
return Err ( Error ::invalid_params (
2020-08-28 15:54:57 -06:00
" Invalid param: not a v2.0 Token mint " . to_string ( ) ,
2020-07-28 23:00:48 -06:00
) ) ;
}
2021-03-09 16:31:33 -06:00
let mint = Mint ::unpack ( & mint_account . data ( ) ) . map_err ( | _ | {
2020-08-28 15:54:57 -06:00
Error ::invalid_params ( " Invalid param: mint could not be unpacked " . to_string ( ) )
} ) ? ;
2020-08-05 00:48:09 -06:00
2020-08-28 15:54:57 -06:00
let supply = token_amount_to_ui_amount ( mint . supply , mint . decimals ) ;
2020-07-28 23:00:48 -06:00
Ok ( new_response ( & bank , supply ) )
}
2020-08-02 10:23:44 -06:00
pub fn get_token_largest_accounts (
& self ,
mint : & Pubkey ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < Vec < RpcTokenAccountBalance > > > {
let bank = self . bank ( commitment ) ;
2020-08-05 00:48:09 -06:00
let ( mint_owner , decimals ) = get_mint_owner_and_decimals ( & bank , mint ) ? ;
2020-08-28 15:54:57 -06:00
if mint_owner ! = spl_token_id_v2_0 ( ) {
2020-08-02 10:23:44 -06:00
return Err ( Error ::invalid_params (
2020-08-28 15:54:57 -06:00
" Invalid param: not a v2.0 Token mint " . to_string ( ) ,
2020-08-02 10:23:44 -06:00
) ) ;
}
2020-12-31 18:06:03 -08:00
let mut token_balances : Vec < RpcTokenAccountBalance > = self
. get_filtered_spl_token_accounts_by_mint ( & bank , & mint , vec! [ ] )
. into_iter ( )
. map ( | ( address , account ) | {
2021-03-09 16:31:33 -06:00
let amount = TokenAccount ::unpack ( & account . data ( ) )
2020-12-31 18:06:03 -08:00
. map ( | account | account . amount )
. unwrap_or ( 0 ) ;
let amount = token_amount_to_ui_amount ( amount , decimals ) ;
RpcTokenAccountBalance {
address : address . to_string ( ) ,
amount ,
}
} )
. collect ( ) ;
2020-08-05 00:48:09 -06:00
token_balances . sort_by ( | a , b | {
a . amount
. amount
. parse ::< u64 > ( )
. unwrap ( )
. cmp ( & b . amount . amount . parse ::< u64 > ( ) . unwrap ( ) )
. reverse ( )
} ) ;
2020-08-02 10:23:44 -06:00
token_balances . truncate ( NUM_LARGEST_ACCOUNTS ) ;
Ok ( new_response ( & bank , token_balances ) )
}
2020-07-28 23:00:48 -06:00
pub fn get_token_accounts_by_owner (
& self ,
owner : & Pubkey ,
token_account_filter : TokenAccountsFilter ,
2020-08-04 11:11:30 -06:00
config : Option < RpcAccountInfoConfig > ,
2020-07-28 23:00:48 -06:00
) -> Result < RpcResponse < Vec < RpcKeyedAccount > > > {
2020-08-04 11:11:30 -06:00
let config = config . unwrap_or_default ( ) ;
let bank = self . bank ( config . commitment ) ;
let encoding = config . encoding . unwrap_or ( UiAccountEncoding ::Binary ) ;
2020-08-10 16:35:29 -06:00
let data_slice_config = config . data_slice ;
check_slice_and_encoding ( & encoding , data_slice_config . is_some ( ) ) ? ;
2020-12-31 18:06:03 -08:00
let ( _ , mint ) = get_token_program_id_and_mint ( & bank , token_account_filter ) ? ;
2020-07-28 23:00:48 -06:00
2020-12-31 18:06:03 -08:00
let mut filters = vec! [ ] ;
2020-07-28 23:00:48 -06:00
if let Some ( mint ) = mint {
// Optional filter on Mint address
filters . push ( RpcFilterType ::Memcmp ( Memcmp {
offset : 0 ,
bytes : MemcmpEncodedBytes ::Binary ( mint . to_string ( ) ) ,
encoding : None ,
} ) ) ;
}
2020-12-31 18:06:03 -08:00
let keyed_accounts = self . get_filtered_spl_token_accounts_by_owner ( & bank , owner , filters ) ;
2020-08-07 11:37:39 -06: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 11:37:39 -06:00
} else {
keyed_accounts
2020-12-31 18:06:03 -08:00
. into_iter ( )
2020-08-07 11:37:39 -06:00
. map ( | ( pubkey , account ) | RpcKeyedAccount {
pubkey : pubkey . to_string ( ) ,
2020-08-10 16:35:29 -06:00
account : UiAccount ::encode (
& pubkey ,
account ,
encoding . clone ( ) ,
None ,
data_slice_config ,
) ,
2020-08-07 11:37:39 -06:00
} )
. collect ( )
} ;
2020-07-28 23:00:48 -06:00
Ok ( new_response ( & bank , accounts ) )
}
pub fn get_token_accounts_by_delegate (
& self ,
delegate : & Pubkey ,
token_account_filter : TokenAccountsFilter ,
2020-08-04 11:11:30 -06:00
config : Option < RpcAccountInfoConfig > ,
2020-07-28 23:00:48 -06:00
) -> Result < RpcResponse < Vec < RpcKeyedAccount > > > {
2020-08-04 11:11:30 -06:00
let config = config . unwrap_or_default ( ) ;
let bank = self . bank ( config . commitment ) ;
let encoding = config . encoding . unwrap_or ( UiAccountEncoding ::Binary ) ;
2020-08-10 16:35:29 -06:00
let data_slice_config = config . data_slice ;
check_slice_and_encoding ( & encoding , data_slice_config . is_some ( ) ) ? ;
2020-07-28 23:00:48 -06: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()
RpcFilterType ::Memcmp ( Memcmp {
offset : 72 ,
bytes : MemcmpEncodedBytes ::Binary (
bs58 ::encode ( bincode ::serialize ( & 1 u32 ) . unwrap ( ) ) . into_string ( ) ,
) ,
encoding : None ,
} ) ,
// Filter on Delegate address
RpcFilterType ::Memcmp ( Memcmp {
offset : 76 ,
bytes : MemcmpEncodedBytes ::Binary ( delegate . to_string ( ) ) ,
encoding : None ,
} ) ,
] ;
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 {
self . get_filtered_spl_token_accounts_by_mint ( & bank , & mint , filters )
} else {
// Filter on Token Account state
filters . push ( RpcFilterType ::DataSize (
TokenAccount ::get_packed_len ( ) as u64
) ) ;
self . get_filtered_program_accounts ( & bank , & token_program_id , filters )
} ;
2020-08-07 11:37:39 -06: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 11:37:39 -06:00
} else {
keyed_accounts
2020-12-31 18:06:03 -08:00
. into_iter ( )
2020-08-07 11:37:39 -06:00
. map ( | ( pubkey , account ) | RpcKeyedAccount {
pubkey : pubkey . to_string ( ) ,
2020-08-10 16:35:29 -06:00
account : UiAccount ::encode (
& pubkey ,
account ,
encoding . clone ( ) ,
None ,
data_slice_config ,
) ,
2020-08-07 11:37:39 -06:00
} )
. collect ( )
} ;
2020-07-28 23:00:48 -06: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 ,
filters : Vec < RpcFilterType > ,
2021-03-09 15:06:07 -06:00
) -> Vec < ( Pubkey , AccountSharedData ) > {
let filter_closure = | account : & AccountSharedData | {
2020-12-31 18:06:03 -08:00
filters . iter ( ) . all ( | filter_type | match filter_type {
2021-03-09 16:31:33 -06:00
RpcFilterType ::DataSize ( size ) = > account . data ( ) . len ( ) as u64 = = * size ,
RpcFilterType ::Memcmp ( compare ) = > compare . bytes_match ( & account . data ( ) ) ,
2020-12-31 18:06:03 -08:00
} )
} ;
if self
. config
. account_indexes
. contains ( & AccountIndex ::ProgramId )
{
bank . get_filtered_indexed_accounts ( & IndexKey ::ProgramId ( * program_id ) , | account | {
2021-01-05 19:42:33 -07:00
// The program-id account index checks for Account owner on inclusion. However, due
2021-02-18 23:42:09 -08:00
// to the current AccountsDb implementation, an account may remain in storage as a
2021-03-09 15:06:07 -06:00
// zero-lamport AccountSharedData::Default() after being wiped and reinitialized in later
2021-01-05 19:42:33 -07:00
// updates. We include the redundant filters here to avoid returning these
// accounts.
2020-12-31 18:06:03 -08:00
account . owner = = * program_id & & filter_closure ( account )
} )
} else {
bank . get_filtered_program_accounts ( program_id , filter_closure )
}
}
/// Get an iterator of spl-token accounts by owner address
fn get_filtered_spl_token_accounts_by_owner (
& self ,
bank : & Arc < Bank > ,
owner_key : & Pubkey ,
mut filters : Vec < RpcFilterType > ,
2021-03-09 15:06:07 -06:00
) -> Vec < ( Pubkey , AccountSharedData ) > {
2021-01-05 19:42:33 -07: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 15:06:07 -06:00
// in storage as a zero-lamport AccountSharedData::Default() after being wiped and reinitialized in
2021-01-05 19:42:33 -07: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
filters . push ( RpcFilterType ::DataSize (
TokenAccount ::get_packed_len ( ) as u64
) ) ;
// Filter on Owner address
filters . push ( RpcFilterType ::Memcmp ( Memcmp {
offset : SPL_TOKEN_ACCOUNT_OWNER_OFFSET ,
bytes : MemcmpEncodedBytes ::Binary ( owner_key . to_string ( ) ) ,
encoding : None ,
} ) ) ;
if self
. config
. account_indexes
. contains ( & AccountIndex ::SplTokenOwner )
{
bank . get_filtered_indexed_accounts ( & IndexKey ::SplTokenOwner ( * owner_key ) , | account | {
account . owner = = spl_token_id_v2_0 ( )
& & filters . iter ( ) . all ( | filter_type | match filter_type {
2021-03-09 16:31:33 -06:00
RpcFilterType ::DataSize ( size ) = > account . data ( ) . len ( ) as u64 = = * size ,
RpcFilterType ::Memcmp ( compare ) = > compare . bytes_match ( & account . data ( ) ) ,
2020-12-31 18:06:03 -08:00
} )
} )
} else {
self . get_filtered_program_accounts ( bank , & spl_token_id_v2_0 ( ) , filters )
}
}
/// Get an iterator of spl-token accounts by mint address
fn get_filtered_spl_token_accounts_by_mint (
& self ,
bank : & Arc < Bank > ,
mint_key : & Pubkey ,
mut filters : Vec < RpcFilterType > ,
2021-03-09 15:06:07 -06:00
) -> 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 15:06:07 -06:00
// as be zero-lamport AccountSharedData::Default() after being wiped and reinitialized in later
2021-01-05 19:42:33 -07: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
filters . push ( RpcFilterType ::DataSize (
TokenAccount ::get_packed_len ( ) as u64
) ) ;
// Filter on Mint address
filters . push ( RpcFilterType ::Memcmp ( Memcmp {
offset : SPL_TOKEN_ACCOUNT_MINT_OFFSET ,
bytes : MemcmpEncodedBytes ::Binary ( mint_key . to_string ( ) ) ,
encoding : None ,
} ) ) ;
if self
. config
. account_indexes
. contains ( & AccountIndex ::SplTokenMint )
{
bank . get_filtered_indexed_accounts ( & IndexKey ::SplTokenMint ( * mint_key ) , | account | {
account . owner = = spl_token_id_v2_0 ( )
& & filters . iter ( ) . all ( | filter_type | match filter_type {
2021-03-09 16:31:33 -06:00
RpcFilterType ::DataSize ( size ) = > account . data ( ) . len ( ) as u64 = = * size ,
RpcFilterType ::Memcmp ( compare ) = > compare . bytes_match ( & account . data ( ) ) ,
2020-12-31 18:06:03 -08:00
} )
} )
} else {
self . get_filtered_program_accounts ( bank , & spl_token_id_v2_0 ( ) , filters )
}
}
2019-02-17 10:29:08 -07:00
}
2018-10-25 16:58:40 -07:00
2020-10-23 20:47:51 -07:00
fn verify_transaction ( transaction : & Transaction ) -> Result < ( ) > {
if transaction . verify ( ) . is_err ( ) {
return Err ( RpcCustomError ::TransactionSignatureVerificationFailure . into ( ) ) ;
}
if let Err ( e ) = transaction . verify_precompiles ( ) {
return Err ( RpcCustomError ::TransactionPrecompileVerificationFailure ( e ) . into ( ) ) ;
}
Ok ( ( ) )
}
2020-07-03 01:46:29 -06:00
fn verify_filter ( input : & RpcFilterType ) -> Result < ( ) > {
input
. verify ( )
. map_err ( | e | Error ::invalid_params ( format! ( " Invalid param: {:?} " , e ) ) )
}
2019-02-17 10:29:08 -07:00
fn verify_pubkey ( input : String ) -> Result < Pubkey > {
2020-05-21 18:30:02 -06:00
input
. parse ( )
2020-07-03 01:46:29 -06:00
. map_err ( | e | Error ::invalid_params ( format! ( " Invalid param: {:?} " , e ) ) )
2019-02-17 10:29:08 -07:00
}
2018-08-14 18:03:48 -06:00
2019-02-17 10:29:08 -07:00
fn verify_signature ( input : & str ) -> Result < Signature > {
2020-05-21 18:30:02 -06:00
input
. parse ( )
2020-07-03 01:46:29 -06:00
. map_err ( | e | Error ::invalid_params ( format! ( " Invalid param: {:?} " , e ) ) )
2018-08-14 18:03:48 -06:00
}
2020-07-28 23:00:48 -06:00
fn verify_token_account_filter (
token_account_filter : RpcTokenAccountsFilter ,
) -> Result < TokenAccountsFilter > {
match token_account_filter {
RpcTokenAccountsFilter ::Mint ( mint_str ) = > {
let mint = verify_pubkey ( mint_str ) ? ;
Ok ( TokenAccountsFilter ::Mint ( mint ) )
}
RpcTokenAccountsFilter ::ProgramId ( program_id_str ) = > {
let program_id = verify_pubkey ( program_id_str ) ? ;
Ok ( TokenAccountsFilter ::ProgramId ( program_id ) )
}
}
}
2020-08-10 16:35:29 -06:00
fn check_slice_and_encoding ( encoding : & UiAccountEncoding , data_slice_is_some : bool ) -> Result < ( ) > {
match encoding {
UiAccountEncoding ::JsonParsed = > {
if data_slice_is_some {
let message =
2020-08-15 22:06:39 -07:00
" Sliced account data can only be encoded using binary (base 58) or base64 encoding. "
2020-08-10 16:35:29 -06:00
. to_string ( ) ;
Err ( error ::Error {
code : error ::ErrorCode ::InvalidRequest ,
message ,
data : None ,
} )
} else {
Ok ( ( ) )
}
}
2020-11-24 12:52:01 -08:00
UiAccountEncoding ::Binary
| UiAccountEncoding ::Base58
| UiAccountEncoding ::Base64
| UiAccountEncoding ::Base64Zstd = > Ok ( ( ) ) ,
2020-08-10 16:35:29 -06:00
}
}
2020-09-03 11:35:06 -06:00
fn get_encoded_account (
bank : & Arc < Bank > ,
pubkey : & Pubkey ,
encoding : UiAccountEncoding ,
data_slice : Option < UiDataSliceConfig > ,
) -> Result < Option < UiAccount > > {
let mut response = None ;
if let Some ( account ) = bank . get_account ( pubkey ) {
if account . owner = = spl_token_id_v2_0 ( ) & & encoding = = UiAccountEncoding ::JsonParsed {
response = Some ( get_parsed_token_account ( bank . clone ( ) , pubkey , account ) ) ;
} else if ( encoding = = UiAccountEncoding ::Binary | | encoding = = UiAccountEncoding ::Base58 )
2021-03-09 16:31:33 -06:00
& & account . data ( ) . len ( ) > 128
2020-09-03 11:35:06 -06:00
{
let message = " Encoded binary (base 58) data should be less than 128 bytes, please use Base64 encoding. " . to_string ( ) ;
return Err ( error ::Error {
code : error ::ErrorCode ::InvalidRequest ,
message ,
data : None ,
} ) ;
} else {
response = Some ( UiAccount ::encode (
pubkey , account , encoding , None , data_slice ,
) ) ;
}
}
Ok ( response )
}
2020-12-31 18:06:03 -08:00
fn get_spl_token_owner_filter ( program_id : & Pubkey , filters : & [ RpcFilterType ] ) -> Option < Pubkey > {
if program_id ! = & spl_token_id_v2_0 ( ) {
return None ;
}
let mut data_size_filter : Option < u64 > = None ;
let mut owner_key : Option < Pubkey > = None ;
for filter in filters {
match filter {
RpcFilterType ::DataSize ( size ) = > data_size_filter = Some ( * size ) ,
RpcFilterType ::Memcmp ( Memcmp {
offset : SPL_TOKEN_ACCOUNT_OWNER_OFFSET ,
bytes : MemcmpEncodedBytes ::Binary ( bytes ) ,
..
} ) = > {
if let Ok ( key ) = Pubkey ::from_str ( bytes ) {
owner_key = Some ( key )
}
}
_ = > { }
}
}
if data_size_filter = = Some ( TokenAccount ::get_packed_len ( ) as u64 ) {
owner_key
} else {
None
}
2020-07-28 23:00:48 -06:00
}
2021-02-09 15:49:13 -07:00
fn get_spl_token_mint_filter ( program_id : & Pubkey , filters : & [ RpcFilterType ] ) -> Option < Pubkey > {
if program_id ! = & spl_token_id_v2_0 ( ) {
return None ;
}
let mut data_size_filter : Option < u64 > = None ;
let mut mint : Option < Pubkey > = None ;
for filter in filters {
match filter {
RpcFilterType ::DataSize ( size ) = > data_size_filter = Some ( * size ) ,
RpcFilterType ::Memcmp ( Memcmp {
offset : SPL_TOKEN_ACCOUNT_MINT_OFFSET ,
bytes : MemcmpEncodedBytes ::Binary ( bytes ) ,
..
} ) = > {
if let Ok ( key ) = Pubkey ::from_str ( bytes ) {
mint = Some ( key )
}
}
_ = > { }
}
}
if data_size_filter = = Some ( TokenAccount ::get_packed_len ( ) as u64 ) {
mint
} else {
None
}
}
2020-08-09 01:50:45 -06:00
pub ( crate ) fn get_parsed_token_account (
bank : Arc < Bank > ,
pubkey : & Pubkey ,
2021-03-09 15:06:07 -06:00
account : AccountSharedData ,
2020-08-10 14:35:36 -06:00
) -> UiAccount {
2021-03-09 16:31:33 -06:00
let additional_data = get_token_account_mint ( & account . data ( ) )
2020-08-07 11:37:39 -06:00
. and_then ( | mint_pubkey | get_mint_owner_and_decimals ( & bank , & mint_pubkey ) . ok ( ) )
2020-08-10 14:35:36 -06:00
. map ( | ( _ , decimals ) | AccountAdditionalData {
spl_token_decimals : Some ( decimals ) ,
} ) ;
UiAccount ::encode (
pubkey ,
account ,
UiAccountEncoding ::JsonParsed ,
additional_data ,
2020-08-10 16:35:29 -06:00
None ,
2020-08-10 14:35:36 -06:00
)
2020-08-07 11:37:39 -06:00
}
pub ( crate ) fn get_parsed_token_accounts < I > (
bank : Arc < Bank > ,
keyed_accounts : I ,
) -> impl Iterator < Item = RpcKeyedAccount >
where
2021-03-09 15:06:07 -06:00
I : Iterator < Item = ( Pubkey , AccountSharedData ) > ,
2020-08-07 11:37:39 -06:00
{
let mut mint_decimals : HashMap < Pubkey , u8 > = HashMap ::new ( ) ;
2020-08-26 11:39:42 -06:00
keyed_accounts . filter_map ( move | ( pubkey , account ) | {
2021-03-09 16:31:33 -06:00
let additional_data = get_token_account_mint ( & account . data ( ) ) . map ( | mint_pubkey | {
2020-08-29 12:38:27 -06:00
let spl_token_decimals = mint_decimals . get ( & mint_pubkey ) . cloned ( ) . or_else ( | | {
let ( _ , decimals ) = get_mint_owner_and_decimals ( & bank , & mint_pubkey ) . ok ( ) ? ;
mint_decimals . insert ( mint_pubkey , decimals ) ;
Some ( decimals )
2020-08-07 11:37:39 -06:00
} ) ;
2020-08-29 12:38:27 -06:00
AccountAdditionalData { spl_token_decimals }
} ) ;
2020-08-10 14:35:36 -06:00
2020-08-29 12:38:27 -06:00
let maybe_encoded_account = UiAccount ::encode (
& pubkey ,
account ,
UiAccountEncoding ::JsonParsed ,
additional_data ,
None ,
) ;
if let UiAccountData ::Json ( _ ) = & maybe_encoded_account . data {
Some ( RpcKeyedAccount {
pubkey : pubkey . to_string ( ) ,
account : maybe_encoded_account ,
} )
} else {
None
}
2020-08-07 11:37:39 -06:00
} )
}
2020-07-28 23:00:48 -06: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 ) = > {
2020-08-05 00:48:09 -06:00
let ( mint_owner , _ ) = get_mint_owner_and_decimals ( & bank , & mint ) ? ;
2020-08-28 15:54:57 -06:00
if mint_owner ! = spl_token_id_v2_0 ( ) {
2020-07-28 23:00:48 -06:00
return Err ( Error ::invalid_params (
2020-08-28 15:54:57 -06:00
" Invalid param: not a v2.0 Token mint " . to_string ( ) ,
2020-07-28 23:00:48 -06:00
) ) ;
}
2020-08-05 00:48:09 -06:00
Ok ( ( mint_owner , Some ( mint ) ) )
2020-07-28 23:00:48 -06:00
}
TokenAccountsFilter ::ProgramId ( program_id ) = > {
2020-08-28 15:54:57 -06:00
if program_id = = spl_token_id_v2_0 ( ) {
2020-07-28 23:00:48 -06:00
Ok ( ( program_id , None ) )
} else {
Err ( Error ::invalid_params (
" Invalid param: unrecognized Token program id " . to_string ( ) ,
) )
}
}
}
}
2020-08-05 00:48:09 -06:00
/// Analyze a mint Pubkey that may be the native_mint and get the mint-account owner (token
/// program_id) and decimals
fn get_mint_owner_and_decimals ( bank : & Arc < Bank > , mint : & Pubkey ) -> Result < ( Pubkey , u8 ) > {
2020-08-28 15:54:57 -06:00
if mint = = & spl_token_v2_0_native_mint ( ) {
Ok ( ( spl_token_id_v2_0 ( ) , spl_token_v2_0 ::native_mint ::DECIMALS ) )
2020-08-05 00:48:09 -06:00
} else {
let mint_account = bank . get_account ( mint ) . ok_or_else ( | | {
Error ::invalid_params ( " Invalid param: could not find mint " . to_string ( ) )
} ) ? ;
2021-03-09 16:31:33 -06:00
let decimals = get_mint_decimals ( & mint_account . data ( ) ) ? ;
2020-08-05 00:48:09 -06:00
Ok ( ( mint_account . owner , decimals ) )
}
}
fn get_mint_decimals ( data : & [ u8 ] ) -> Result < u8 > {
2020-08-28 15:54:57 -06:00
Mint ::unpack ( data )
2020-08-05 00:48:09 -06:00
. map_err ( | _ | {
Error ::invalid_params ( " Invalid param: Token mint could not be unpacked " . to_string ( ) )
} )
2020-08-28 15:54:57 -06:00
. map ( | mint | mint . decimals )
2020-08-05 00:48:09 -06:00
}
2020-07-29 20:05:41 -06:00
fn _send_transaction (
meta : JsonRpcRequestProcessor ,
transaction : Transaction ,
wire_transaction : Vec < u8 > ,
last_valid_slot : Slot ,
2020-12-29 09:48:43 -07:00
durable_nonce_info : Option < ( Pubkey , Hash ) > ,
2020-07-29 20:05:41 -06:00
) -> Result < String > {
2020-07-29 20:07:12 -06:00
if transaction . signatures . is_empty ( ) {
2020-09-15 22:30:04 -07:00
return Err ( RpcCustomError ::TransactionSignatureVerificationFailure . into ( ) ) ;
2020-07-29 20:07:12 -06:00
}
2020-07-29 20:05:41 -06:00
let signature = transaction . signatures [ 0 ] ;
2020-12-29 09:48:43 -07:00
let transaction_info = TransactionInfo ::new (
signature ,
wire_transaction ,
last_valid_slot ,
durable_nonce_info ,
) ;
2020-07-29 20:05:41 -06:00
meta . transaction_sender
. lock ( )
. unwrap ( )
. send ( transaction_info )
. unwrap_or_else ( | err | warn! ( " Failed to enqueue transaction: {} " , err ) ) ;
Ok ( signature . to_string ( ) )
}
2021-02-26 21:42:09 -08:00
// Minimal RPC interface that trusted validators are expected to provide
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 ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < u64 > > ;
#[ rpc(meta, name = " getEpochInfo " ) ]
fn get_epoch_info (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < EpochInfo > ;
#[ 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 " ) ]
fn get_slot (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < Slot > ;
#[ rpc(meta, name = " getSnapshotSlot " ) ]
fn get_snapshot_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > ;
#[ rpc(meta, name = " getTransactionCount " ) ]
fn get_transaction_count (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> 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 ,
commitment : Option < CommitmentConfig > ,
) -> 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 ,
slot : Option < Slot > ,
commitment : Option < CommitmentConfig > ,
) -> Result < Option < RpcLeaderSchedule > > ;
}
pub struct MinimalImpl ;
impl Minimal for MinimalImpl {
type Metadata = JsonRpcRequestProcessor ;
fn get_balance (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < u64 > > {
debug! ( " get_balance rpc request received: {:?} " , pubkey_str ) ;
let pubkey = verify_pubkey ( pubkey_str ) ? ;
Ok ( meta . get_balance ( & pubkey , commitment ) )
}
2018-09-26 17:12:40 -07:00
2021-02-26 21:42:09 -08:00
fn get_epoch_info (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < EpochInfo > {
debug! ( " get_epoch_info rpc request received " ) ;
let bank = meta . bank ( commitment ) ;
Ok ( bank . get_epoch_info ( ) )
}
2019-02-26 12:25:46 -08:00
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 {
identity : meta . config . identity_pubkey . to_string ( ) ,
} )
2020-09-03 11:35:06 -06:00
}
2021-02-26 21:42:09 -08:00
fn get_slot (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < Slot > {
debug! ( " get_slot rpc request received " ) ;
Ok ( meta . get_slot ( commitment ) )
2020-09-03 11:35:06 -06:00
}
2021-02-26 21:42:09 -08: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 | {
get_highest_snapshot_archive_path ( & snapshot_config . snapshot_package_output_path )
. map ( | ( _ , ( slot , _ , _ ) ) | slot )
} )
. ok_or_else ( | | RpcCustomError ::NoSnapshot . into ( ) )
2020-09-08 09:23:16 -07:00
}
2019-09-26 23:27:13 +05:30
2021-02-26 21:42:09 -08:00
fn get_transaction_count (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < u64 > {
debug! ( " get_transaction_count rpc request received " ) ;
Ok ( meta . get_transaction_count ( commitment ) )
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 01:46:29 -06:00
}
2019-06-29 10:59:07 -06: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 ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcVoteAccountStatus > {
debug! ( " get_vote_accounts rpc request received " ) ;
meta . get_vote_accounts ( commitment )
}
2020-05-29 12:50:25 -06: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 ,
slot : Option < Slot > ,
commitment : Option < CommitmentConfig > ,
) -> Result < Option < RpcLeaderSchedule > > {
let bank = meta . bank ( commitment ) ;
let slot = slot . unwrap_or_else ( | | bank . slot ( ) ) ;
let epoch = bank . epoch_schedule ( ) . get_epoch ( slot ) ;
debug! ( " get_leader_schedule rpc request received: {:?} " , slot ) ;
Ok (
solana_ledger ::leader_schedule_utils ::leader_schedule ( epoch , & bank ) . map (
| leader_schedule | {
let mut leader_schedule_by_identity = HashMap ::new ( ) ;
for ( slot_index , identity_pubkey ) in
leader_schedule . get_slot_leaders ( ) . iter ( ) . enumerate ( )
{
leader_schedule_by_identity
. entry ( identity_pubkey )
. or_insert_with ( Vec ::new )
. push ( slot_index ) ;
}
2019-08-27 18:17:03 -04:00
2021-02-26 21:42:09 -08:00
leader_schedule_by_identity
. into_iter ( )
. map ( | ( identity_pubkey , slot_indices ) | {
( identity_pubkey . to_string ( ) , slot_indices )
} )
. collect ( )
} ,
) ,
)
}
2019-10-22 16:41:18 -04:00
}
2021-02-26 21:42:09 -08:00
}
2019-10-22 16:41:18 -04:00
2021-02-26 21:42:09 -08:00
// 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 {
use super ::* ;
#[ rpc ]
pub trait Full {
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 > > ;
#[ 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 = " getProgramAccounts " ) ]
fn get_program_accounts (
& self ,
meta : Self ::Metadata ,
program_id_str : String ,
config : Option < RpcProgramAccountsConfig > ,
) -> Result < Vec < RpcKeyedAccount > > ;
#[ rpc(meta, name = " getMinimumBalanceForRentExemption " ) ]
fn get_minimum_balance_for_rent_exemption (
& self ,
meta : Self ::Metadata ,
data_len : usize ,
commitment : Option < CommitmentConfig > ,
) -> Result < u64 > ;
#[ rpc(meta, name = " getInflationGovernor " ) ]
fn get_inflation_governor (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcInflationGovernor > ;
#[ 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 = " 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 = " getBlockCommitment " ) ]
fn get_block_commitment (
& self ,
meta : Self ::Metadata ,
block : Slot ,
) -> Result < RpcBlockCommitment < BlockCommitmentArray > > ;
#[ rpc(meta, name = " getGenesisHash " ) ]
fn get_genesis_hash ( & self , meta : Self ::Metadata ) -> Result < String > ;
#[ 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 > > ;
#[ rpc(meta, name = " getSignatureStatuses " ) ]
fn get_signature_statuses (
& self ,
meta : Self ::Metadata ,
signature_strs : Vec < String > ,
config : Option < RpcSignatureStatusConfig > ,
) -> Result < RpcResponse < Vec < Option < TransactionStatus > > > > ;
#[ rpc(meta, name = " getMaxRetransmitSlot " ) ]
fn get_max_retransmit_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > ;
#[ rpc(meta, name = " getMaxShredInsertSlot " ) ]
fn get_max_shred_insert_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > ;
// DEPRECATED
#[ rpc(meta, name = " getTotalSupply " ) ]
fn get_total_supply (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < u64 > ;
#[ 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 ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < RpcSupply > > ;
#[ rpc(meta, name = " requestAirdrop " ) ]
fn request_airdrop (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
lamports : u64 ,
commitment : Option < CommitmentConfig > ,
) -> 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 = " getSlotLeader " ) ]
fn get_slot_leader (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < String > ;
#[ rpc(meta, name = " minimumLedgerSlot " ) ]
fn minimum_ledger_slot ( & self , meta : Self ::Metadata ) -> Result < Slot > ;
#[ rpc(meta, name = " getConfirmedBlock " ) ]
fn get_confirmed_block (
& self ,
meta : Self ::Metadata ,
slot : Slot ,
encoding : Option < UiTransactionEncoding > ,
) -> Result < Option < EncodedConfirmedBlock > > ;
#[ rpc(meta, name = " getBlockTime " ) ]
fn get_block_time ( & self , meta : Self ::Metadata , slot : Slot )
-> Result < Option < UnixTimestamp > > ;
#[ rpc(meta, name = " getConfirmedBlocks " ) ]
fn get_confirmed_blocks (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
end_slot : Option < Slot > ,
) -> Result < Vec < Slot > > ;
#[ rpc(meta, name = " getConfirmedBlocksWithLimit " ) ]
fn get_confirmed_blocks_with_limit (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
limit : usize ,
) -> Result < Vec < Slot > > ;
#[ rpc(meta, name = " getConfirmedTransaction " ) ]
fn get_confirmed_transaction (
& self ,
meta : Self ::Metadata ,
signature_str : String ,
encoding : Option < UiTransactionEncoding > ,
) -> Result < Option < EncodedConfirmedTransaction > > ;
#[ 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 > > ;
#[ rpc(meta, name = " getConfirmedSignaturesForAddress2 " ) ]
fn get_confirmed_signatures_for_address2 (
& self ,
meta : Self ::Metadata ,
address : String ,
config : Option < RpcGetConfirmedSignaturesForAddress2Config > ,
) -> Result < Vec < RpcConfirmedTransactionStatusWithSignature > > ;
#[ rpc(meta, name = " getFirstAvailableBlock " ) ]
fn get_first_available_block ( & self , meta : Self ::Metadata ) -> Result < Slot > ;
#[ rpc(meta, name = " getStakeActivation " ) ]
fn get_stake_activation (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
config : Option < RpcStakeConfig > ,
) -> 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 > > ;
#[ 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 FullImpl ;
impl Full for FullImpl {
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 ) ? ;
Ok ( meta . confirm_transaction ( & signature , commitment ) )
}
2019-02-26 12:25:46 -08:00
2021-02-26 21:42:09 -08:00
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 )
}
2020-09-22 12:26:32 -07:00
2021-02-26 21:42:09 -08:00
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 ( )
) ;
2020-09-22 12:26:32 -07:00
2021-02-26 21:42:09 -08:00
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! (
" Too many inputs provided; max {} " ,
max_multiple_accounts
) ) ) ;
}
let mut pubkeys : Vec < Pubkey > = vec! [ ] ;
for pubkey_str in pubkey_strs {
pubkeys . push ( verify_pubkey ( pubkey_str ) ? ) ;
}
meta . get_multiple_accounts ( pubkeys , config )
2020-09-22 12:26:32 -07:00
}
2021-02-26 21:42:09 -08:00
fn get_minimum_balance_for_rent_exemption (
& self ,
meta : Self ::Metadata ,
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 ) )
}
2020-09-22 12:26:32 -07:00
2021-02-26 21:42:09 -08:00
fn get_program_accounts (
& self ,
meta : Self ::Metadata ,
program_id_str : String ,
config : Option < RpcProgramAccountsConfig > ,
) -> Result < Vec < RpcKeyedAccount > > {
debug! (
" get_program_accounts rpc request received: {:?} " ,
program_id_str
) ;
let program_id = verify_pubkey ( program_id_str ) ? ;
let ( config , filters ) = if let Some ( config ) = config {
(
Some ( config . account_config ) ,
config . filters . unwrap_or_default ( ) ,
)
2019-04-23 14:46:41 -07:00
} else {
2021-02-26 21:42:09 -08:00
( None , vec! [ ] )
} ;
if filters . len ( ) > MAX_GET_PROGRAM_ACCOUNT_FILTERS {
return Err ( Error ::invalid_params ( format! (
" Too many filters provided; max {} " ,
MAX_GET_PROGRAM_ACCOUNT_FILTERS
) ) ) ;
}
for filter in & filters {
verify_filter ( filter ) ? ;
2019-04-23 14:46:41 -07:00
}
2021-02-26 21:42:09 -08:00
meta . get_program_accounts ( & program_id , config , filters )
2019-04-23 14:46:41 -07:00
}
2021-02-26 21:42:09 -08:00
fn get_inflation_governor (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcInflationGovernor > {
debug! ( " get_inflation_governor rpc request received " ) ;
Ok ( meta . get_inflation_governor ( commitment ) )
}
2019-10-14 16:24:10 -06:00
2021-02-26 21:42:09 -08:00
fn get_inflation_rate ( & self , meta : Self ::Metadata ) -> Result < RpcInflationRate > {
debug! ( " get_inflation_rate rpc request received " ) ;
Ok ( meta . get_inflation_rate ( ) )
}
2019-08-21 18:16:40 -07:00
2021-02-26 21:42:09 -08:00
fn get_epoch_schedule ( & self , meta : Self ::Metadata ) -> Result < EpochSchedule > {
debug! ( " get_epoch_schedule rpc request received " ) ;
Ok ( meta . get_epoch_schedule ( ) )
2021-01-14 21:45:11 -08:00
}
2021-02-26 21:42:09 -08:00
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 12:42:58 -07:00
2021-02-26 21:42:09 -08:00
let limit = limit . unwrap_or ( PERFORMANCE_SAMPLES_LIMIT ) ;
2020-07-28 18:28:51 -06:00
2021-02-26 21:42:09 -08:00
if limit > PERFORMANCE_SAMPLES_LIMIT {
return Err ( Error ::invalid_params ( format! (
" Invalid limit; max {} " ,
PERFORMANCE_SAMPLES_LIMIT
) ) ) ;
}
2019-12-18 12:42:58 -07: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 ( )
} ) ?
. iter ( )
. map ( | ( slot , sample ) | RpcPerfSample {
slot : * slot ,
num_transactions : sample . num_transactions ,
num_slots : sample . num_slots ,
sample_period_secs : sample . sample_period_secs ,
} )
. 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 ;
fn valid_address_or_none ( addr : & SocketAddr ) -> Option < SocketAddr > {
if ContactInfo ::is_valid_address ( addr ) {
Some ( * addr )
} else {
None
}
}
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
& & ContactInfo ::is_valid_address ( & contact_info . gossip )
{
let ( version , feature_set ) = if let Some ( version ) =
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 ) ,
version ,
feature_set ,
2021-02-24 08:38:29 -08:00
} )
2021-02-26 21:42:09 -08:00
} else {
None // Exclude spy nodes
}
} )
. collect ( ) )
}
2021-01-14 21:45:11 -08:00
2021-02-26 21:42:09 -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 ) )
}
2021-01-14 21:45:11 -08:00
2021-02-26 21:42:09 -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 ( ) )
2020-04-06 04:04:54 -06:00
}
2021-02-26 21:42:09 -08:00
fn get_recent_blockhash (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < RpcBlockhashFeeCalculator > > {
debug! ( " get_recent_blockhash rpc request received " ) ;
Ok ( meta . get_recent_blockhash ( commitment ) )
2020-03-23 11:25:39 -06:00
}
2019-03-21 07:43:21 -07:00
2021-02-26 21:42:09 -08:00
fn get_fees (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < RpcFees > > {
debug! ( " get_fees rpc request received " ) ;
Ok ( meta . get_fees ( commitment ) )
}
2019-06-12 16:43:05 -07:00
2021-02-26 21:42:09 -08: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 " ) ;
let blockhash = Hash ::from_str ( & blockhash )
. map_err ( | e | Error ::invalid_params ( format! ( " {:?} " , e ) ) ) ? ;
Ok ( meta . get_fee_calculator_for_blockhash ( & blockhash , commitment ) )
}
2021-02-23 13:06:33 -08:00
2021-02-26 21:42:09 -08: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-02-23 13:06:33 -08:00
2021-02-26 21:42:09 -08: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 ) ? ;
Ok ( meta . get_signature_confirmation_status ( signature , commitment ) )
}
2019-02-26 12:25:46 -08:00
2021-02-26 21:42:09 -08: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 ) ? ;
Ok ( meta . get_signature_status ( signature , commitment ) )
}
2019-06-21 22:00:26 -06:00
2021-02-26 21:42:09 -08:00
fn get_signature_statuses (
& self ,
meta : Self ::Metadata ,
signature_strs : Vec < String > ,
config : Option < RpcSignatureStatusConfig > ,
) -> Result < RpcResponse < Vec < Option < TransactionStatus > > > > {
debug! (
" get_signature_statuses rpc request received: {:?} " ,
signature_strs . len ( )
) ;
if signature_strs . len ( ) > MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS {
return Err ( Error ::invalid_params ( format! (
" Too many inputs provided; max {} " ,
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS
) ) ) ;
}
let mut signatures : Vec < Signature > = vec! [ ] ;
for signature_str in signature_strs {
signatures . push ( verify_signature ( & signature_str ) ? ) ;
}
meta . get_signature_statuses ( signatures , config )
}
2020-05-04 17:46:10 -06: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 12:05:29 -06: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 get_total_supply (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < u64 > {
debug! ( " get_total_supply rpc request received " ) ;
Ok ( meta . get_total_supply ( commitment ) )
}
2018-10-15 11:01:40 -06:00
2021-02-26 21:42:09 -08:00
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 ) )
}
2020-06-05 21:23:13 -07:00
2021-02-26 21:42:09 -08:00
fn get_supply (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < RpcResponse < RpcSupply > > {
debug! ( " get_supply rpc request received " ) ;
Ok ( meta . get_supply ( commitment ) )
}
2020-06-05 21:23:13 -07:00
2021-02-26 21:42:09 -08:00
fn request_airdrop (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
lamports : u64 ,
commitment : Option < CommitmentConfig > ,
) -> Result < String > {
debug! ( " request_airdrop rpc request received " ) ;
trace! (
" request_airdrop id={} lamports={} commitment: {:?} " ,
pubkey_str ,
lamports ,
& commitment
) ;
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 ) ? ;
let pubkey = verify_pubkey ( pubkey_str ) ? ;
2018-10-15 11:01:40 -06:00
2021-02-26 21:42:09 -08:00
let ( blockhash , last_valid_slot ) = {
let bank = meta . bank ( commitment ) ;
2019-02-26 12:25:46 -08:00
2021-02-26 21:42:09 -08:00
let blockhash = bank . confirmed_last_blockhash ( ) . 0 ;
(
blockhash ,
bank . get_blockhash_last_valid_slot ( & 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-02-26 21:42:09 -08:00
_send_transaction ( meta , transaction , wire_transaction , last_valid_slot , None )
2020-12-29 09:48:43 -07: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 " ) ;
let config = config . unwrap_or_default ( ) ;
let encoding = config . encoding . unwrap_or ( UiTransactionEncoding ::Base58 ) ;
let ( wire_transaction , transaction ) = deserialize_transaction ( data , encoding ) ? ;
let preflight_commitment = config
. preflight_commitment
. map ( | commitment | CommitmentConfig { commitment } ) ;
let preflight_bank = & * meta . bank ( preflight_commitment ) ;
let mut last_valid_slot = preflight_bank
. get_blockhash_last_valid_slot ( & transaction . message . recent_blockhash )
. unwrap_or ( 0 ) ;
let durable_nonce_info = solana_sdk ::transaction ::uses_durable_nonce ( & transaction )
. and_then ( | nonce_ix | {
solana_sdk ::transaction ::get_nonce_pubkey_from_instruction (
& nonce_ix ,
& transaction ,
)
} )
. map ( | & pubkey | ( pubkey , transaction . message . recent_blockhash ) ) ;
if durable_nonce_info . is_some ( ) {
// While it uses a defined constant, this last_valid_slot value is chosen arbitrarily.
// 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.
last_valid_slot = preflight_bank . slot ( ) + MAX_RECENT_BLOCKHASHES as u64 ;
2020-09-27 22:29:00 -07:00
}
2021-02-26 21:42:09 -08:00
if ! config . skip_preflight {
if let Err ( e ) = verify_transaction ( & transaction ) {
return Err ( e ) ;
}
match meta . health . check ( ) {
RpcHealthStatus ::Ok = > ( ) ,
2021-03-04 21:18:08 -08:00
RpcHealthStatus ::Unknown = > {
return Err ( RpcCustomError ::NodeUnhealthy {
num_slots_behind : None ,
}
. into ( ) ) ;
}
2021-02-26 21:42:09 -08:00
RpcHealthStatus ::Behind { num_slots } = > {
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-02-26 21:42:09 -08:00
if let ( Err ( err ) , logs ) = preflight_bank . simulate_transaction ( transaction . clone ( ) ) {
return Err ( RpcCustomError ::SendTransactionPreflightFailure {
message : format ! ( " Transaction simulation failed: {} " , err ) ,
result : RpcSimulateTransactionResult {
err : Some ( err ) ,
logs : Some ( logs ) ,
} ,
}
. 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 ,
transaction ,
wire_transaction ,
last_valid_slot ,
durable_nonce_info ,
)
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 " ) ;
let config = config . unwrap_or_default ( ) ;
let encoding = config . encoding . unwrap_or ( UiTransactionEncoding ::Base58 ) ;
let ( _ , transaction ) = deserialize_transaction ( data , encoding ) ? ;
if config . sig_verify {
if let Err ( e ) = verify_transaction ( & transaction ) {
return Err ( e ) ;
}
}
2019-08-07 20:06:27 -06:00
2021-02-26 21:42:09 -08:00
let bank = & * meta . bank ( config . commitment ) ;
let ( result , logs ) = bank . simulate_transaction ( transaction ) ;
2020-03-04 14:44:21 -08:00
2021-02-26 21:42:09 -08:00
Ok ( new_response (
& bank ,
RpcSimulateTransactionResult {
err : result . err ( ) ,
logs : Some ( logs ) ,
} ,
) )
}
2019-08-10 22:54:46 -07:00
2021-02-26 21:42:09 -08:00
fn get_slot_leader (
& self ,
meta : Self ::Metadata ,
commitment : Option < CommitmentConfig > ,
) -> Result < String > {
debug! ( " get_slot_leader rpc request received " ) ;
Ok ( meta . get_slot_leader ( commitment ) )
}
2019-11-11 13:18:34 -05: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-26 00:40:36 -07:00
2021-02-26 21:42:09 -08:00
fn get_confirmed_block (
& self ,
meta : Self ::Metadata ,
slot : Slot ,
encoding : Option < UiTransactionEncoding > ,
) -> Result < Option < EncodedConfirmedBlock > > {
debug! ( " get_confirmed_block rpc request received: {:?} " , slot ) ;
meta . get_confirmed_block ( slot , encoding )
}
2019-12-18 16:51:47 -07:00
2021-02-26 21:42:09 -08:00
fn get_confirmed_blocks (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
end_slot : Option < Slot > ,
) -> Result < Vec < Slot > > {
debug! (
" get_confirmed_blocks rpc request received: {}-{:?} " ,
start_slot , end_slot
) ;
meta . get_confirmed_blocks ( start_slot , end_slot )
}
2020-09-30 13:47:12 -07:00
2021-02-26 21:42:09 -08:00
fn get_confirmed_blocks_with_limit (
& self ,
meta : Self ::Metadata ,
start_slot : Slot ,
limit : usize ,
) -> Result < Vec < Slot > > {
debug! (
" get_confirmed_blocks_with_limit rpc request received: {}-{} " ,
start_slot , limit ,
) ;
meta . get_confirmed_blocks_with_limit ( start_slot , limit )
}
2020-04-09 00:57:30 -06:00
2021-02-26 21:42:09 -08:00
fn get_block_time (
& self ,
meta : Self ::Metadata ,
slot : Slot ,
) -> Result < Option < UnixTimestamp > > {
meta . get_block_time ( slot )
}
2020-04-09 21:21:31 -06:00
2021-02-26 21:42:09 -08:00
fn get_confirmed_transaction (
& self ,
meta : Self ::Metadata ,
signature_str : String ,
encoding : Option < UiTransactionEncoding > ,
) -> Result < Option < EncodedConfirmedTransaction > > {
debug! (
" get_confirmed_transaction rpc request received: {:?} " ,
signature_str
) ;
let signature = verify_signature ( & signature_str ) ? ;
Ok ( meta . get_confirmed_transaction ( signature , encoding ) )
2020-04-09 21:21:31 -06:00
}
2021-02-26 21:42:09 -08: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
) ;
let pubkey = verify_pubkey ( pubkey_str ) ? ;
if end_slot < start_slot {
return Err ( Error ::invalid_params ( format! (
" start_slot {} must be less than or equal to end_slot {} " ,
start_slot , end_slot
) ) ) ;
}
if end_slot - start_slot > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE {
return Err ( Error ::invalid_params ( format! (
" Slot range too large; max {} " ,
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE
) ) ) ;
}
Ok ( meta
. get_confirmed_signatures_for_address ( pubkey , start_slot , end_slot )
. iter ( )
. map ( | signature | signature . to_string ( ) )
. collect ( ) )
2020-04-09 21:21:31 -06:00
}
2020-04-22 14:33:06 -06:00
2021-02-26 21:42:09 -08:00
fn get_confirmed_signatures_for_address2 (
& self ,
meta : Self ::Metadata ,
address : String ,
config : Option < RpcGetConfirmedSignaturesForAddress2Config > ,
) -> Result < Vec < RpcConfirmedTransactionStatusWithSignature > > {
let address = verify_pubkey ( address ) ? ;
let config = config . unwrap_or_default ( ) ;
let before = if let Some ( before ) = config . before {
Some ( verify_signature ( & before ) ? )
} else {
None
} ;
let until = if let Some ( until ) = config . until {
Some ( verify_signature ( & until ) ? )
} else {
None
} ;
let limit = config
. limit
. unwrap_or ( MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT ) ;
2020-07-27 11:42:49 -07:00
2021-02-26 21:42:09 -08:00
if limit = = 0 | | limit > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT {
return Err ( Error ::invalid_params ( format! (
" Invalid limit; max {} " ,
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS2_LIMIT
) ) ) ;
}
2020-07-27 11:42:49 -07:00
2021-02-26 21:42:09 -08:00
meta . get_confirmed_signatures_for_address2 ( address , before , until , limit )
2020-07-27 11:42:49 -07:00
}
2021-02-26 21:42:09 -08:00
fn get_first_available_block ( & self , meta : Self ::Metadata ) -> Result < Slot > {
debug! ( " get_first_available_block rpc request received " ) ;
Ok ( meta . get_first_available_block ( ) )
}
2020-07-06 13:28:40 -06:00
2021-02-26 21:42:09 -08:00
fn get_stake_activation (
& self ,
meta : Self ::Metadata ,
pubkey_str : String ,
config : Option < RpcStakeConfig > ,
) -> Result < RpcStakeActivation > {
debug! (
" get_stake_activation rpc request received: {:?} " ,
pubkey_str
) ;
let pubkey = verify_pubkey ( pubkey_str ) ? ;
meta . get_stake_activation ( & pubkey , config )
}
2020-07-28 23:00:48 -06:00
2021-02-26 21:42:09 -08:00
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 )
}
2020-07-28 23:00:48 -06:00
2021-02-26 21:42:09 -08:00
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 )
}
2020-07-28 23:00:48 -06:00
2021-02-26 21:42:09 -08: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 )
}
2020-08-02 10:23:44 -06:00
2021-02-26 21:42:09 -08:00
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 )
}
2020-07-28 23:00:48 -06:00
2021-02-26 21:42:09 -08:00
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 )
}
2020-07-28 23:00:48 -06:00
}
2019-11-11 13:18:34 -05:00
}
2020-10-05 21:21:33 -06:00
const WORST_CASE_BASE58_TX : usize = 1683 ; // Golden, bump if PACKET_DATA_SIZE changes
2020-10-05 22:47:47 -06:00
const WORST_CASE_BASE64_TX : usize = 1644 ; // Golden, bump if PACKET_DATA_SIZE changes
fn deserialize_transaction (
encoded_transaction : String ,
encoding : UiTransactionEncoding ,
) -> Result < ( Vec < u8 > , Transaction ) > {
let wire_transaction = match encoding {
UiTransactionEncoding ::Base58 = > {
2020-10-13 13:33:38 -06:00
inc_new_counter_info! ( " rpc-base58_encoded_tx " , 1 ) ;
2020-10-05 22:47:47 -06:00
if encoded_transaction . len ( ) > WORST_CASE_BASE58_TX {
return Err ( Error ::invalid_params ( format! (
" encoded transaction too large: {} bytes (max: encoded/raw {}/{}) " ,
encoded_transaction . len ( ) ,
WORST_CASE_BASE58_TX ,
PACKET_DATA_SIZE ,
) ) ) ;
}
bs58 ::decode ( encoded_transaction )
. into_vec ( )
. map_err ( | e | Error ::invalid_params ( format! ( " {:?} " , e ) ) ) ?
}
UiTransactionEncoding ::Base64 = > {
2020-10-13 13:33:38 -06:00
inc_new_counter_info! ( " rpc-base64_encoded_tx " , 1 ) ;
2020-10-05 22:47:47 -06:00
if encoded_transaction . len ( ) > WORST_CASE_BASE64_TX {
return Err ( Error ::invalid_params ( format! (
" encoded transaction too large: {} bytes (max: encoded/raw {}/{}) " ,
encoded_transaction . len ( ) ,
WORST_CASE_BASE64_TX ,
PACKET_DATA_SIZE ,
) ) ) ;
}
base64 ::decode ( encoded_transaction )
. map_err ( | e | Error ::invalid_params ( format! ( " {:?} " , e ) ) ) ?
}
_ = > {
return Err ( Error ::invalid_params ( format! (
" unsupported transaction encoding: {}. Supported encodings: base58, base64 " ,
encoding
) ) )
}
} ;
2020-09-15 15:25:00 +08:00
if wire_transaction . len ( ) > PACKET_DATA_SIZE {
2020-05-21 18:30:02 -06:00
let err = format! (
2020-05-19 12:08:19 -07:00
" transaction too large: {} bytes (max: {} bytes) " ,
wire_transaction . len ( ) ,
PACKET_DATA_SIZE
) ;
2020-05-21 18:30:02 -06:00
info! ( " {} " , err ) ;
return Err ( Error ::invalid_params ( & err ) ) ;
2020-05-19 12:08:19 -07:00
}
2020-07-09 00:08:05 +00:00
bincode ::options ( )
. with_limit ( PACKET_DATA_SIZE as u64 )
. with_fixint_encoding ( )
. allow_trailing_bytes ( )
2020-07-08 15:54:42 -06:00
. deserialize_from ( & wire_transaction [ .. ] )
2020-05-19 12:08:19 -07:00
. map_err ( | err | {
info! ( " transaction deserialize error: {:?} " , err ) ;
2020-05-21 18:30:02 -06:00
Error ::invalid_params ( & err . to_string ( ) )
2020-05-19 12:08:19 -07:00
} )
2021-01-20 18:11:58 -08:00
. and_then ( | transaction : Transaction | {
if let Err ( err ) = transaction . sanitize ( ) {
Err ( Error ::invalid_params ( format! (
" invalid transaction: {} " ,
err
) ) )
} else {
Ok ( transaction )
}
} )
2020-05-19 12:08:19 -07:00
. map ( | transaction | ( wire_transaction , transaction ) )
}
2021-03-01 13:20:04 -08:00
pub ( crate ) fn create_validator_exit ( exit : & Arc < AtomicBool > ) -> Arc < RwLock < ValidatorExit > > {
2020-06-16 23:30:59 -06:00
let mut validator_exit = ValidatorExit ::default ( ) ;
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 23:30:59 -06:00
}
2018-08-13 11:24:39 -06:00
#[ cfg(test) ]
2019-08-20 23:59:31 -07:00
pub mod tests {
2021-02-26 21:42:09 -08:00
use super ::{ rpc_full ::* , rpc_minimal ::* , * } ;
2019-10-14 16:24:10 -06:00
use crate ::{
2020-09-28 20:43:05 -06:00
contact_info ::ContactInfo ,
non_circulating_supply ::non_circulating_accounts ,
optimistically_confirmed_bank_tracker ::{
BankNotification , OptimisticallyConfirmedBankTracker ,
} ,
2020-01-13 14:13:52 -07:00
replay_stage ::tests ::create_test_transactions_and_populate_blockstore ,
2020-09-28 20:43:05 -06:00
rpc_subscriptions ::RpcSubscriptions ,
2019-10-14 16:24:10 -06:00
} ;
2020-01-12 22:34:30 -07:00
use bincode ::deserialize ;
2021-02-02 19:53:08 -07:00
use jsonrpc_core ::{ futures , ErrorCode , MetaIoHandler , Output , Response , Value } ;
2020-06-11 16:51:25 -06:00
use jsonrpc_core_client ::transports ::local ;
2020-07-03 01:46:29 -06:00
use solana_client ::rpc_filter ::{ Memcmp , MemcmpEncodedBytes } ;
2019-12-14 12:23:02 -07:00
use solana_ledger ::{
2020-09-24 14:22:22 -07:00
blockstore_meta ::PerfSample ,
2020-03-21 10:54:40 -07:00
blockstore_processor ::fill_blockstore_slot_with_ticks ,
genesis_utils ::{ create_genesis_config , GenesisConfigInfo } ,
2019-12-14 12:23:02 -07:00
} ;
2020-12-12 17:22:34 -08:00
use solana_runtime ::{
2021-02-18 23:42:09 -08:00
accounts_background_service ::AbsRequestSender , commitment ::BlockCommitment ,
2020-12-12 17:22:34 -08:00
} ;
2019-10-14 16:24:10 -06:00
use solana_sdk ::{
2020-05-26 13:06:21 -06:00
clock ::MAX_RECENT_BLOCKHASHES ,
2019-10-14 16:24:10 -06:00
fee_calculator ::DEFAULT_BURN_PERCENT ,
hash ::{ hash , Hash } ,
instruction ::InstructionError ,
2020-05-30 00:17:44 -06:00
message ::Message ,
2020-07-03 01:46:29 -06:00
nonce , rpc_port ,
2020-02-20 14:28:55 -07:00
signature ::{ Keypair , Signer } ,
2020-09-08 09:23:16 -07:00
system_program , system_transaction ,
2020-09-09 09:33:14 -06:00
timing ::slot_duration_from_slots_per_year ,
2020-03-23 11:25:39 -06:00
transaction ::{ self , TransactionError } ,
2019-10-14 16:24:10 -06:00
} ;
2020-09-24 13:10:29 +08:00
use solana_transaction_status ::{
EncodedTransaction , EncodedTransactionWithStatusMeta , UiMessage ,
} ;
2019-12-11 22:04:54 -08:00
use solana_vote_program ::{
vote_instruction ,
2021-01-11 16:27:30 -07:00
vote_state ::{ BlockTimestamp , Vote , VoteInit , VoteStateVersions , MAX_LOCKOUT_HISTORY } ,
2019-12-11 22:04:54 -08:00
} ;
2020-08-28 15:54:57 -06:00
use spl_token_v2_0 ::{
2020-11-04 11:18:20 -08:00
solana_program ::{ program_option ::COption , pubkey ::Pubkey as SplTokenPubkey } ,
2020-09-22 17:08:54 -06:00
state ::AccountState as TokenAccountState ,
state ::Mint ,
2020-07-30 14:52:28 -07:00
} ;
2020-10-26 13:23:45 -06:00
use std ::collections ::HashMap ;
2018-08-13 11:24:39 -06:00
2019-12-07 00:12:25 -07:00
const TEST_MINT_LAMPORTS : u64 = 1_000_000 ;
2020-06-09 08:43:16 -07:00
const TEST_SLOTS_PER_EPOCH : u64 = DELINQUENT_VALIDATOR_SLOT_DISTANCE + 1 ;
2019-06-21 22:00:26 -06:00
2019-10-14 16:24:10 -06:00
struct RpcHandler {
2020-06-07 21:54:03 -06:00
io : MetaIoHandler < JsonRpcRequestProcessor > ,
meta : JsonRpcRequestProcessor ,
2019-10-14 16:24:10 -06:00
bank : Arc < Bank > ,
2019-12-11 22:04:54 -08:00
bank_forks : Arc < RwLock < BankForks > > ,
2019-10-14 16:24:10 -06:00
blockhash : Hash ,
alice : Keypair ,
leader_pubkey : Pubkey ,
2020-07-23 18:50:42 -07:00
leader_vote_keypair : Arc < Keypair > ,
2019-11-04 16:44:27 -07:00
block_commitment_cache : Arc < RwLock < BlockCommitmentCache > > ,
2019-11-25 12:08:03 -07:00
confirmed_block_signatures : Vec < Signature > ,
2019-10-14 16:24:10 -06:00
}
fn start_rpc_handler_with_tx ( pubkey : & Pubkey ) -> RpcHandler {
2020-10-26 13:23:45 -06:00
start_rpc_handler_with_tx_and_blockstore ( pubkey , vec! [ ] )
2019-12-14 12:23:02 -07:00
}
2020-01-13 14:13:52 -07:00
fn start_rpc_handler_with_tx_and_blockstore (
2019-12-14 12:23:02 -07:00
pubkey : & Pubkey ,
2020-01-13 14:13:52 -07:00
blockstore_roots : Vec < Slot > ,
2019-12-14 12:23:02 -07:00
) -> RpcHandler {
2019-12-11 22:04:54 -08:00
let ( bank_forks , alice , leader_vote_keypair ) = new_bank_forks ( ) ;
2019-03-18 14:18:43 -07:00
let bank = bank_forks . read ( ) . unwrap ( ) . working_bank ( ) ;
2021-01-11 16:27:30 -07:00
let vote_pubkey = leader_vote_keypair . pubkey ( ) ;
let mut vote_account = bank . get_account ( & vote_pubkey ) . unwrap_or_default ( ) ;
let mut vote_state = VoteState ::from ( & vote_account ) . unwrap_or_default ( ) ;
vote_state . last_timestamp = BlockTimestamp {
slot : bank . slot ( ) ,
timestamp : bank . clock ( ) . unix_timestamp ,
} ;
let versioned = VoteStateVersions ::new_current ( vote_state ) ;
VoteState ::to ( & versioned , & mut vote_account ) . unwrap ( ) ;
bank . store_account ( & vote_pubkey , & vote_account ) ;
2019-11-11 13:18:34 -05:00
let ledger_path = get_tmp_ledger_path! ( ) ;
2020-01-13 14:13:52 -07:00
let blockstore = Blockstore ::open ( & ledger_path ) . unwrap ( ) ;
let blockstore = Arc ::new ( blockstore ) ;
2019-11-25 12:08:03 -07:00
let keypair1 = Keypair ::new ( ) ;
let keypair2 = Keypair ::new ( ) ;
let keypair3 = Keypair ::new ( ) ;
bank . transfer ( 4 , & alice , & keypair2 . pubkey ( ) ) . unwrap ( ) ;
2020-01-13 14:13:52 -07:00
let confirmed_block_signatures = create_test_transactions_and_populate_blockstore (
2019-11-25 12:08:03 -07:00
vec! [ & alice , & keypair1 , & keypair2 , & keypair3 ] ,
0 ,
bank . clone ( ) ,
2020-01-13 14:13:52 -07:00
blockstore . clone ( ) ,
2019-11-25 12:08:03 -07:00
) ;
2019-10-14 16:24:10 -06:00
2020-03-30 17:53:25 -06:00
let mut commitment_slot0 = BlockCommitment ::default ( ) ;
commitment_slot0 . increase_confirmation_stake ( 2 , 9 ) ;
let mut commitment_slot1 = BlockCommitment ::default ( ) ;
commitment_slot1 . increase_confirmation_stake ( 1 , 9 ) ;
2020-03-30 11:29:30 -06:00
let mut block_commitment : HashMap < u64 , BlockCommitment > = HashMap ::new ( ) ;
2020-05-15 17:35:43 +01:00
block_commitment . entry ( 0 ) . or_insert ( commitment_slot0 ) ;
block_commitment . entry ( 1 ) . or_insert ( commitment_slot1 ) ;
2020-03-30 11:29:30 -06:00
let block_commitment_cache = Arc ::new ( RwLock ::new ( BlockCommitmentCache ::new (
block_commitment ,
2020-03-30 17:53:25 -06:00
10 ,
2020-08-12 21:51:15 -06:00
CommitmentSlots ::new_from_slot ( bank . slot ( ) ) ,
2020-03-30 11:29:30 -06:00
) ) ) ;
2020-05-15 17:35:43 +01:00
let mut roots = blockstore_roots ;
2019-12-18 16:51:47 -07:00
if ! roots . is_empty ( ) {
2020-04-28 11:20:43 -06:00
roots . retain ( | & x | x > 0 ) ;
2019-12-18 16:51:47 -07:00
let mut parent_bank = bank ;
for ( i , root ) in roots . iter ( ) . enumerate ( ) {
let new_bank =
Bank ::new_from_parent ( & parent_bank , parent_bank . collector_id ( ) , * root ) ;
parent_bank = bank_forks . write ( ) . unwrap ( ) . insert ( new_bank ) ;
2020-04-28 11:20:43 -06:00
let parent = if i > 0 { roots [ i - 1 ] } else { 0 } ;
2020-01-13 14:13:52 -07:00
fill_blockstore_slot_with_ticks ( & blockstore , 5 , * root , parent , Hash ::default ( ) ) ;
2019-12-18 16:51:47 -07:00
}
2020-01-13 14:13:52 -07:00
blockstore . set_roots ( & roots ) . unwrap ( ) ;
2019-12-18 16:51:47 -07:00
let new_bank = Bank ::new_from_parent (
& parent_bank ,
parent_bank . collector_id ( ) ,
roots . iter ( ) . max ( ) . unwrap ( ) + 1 ,
) ;
bank_forks . write ( ) . unwrap ( ) . insert ( new_bank ) ;
2020-04-28 11:20:43 -06:00
for root in roots . iter ( ) {
2020-12-12 17:22:34 -08:00
bank_forks
. write ( )
. unwrap ( )
2021-02-18 23:42:09 -08:00
. set_root ( * root , & AbsRequestSender ::default ( ) , Some ( 0 ) ) ;
2020-09-09 09:33:14 -06:00
let mut stakes = HashMap ::new ( ) ;
2021-03-09 15:06:07 -06:00
stakes . insert (
leader_vote_keypair . pubkey ( ) ,
( 1 , AccountSharedData ::default ( ) ) ,
) ;
2020-10-26 13:23:45 -06:00
let block_time = bank_forks
. read ( )
. unwrap ( )
. get ( * root )
. unwrap ( )
. clock ( )
. unix_timestamp ;
blockstore . cache_block_time ( * root , block_time ) . unwrap ( ) ;
2020-04-28 11:20:43 -06:00
}
2019-12-18 16:51:47 -07:00
}
let bank = bank_forks . read ( ) . unwrap ( ) . working_bank ( ) ;
2019-12-14 12:23:02 -07:00
2019-07-09 22:06:47 -07:00
let leader_pubkey = * bank . collector_id ( ) ;
2019-03-03 22:01:09 -08:00
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
2019-08-20 23:59:31 -07:00
let validator_exit = create_validator_exit ( & exit ) ;
2018-08-14 18:03:48 -06:00
2019-06-10 22:18:32 -07:00
let blockhash = bank . confirmed_last_blockhash ( ) . 0 ;
2019-05-20 10:03:19 -07:00
let tx = system_transaction ::transfer ( & alice , pubkey , 20 , blockhash ) ;
2018-08-14 18:03:48 -06:00
bank . process_transaction ( & tx ) . expect ( " process transaction " ) ;
2020-05-12 21:05:05 -06:00
let tx =
system_transaction ::transfer ( & alice , & non_circulating_accounts ( ) [ 0 ] , 20 , blockhash ) ;
bank . process_transaction ( & tx ) . expect ( " process transaction " ) ;
2018-08-14 18:03:48 -06:00
2020-01-21 12:42:23 -08:00
let tx = system_transaction ::transfer ( & alice , pubkey , std ::u64 ::MAX , blockhash ) ;
2019-04-05 19:07:30 -06:00
let _ = bank . process_transaction ( & tx ) ;
2020-06-07 21:54:03 -06:00
let cluster_info = Arc ::new ( ClusterInfo ::default ( ) ) ;
2020-07-08 19:13:42 -06:00
let tpu_address = cluster_info . my_contact_info ( ) . tpu ;
2020-06-07 21:54:03 -06:00
cluster_info . insert_info ( ContactInfo ::new_with_pubkey_socketaddr (
& leader_pubkey ,
& socketaddr! ( " 127.0.0.1:1234 " ) ,
) ) ;
2020-09-22 12:26:32 -07:00
let sample1 = PerfSample {
num_slots : 1 ,
num_transactions : 4 ,
sample_period_secs : 60 ,
} ;
blockstore
. write_perf_sample ( 0 , & sample1 )
. expect ( " write to blockstore " ) ;
2021-02-23 13:06:33 -08:00
let max_slots = Arc ::new ( MaxSlots ::default ( ) ) ;
max_slots . retransmit . store ( 42 , Ordering ::Relaxed ) ;
max_slots . shred_insert . store ( 43 , Ordering ::Relaxed ) ;
2020-07-10 19:14:41 -06:00
let ( meta , receiver ) = JsonRpcRequestProcessor ::new (
2020-02-11 18:01:49 -07:00
JsonRpcConfig {
2020-03-23 11:25:39 -06:00
enable_rpc_transaction_history : true ,
2020-03-04 14:44:21 -08:00
identity_pubkey : * pubkey ,
2020-02-11 18:01:49 -07:00
.. JsonRpcConfig ::default ( )
} ,
2021-01-14 21:45:11 -08:00
None ,
2019-12-11 22:04:54 -08:00
bank_forks . clone ( ) ,
2019-11-04 16:44:27 -07:00
block_commitment_cache . clone ( ) ,
2020-01-13 14:13:52 -07:00
blockstore ,
2019-12-19 23:27:54 -08:00
validator_exit ,
2020-05-30 00:39:24 -07:00
RpcHealth ::stub ( ) ,
2020-06-05 21:23:13 -07:00
cluster_info . clone ( ) ,
2020-06-07 21:54:03 -06:00
Hash ::default ( ) ,
2021-02-05 00:21:53 -07:00
Arc ::new ( tokio ::runtime ::Runtime ::new ( ) . unwrap ( ) ) ,
2020-07-23 09:54:57 -07:00
None ,
2020-09-28 20:43:05 -06: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
max_slots ,
2020-06-07 21:54:03 -06:00
) ;
2020-12-17 14:37:22 -08:00
SendTransactionService ::new ( tpu_address , & bank_forks , None , receiver , 1000 , 1 ) ;
2018-08-13 11:24:39 -06:00
2020-06-05 21:23:13 -07:00
cluster_info . insert_info ( ContactInfo ::new_with_pubkey_socketaddr (
& leader_pubkey ,
& socketaddr! ( " 127.0.0.1:1234 " ) ,
) ) ;
2018-08-13 11:24:39 -06: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 ( ) ) ;
2019-10-14 16:24:10 -06:00
RpcHandler {
io ,
meta ,
bank ,
2019-12-11 22:04:54 -08:00
bank_forks ,
2019-10-14 16:24:10 -06:00
blockhash ,
alice ,
leader_pubkey ,
2019-12-11 22:04:54 -08:00
leader_vote_keypair ,
2019-11-04 16:44:27 -07:00
block_commitment_cache ,
2019-11-25 12:08:03 -07:00
confirmed_block_signatures ,
2019-10-14 16:24:10 -06:00
}
2018-10-15 11:01:40 -06: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 23:30:59 -06:00
let genesis = create_genesis_config ( 100 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis . genesis_config ) ) ;
bank . transfer ( 20 , & genesis . mint_keypair , & bob_pubkey )
. unwrap ( ) ;
let request_processor = JsonRpcRequestProcessor ::new_from_bank ( & bank ) ;
2020-07-03 17:39:14 -06:00
assert_eq! ( request_processor . get_transaction_count ( None ) , 1 ) ;
2018-10-15 11:01:40 -06:00
}
#[ test ]
fn test_rpc_get_balance ( ) {
2020-06-16 23:30:59 -06:00
let genesis = create_genesis_config ( 20 ) ;
let mint_pubkey = genesis . mint_keypair . pubkey ( ) ;
let bank = Arc ::new ( Bank ::new ( & genesis . genesis_config ) ) ;
let meta = JsonRpcRequestProcessor ::new_from_bank ( & bank ) ;
let mut io = MetaIoHandler ::default ( ) ;
2021-02-26 21:42:09 -08:00
io . extend_with ( rpc_minimal ::MinimalImpl . to_delegate ( ) ) ;
2018-08-14 18:03:48 -06:00
2018-08-13 11:24:39 -06:00
let req = format! (
2018-08-15 12:41:39 -06:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["{}"]}}"# ,
2020-06-16 23:30:59 -06:00
mint_pubkey
2018-08-13 11:24:39 -06:00
) ;
2018-10-15 11:01:40 -06:00
let res = io . handle_request_sync ( & req , meta ) ;
2019-11-12 14:49:41 -05:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
" value " :20 ,
} ,
" id " : 1 ,
} ) ;
let result = serde_json ::from_str ::< Value > ( & res . expect ( " actual response " ) )
2018-08-13 11:24:39 -06:00
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
2018-10-15 11:01:40 -06:00
}
2020-06-11 16:51:25 -06:00
#[ test ]
fn test_rpc_get_balance_via_client ( ) {
2020-06-16 23:30:59 -06:00
let genesis = create_genesis_config ( 20 ) ;
let mint_pubkey = genesis . mint_keypair . pubkey ( ) ;
let bank = Arc ::new ( Bank ::new ( & genesis . genesis_config ) ) ;
let meta = JsonRpcRequestProcessor ::new_from_bank ( & bank ) ;
let mut io = MetaIoHandler ::default ( ) ;
2021-02-26 21:42:09 -08:00
io . extend_with ( rpc_minimal ::MinimalImpl . to_delegate ( ) ) ;
2020-06-16 23:30:59 -06: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 16:51:25 -06:00
client
2020-06-16 23:30:59 -06:00
. get_balance ( mint_pubkey . to_string ( ) , None )
2021-02-02 19:53:08 -07: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 19:53:08 -07:00
let client = use_client ( client , mint_pubkey ) ;
futures ::join! ( client , server )
2020-06-11 16:51:25 -06:00
} ;
2021-02-02 19:53:08 -07:00
let ( response , _ ) = futures ::executor ::block_on ( fut ) ;
assert_eq! ( response , 20 ) ;
2020-06-11 16:51:25 -06:00
}
2019-04-23 14:46:41 -07:00
#[ test ]
fn test_rpc_get_cluster_nodes ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler {
io ,
meta ,
leader_pubkey ,
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2019-04-23 14:46:41 -07:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getClusterNodes"}"# ;
2019-04-23 14:46:41 -07:00
let res = io . handle_request_sync ( & req , meta ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let expected = format! (
2020-09-21 19:54:43 -07:00
r # "{{"jsonrpc":"2.0","result":[{{"pubkey": "{}", "gossip": "127.0.0.1:1235", "tpu": "127.0.0.1:1234", "rpc": "127.0.0.1:{}", "version": null, "featureSet": null}}],"id":1}}"# ,
2019-05-23 23:20:04 -07:00
leader_pubkey ,
2020-01-30 11:13:29 -07:00
rpc_port ::DEFAULT_RPC_PORT
2019-04-23 14:46:41 -07:00
) ;
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
2020-09-22 12:26:32 -07:00
#[ test ]
fn test_rpc_get_recent_performance_samples ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-09-22 12:26:32 -07:00
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getRecentPerformanceSamples"}"# ;
let res = io . handle_request_sync ( & req , meta ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" id " : 1 ,
" result " : [
2020-09-24 14:22:22 -07:00
{
" slot " : 0 ,
" numSlots " : 1 ,
" numTransactions " : 4 ,
" samplePeriodSecs " : 60
}
2020-09-22 12:26:32 -07:00
] ,
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
#[ test ]
fn test_rpc_get_recent_performance_samples_invalid_limit ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-09-22 12:26:32 -07:00
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getRecentPerformanceSamples","params":[10000]}"# ;
let res = io . handle_request_sync ( & req , meta ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" error " : {
" code " : - 32602 ,
" message " : " Invalid limit; max 720 "
} ,
" id " : 1
} ) ;
let expected : Response =
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
2019-04-23 14:46:41 -07:00
#[ test ]
fn test_rpc_get_slot_leader ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler {
io ,
meta ,
leader_pubkey ,
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2019-04-23 14:46:41 -07:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getSlotLeader"}"# ;
2019-04-23 14:46:41 -07:00
let res = io . handle_request_sync ( & req , meta ) ;
2019-07-09 22:06:47 -07:00
let expected = format! ( r # "{{"jsonrpc":"2.0","result":"{}","id":1}}"# , leader_pubkey ) ;
2019-04-23 14:46:41 -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 " ) ;
assert_eq! ( expected , result ) ;
}
2018-10-15 11:01:40 -06: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 23:30:59 -06:00
let genesis = create_genesis_config ( 10 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis . genesis_config ) ) ;
// 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 ( ) ;
let meta = JsonRpcRequestProcessor ::new_from_bank ( & bank ) ;
let mut io = MetaIoHandler ::default ( ) ;
2021-02-26 21:42:09 -08:00
io . extend_with ( rpc_minimal ::MinimalImpl . to_delegate ( ) ) ;
2018-08-13 11:24:39 -06:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}"# ;
2018-10-15 11:01:40 -06:00
let res = io . handle_request_sync ( & req , meta ) ;
2020-05-15 17:35:43 +01:00
let expected = r # "{"jsonrpc":"2.0","result":4,"id":1}"# ;
2018-08-14 18:03:48 -06:00
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
2020-01-21 13:05:04 -07:00
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
#[ test ]
fn test_rpc_minimum_ledger_slot ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-01-21 13:05:04 -07:00
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"minimumLedgerSlot"}"# ;
2020-01-21 13:05:04 -07:00
let res = io . handle_request_sync ( & req , meta ) ;
let expected = r # "{"jsonrpc":"2.0","result":0,"id":1}"# ;
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
2018-08-13 11:24:39 -06:00
. expect ( " actual response deserialization " ) ;
2018-08-14 18:03:48 -06:00
assert_eq! ( expected , result ) ;
2018-10-15 11:01:40 -06:00
}
2019-06-21 22:00:26 -06:00
#[ test ]
fn test_rpc_get_total_supply ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2019-06-21 22:00:26 -06:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getTotalSupply"}"# ;
2019-06-21 22:00:26 -06:00
let rep = io . handle_request_sync ( & req , meta ) ;
let res : Response = serde_json ::from_str ( & rep . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let supply : u64 = if let Response ::Single ( res ) = res {
if let Output ::Success ( res ) = res {
if let Value ::Number ( num ) = res . result {
num . as_u64 ( ) . unwrap ( )
} else {
panic! ( " Expected number " ) ;
}
} else {
panic! ( " Expected success " ) ;
}
} else {
panic! ( " Expected single response " ) ;
} ;
assert! ( supply > = TEST_MINT_LAMPORTS ) ;
}
2020-05-12 21:05:05 -06:00
#[ test ]
fn test_get_supply ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-05-12 21:05:05 -06:00
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getSupply"}"# ;
let res = io . handle_request_sync ( & req , meta ) ;
2020-05-12 21:05:05 -06:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let supply : RpcSupply = serde_json ::from_value ( json [ " result " ] [ " value " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( supply . non_circulating , 20 ) ;
assert! ( supply . circulating > = TEST_MINT_LAMPORTS ) ;
assert! ( supply . total > = TEST_MINT_LAMPORTS + 20 ) ;
let expected_accounts : Vec < String > = non_circulating_accounts ( )
. iter ( )
. map ( | pubkey | pubkey . to_string ( ) )
. collect ( ) ;
assert_eq! (
supply . non_circulating_accounts . len ( ) ,
expected_accounts . len ( )
) ;
for address in supply . non_circulating_accounts {
assert! ( expected_accounts . contains ( & address ) ) ;
}
}
2020-05-04 17:46:10 -06:00
#[ test ]
fn test_get_largest_accounts ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-05-04 17:46:10 -06:00
let RpcHandler {
io , meta , alice , ..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getLargestAccounts"}"# ;
2020-05-04 17:46:10 -06:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let largest_accounts : Vec < RpcAccountBalance > =
serde_json ::from_value ( json [ " result " ] [ " value " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
2020-08-31 21:51:52 -07:00
assert_eq! ( largest_accounts . len ( ) , 20 ) ;
2020-05-04 17:46:10 -06:00
// Get Alice balance
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["{}"]}}"# ,
alice . pubkey ( )
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let alice_balance : u64 = serde_json ::from_value ( json [ " result " ] [ " value " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert! ( largest_accounts . contains ( & RpcAccountBalance {
address : alice . pubkey ( ) . to_string ( ) ,
lamports : alice_balance ,
} ) ) ;
// Get Bob balance
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["{}"]}}"# ,
bob_pubkey
) ;
2020-05-12 21:05:05 -06:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2020-05-04 17:46:10 -06:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let bob_balance : u64 = serde_json ::from_value ( json [ " result " ] [ " value " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert! ( largest_accounts . contains ( & RpcAccountBalance {
address : bob_pubkey . to_string ( ) ,
lamports : bob_balance ,
} ) ) ;
2020-05-12 21:05:05 -06:00
// Test Circulating/NonCirculating Filter
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getLargestAccounts","params":[{"filter":"circulating"}]}"# ;
2020-05-12 21:05:05 -06:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let largest_accounts : Vec < RpcAccountBalance > =
serde_json ::from_value ( json [ " result " ] [ " value " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
2020-09-15 18:23:21 -07:00
assert_eq! ( largest_accounts . len ( ) , 20 ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getLargestAccounts","params":[{"filter":"nonCirculating"}]}"# ;
let res = io . handle_request_sync ( & req , meta ) ;
2020-05-12 21:05:05 -06:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let largest_accounts : Vec < RpcAccountBalance > =
serde_json ::from_value ( json [ " result " ] [ " value " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( largest_accounts . len ( ) , 1 ) ;
2020-05-04 17:46:10 -06:00
}
2019-09-26 23:27:13 +05:30
#[ test ]
fn test_rpc_get_minimum_balance_for_rent_exemption ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-09-26 23:27:13 +05:30
let data_len = 50 ;
2019-10-14 16:24:10 -06:00
let RpcHandler { io , meta , bank , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2019-09-26 23:27:13 +05:30
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getMinimumBalanceForRentExemption","params":[{}]}}"# ,
data_len
) ;
let rep = io . handle_request_sync ( & req , meta ) ;
let res : Response = serde_json ::from_str ( & rep . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let minimum_balance : u64 = if let Response ::Single ( res ) = res {
if let Output ::Success ( res ) = res {
if let Value ::Number ( num ) = res . result {
num . as_u64 ( ) . unwrap ( )
} else {
panic! ( " Expected number " ) ;
}
} else {
panic! ( " Expected success " ) ;
}
} else {
panic! ( " Expected single response " ) ;
} ;
assert_eq! (
minimum_balance ,
bank . get_minimum_balance_for_rent_exemption ( data_len )
) ;
}
2019-08-27 18:17:03 -04:00
#[ test ]
fn test_rpc_get_inflation ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler { io , meta , bank , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2019-08-27 18:17:03 -04:00
2020-05-29 12:50:25 -06:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getInflationGovernor"}"# ;
let rep = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let res : Response = serde_json ::from_str ( & rep . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let inflation_governor : RpcInflationGovernor = if let Response ::Single ( res ) = res {
if let Output ::Success ( res ) = res {
serde_json ::from_value ( res . result ) . unwrap ( )
} else {
panic! ( " Expected success " ) ;
}
} else {
panic! ( " Expected single response " ) ;
} ;
let expected_inflation_governor : RpcInflationGovernor = bank . inflation ( ) . into ( ) ;
assert_eq! ( inflation_governor , expected_inflation_governor ) ;
2020-07-01 15:43:25 -07:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getInflationRate"}"# ; // Queries current epoch
let rep = io . handle_request_sync ( & req , meta ) ;
2020-05-29 12:50:25 -06:00
let res : Response = serde_json ::from_str ( & rep . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let inflation_rate : RpcInflationRate = if let Response ::Single ( res ) = res {
if let Output ::Success ( res ) = res {
serde_json ::from_value ( res . result ) . unwrap ( )
} else {
panic! ( " Expected success " ) ;
}
} else {
panic! ( " Expected single response " ) ;
} ;
2020-07-01 15:43:25 -07:00
let inflation = bank . inflation ( ) ;
let epoch = bank . epoch ( ) ;
2020-12-11 16:42:39 +09:00
let slot_in_year = bank . slot_in_year_for_inflation ( ) ;
2020-05-29 12:50:25 -06:00
let expected_inflation_rate = RpcInflationRate {
2020-12-11 16:42:39 +09:00
total : inflation . total ( slot_in_year ) ,
validator : inflation . validator ( slot_in_year ) ,
foundation : inflation . foundation ( slot_in_year ) ,
2020-05-29 12:50:25 -06:00
epoch ,
} ;
assert_eq! ( inflation_rate , expected_inflation_rate ) ;
2019-08-27 18:17:03 -04:00
}
2019-10-22 16:41:18 -04:00
#[ test ]
fn test_rpc_get_epoch_schedule ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-22 16:41:18 -04:00
let RpcHandler { io , meta , bank , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getEpochSchedule"}"# ;
2019-10-22 16:41:18 -04:00
let rep = io . handle_request_sync ( & req , meta ) ;
let res : Response = serde_json ::from_str ( & rep . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let epoch_schedule : EpochSchedule = if let Response ::Single ( res ) = res {
if let Output ::Success ( res ) = res {
serde_json ::from_value ( res . result ) . unwrap ( )
} else {
panic! ( " Expected success " ) ;
}
} else {
panic! ( " Expected single response " ) ;
} ;
assert_eq! ( epoch_schedule , * bank . epoch_schedule ( ) ) ;
}
2019-12-17 16:26:31 -07:00
#[ test ]
fn test_rpc_get_leader_schedule ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-12-17 16:26:31 -07:00
let RpcHandler { io , meta , bank , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
for req in [
r # "{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [0]}"# ,
r # "{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule"}"# ,
]
. iter ( )
{
let rep = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let res : Response = serde_json ::from_str ( & rep . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2019-12-18 12:42:58 -07:00
let schedule : Option < RpcLeaderSchedule > = if let Response ::Single ( res ) = res {
2019-12-17 16:26:31 -07:00
if let Output ::Success ( res ) = res {
serde_json ::from_value ( res . result ) . unwrap ( )
} else {
panic! ( " Expected success for {} " , req ) ;
}
} else {
panic! ( " Expected single response " ) ;
} ;
2019-12-18 12:42:58 -07:00
let schedule = schedule . expect ( " leader schedule " ) ;
let bob_schedule = schedule
. get ( & bank . collector_id ( ) . to_string ( ) )
. expect ( " leader not in the leader schedule " ) ;
2019-12-17 16:26:31 -07:00
assert_eq! (
2019-12-18 12:42:58 -07:00
bob_schedule . len ( ) ,
2019-12-17 16:26:31 -07:00
solana_ledger ::leader_schedule_utils ::leader_schedule ( bank . epoch ( ) , & bank )
. unwrap ( )
. get_slot_leaders ( )
. len ( )
) ;
}
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [42424242]}"# ;
let rep = io . handle_request_sync ( & req , meta ) ;
let res : Response = serde_json ::from_str ( & rep . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2019-12-18 12:42:58 -07:00
let schedule : Option < RpcLeaderSchedule > = if let Response ::Single ( res ) = res {
2019-12-17 16:26:31 -07:00
if let Output ::Success ( res ) = res {
serde_json ::from_value ( res . result ) . unwrap ( )
} else {
panic! ( " Expected success " ) ;
}
} else {
panic! ( " Expected single response " ) ;
} ;
assert_eq! ( schedule , None ) ;
}
2018-10-15 11:01:40 -06:00
#[ test ]
fn test_rpc_get_account_info ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-08-10 16:35:29 -06:00
let RpcHandler { io , meta , bank , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2018-09-20 13:20:37 -07:00
let req = format! (
2018-09-20 14:51:17 -07:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}"]}}"# ,
2018-09-20 13:20:37 -07:00
bob_pubkey
) ;
2020-08-10 16:35:29 -06:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2019-11-12 14:49:41 -05:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
" value " :{
2020-08-15 17:56:09 -07:00
" owner " : " 11111111111111111111111111111111 " ,
" lamports " : 20 ,
" data " : " " ,
" executable " : false ,
" rentEpoch " : 0
2019-11-12 14:49:41 -05:00
} ,
2020-08-15 17:56:09 -07:00
} ,
2019-11-12 14:49:41 -05:00
" id " : 1 ,
} ) ;
2018-09-20 13:20:37 -07:00
let expected : Response =
2019-11-12 14:49:41 -05:00
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
2018-10-15 11:01:40 -06:00
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
2020-08-10 16:35:29 -06:00
2020-10-19 12:12:08 -07:00
let address = solana_sdk ::pubkey ::new_rand ( ) ;
2020-08-10 16:35:29 -06:00
let data = vec! [ 1 , 2 , 3 , 4 , 5 ] ;
2021-03-09 15:06:07 -06:00
let mut account = AccountSharedData ::new ( 42 , 5 , & Pubkey ::default ( ) ) ;
2020-08-10 16:35:29 -06:00
account . data = data . clone ( ) ;
bank . store_account ( & address , & account ) ;
let req = format! (
2020-08-15 22:06:39 -07:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"base64"}}]}}"# ,
2020-08-10 16:35:29 -06:00
address
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2020-08-15 17:56:09 -07:00
assert_eq! (
result [ " result " ] [ " value " ] [ " data " ] ,
2020-08-15 22:06:39 -07:00
json! ( [ base64 ::encode ( & data ) , " base64 " ] ) ,
2020-08-15 17:56:09 -07:00
) ;
2020-08-10 16:35:29 -06:00
let req = format! (
2020-08-15 22:06:39 -07:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"base64", "dataSlice": {{"length": 2, "offset": 1}}}}]}}"# ,
2020-08-10 16:35:29 -06:00
address
) ;
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_eq! (
result [ " result " ] [ " value " ] [ " data " ] ,
2020-08-15 22:06:39 -07:00
json! ( [ base64 ::encode ( & data [ 1 .. 3 ] ) , " base64 " ] ) ,
2020-08-10 16:35:29 -06:00
) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"binary", "dataSlice": {{"length": 2, "offset": 1}}}}]}}"# ,
address
) ;
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_eq! (
result [ " result " ] [ " value " ] [ " data " ] ,
bs58 ::encode ( & data [ 1 .. 3 ] ) . into_string ( ) ,
) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding":"jsonParsed", "dataSlice": {{"length": 2, "offset": 1}}}}]}}"# ,
address
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
result [ " error " ] . as_object ( ) . unwrap ( ) ;
2018-10-15 11:01:40 -06:00
}
2018-09-20 13:20:37 -07:00
2020-09-03 11:35:06 -06:00
#[ test ]
fn test_rpc_get_multiple_accounts ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-09-03 11:35:06 -06:00
let RpcHandler { io , meta , bank , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
let address = Pubkey ::new ( & [ 9 ; 32 ] ) ;
let data = vec! [ 1 , 2 , 3 , 4 , 5 ] ;
2021-03-09 15:06:07 -06:00
let mut account = AccountSharedData ::new ( 42 , 5 , & Pubkey ::default ( ) ) ;
2020-09-03 11:35:06 -06:00
account . data = data . clone ( ) ;
bank . store_account ( & address , & account ) ;
let non_existent_address = Pubkey ::new ( & [ 8 ; 32 ] ) ;
// Test 3 accounts, one non-existent, and one with data
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getMultipleAccounts","params":[["{}", "{}", "{}"]]}}"# ,
bob_pubkey , non_existent_address , address ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
" value " :[ {
" owner " : " 11111111111111111111111111111111 " ,
" lamports " : 20 ,
" data " : [ " " , " base64 " ] ,
" executable " : false ,
" rentEpoch " : 0
} ,
null ,
{
" owner " : " 11111111111111111111111111111111 " ,
" lamports " : 42 ,
" data " : [ base64 ::encode ( & data ) , " base64 " ] ,
" executable " : false ,
" rentEpoch " : 0
} ] ,
} ,
" 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 " ) ;
assert_eq! ( expected , result ) ;
// Test config settings still work with multiple accounts
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " , " id " :1 , " method " :" getMultipleAccounts " , " params " :[
[ " {} " , " {} " , " {} " ] ,
{ { " encoding " :" base58 " } }
]
} } " #,
bob_pubkey , non_existent_address , address ,
) ;
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_eq! ( result [ " result " ] [ " value " ] . as_array ( ) . unwrap ( ) . len ( ) , 3 ) ;
assert_eq! (
result [ " result " ] [ " value " ] [ 2 ] [ " data " ] ,
json! ( [ bs58 ::encode ( & data ) . into_string ( ) , " base58 " ] ) ,
) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " , " id " :1 , " method " :" getMultipleAccounts " , " params " :[
[ " {} " , " {} " , " {} " ] ,
{ { " encoding " :" base64 " , " dataSlice " : { { " length " : 2 , " offset " : 1 } } } }
]
} } " #,
bob_pubkey , non_existent_address , address ,
) ;
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_eq! ( result [ " result " ] [ " value " ] . as_array ( ) . unwrap ( ) . len ( ) , 3 ) ;
assert_eq! (
result [ " result " ] [ " value " ] [ 2 ] [ " data " ] ,
json! ( [ base64 ::encode ( & data [ 1 .. 3 ] ) , " base64 " ] ) ,
) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " , " id " :1 , " method " :" getMultipleAccounts " , " params " :[
[ " {} " , " {} " , " {} " ] ,
{ { " encoding " :" binary " , " dataSlice " : { { " length " : 2 , " offset " : 1 } } } }
]
} } " #,
bob_pubkey , non_existent_address , address ,
) ;
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_eq! ( result [ " result " ] [ " value " ] . as_array ( ) . unwrap ( ) . len ( ) , 3 ) ;
assert_eq! (
result [ " result " ] [ " value " ] [ 2 ] [ " data " ] ,
bs58 ::encode ( & data [ 1 .. 3 ] ) . into_string ( ) ,
) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " , " id " :1 , " method " :" getMultipleAccounts " , " params " :[
[ " {} " , " {} " , " {} " ] ,
{ { " encoding " :" jsonParsed " , " dataSlice " : { { " length " : 2 , " offset " : 1 } } } }
]
} } " #,
bob_pubkey , non_existent_address , address ,
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
result [ " error " ] . as_object ( ) . unwrap ( ) ;
}
2019-06-29 10:59:07 -06:00
#[ test ]
fn test_rpc_get_program_accounts ( ) {
let bob = Keypair ::new ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler {
io ,
meta ,
bank ,
blockhash ,
2020-07-03 01:46:29 -06:00
alice ,
2019-10-14 16:24:10 -06:00
..
} = start_rpc_handler_with_tx ( & bob . pubkey ( ) ) ;
2019-06-29 10:59:07 -06:00
2020-10-19 12:12:08 -07:00
let new_program_id = solana_sdk ::pubkey ::new_rand ( ) ;
2019-06-29 10:59:07 -06:00
let tx = system_transaction ::assign ( & bob , blockhash , & new_program_id ) ;
bank . process_transaction ( & tx ) . unwrap ( ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getProgramAccounts","params":["{}"]}}"# ,
new_program_id
) ;
2020-07-03 01:46:29 -06:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2019-06-29 10:59:07 -06:00
let expected = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
2020-01-15 00:25:45 -07:00
" result " :[
{ {
" pubkey " : " {} " ,
" account " : { {
2020-01-15 15:33:53 -07:00
" owner " : " {} " ,
2020-01-15 00:25:45 -07:00
" lamports " : 20 ,
2020-01-15 15:33:53 -07:00
" data " : " " ,
2020-01-15 00:25:45 -07:00
" executable " : false ,
" rentEpoch " : 0
} }
} }
] ,
2019-06-29 10:59:07 -06:00
" id " :1 } }
" #,
bob . pubkey ( ) ,
2020-01-15 15:33:53 -07:00
new_program_id
2019-06-29 10:59:07 -06: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 " ) ;
assert_eq! ( expected , result ) ;
2020-07-03 01:46:29 -06:00
// Set up nonce accounts to test filters
let nonce_keypair0 = Keypair ::new ( ) ;
let instruction = system_instruction ::create_nonce_account (
& alice . pubkey ( ) ,
& nonce_keypair0 . pubkey ( ) ,
& bob . pubkey ( ) ,
100_000 ,
) ;
let message = Message ::new ( & instruction , Some ( & alice . pubkey ( ) ) ) ;
let tx = Transaction ::new ( & [ & alice , & nonce_keypair0 ] , message , blockhash ) ;
bank . process_transaction ( & tx ) . unwrap ( ) ;
let nonce_keypair1 = Keypair ::new ( ) ;
2020-10-19 12:12:08 -07:00
let authority = solana_sdk ::pubkey ::new_rand ( ) ;
2020-07-03 01:46:29 -06:00
let instruction = system_instruction ::create_nonce_account (
& alice . pubkey ( ) ,
& nonce_keypair1 . pubkey ( ) ,
& authority ,
100_000 ,
) ;
let message = Message ::new ( & instruction , Some ( & alice . pubkey ( ) ) ) ;
let tx = Transaction ::new ( & [ & alice , & nonce_keypair1 ] , message , blockhash ) ;
bank . process_transaction ( & tx ) . unwrap ( ) ;
// Test memcmp filter; filter on Initialized state
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getProgramAccounts " ,
" params " :[ " {} " , { { " filters " : [
{ {
" memcmp " : { { " offset " : 4 , " bytes " : " {} " } }
} }
] } } ]
} } " #,
system_program ::id ( ) ,
bs58 ::encode ( vec! [ 1 ] ) . into_string ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let accounts : Vec < RpcKeyedAccount > = serde_json ::from_value ( json [ " result " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( accounts . len ( ) , 2 ) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getProgramAccounts " ,
" params " :[ " {} " , { { " filters " : [
{ {
" memcmp " : { { " offset " : 0 , " bytes " : " {} " } }
} }
] } } ]
} } " #,
system_program ::id ( ) ,
bs58 ::encode ( vec! [ 1 ] ) . into_string ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let accounts : Vec < RpcKeyedAccount > = serde_json ::from_value ( json [ " result " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( accounts . len ( ) , 0 ) ;
// Test dataSize filter
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getProgramAccounts " ,
" params " :[ " {} " , { { " filters " : [
{ {
" dataSize " : { }
} }
] } } ]
} } " #,
system_program ::id ( ) ,
nonce ::State ::size ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let accounts : Vec < RpcKeyedAccount > = serde_json ::from_value ( json [ " result " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( accounts . len ( ) , 2 ) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getProgramAccounts " ,
" params " :[ " {} " , { { " filters " : [
{ {
" dataSize " : 1
} }
] } } ]
} } " #,
system_program ::id ( ) ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let accounts : Vec < RpcKeyedAccount > = serde_json ::from_value ( json [ " result " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( accounts . len ( ) , 0 ) ;
// Test multiple filters
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getProgramAccounts " ,
" params " :[ " {} " , { { " filters " : [
{ {
" memcmp " : { { " offset " : 4 , " bytes " : " {} " } }
} } ,
{ {
" memcmp " : { { " offset " : 8 , " bytes " : " {} " } }
} }
] } } ]
} } " #,
system_program ::id ( ) ,
bs58 ::encode ( vec! [ 1 ] ) . into_string ( ) ,
authority ,
) ; // Filter on Initialized and Nonce authority
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let accounts : Vec < RpcKeyedAccount > = serde_json ::from_value ( json [ " result " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( accounts . len ( ) , 1 ) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getProgramAccounts " ,
" params " :[ " {} " , { { " filters " : [
{ {
" memcmp " : { { " offset " : 4 , " bytes " : " {} " } }
} } ,
{ {
" dataSize " : 1
} }
] } } ]
} } " #,
system_program ::id ( ) ,
bs58 ::encode ( vec! [ 1 ] ) . into_string ( ) ,
) ; // Filter on Initialized and non-matching data size
let res = io . handle_request_sync ( & req , meta ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let accounts : Vec < RpcKeyedAccount > = serde_json ::from_value ( json [ " result " ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( accounts . len ( ) , 0 ) ;
2019-06-29 10:59:07 -06:00
}
2020-05-19 12:08:19 -07:00
#[ test ]
fn test_rpc_simulate_transaction ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-05-19 12:08:19 -07:00
let RpcHandler {
io ,
meta ,
blockhash ,
alice ,
bank ,
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
let mut tx = system_transaction ::transfer ( & alice , & bob_pubkey , 1234 , blockhash ) ;
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 ( ) ;
bank . freeze ( ) ; // Ensure the root bank is frozen, `start_rpc_handler_with_tx()` doesn't do this
// Good signature with sigVerify=true
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}", {{"sigVerify": true}}]}}"# ,
tx_serialized_encoded ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
2020-11-12 12:44:37 -08:00
" value " :{ " err " :null , " logs " :[
" Program 11111111111111111111111111111111 invoke [1] " ,
" Program 11111111111111111111111111111111 success "
] }
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 " ) ;
assert_eq! ( expected , result ) ;
// Bad signature with sigVerify=true
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}", {{"sigVerify": true}}]}}"# ,
tx_badsig_serialized_encoded ,
) ;
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 " ) ;
assert_eq! ( expected , result ) ;
// Bad signature with sigVerify=false
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}", {{"sigVerify": false}}]}}"# ,
tx_serialized_encoded ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
2020-11-12 12:44:37 -08:00
" value " :{ " err " :null , " logs " :[
" Program 11111111111111111111111111111111 invoke [1] " ,
" Program 11111111111111111111111111111111 success "
] }
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 " ) ;
assert_eq! ( expected , result ) ;
// Bad signature with default sigVerify setting (false)
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}"]}}"# ,
tx_serialized_encoded ,
) ;
2020-05-29 08:26:06 +01:00
let res = io . handle_request_sync ( & req , meta ) ;
2020-05-19 12:08:19 -07:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
2020-11-12 12:44:37 -08:00
" value " :{ " err " :null , " logs " :[
" Program 11111111111111111111111111111111 invoke [1] " ,
" Program 11111111111111111111111111111111 success "
] }
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 " ) ;
assert_eq! ( expected , result ) ;
}
#[ test ]
#[ should_panic ]
fn test_rpc_simulate_transaction_panic_on_unfrozen_bank ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-05-19 12:08:19 -07:00
let RpcHandler {
io ,
meta ,
blockhash ,
alice ,
bank ,
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
let tx = system_transaction ::transfer ( & alice , & bob_pubkey , 1234 , blockhash ) ;
let tx_serialized_encoded = bs58 ::encode ( serialize ( & tx ) . unwrap ( ) ) . into_string ( ) ;
assert! ( ! bank . is_frozen ( ) ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"simulateTransaction","params":["{}", {{"sigVerify": true}}]}}"# ,
tx_serialized_encoded ,
) ;
// should panic because `bank` is not frozen
2020-05-29 08:26:06 +01:00
let _ = io . handle_request_sync ( & req , meta ) ;
2020-05-19 12:08:19 -07:00
}
2018-10-15 11:01:40 -06:00
#[ test ]
fn test_rpc_confirm_tx ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler {
io ,
meta ,
blockhash ,
alice ,
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2019-05-20 10:03:19 -07:00
let tx = system_transaction ::transfer ( & alice , & bob_pubkey , 20 , blockhash ) ;
2018-10-15 11:01:40 -06:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"confirmTransaction","params":["{}"]}}"# ,
2018-10-26 14:43:34 -07:00
tx . signatures [ 0 ]
2018-10-15 11:01:40 -06:00
) ;
let res = io . handle_request_sync ( & req , meta ) ;
2019-11-12 14:49:41 -05:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
" value " :true ,
} ,
" id " : 1 ,
} ) ;
2018-10-15 11:01:40 -06:00
let expected : Response =
2019-11-12 14:49:41 -05:00
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
2018-09-20 13:20:37 -07:00
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
2018-08-13 11:24:39 -06:00
}
2018-10-15 11:01:40 -06:00
2018-08-13 11:24:39 -06:00
#[ test ]
2018-10-15 11:01:40 -06:00
fn test_rpc_get_signature_status ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-04-02 02:30:58 +08:00
let RpcHandler {
io ,
meta ,
blockhash ,
alice ,
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
let tx = system_transaction ::transfer ( & alice , & bob_pubkey , 20 , blockhash ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"# ,
tx . signatures [ 0 ]
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected_res : Option < transaction ::Result < ( ) > > = Some ( Ok ( ( ) ) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : expected_res ,
" 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 " ) ;
assert_eq! ( expected , result ) ;
// Test getSignatureStatus request on unprocessed tx
let tx = system_transaction ::transfer ( & alice , & bob_pubkey , 10 , blockhash ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"# ,
tx . signatures [ 0 ]
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected_res : Option < String > = None ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : expected_res ,
" 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 " ) ;
assert_eq! ( expected , result ) ;
// Test getSignatureStatus request on a TransactionError
let tx = system_transaction ::transfer ( & alice , & bob_pubkey , std ::u64 ::MAX , blockhash ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"# ,
tx . signatures [ 0 ]
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let expected_res : Option < transaction ::Result < ( ) > > = Some ( Err (
TransactionError ::InstructionError ( 0 , InstructionError ::Custom ( 1 ) ) ,
) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : expected_res ,
" 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 " ) ;
assert_eq! ( expected , result ) ;
}
#[ test ]
fn test_rpc_get_signature_statuses ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler {
io ,
meta ,
blockhash ,
alice ,
2020-03-23 11:25:39 -06:00
confirmed_block_signatures ,
2019-10-14 16:24:10 -06:00
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2018-08-15 10:37:02 -06:00
2018-10-15 11:01:40 -06:00
let req = format! (
2020-04-02 02:30:58 +08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"# ,
2020-03-23 11:25:39 -06:00
confirmed_block_signatures [ 0 ]
2018-10-15 11:01:40 -06:00
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2020-03-23 11:25:39 -06:00
let expected_res : transaction ::Result < ( ) > = Ok ( ( ) ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
2020-03-26 19:21:01 -06:00
let result : Option < TransactionStatus > =
serde_json ::from_value ( json [ " result " ] [ " value " ] [ 0 ] . clone ( ) )
. expect ( " actual response deserialization " ) ;
2020-03-30 17:53:25 -06:00
let result = result . as_ref ( ) . unwrap ( ) ;
assert_eq! ( expected_res , result . status ) ;
2020-04-22 12:22:09 -06:00
assert_eq! ( None , result . confirmations ) ;
2018-08-13 11:24:39 -06:00
2018-10-15 11:01:40 -06:00
// Test getSignatureStatus request on unprocessed tx
2019-05-20 10:03:19 -07:00
let tx = system_transaction ::transfer ( & alice , & bob_pubkey , 10 , blockhash ) ;
2018-10-15 11:01:40 -06:00
let req = format! (
2020-04-02 02:30:58 +08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"# ,
2018-10-26 14:43:34 -07:00
tx . signatures [ 0 ]
2018-10-15 11:01:40 -06:00
) ;
2019-04-05 19:07:30 -06:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2020-03-23 11:25:39 -06:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
2020-03-26 19:21:01 -06: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 19:07:30 -06:00
// Test getSignatureStatus request on a TransactionError
let req = format! (
2020-04-02 02:30:58 +08:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatuses","params":[["{}"]]}}"# ,
2020-03-23 11:25:39 -06:00
confirmed_block_signatures [ 1 ]
2019-04-05 19:07:30 -06:00
) ;
2020-05-15 17:35:43 +01:00
let res = io . handle_request_sync ( & req , meta ) ;
2020-03-23 11:25:39 -06:00
let expected_res : transaction ::Result < ( ) > = Err ( TransactionError ::InstructionError (
0 ,
2020-04-01 09:01:11 -07:00
InstructionError ::Custom ( 1 ) ,
2019-04-05 19:07:30 -06:00
) ) ;
2020-03-23 11:25:39 -06:00
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
2020-03-26 19:21:01 -06: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 ) ;
2018-10-15 11:01:40 -06:00
}
#[ test ]
2019-03-02 10:25:16 -08:00
fn test_rpc_get_recent_blockhash ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler {
io ,
meta ,
blockhash ,
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2018-10-15 11:01:40 -06:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getRecentBlockhash"}"# ;
2018-10-15 11:01:40 -06: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 14:49:41 -05:00
" result " : {
" context " :{ " slot " :0 } ,
2020-01-15 00:25:45 -07:00
" value " :{
" blockhash " : blockhash . to_string ( ) ,
" feeCalculator " : {
" lamportsPerSignature " : 0 ,
2020-02-28 13:27:01 -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 " ) ;
2020-05-26 13:06:21 -06:00
assert_eq! ( expected , result ) ;
}
#[ test ]
fn test_rpc_get_fees ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-05-26 13:06:21 -06:00
let RpcHandler {
io ,
meta ,
blockhash ,
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getFees"}"# ;
let res = io . handle_request_sync ( & req , meta ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
" value " :{
" blockhash " : blockhash . to_string ( ) ,
" feeCalculator " : {
" lamportsPerSignature " : 0 ,
} ,
" lastValidSlot " : MAX_RECENT_BLOCKHASHES ,
} } ,
" 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 " ) ;
2020-02-28 13:27:01 -07:00
assert_eq! ( expected , result ) ;
}
2020-03-06 17:01:31 -07:00
#[ test ]
fn test_rpc_get_fee_calculator_for_blockhash ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-03-06 17:01:31 -07:00
let RpcHandler { io , meta , bank , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
let ( blockhash , fee_calculator ) = bank . last_blockhash_with_fee_calculator ( ) ;
let fee_calculator = RpcFeeCalculator { fee_calculator } ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getFeeCalculatorForBlockhash","params":["{:?}"]}}"# ,
blockhash
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
" 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 " ) ;
assert_eq! ( expected , result ) ;
// Expired (non-existent) blockhash
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getFeeCalculatorForBlockhash","params":["{:?}"]}}"# ,
Hash ::default ( )
) ;
2020-05-15 17:35:43 +01:00
let res = io . handle_request_sync ( & req , meta ) ;
2020-03-06 17:01:31 -07:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
" 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 " ) ;
assert_eq! ( expected , result ) ;
}
2020-02-28 13:27:01 -07:00
#[ test ]
fn test_rpc_get_fee_rate_governor ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-02-28 13:27:01 -07:00
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getFeeRateGovernor"}"# ;
2020-02-28 13:27:01 -07:00
let res = io . handle_request_sync ( & req , meta ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" context " :{ " slot " :0 } ,
" value " :{
" feeRateGovernor " : {
" burnPercent " : DEFAULT_BURN_PERCENT ,
2020-01-15 00:25:45 -07:00
" maxLamportsPerSignature " : 0 ,
" minLamportsPerSignature " : 0 ,
" targetLamportsPerSignature " : 0 ,
" targetSignaturesPerSlot " : 0
}
} } ,
2019-06-10 22:18:32 -07:00
" id " : 1
} ) ;
2018-10-15 11:01:40 -06:00
let expected : Response =
2019-06-10 22:18:32 -07:00
serde_json ::from_value ( expected ) . expect ( " expected response deserialization " ) ;
2018-08-13 11:24:39 -06:00
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
2018-10-15 11:01:40 -06:00
2018-08-13 11:24:39 -06:00
#[ test ]
2018-11-01 11:30:56 -06:00
fn test_rpc_fail_request_airdrop ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2018-10-15 11:01:40 -06:00
2019-12-16 14:05:17 -07:00
// Expect internal error because no faucet is available
2018-10-15 11:01:40 -06:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"requestAirdrop","params":["{}", 50]}}"# ,
bob_pubkey
) ;
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 11:01:40 -06: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 " ) ;
assert_eq! ( expected , result ) ;
}
#[ test ]
fn test_rpc_send_bad_tx ( ) {
2020-09-28 20:43:05 -06:00
let genesis = create_genesis_config ( 100 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis . genesis_config ) ) ;
let meta = JsonRpcRequestProcessor ::new_from_bank ( & bank ) ;
2018-08-15 10:37:02 -06:00
2018-08-13 11:24:39 -06: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 11:24:39 -06:00
2020-01-21 22:16:07 -07:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":["37u9WtQpcm6ULa3Vmu7ySnANv"]}"# ;
2020-05-15 17:35:43 +01:00
let res = io . handle_request_sync ( req , meta ) ;
2020-05-21 18:30:02 -06: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 11:24:39 -06:00
}
2018-10-15 11:01:40 -06: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 22:06:58 -06:00
let block_commitment_cache = Arc ::new ( RwLock ::new ( BlockCommitmentCache ::default ( ) ) ) ;
2020-08-04 21:49:37 -06: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 ( ) ) ;
2020-06-05 21:23:13 -07:00
let cluster_info = Arc ::new ( ClusterInfo ::new_with_invalid_keypair (
ContactInfo ::new_with_socketaddr ( & socketaddr! ( " 127.0.0.1:1234 " ) ) ,
) ) ;
2020-07-08 19:13:42 -06:00
let tpu_address = cluster_info . my_contact_info ( ) . tpu ;
2020-07-10 19:14:41 -06:00
let ( meta , receiver ) = JsonRpcRequestProcessor ::new (
2020-06-07 21:54:03 -06: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 21:54:03 -06:00
block_commitment_cache ,
blockstore ,
validator_exit ,
health . clone ( ) ,
2020-07-08 19:13:42 -06:00
cluster_info ,
2020-06-07 21:54:03 -06:00
Hash ::default ( ) ,
2021-02-05 00:21:53 -07:00
Arc ::new ( tokio ::runtime ::Runtime ::new ( ) . unwrap ( ) ) ,
2020-07-23 09:54:57 -07:00
None ,
2020-09-28 20:43:05 -06: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 ( ) ) ,
2020-06-07 21:54:03 -06:00
) ;
2020-12-17 14:37:22 -08:00
SendTransactionService ::new ( tpu_address , & bank_forks , None , receiver , 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 (
2020-09-15 22:30:04 -07:00
r # "{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found","data":{"err":"BlockhashNotFound","logs":[]}},"id":1}"# . to_string ( ) ,
2020-06-01 13:53:37 -07:00
)
) ;
2020-08-04 20:46:25 -06: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 20:03:30 -06:00
let recent_blockhash = bank_forks . read ( ) . unwrap ( ) . root_bank ( ) . last_blockhash ( ) ;
2020-08-04 21:49:37 -06:00
bad_transaction . sign ( & [ & mint_keypair ] , recent_blockhash ) ;
2020-08-04 20:46:25 -06: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-20 18:11:58 -08:00
r # "{"jsonrpc":"2.0","error":{"code":-32602,"message":"invalid transaction: index out of bounds"},"id":1}"# . to_string ( ) ,
2020-08-04 20:46:25 -06: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 20:03:30 -06: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 20:03:30 -06: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 20:03:30 -06:00
2021-01-20 18:11:58 -08:00
// sendTransaction will fail due to sanitization failure
2020-07-29 20:03:30 -06: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 20:03:30 -06:00
bs58 ::encode ( serialize ( & bad_transaction ) . unwrap ( ) ) . into_string ( )
) ;
let res = io . handle_request_sync ( & req , meta ) ;
assert_eq! (
res ,
Some (
2021-01-20 18:11:58 -08:00
r # "{"jsonrpc":"2.0","error":{"code":-32602,"message":"invalid transaction: index out of bounds"},"id":1}"# . to_string ( ) ,
2020-07-29 20:03:30 -06:00
)
) ;
2020-06-01 13:53:37 -07:00
}
2020-07-03 01:46:29 -06:00
#[ test ]
fn test_rpc_verify_filter ( ) {
let filter = RpcFilterType ::Memcmp ( Memcmp {
offset : 0 ,
bytes : MemcmpEncodedBytes ::Binary (
" 13LeFbG6m2EP1fqCj9k66fcXsoTHMMtgr7c78AivUrYD " . to_string ( ) ,
) ,
encoding : None ,
} ) ;
assert_eq! ( verify_filter ( & filter ) , Ok ( ( ) ) ) ;
// Invalid base-58
let filter = RpcFilterType ::Memcmp ( Memcmp {
offset : 0 ,
bytes : MemcmpEncodedBytes ::Binary ( " III " . to_string ( ) ) ,
encoding : None ,
} ) ;
assert! ( verify_filter ( & filter ) . is_err ( ) ) ;
}
2018-10-15 11:01:40 -06:00
#[ test ]
fn test_rpc_verify_pubkey ( ) {
2020-10-19 12:12:08 -07:00
let pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2018-10-15 11:01:40 -06:00
assert_eq! ( verify_pubkey ( pubkey . to_string ( ) ) . unwrap ( ) , pubkey ) ;
let bad_pubkey = " a1b2c3d4 " ;
assert_eq! (
verify_pubkey ( bad_pubkey . to_string ( ) ) ,
2020-07-03 01:46:29 -06:00
Err ( Error ::invalid_params ( " Invalid param: WrongSize " ) )
2018-10-15 11:01:40 -06: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 11:01:40 -06: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 11:01:40 -06:00
) ;
let bad_signature = " a1b2c3d4 " ;
assert_eq! (
2018-10-24 14:06:45 -07:00
verify_signature ( & bad_signature . to_string ( ) ) ,
2020-07-03 01:46:29 -06:00
Err ( Error ::invalid_params ( " Invalid param: WrongSize " ) )
2018-10-15 11:01:40 -06: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 > ) {
2019-11-08 23:56:57 -05: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 ,
2019-11-08 23:56:57 -05:00
} = create_genesis_config ( TEST_MINT_LAMPORTS ) ;
2019-09-26 23:27:13 +05:30
2019-11-08 23:56:57 -05: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 ) ;
2019-09-26 23:27:13 +05:30
2019-11-08 23:56:57 -05:00
let bank = Bank ::new ( & genesis_config ) ;
2019-03-18 14:18:43 -07:00
(
2020-06-12 11:04:17 -06: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 ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-03-04 14:44:21 -08:00
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getIdentity"}"# ;
2020-03-04 14:44:21 -08:00
let res = io . handle_request_sync ( & req , meta ) ;
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
" identity " : bob_pubkey . to_string ( )
} ,
" 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 " ) ;
assert_eq! ( expected , result ) ;
}
2021-02-23 13:06:33 -08:00
fn test_basic_slot ( method : & str , expected : Slot ) {
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
let req = format! ( " {{ \" jsonrpc \" : \" 2.0 \" , \" id \" :1, \" method \" : \" {} \" }} " , method ) ;
let res = io . handle_request_sync ( & req , meta ) ;
let json : Value = serde_json ::from_str ( & res . unwrap ( ) ) . unwrap ( ) ;
let slot : Slot = serde_json ::from_value ( json [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( slot , expected ) ;
}
#[ test ]
fn test_rpc_get_max_slots ( ) {
test_basic_slot ( " getMaxRetransmitSlot " , 42 ) ;
test_basic_slot ( " getMaxShredInsertSlot " , 43 ) ;
}
2019-08-07 20:06:27 -06:00
#[ test ]
fn test_rpc_get_version ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler { io , meta , .. } = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2019-08-07 20:06:27 -06:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getVersion"}"# ;
2019-08-07 20:06:27 -06:00
let res = io . handle_request_sync ( & req , meta ) ;
2020-09-21 19:54:43 -07:00
let version = solana_version ::Version ::default ( ) ;
2019-08-07 20:06:27 -06:00
let expected = json! ( {
" jsonrpc " : " 2.0 " ,
" result " : {
2020-09-21 19:54:43 -07:00
" solana-core " : version . to_string ( ) ,
" feature-set " : version . feature_set ,
2019-08-07 20:06:27 -06: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 " ) ;
assert_eq! ( expected , result ) ;
}
2019-10-14 16:24:10 -06:00
#[ test ]
2019-11-04 16:44:27 -07:00
fn test_rpc_processor_get_block_commitment ( ) {
2019-10-14 16:24:10 -06:00
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
let validator_exit = create_validator_exit ( & exit ) ;
2020-03-30 11:29:30 -06:00
let bank_forks = new_bank_forks ( ) . 0 ;
2020-04-22 12:22:09 -06:00
let ledger_path = get_tmp_ledger_path! ( ) ;
let blockstore = Arc ::new ( Blockstore ::open ( & ledger_path ) . unwrap ( ) ) ;
2020-03-30 11:29:30 -06:00
2020-04-20 23:25:49 -06:00
let commitment_slot0 = BlockCommitment ::new ( [ 8 ; MAX_LOCKOUT_HISTORY + 1 ] ) ;
let commitment_slot1 = BlockCommitment ::new ( [ 9 ; MAX_LOCKOUT_HISTORY + 1 ] ) ;
2019-11-04 16:44:27 -07:00
let mut block_commitment : HashMap < u64 , BlockCommitment > = HashMap ::new ( ) ;
block_commitment
. entry ( 0 )
2020-05-15 17:35:43 +01:00
. or_insert_with ( | | commitment_slot0 . clone ( ) ) ;
2019-11-04 16:44:27 -07:00
block_commitment
. entry ( 1 )
2020-05-15 17:35:43 +01:00
. or_insert_with ( | | commitment_slot1 . clone ( ) ) ;
2020-03-30 11:29:30 -06:00
let block_commitment_cache = Arc ::new ( RwLock ::new ( BlockCommitmentCache ::new (
block_commitment ,
42 ,
2020-08-12 21:51:15 -06:00
CommitmentSlots ::new_from_slot ( bank_forks . read ( ) . unwrap ( ) . highest_slot ( ) ) ,
2020-03-30 11:29:30 -06:00
) ) ) ;
2019-10-14 16:24:10 -06:00
2020-06-05 21:23:13 -07:00
let cluster_info = Arc ::new ( ClusterInfo ::default ( ) ) ;
2020-07-08 19:13:42 -06:00
let tpu_address = cluster_info . my_contact_info ( ) . tpu ;
2020-07-10 19:14:41 -06: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 16:44:27 -07:00
block_commitment_cache ,
2020-04-22 12:22:09 -06: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 19:13:42 -06:00
cluster_info ,
2020-06-07 21:54:03 -06:00
Hash ::default ( ) ,
2021-02-05 00:21:53 -07:00
Arc ::new ( tokio ::runtime ::Runtime ::new ( ) . unwrap ( ) ) ,
2020-07-23 09:54:57 -07:00
None ,
2020-09-28 20:43:05 -06: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 ( ) ) ,
2019-10-14 16:24:10 -06:00
) ;
2020-12-17 14:37:22 -08:00
SendTransactionService ::new ( tpu_address , & bank_forks , None , receiver , 1000 , 1 ) ;
2019-10-14 16:24:10 -06:00
assert_eq! (
2019-11-04 16:44:27 -07:00
request_processor . get_block_commitment ( 0 ) ,
2020-01-15 00:25:45 -07:00
RpcBlockCommitment {
2020-01-21 20:17:33 -07:00
commitment : Some ( commitment_slot0 . commitment ) ,
2020-01-15 00:25:45 -07:00
total_stake : 42 ,
}
2019-10-14 16:24:10 -06:00
) ;
assert_eq! (
2019-11-04 16:44:27 -07:00
request_processor . get_block_commitment ( 1 ) ,
2020-01-15 00:25:45 -07:00
RpcBlockCommitment {
2020-01-21 20:17:33 -07:00
commitment : Some ( commitment_slot1 . commitment ) ,
2020-01-15 00:25:45 -07:00
total_stake : 42 ,
}
) ;
assert_eq! (
request_processor . get_block_commitment ( 2 ) ,
RpcBlockCommitment {
commitment : None ,
total_stake : 42 ,
}
2019-10-14 16:24:10 -06:00
) ;
}
#[ test ]
2019-11-04 16:44:27 -07:00
fn test_rpc_get_block_commitment ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-10-14 16:24:10 -06:00
let RpcHandler {
io ,
meta ,
2019-11-04 16:44:27 -07:00
block_commitment_cache ,
2019-10-14 16:24:10 -06:00
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getBlockCommitment","params":[0]}"# ;
2019-10-14 16:24:10 -06:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2020-01-15 00:25:45 -07:00
let RpcBlockCommitment {
commitment ,
total_stake ,
} = if let Response ::Single ( res ) = result {
if let Output ::Success ( res ) = res {
serde_json ::from_value ( res . result ) . unwrap ( )
2019-10-14 16:24:10 -06:00
} else {
2020-01-15 00:25:45 -07:00
panic! ( " Expected success " ) ;
}
} else {
panic! ( " Expected single response " ) ;
} ;
2019-10-14 16:24:10 -06:00
assert_eq! (
2019-11-04 16:44:27 -07:00
commitment ,
block_commitment_cache
2019-10-14 16:24:10 -06:00
. read ( )
. unwrap ( )
2019-11-04 16:44:27 -07:00
. get_block_commitment ( 0 )
2020-01-21 20:17:33 -07:00
. map ( | block_commitment | block_commitment . commitment )
2019-10-14 16:24:10 -06:00
) ;
2020-03-30 17:53:25 -06:00
assert_eq! ( total_stake , 10 ) ;
2019-10-14 16:24:10 -06:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getBlockCommitment","params":[2]}"# ;
2019-10-14 16:24:10 -06:00
let res = io . handle_request_sync ( & req , meta ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2020-04-20 23:25:49 -06:00
let commitment_response : RpcBlockCommitment < BlockCommitmentArray > =
2019-10-14 16:24:10 -06:00
if let Response ::Single ( res ) = result {
if let Output ::Success ( res ) = res {
serde_json ::from_value ( res . result ) . unwrap ( )
} else {
panic! ( " Expected success " ) ;
}
} else {
panic! ( " Expected single response " ) ;
} ;
2020-01-15 00:25:45 -07:00
assert_eq! ( commitment_response . commitment , None ) ;
2020-03-30 17:53:25 -06:00
assert_eq! ( commitment_response . total_stake , 10 ) ;
2019-10-14 16:24:10 -06:00
}
2019-11-25 12:08:03 -07:00
#[ test ]
fn test_get_confirmed_block ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-11-25 12:08:03 -07:00
let RpcHandler {
io ,
meta ,
confirmed_block_signatures ,
blockhash ,
..
} = start_rpc_handler_with_tx ( & bob_pubkey ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlock","params":[0]}"# ;
2020-01-12 22:34:30 -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 " ) ;
2020-09-24 13:10:29 +08:00
let confirmed_block : Option < EncodedConfirmedBlock > =
2020-01-12 22:34:30 -07:00
serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
let confirmed_block = confirmed_block . unwrap ( ) ;
assert_eq! ( confirmed_block . transactions . len ( ) , 3 ) ;
2020-09-24 13:10:29 +08:00
for EncodedTransactionWithStatusMeta { transaction , meta } in
2020-01-15 00:25:45 -07:00
confirmed_block . transactions . into_iter ( )
{
2020-03-26 13:29:30 -07:00
if let EncodedTransaction ::Json ( transaction ) = transaction {
2020-01-12 22:34:30 -07:00
if transaction . signatures [ 0 ] = = confirmed_block_signatures [ 0 ] . to_string ( ) {
2020-04-04 16:13:26 -07:00
let meta = meta . unwrap ( ) ;
2020-06-19 16:15:13 -06:00
let transaction_recent_blockhash = match transaction . message {
2020-07-01 14:06:40 -06:00
UiMessage ::Parsed ( message ) = > message . recent_blockhash ,
UiMessage ::Raw ( message ) = > message . recent_blockhash ,
2020-06-19 16:15:13 -06:00
} ;
assert_eq! ( transaction_recent_blockhash , blockhash . to_string ( ) ) ;
2020-04-04 16:13:26 -07:00
assert_eq! ( meta . status , Ok ( ( ) ) ) ;
assert_eq! ( meta . err , None ) ;
2020-01-12 22:34:30 -07: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 22:34:30 -07: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 22:34:30 -07:00
Err ( TransactionError ::InstructionError (
0 ,
2020-04-01 09:01:11 -07:00
InstructionError ::Custom ( 1 )
2020-01-12 22:34:30 -07:00
) )
) ;
} else {
2020-01-15 00:25:45 -07:00
assert_eq! ( meta , None ) ;
2020-01-12 22:34:30 -07:00
}
}
}
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlock","params":[0,"binary"]}"# ;
2019-11-25 12:08:03 -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 " ) ;
2020-09-24 13:10:29 +08:00
let confirmed_block : Option < EncodedConfirmedBlock > =
2019-11-25 12:08:03 -07:00
serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
let confirmed_block = confirmed_block . unwrap ( ) ;
assert_eq! ( confirmed_block . transactions . len ( ) , 3 ) ;
2020-09-24 13:10:29 +08:00
for EncodedTransactionWithStatusMeta { transaction , meta } in
2020-01-15 00:25:45 -07:00
confirmed_block . transactions . into_iter ( )
{
2020-08-15 17:56:09 -07:00
if let EncodedTransaction ::LegacyBinary ( transaction ) = transaction {
2020-01-12 22:34:30 -07: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 ( ) ;
2020-01-12 22:34:30 -07:00
assert_eq! ( decoded_transaction . message . recent_blockhash , blockhash ) ;
2020-04-04 16:13:26 -07:00
assert_eq! ( meta . status , Ok ( ( ) ) ) ;
assert_eq! ( meta . err , None ) ;
2020-01-12 22:34:30 -07: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 22:34:30 -07:00
assert_eq! (
2020-04-04 16:13:26 -07:00
meta . status ,
2020-01-12 22:34:30 -07:00
Err ( TransactionError ::InstructionError (
0 ,
2020-04-01 09:01:11 -07:00
InstructionError ::Custom ( 1 )
2020-01-12 22:34:30 -07:00
) )
) ;
} else {
2020-01-15 00:25:45 -07:00
assert_eq! ( meta , None ) ;
2020-01-12 22:34:30 -07:00
}
2019-11-25 12:08:03 -07:00
}
}
}
2019-11-26 00:40:36 -07:00
2019-12-18 16:51:47 -07:00
#[ test ]
fn test_get_confirmed_blocks ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2019-12-18 16:51:47 -07:00
let roots = vec! [ 0 , 1 , 3 , 4 , 8 ] ;
2020-04-28 11:20:43 -06:00
let RpcHandler {
io ,
meta ,
block_commitment_cache ,
..
2020-10-26 13:23:45 -06:00
} = start_rpc_handler_with_tx_and_blockstore ( & bob_pubkey , roots . clone ( ) ) ;
2020-04-28 11:20:43 -06:00
block_commitment_cache
. write ( )
. unwrap ( )
2020-07-07 17:59:46 -06:00
. set_highest_confirmed_root ( 8 ) ;
2019-12-18 16:51:47 -07:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0]}"# ;
2019-12-18 16:51:47 -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 confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
2020-04-28 10:22:10 -06:00
assert_eq! ( confirmed_blocks , roots [ 1 .. ] . to_vec ( ) ) ;
2019-12-18 16:51:47 -07:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[2]}"# ;
2019-12-18 16:51:47 -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 confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( confirmed_blocks , vec! [ 3 , 4 , 8 ] ) ;
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0,4]}"# ;
2019-12-18 16:51:47 -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 confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
2020-04-28 10:22:10 -06:00
assert_eq! ( confirmed_blocks , vec! [ 1 , 3 , 4 ] ) ;
2019-12-18 16:51:47 -07:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0,7]}"# ;
2019-12-18 16:51:47 -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 confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
2020-04-28 10:22:10 -06:00
assert_eq! ( confirmed_blocks , vec! [ 1 , 3 , 4 ] ) ;
2019-12-18 16:51:47 -07:00
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[9,11]}"# ;
2020-07-06 08:37:04 -07:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2019-12-18 16:51:47 -07:00
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( confirmed_blocks , Vec ::< Slot > ::new ( ) ) ;
2020-07-06 08:37:04 -07:00
block_commitment_cache
. write ( )
. unwrap ( )
2020-07-10 12:57:32 -07:00
. set_highest_confirmed_root ( std ::u64 ::MAX ) ;
2020-07-06 08:37:04 -07:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0,{}]}}"# ,
MAX_GET_CONFIRMED_BLOCKS_RANGE
) ;
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 confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( confirmed_blocks , vec! [ 1 , 3 , 4 , 8 ] ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocks","params":[0,{}]}}"# ,
MAX_GET_CONFIRMED_BLOCKS_RANGE + 1
) ;
let res = io . handle_request_sync ( & req , meta ) ;
assert_eq! (
res ,
Some (
r # "{"jsonrpc":"2.0","error":{"code":-32602,"message":"Slot range too large; max 500000"},"id":1}"# . to_string ( ) ,
)
) ;
2019-12-18 16:51:47 -07:00
}
2020-09-30 13:47:12 -07:00
#[ test ]
fn test_get_confirmed_blocks_with_limit ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-09-30 13:47:12 -07:00
let roots = vec! [ 0 , 1 , 3 , 4 , 8 ] ;
let RpcHandler {
io ,
meta ,
block_commitment_cache ,
..
2020-10-26 13:23:45 -06:00
} = start_rpc_handler_with_tx_and_blockstore ( & bob_pubkey , roots ) ;
2020-09-30 13:47:12 -07:00
block_commitment_cache
. write ( )
. unwrap ( )
. set_highest_confirmed_root ( 8 ) ;
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocksWithLimit","params":[0,500001]}"# ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
assert_eq! (
res ,
Some (
r # "{"jsonrpc":"2.0","error":{"code":-32602,"message":"Limit too large; max 500000"},"id":1}"# . to_string ( ) ,
)
) ;
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocksWithLimit","params":[0,0]}"# ;
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 confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert! ( confirmed_blocks . is_empty ( ) ) ;
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocksWithLimit","params":[2,2]}"# ;
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 confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( confirmed_blocks , vec! [ 3 , 4 ] ) ;
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocksWithLimit","params":[2,3]}"# ;
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 confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( confirmed_blocks , vec! [ 3 , 4 , 8 ] ) ;
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocksWithLimit","params":[2,500000]}"# ;
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 confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( confirmed_blocks , vec! [ 3 , 4 , 8 ] ) ;
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlocksWithLimit","params":[9,500000]}"# ;
let res = io . handle_request_sync ( & req , meta ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
let confirmed_blocks : Vec < Slot > = serde_json ::from_value ( result [ " result " ] . clone ( ) ) . unwrap ( ) ;
assert_eq! ( confirmed_blocks , Vec ::< Slot > ::new ( ) ) ;
}
2019-11-26 00:40:36 -07:00
#[ test ]
fn test_get_block_time ( ) {
2020-10-19 12:12:08 -07:00
let bob_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-05-04 19:39:27 -06:00
let RpcHandler {
io ,
meta ,
bank ,
block_commitment_cache ,
2020-10-26 13:23:45 -06:00
bank_forks ,
2020-05-04 19:39:27 -06:00
..
2020-10-26 13:23:45 -06:00
} = start_rpc_handler_with_tx_and_blockstore ( & bob_pubkey , vec! [ 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ) ;
let base_timestamp = bank_forks
. read ( )
. unwrap ( )
. get ( 0 )
. unwrap ( )
. unix_timestamp_from_genesis ( ) ;
2020-05-04 19:39:27 -06:00
block_commitment_cache
. write ( )
. unwrap ( )
2020-07-07 17:59:46 -06:00
. set_highest_confirmed_root ( 7 ) ;
2019-11-26 00:40:36 -07:00
let slot_duration = slot_duration_from_slots_per_year ( bank . slots_per_year ( ) ) ;
2019-12-14 12:23:02 -07:00
let slot = 2 ;
2019-11-26 00:40:36 -07:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getBlockTime","params":[{}]}}"# ,
slot
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2019-12-14 12:23:02 -07:00
let expected = format! ( r # "{{"jsonrpc":"2.0","result":{},"id":1}}"# , base_timestamp ) ;
2019-11-26 00:40:36 -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 " ) ;
assert_eq! ( expected , result ) ;
2019-12-14 12:23:02 -07:00
let slot = 7 ;
2019-11-26 00:40:36 -07:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getBlockTime","params":[{}]}}"# ,
slot
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = format! (
r # "{{"jsonrpc":"2.0","result":{},"id":1}}"# ,
2021-01-11 16:27:30 -07:00
base_timestamp + ( 7 * slot_duration ) . as_secs ( ) as i64
2019-11-26 00:40:36 -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 " ) ;
assert_eq! ( expected , result ) ;
2019-12-14 12:23:02 -07:00
let slot = 12345 ;
2019-11-26 00:40:36 -07:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getBlockTime","params":[{}]}}"# ,
slot
) ;
let res = io . handle_request_sync ( & req , meta ) ;
2020-08-20 15:05:30 -06:00
let expected = r # "{"jsonrpc":"2.0","error":{"code":-32004,"message":"Block not available for slot 12345"},"id":1}"# ;
2019-11-26 00:40:36 -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 " ) ;
assert_eq! ( expected , result ) ;
}
2019-12-07 00:12:25 -07:00
2020-07-20 17:03:40 -06:00
fn advance_block_commitment_cache (
block_commitment_cache : & Arc < RwLock < BlockCommitmentCache > > ,
bank_forks : & Arc < RwLock < BankForks > > ,
) {
let mut new_block_commitment = BlockCommitmentCache ::new (
HashMap ::new ( ) ,
0 ,
2020-08-12 21:51:15 -06:00
CommitmentSlots ::new_from_slot ( bank_forks . read ( ) . unwrap ( ) . highest_slot ( ) ) ,
2020-07-20 17:03:40 -06:00
) ;
let mut w_block_commitment_cache = block_commitment_cache . write ( ) . unwrap ( ) ;
std ::mem ::swap ( & mut * w_block_commitment_cache , & mut new_block_commitment ) ;
}
2019-12-07 00:12:25 -07:00
#[ test ]
fn test_get_vote_accounts ( ) {
let RpcHandler {
io ,
meta ,
2019-12-11 22:04:54 -08:00
mut bank ,
bank_forks ,
2019-12-07 00:12:25 -07:00
alice ,
2019-12-11 22:04:54 -08:00
leader_vote_keypair ,
2020-07-20 17:03:40 -06:00
block_commitment_cache ,
2019-12-07 00:12:25 -07:00
..
2020-10-19 12:12:08 -07:00
} = start_rpc_handler_with_tx ( & solana_sdk ::pubkey ::new_rand ( ) ) ;
2019-12-07 00:12:25 -07:00
assert_eq! ( bank . vote_accounts ( ) . len ( ) , 1 ) ;
2019-12-14 01:53:45 -07:00
// Create a vote account with no stake.
let alice_vote_keypair = Keypair ::new ( ) ;
2019-12-07 00:12:25 -07:00
let instructions = vote_instruction ::create_account (
& alice . pubkey ( ) ,
2019-12-14 01:53:45 -07:00
& alice_vote_keypair . pubkey ( ) ,
2019-12-07 00:12:25 -07:00
& VoteInit {
node_pubkey : alice . pubkey ( ) ,
2019-12-14 01:53:45 -07:00
authorized_voter : alice_vote_keypair . pubkey ( ) ,
authorized_withdrawer : alice_vote_keypair . pubkey ( ) ,
2019-12-07 00:12:25 -07:00
commission : 0 ,
} ,
bank . get_minimum_balance_for_rent_exemption ( VoteState ::size_of ( ) ) ,
) ;
2020-06-24 14:52:38 -06:00
let message = Message ::new ( & instructions , Some ( & alice . pubkey ( ) ) ) ;
2020-05-30 00:17:44 -06:00
let transaction = Transaction ::new (
2019-12-14 01:53:45 -07:00
& [ & alice , & alice_vote_keypair ] ,
2020-05-30 00:17:44 -06:00
message ,
2019-12-07 00:12:25 -07:00
bank . last_blockhash ( ) ,
) ;
bank . process_transaction ( & transaction )
. expect ( " process transaction " ) ;
assert_eq! ( bank . vote_accounts ( ) . len ( ) , 2 ) ;
2020-01-22 09:22:09 -07:00
// Check getVoteAccounts: the bootstrap validator vote account will be delinquent as it has
2019-12-14 01:53:45 -07:00
// stake but has never voted, and the vote account with no stake should not be present.
{
2020-05-15 17:35:43 +01:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts"}"# ;
2019-12-14 01:53:45 -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! ( 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 ) ;
}
}
2019-12-11 22:04:54 -08:00
// Advance bank to the next epoch
for _ in 0 .. TEST_SLOTS_PER_EPOCH {
bank . freeze ( ) ;
2019-12-14 01:53:45 -07:00
// Votes
2020-04-24 13:03:46 -06:00
let instructions = [
2019-12-14 01:53:45 -07: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
bank = bank_forks . write ( ) . unwrap ( ) . insert ( Bank ::new_from_parent (
& bank ,
& Pubkey ::default ( ) ,
bank . slot ( ) + 1 ,
) ) ;
2020-07-20 17:03:40 -06:00
advance_block_commitment_cache ( & block_commitment_cache , & bank_forks ) ;
2019-12-11 22:04:54 -08:00
let transaction = Transaction ::new_signed_with_payer (
2020-04-24 13:03:46 -06:00
& instructions ,
2019-12-11 22:04:54 -08:00
Some ( & alice . pubkey ( ) ) ,
2019-12-14 01:53:45 -07:00
& [ & alice , & leader_vote_keypair , & alice_vote_keypair ] ,
2019-12-11 22:04:54 -08:00
bank . last_blockhash ( ) ,
) ;
bank . process_transaction ( & transaction )
. expect ( " process transaction " ) ;
}
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"# ,
2021-01-26 12:23:07 -07:00
json! ( [ CommitmentConfig ::processed ( ) ] )
2019-12-11 22:04:54 -08:00
) ;
2019-12-07 00:12:25 -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 ( ) ;
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 01:53:45 -07: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[0];
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 01:53:45 -07:00
// Advance bank with no voting
bank . freeze ( ) ;
bank_forks . write ( ) . unwrap ( ) . insert ( Bank ::new_from_parent (
& bank ,
& Pubkey ::default ( ) ,
bank . slot ( ) + TEST_SLOTS_PER_EPOCH ,
) ) ;
2020-07-20 17:03:40 -06:00
advance_block_commitment_cache ( & block_commitment_cache , & bank_forks ) ;
2019-12-14 01:53:45 -07: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 12:23:07 -07:00
json! ( [ CommitmentConfig ::processed ( ) ] )
2019-12-14 01:53:45 -07:00
) ;
2020-05-15 17:35:43 +01:00
let res = io . handle_request_sync ( & req , meta ) ;
2019-12-14 01:53:45 -07: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 ,
leader_vote_keypair . pubkey ( ) . to_string ( )
) ;
}
}
2019-12-07 00:12:25 -07:00
}
2020-06-25 22:06:58 -06:00
#[ test ]
fn test_is_confirmed_rooted ( ) {
let bank = Arc ::new ( Bank ::default ( ) ) ;
let ledger_path = get_tmp_ledger_path! ( ) ;
let blockstore = Arc ::new ( Blockstore ::open ( & ledger_path ) . unwrap ( ) ) ;
blockstore . set_roots ( & [ 0 , 1 ] ) . unwrap ( ) ;
// 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 17:59:46 -06:00
let highest_confirmed_root = 1 ;
2020-07-07 20:13:30 -06:00
let block_commitment_cache = BlockCommitmentCache ::new (
block_commitment ,
50 ,
2020-07-17 11:54:49 -06:00
CommitmentSlots {
2020-07-17 09:24:51 -06:00
slot : bank . slot ( ) ,
highest_confirmed_root ,
2020-08-12 21:51:15 -06:00
.. CommitmentSlots ::default ( )
2020-07-17 09:24:51 -06:00
} ,
2020-07-07 20:13:30 -06:00
) ;
2020-06-25 22:06:58 -06:00
2020-07-07 20:13:30 -06:00
assert! ( is_confirmed_rooted (
& block_commitment_cache ,
& bank ,
& blockstore ,
0
) ) ;
assert! ( is_confirmed_rooted (
& block_commitment_cache ,
& bank ,
& blockstore ,
1
) ) ;
2020-06-25 22:06:58 -06:00
assert! ( ! is_confirmed_rooted (
& block_commitment_cache ,
2020-07-07 20:13:30 -06:00
& bank ,
2020-06-25 22:06:58 -06:00
& blockstore ,
2
) ) ;
assert! ( ! is_confirmed_rooted (
& block_commitment_cache ,
2020-07-07 20:13:30 -06:00
& bank ,
2020-06-25 22:06:58 -06:00
& blockstore ,
3
) ) ;
}
2020-07-28 23:00:48 -06:00
#[ test ]
fn test_token_rpcs ( ) {
2020-10-19 12:23:14 -07:00
let RpcHandler { io , meta , bank , .. } =
start_rpc_handler_with_tx ( & solana_sdk ::pubkey ::new_rand ( ) ) ;
2020-07-28 23:00:48 -06:00
2020-08-28 22:06:30 -06:00
let mut account_data = vec! [ 0 ; TokenAccount ::get_packed_len ( ) ] ;
2020-07-30 14:52:28 -07:00
let mint = SplTokenPubkey ::new ( & [ 2 ; 32 ] ) ;
let owner = SplTokenPubkey ::new ( & [ 3 ; 32 ] ) ;
let delegate = SplTokenPubkey ::new ( & [ 4 ; 32 ] ) ;
2020-09-22 17:08:54 -06:00
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 ( ) ;
2021-03-09 15:06:07 -06:00
let token_account = AccountSharedData {
2020-07-28 23:00:48 -06:00
lamports : 111 ,
data : account_data . to_vec ( ) ,
2020-08-28 15:54:57 -06:00
owner : spl_token_id_v2_0 ( ) ,
2021-03-09 15:06:07 -06:00
.. AccountSharedData ::default ( )
2020-07-28 23:00:48 -06:00
} ;
2020-10-19 12:12:08 -07:00
let token_account_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-07-28 23:00:48 -06:00
bank . store_account ( & token_account_pubkey , & token_account ) ;
2020-08-05 00:48:09 -06:00
// Add the mint
2020-08-28 22:06:30 -06:00
let mut mint_data = vec! [ 0 ; Mint ::get_packed_len ( ) ] ;
2020-09-22 17:08:54 -06:00
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 ( ) ;
2021-03-09 15:06:07 -06:00
let mint_account = AccountSharedData {
2020-08-05 00:48:09 -06:00
lamports : 111 ,
data : mint_data . to_vec ( ) ,
2020-08-28 15:54:57 -06:00
owner : spl_token_id_v2_0 ( ) ,
2021-03-09 15:06:07 -06:00
.. AccountSharedData ::default ( )
2020-08-05 00:48:09 -06:00
} ;
bank . store_account ( & Pubkey ::from_str ( & mint . to_string ( ) ) . unwrap ( ) , & mint_account ) ;
2020-07-28 23:00:48 -06:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenAccountBalance","params":["{}"]}}"# ,
token_account_pubkey ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2020-08-07 11:37:39 -06:00
let balance : UiTokenAmount =
2020-08-05 00:48:09 -06:00
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
let error = f64 ::EPSILON ;
2021-03-02 22:51:41 -07:00
assert! ( ( balance . ui_amount . unwrap ( ) - 4.2 ) . abs ( ) < error ) ;
2020-08-05 00:48:09 -06:00
assert_eq! ( balance . amount , 420. to_string ( ) ) ;
assert_eq! ( balance . decimals , 2 ) ;
2021-03-02 22:51:41 -07:00
assert_eq! ( balance . ui_amount_string , " 4.2 " . to_string ( ) ) ;
2020-07-28 23:00:48 -06:00
// Test non-existent token account
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenAccountBalance","params":["{}"]}}"# ,
2020-10-19 12:12:08 -07:00
solana_sdk ::pubkey ::new_rand ( ) ,
2020-07-28 23:00:48 -06: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 " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
2020-08-28 15:54:57 -06:00
// Test get token supply, pulls supply from mint
2020-07-28 23:00:48 -06:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenSupply","params":["{}"]}}"# ,
mint ,
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
2020-08-07 11:37:39 -06:00
let supply : UiTokenAmount =
2020-08-05 00:48:09 -06:00
serde_json ::from_value ( result [ " result " ] [ " value " ] . clone ( ) ) . unwrap ( ) ;
let error = f64 ::EPSILON ;
2021-03-02 22:51:41 -07:00
assert! ( ( supply . ui_amount . unwrap ( ) - 5.0 ) . abs ( ) < error ) ;
2020-08-28 15:54:57 -06:00
assert_eq! ( supply . amount , 500. to_string ( ) ) ;
2020-08-05 00:48:09 -06:00
assert_eq! ( supply . decimals , 2 ) ;
2021-03-02 22:51:41 -07:00
assert_eq! ( supply . ui_amount_string , " 5 " . to_string ( ) ) ;
2020-07-28 23:00:48 -06:00
// Test non-existent mint address
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenSupply","params":["{}"]}}"# ,
2020-10-19 12:12:08 -07:00
solana_sdk ::pubkey ::new_rand ( ) ,
2020-07-28 23:00:48 -06: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 " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
2020-08-28 15:54:57 -06:00
// Add another token account with the same owner, delegate, and mint
2020-10-19 12:12:08 -07:00
let other_token_account_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-08-28 15:54:57 -06:00
bank . store_account ( & other_token_account_pubkey , & token_account ) ;
2020-07-28 23:00:48 -06:00
// Add another token account with the same owner and delegate but different mint
2020-08-28 22:06:30 -06:00
let mut account_data = vec! [ 0 ; TokenAccount ::get_packed_len ( ) ] ;
2020-07-30 14:52:28 -07:00
let new_mint = SplTokenPubkey ::new ( & [ 5 ; 32 ] ) ;
2020-09-22 17:08:54 -06:00
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 ( ) ;
2021-03-09 15:06:07 -06:00
let token_account = AccountSharedData {
2020-07-28 23:00:48 -06:00
lamports : 111 ,
data : account_data . to_vec ( ) ,
2020-08-28 15:54:57 -06:00
owner : spl_token_id_v2_0 ( ) ,
2021-03-09 15:06:07 -06:00
.. AccountSharedData ::default ( )
2020-07-28 23:00:48 -06:00
} ;
2020-10-19 12:12:08 -07:00
let token_with_different_mint_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-07-28 23:00:48 -06:00
bank . store_account ( & token_with_different_mint_pubkey , & token_account ) ;
// Test getTokenAccountsByOwner with Token program id returns all accounts, regardless of Mint address
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
owner ,
2020-08-28 15:54:57 -06:00
spl_token_id_v2_0 ( ) ,
2020-07-28 23:00:48 -06: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-08-26 11:39:42 -06:00
// Test getTokenAccountsByOwner with jsonParsed encoding doesn't return accounts with invalid mints
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
" params " :[ " {} " , { { " programId " : " {} " } } , { { " encoding " : " jsonParsed " } } ]
} } " #,
owner ,
2020-08-28 15:54:57 -06:00
spl_token_id_v2_0 ( ) ,
2020-08-26 11:39:42 -06: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-29 12:38:27 -06: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 " ,
" params " :[ " {} " , { { " encoding " : " jsonParsed " } } ]
} } " #,
spl_token_id_v2_0 ( ) ,
) ;
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 ( ) ;
2020-08-31 21:51:52 -07:00
assert_eq! ( accounts . len ( ) , 4 ) ;
2020-08-29 12:38:27 -06:00
2020-07-28 23:00:48 -06:00
// Test returns only mint accounts
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 , " method " :" getTokenAccountsByOwner " ,
" params " :[ " {} " , { { " mint " : " {} " } } ]
} } " #,
owner , mint ,
) ;
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 ) ;
// Test non-existent Mint/program id
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
owner ,
2020-10-19 12:12:08 -07:00
solana_sdk ::pubkey ::new_rand ( ) ,
2020-07-28 23:00:48 -06: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 " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
" params " :[ " {} " , { { " mint " : " {} " } } ]
} } " #,
owner ,
2020-10-19 12:12:08 -07:00
solana_sdk ::pubkey ::new_rand ( ) ,
2020-07-28 23:00:48 -06: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 " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
// Test non-existent Owner
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByOwner " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
2020-10-19 12:12:08 -07:00
solana_sdk ::pubkey ::new_rand ( ) ,
2020-08-28 15:54:57 -06:00
spl_token_id_v2_0 ( ) ,
2020-07-28 23:00:48 -06: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! ( accounts . is_empty ( ) ) ;
// Test getTokenAccountsByDelegate with Token program id returns all accounts, regardless of Mint address
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByDelegate " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
delegate ,
2020-08-28 15:54:57 -06:00
spl_token_id_v2_0 ( ) ,
2020-07-28 23:00:48 -06: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 ) ;
// Test returns only mint accounts
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 , " method " :
" getTokenAccountsByDelegate " ,
" params " :[ " {} " , { { " mint " : " {} " } } ]
} } " #,
delegate , mint ,
) ;
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 ) ;
// Test non-existent Mint/program id
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByDelegate " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
delegate ,
2020-10-19 12:12:08 -07:00
solana_sdk ::pubkey ::new_rand ( ) ,
2020-07-28 23:00:48 -06: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 " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByDelegate " ,
" params " :[ " {} " , { { " mint " : " {} " } } ]
} } " #,
delegate ,
2020-10-19 12:12:08 -07:00
solana_sdk ::pubkey ::new_rand ( ) ,
2020-07-28 23:00:48 -06: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 " ) ;
assert! ( result . get ( " error " ) . is_some ( ) ) ;
2020-08-02 10:23:44 -06:00
// Test non-existent Delegate
2020-07-28 23:00:48 -06:00
let req = format! (
r #" {{
" jsonrpc " :" 2.0 " ,
" id " :1 ,
" method " :" getTokenAccountsByDelegate " ,
" params " :[ " {} " , { { " programId " : " {} " } } ]
} } " #,
2020-10-19 12:12:08 -07:00
solana_sdk ::pubkey ::new_rand ( ) ,
2020-08-28 15:54:57 -06:00
spl_token_id_v2_0 ( ) ,
2020-07-28 23:00:48 -06:00
) ;
2020-08-02 10:23:44 -06:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
2020-07-28 23:00:48 -06:00
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-08-02 10:23:44 -06:00
// Add new_mint, and another token account on new_mint with different balance
2020-08-28 22:06:30 -06:00
let mut mint_data = vec! [ 0 ; Mint ::get_packed_len ( ) ] ;
2020-09-22 17:08:54 -06:00
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 ( ) ;
2021-03-09 15:06:07 -06:00
let mint_account = AccountSharedData {
2020-08-02 10:23:44 -06:00
lamports : 111 ,
data : mint_data . to_vec ( ) ,
2020-08-28 15:54:57 -06:00
owner : spl_token_id_v2_0 ( ) ,
2021-03-09 15:06:07 -06:00
.. AccountSharedData ::default ( )
2020-08-02 10:23:44 -06:00
} ;
bank . store_account (
& Pubkey ::from_str ( & new_mint . to_string ( ) ) . unwrap ( ) ,
& mint_account ,
) ;
2020-08-28 22:06:30 -06:00
let mut account_data = vec! [ 0 ; TokenAccount ::get_packed_len ( ) ] ;
2020-09-22 17:08:54 -06:00
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 ( ) ;
2021-03-09 15:06:07 -06:00
let token_account = AccountSharedData {
2020-08-02 10:23:44 -06:00
lamports : 111 ,
data : account_data . to_vec ( ) ,
2020-08-28 15:54:57 -06:00
owner : spl_token_id_v2_0 ( ) ,
2021-03-09 15:06:07 -06:00
.. AccountSharedData ::default ( )
2020-08-02 10:23:44 -06:00
} ;
2020-10-19 12:12:08 -07:00
let token_with_smaller_balance = solana_sdk ::pubkey ::new_rand ( ) ;
2020-08-02 10:23:44 -06:00
bank . store_account ( & token_with_smaller_balance , & token_account ) ;
// Test largest token accounts
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getTokenLargestAccounts","params":["{}"]}}"# ,
new_mint ,
) ;
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 ( ) ,
2020-08-07 11:37:39 -06:00
amount : UiTokenAmount {
2021-03-02 22:51:41 -07:00
ui_amount : Some ( 0.42 ) ,
2020-08-05 00:48:09 -06:00
decimals : 2 ,
amount : " 42 " . to_string ( ) ,
2021-03-02 22:51:41 -07:00
ui_amount_string : " 0.42 " . to_string ( ) ,
2020-08-05 00:48:09 -06:00
}
2020-08-02 10:23:44 -06:00
} ,
RpcTokenAccountBalance {
address : token_with_smaller_balance . to_string ( ) ,
2020-08-07 11:37:39 -06:00
amount : UiTokenAmount {
2021-03-02 22:51:41 -07:00
ui_amount : Some ( 0.1 ) ,
2020-08-05 00:48:09 -06:00
decimals : 2 ,
amount : " 10 " . to_string ( ) ,
2021-03-02 22:51:41 -07:00
ui_amount_string : " 0.1 " . to_string ( ) ,
2020-08-05 00:48:09 -06:00
}
2020-08-02 10:23:44 -06:00
}
]
) ;
2020-07-28 23:00:48 -06:00
}
2020-08-10 14:35:36 -06:00
#[ test ]
fn test_token_parsing ( ) {
2020-10-19 12:23:14 -07:00
let RpcHandler { io , meta , bank , .. } =
start_rpc_handler_with_tx ( & solana_sdk ::pubkey ::new_rand ( ) ) ;
2020-08-10 14:35:36 -06:00
2020-08-28 22:06:30 -06:00
let mut account_data = vec! [ 0 ; TokenAccount ::get_packed_len ( ) ] ;
2020-08-10 14:35:36 -06:00
let mint = SplTokenPubkey ::new ( & [ 2 ; 32 ] ) ;
let owner = SplTokenPubkey ::new ( & [ 3 ; 32 ] ) ;
let delegate = SplTokenPubkey ::new ( & [ 4 ; 32 ] ) ;
2020-09-22 17:08:54 -06:00
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 ( ) ;
2021-03-09 15:06:07 -06:00
let token_account = AccountSharedData {
2020-08-10 14:35:36 -06:00
lamports : 111 ,
data : account_data . to_vec ( ) ,
2020-08-28 15:54:57 -06:00
owner : spl_token_id_v2_0 ( ) ,
2021-03-09 15:06:07 -06:00
.. AccountSharedData ::default ( )
2020-08-10 14:35:36 -06:00
} ;
2020-10-19 12:12:08 -07:00
let token_account_pubkey = solana_sdk ::pubkey ::new_rand ( ) ;
2020-08-10 14:35:36 -06:00
bank . store_account ( & token_account_pubkey , & token_account ) ;
// Add the mint
2020-08-28 22:06:30 -06:00
let mut mint_data = vec! [ 0 ; Mint ::get_packed_len ( ) ] ;
2020-09-22 17:08:54 -06:00
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 ( ) ;
2021-03-09 15:06:07 -06:00
let mint_account = AccountSharedData {
2020-08-10 14:35:36 -06:00
lamports : 111 ,
data : mint_data . to_vec ( ) ,
2020-08-28 15:54:57 -06:00
owner : spl_token_id_v2_0 ( ) ,
2021-03-09 15:06:07 -06:00
.. AccountSharedData ::default ( )
2020-08-10 14:35:36 -06:00
} ;
bank . store_account ( & Pubkey ::from_str ( & mint . to_string ( ) ) . unwrap ( ) , & mint_account ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding": "jsonParsed"}}]}}"# ,
token_account_pubkey ,
) ;
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_eq! (
result [ " result " ] [ " value " ] [ " data " ] ,
json! ( {
" program " : " spl-token " ,
2020-08-28 22:06:30 -06:00
" space " : TokenAccount ::get_packed_len ( ) ,
2020-08-10 14:35:36 -06:00
" parsed " : {
" type " : " account " ,
" info " : {
" mint " : mint . to_string ( ) ,
" owner " : owner . to_string ( ) ,
" tokenAmount " : {
2021-02-25 14:53:40 -07:00
" uiAmount " : 4.2 ,
2020-08-10 14:35:36 -06:00
" decimals " : 2 ,
" amount " : " 420 " ,
2021-03-02 22:51:41 -07:00
" uiAmountString " : " 4.2 " ,
2020-08-10 14:35:36 -06:00
} ,
" delegate " : delegate . to_string ( ) ,
2020-08-28 15:54:57 -06:00
" state " : " initialized " ,
" isNative " : true ,
" rentExemptReserve " : {
2021-02-25 14:53:40 -07:00
" uiAmount " : 0.1 ,
2020-08-28 15:54:57 -06:00
" decimals " : 2 ,
" amount " : " 10 " ,
2021-03-02 22:51:41 -07:00
" uiAmountString " : " 0.1 " ,
2020-08-28 15:54:57 -06:00
} ,
2020-08-10 14:35:36 -06:00
" delegatedAmount " : {
2021-02-25 14:53:40 -07:00
" uiAmount " : 0.3 ,
2020-08-10 14:35:36 -06:00
" decimals " : 2 ,
" amount " : " 30 " ,
2021-03-02 22:51:41 -07:00
" uiAmountString " : " 0.3 " ,
2020-08-10 14:35:36 -06:00
} ,
2020-08-28 15:54:57 -06:00
" closeAuthority " : owner . to_string ( ) ,
2020-08-10 14:35:36 -06:00
}
}
} )
) ;
// Test Mint
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}", {{"encoding": "jsonParsed"}}]}}"# ,
mint ,
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let result : Value = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! (
result [ " result " ] [ " value " ] [ " data " ] ,
json! ( {
" program " : " spl-token " ,
2020-08-28 22:06:30 -06:00
" space " : Mint ::get_packed_len ( ) ,
2020-08-10 14:35:36 -06:00
" parsed " : {
" type " : " mint " ,
" info " : {
2020-08-28 15:54:57 -06:00
" mintAuthority " : owner . to_string ( ) ,
2020-08-10 14:35:36 -06:00
" decimals " : 2 ,
2020-08-28 15:54:57 -06:00
" supply " : " 500 " . to_string ( ) ,
2020-08-10 14:35:36 -06:00
" isInitialized " : true ,
2020-08-28 15:54:57 -06:00
" freezeAuthority " : owner . to_string ( ) ,
2020-08-10 14:35:36 -06:00
}
}
} )
) ;
}
2020-09-28 20:43:05 -06:00
2020-12-31 18:06:03 -08:00
#[ test ]
fn test_get_spl_token_owner_filter ( ) {
let owner = Pubkey ::new_unique ( ) ;
assert_eq! (
get_spl_token_owner_filter (
& Pubkey ::from_str ( " TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA " ) . unwrap ( ) ,
& [
RpcFilterType ::Memcmp ( Memcmp {
offset : 32 ,
bytes : MemcmpEncodedBytes ::Binary ( owner . to_string ( ) ) ,
encoding : None
} ) ,
RpcFilterType ::DataSize ( 165 )
] ,
)
. unwrap ( ) ,
owner
) ;
// Filtering on mint instead of owner
assert! ( get_spl_token_owner_filter (
& Pubkey ::from_str ( " TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA " ) . unwrap ( ) ,
& [
RpcFilterType ::Memcmp ( Memcmp {
offset : 0 ,
bytes : MemcmpEncodedBytes ::Binary ( owner . to_string ( ) ) ,
encoding : None
} ) ,
RpcFilterType ::DataSize ( 165 )
] ,
)
. is_none ( ) ) ;
// Wrong program id
assert! ( get_spl_token_owner_filter (
& Pubkey ::new_unique ( ) ,
& [
RpcFilterType ::Memcmp ( Memcmp {
offset : 32 ,
bytes : MemcmpEncodedBytes ::Binary ( owner . to_string ( ) ) ,
encoding : None
} ) ,
RpcFilterType ::DataSize ( 165 )
] ,
)
. is_none ( ) ) ;
}
2020-09-28 20:43:05 -06: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 ( ) ) ) ;
let cluster_info = Arc ::new ( ClusterInfo ::default ( ) ) ;
let GenesisConfigInfo { genesis_config , .. } = create_genesis_config ( 100 ) ;
let bank = Bank ::new ( & genesis_config ) ;
let bank_forks = Arc ::new ( RwLock ::new ( BankForks ::new ( bank ) ) ) ;
let bank0 = bank_forks . read ( ) . unwrap ( ) . get ( 0 ) . unwrap ( ) . clone ( ) ;
let bank1 = Bank ::new_from_parent ( & bank0 , & Pubkey ::default ( ) , 1 ) ;
bank_forks . write ( ) . unwrap ( ) . insert ( bank1 ) ;
let bank1 = bank_forks . read ( ) . unwrap ( ) . get ( 1 ) . unwrap ( ) . clone ( ) ;
let bank2 = Bank ::new_from_parent ( & bank1 , & Pubkey ::default ( ) , 2 ) ;
bank_forks . write ( ) . unwrap ( ) . insert ( bank2 ) ;
let bank2 = bank_forks . read ( ) . unwrap ( ) . get ( 2 ) . unwrap ( ) . clone ( ) ;
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 ( ) ;
let subscriptions = Arc ::new ( RpcSubscriptions ::new (
& exit ,
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 20:43:05 -06:00
bank_forks . clone ( ) ,
block_commitment_cache ,
blockstore ,
validator_exit ,
RpcHealth ::stub ( ) ,
cluster_info ,
Hash ::default ( ) ,
2021-02-05 00:21:53 -07:00
Arc ::new ( tokio ::runtime ::Runtime ::new ( ) . unwrap ( ) ) ,
2020-09-28 20:43:05 -06:00
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 ( ) ) ,
2020-09-28 20:43:05 -06: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 20:43:05 -06:00
2021-01-26 12:23:07 -07:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment":"confirmed"}]}"# ;
2020-09-28 20:43:05 -06: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 ) ;
OptimisticallyConfirmedBankTracker ::process_notification (
BankNotification ::OptimisticallyConfirmed ( 2 ) ,
& bank_forks ,
& optimistically_confirmed_bank ,
& subscriptions ,
& mut pending_optimistically_confirmed_banks ,
) ;
2021-01-26 12:23:07 -07:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"# ;
2020-09-28 20:43:05 -06: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 , 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-01-26 12:23:07 -07:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"# ;
2020-09-28 20:43:05 -06: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 , 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-01-26 12:23:07 -07:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"# ;
2020-09-28 20:43:05 -06: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 , 2 ) ;
// Test freezing an optimistically confirmed bank will update cache
let bank3 = bank_forks . read ( ) . unwrap ( ) . get ( 3 ) . unwrap ( ) . clone ( ) ;
OptimisticallyConfirmedBankTracker ::process_notification (
BankNotification ::Frozen ( bank3 ) ,
& bank_forks ,
& optimistically_confirmed_bank ,
& subscriptions ,
& mut pending_optimistically_confirmed_banks ,
) ;
2021-01-26 12:23:07 -07:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"getSlot","params":[{"commitment": "confirmed"}]}"# ;
2020-09-28 20:43:05 -06:00
let res = io . handle_request_sync ( & req , meta ) ;
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 21:21:33 -06:00
#[ test ]
fn test_worst_case_encoded_tx_goldens ( ) {
let ff_tx = vec! [ 0xff u8 ; PACKET_DATA_SIZE ] ;
2020-10-05 22:47:47 -06:00
let tx58 = bs58 ::encode ( & ff_tx ) . into_string ( ) ;
2020-10-05 21:21:33 -06:00
assert_eq! ( tx58 . len ( ) , WORST_CASE_BASE58_TX ) ;
2020-10-05 22:47:47 -06:00
let tx64 = base64 ::encode ( & ff_tx ) ;
assert_eq! ( tx64 . len ( ) , WORST_CASE_BASE64_TX ) ;
}
#[ test ]
2021-01-20 18:11:58 -08:00
fn test_deserialize_transaction_too_large_payloads_fail ( ) {
2020-10-05 22:47:47 -06: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 ] ;
let tx58 = bs58 ::encode ( & tx_ser ) . into_string ( ) ;
let tx58_len = tx58 . len ( ) ;
let expect58 = Error ::invalid_params ( format! (
" encoded transaction too large: {} bytes (max: encoded/raw {}/{}) " ,
tx58_len , WORST_CASE_BASE58_TX , PACKET_DATA_SIZE ,
) ) ;
assert_eq! (
deserialize_transaction ( tx58 , UiTransactionEncoding ::Base58 ) . unwrap_err ( ) ,
expect58
) ;
let tx64 = base64 ::encode ( & tx_ser ) ;
let tx64_len = tx64 . len ( ) ;
let expect64 = Error ::invalid_params ( format! (
" encoded transaction too large: {} bytes (max: encoded/raw {}/{}) " ,
tx64_len , WORST_CASE_BASE64_TX , PACKET_DATA_SIZE ,
) ) ;
assert_eq! (
deserialize_transaction ( tx64 , UiTransactionEncoding ::Base64 ) . unwrap_err ( ) ,
expect64
) ;
let too_big = PACKET_DATA_SIZE + 1 ;
let tx_ser = vec! [ 0x00 u8 ; too_big ] ;
let tx58 = bs58 ::encode ( & tx_ser ) . into_string ( ) ;
let expect = Error ::invalid_params ( format! (
" transaction too large: {} bytes (max: {} bytes) " ,
too_big , PACKET_DATA_SIZE
) ) ;
assert_eq! (
deserialize_transaction ( tx58 , UiTransactionEncoding ::Base58 ) . unwrap_err ( ) ,
expect
) ;
let tx64 = base64 ::encode ( & tx_ser ) ;
assert_eq! (
deserialize_transaction ( tx64 , UiTransactionEncoding ::Base64 ) . unwrap_err ( ) ,
expect
) ;
2020-10-05 21:21:33 -06:00
}
2021-01-20 18:11:58 -08:00
#[ test ]
fn test_deserialize_transaction_unsanitary ( ) {
let unsanitary_tx58 = " ju9xZWuDBX4pRxX2oZkTjxU5jB4SSTgEGhX8bQ8PURNzyzqKMPPpNvWihx8zUe \
FfrbVNoAaEsNKZvGzAnTDy5bhNT9kt6KFCTBixpvrLCzg4M5UdFUQYrn1gdgjX \
pLHxcaShD81xBNaFDgnA2nkkdHnKtZt4hVSfKAmw3VRZbjrZ7L2fKZBx21CwsG \
hD6onjM2M3qZW5C8J6d1pj41MxKmZgPBSha3MyKkNLkAGFASK "
. to_string ( ) ;
let expect58 =
Error ::invalid_params ( " invalid transaction: index out of bounds " . to_string ( ) ) ;
assert_eq! (
deserialize_transaction ( unsanitary_tx58 , UiTransactionEncoding ::Base58 ) . unwrap_err ( ) ,
expect58
) ;
}
2018-08-13 11:24:39 -06:00
}