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-06-25 22:06:58 -06:00
|
|
|
cluster_info::ClusterInfo, contact_info::ContactInfo,
|
|
|
|
non_circulating_supply::calculate_non_circulating_supply, rpc_error::RpcCustomError,
|
2020-07-09 12:28:26 -06:00
|
|
|
rpc_health::*, validator::ValidatorExit,
|
2019-10-14 16:24:10 -06:00
|
|
|
};
|
2020-07-09 00:08:05 +00:00
|
|
|
use bincode::{config::Options, serialize};
|
2020-05-11 15:47:40 -06:00
|
|
|
use jsonrpc_core::{Error, Metadata, Result};
|
2019-02-04 17:41:03 -07:00
|
|
|
use jsonrpc_derive::rpc;
|
2020-06-30 22:55:11 -06:00
|
|
|
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
2020-04-20 22:01:09 -07:00
|
|
|
use solana_client::{
|
2020-05-12 21:05:05 -06:00
|
|
|
rpc_config::*,
|
2020-07-03 01:46:29 -06:00
|
|
|
rpc_filter::RpcFilterType,
|
2020-04-20 22:01:09 -07:00
|
|
|
rpc_request::{
|
2020-06-09 08:43:16 -07:00
|
|
|
DELINQUENT_VALIDATOR_SLOT_DISTANCE, MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE,
|
2020-05-12 21:05:05 -06:00
|
|
|
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS, 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-06-17 09:27:03 -06:00
|
|
|
use solana_ledger::{blockstore::Blockstore, blockstore_db::BlockstoreError, get_tmp_ledger_path};
|
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,
|
|
|
|
bank::Bank,
|
|
|
|
bank_forks::BankForks,
|
|
|
|
commitment::{BlockCommitmentArray, BlockCommitmentCache},
|
|
|
|
log_collector::LogCollector,
|
2020-07-09 12:28:26 -06:00
|
|
|
send_transaction_service::SendTransactionService,
|
2020-06-17 09:27:03 -06:00
|
|
|
};
|
2019-10-14 16:24:10 -06:00
|
|
|
use solana_sdk::{
|
2020-07-06 13:28:40 -06:00
|
|
|
account_utils::StateMut,
|
2020-07-01 15:43:25 -07:00
|
|
|
clock::{Slot, UnixTimestamp},
|
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,
|
2019-11-14 16:34:39 -07:00
|
|
|
signature::Signature,
|
2020-07-06 13:28:40 -06:00
|
|
|
stake_history::StakeHistory,
|
|
|
|
sysvar::{stake_history, Sysvar},
|
2019-11-26 00:40:36 -07:00
|
|
|
timing::slot_duration_from_slots_per_year,
|
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::{
|
2020-07-01 14:06:40 -06:00
|
|
|
ConfirmedBlock, ConfirmedTransaction, 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};
|
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-06-13 13:20:08 -07:00
|
|
|
rc::Rc,
|
2020-03-06 17:01:31 -07:00
|
|
|
str::FromStr,
|
2020-06-16 23:30:59 -06:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
Arc, RwLock,
|
|
|
|
},
|
2019-10-14 16:24:10 -06:00
|
|
|
};
|
2018-08-10 17:05:23 -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-02-11 18:01:49 -07:00
|
|
|
pub enable_validator_exit: bool,
|
2020-03-06 17:03:10 -07:00
|
|
|
pub enable_set_log_filter: bool,
|
2020-03-23 11:25:39 -06:00
|
|
|
pub enable_rpc_transaction_history: 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,
|
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,
|
2019-08-20 23:59:31 -07:00
|
|
|
validator_exit: Arc<RwLock<Option<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-06-05 21:23:13 -07:00
|
|
|
send_transaction_service: Arc<SendTransactionService>,
|
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 {
|
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
|
|
|
|
2020-06-25 17:08:55 -06:00
|
|
|
let commitment_level = match commitment {
|
|
|
|
None => CommitmentLevel::Max,
|
|
|
|
Some(config) => config.commitment,
|
|
|
|
};
|
|
|
|
|
2020-07-03 17:39:14 -06:00
|
|
|
let slot = match commitment_level {
|
2020-06-25 17:08:55 -06:00
|
|
|
CommitmentLevel::Recent => {
|
2020-07-03 17:39:14 -06:00
|
|
|
let slot = r_bank_forks.highest_slot();
|
|
|
|
debug!("RPC using working_bank: {:?}", slot);
|
|
|
|
slot
|
2020-05-18 12:49:01 -06:00
|
|
|
}
|
2020-06-25 17:08:55 -06:00
|
|
|
CommitmentLevel::Root => {
|
2020-05-18 12:49:01 -06:00
|
|
|
let slot = r_bank_forks.root();
|
|
|
|
debug!("RPC using node root: {:?}", slot);
|
2020-07-03 17:39:14 -06:00
|
|
|
slot
|
2020-05-18 12:49:01 -06:00
|
|
|
}
|
2020-06-25 17:08:55 -06:00
|
|
|
CommitmentLevel::Single | CommitmentLevel::SingleGossip => {
|
2020-05-18 12:49:01 -06:00
|
|
|
let slot = self
|
|
|
|
.block_commitment_cache
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.highest_confirmed_slot();
|
|
|
|
debug!("RPC using confirmed slot: {:?}", slot);
|
2020-07-03 17:39:14 -06:00
|
|
|
slot
|
2020-05-18 12:49:01 -06:00
|
|
|
}
|
2020-06-25 17:08:55 -06:00
|
|
|
CommitmentLevel::Max => {
|
2020-07-03 17:39:14 -06:00
|
|
|
let slot = self
|
2020-05-18 12:49:01 -06:00
|
|
|
.block_commitment_cache
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2020-07-07 17:59:46 -06:00
|
|
|
.highest_confirmed_root();
|
2020-07-03 17:39:14 -06:00
|
|
|
debug!("RPC using block: {:?}", slot);
|
|
|
|
slot
|
2020-05-18 12:49:01 -06:00
|
|
|
}
|
2020-07-03 17:39:14 -06:00
|
|
|
};
|
|
|
|
r_bank_forks.get(slot).cloned().unwrap()
|
2019-02-20 21:23:44 -08:00
|
|
|
}
|
|
|
|
|
2019-03-03 22:01:09 -08:00
|
|
|
pub fn new(
|
|
|
|
config: JsonRpcConfig,
|
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-12-19 23:27:54 -08:00
|
|
|
validator_exit: Arc<RwLock<Option<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-06-05 21:23:13 -07:00
|
|
|
send_transaction_service: Arc<SendTransactionService>,
|
2019-03-03 22:01:09 -08:00
|
|
|
) -> Self {
|
2020-06-07 21:54:03 -06:00
|
|
|
Self {
|
2019-11-11 13:18:34 -05:00
|
|
|
config,
|
2019-03-18 14:18:43 -07:00
|
|
|
bank_forks,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache,
|
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
|
|
|
health,
|
2020-06-07 21:54:03 -06:00
|
|
|
cluster_info,
|
|
|
|
genesis_hash,
|
2020-06-05 21:23:13 -07:00
|
|
|
send_transaction_service,
|
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-06-16 23:30:59 -06:00
|
|
|
Self {
|
|
|
|
config: JsonRpcConfig::default(),
|
|
|
|
bank_forks: bank_forks.clone(),
|
|
|
|
block_commitment_cache: Arc::new(RwLock::new(BlockCommitmentCache::new(
|
|
|
|
HashMap::new(),
|
|
|
|
0,
|
|
|
|
0,
|
2020-07-08 18:50:13 -06:00
|
|
|
bank.slot(),
|
2020-06-16 23:30:59 -06:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
))),
|
|
|
|
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,
|
|
|
|
send_transaction_service: Arc::new(SendTransactionService::new(
|
2020-07-08 19:13:42 -06:00
|
|
|
tpu_address,
|
2020-06-16 23:30:59 -06:00
|
|
|
&bank_forks,
|
|
|
|
&exit,
|
|
|
|
)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-07-03 17:39:14 -06:00
|
|
|
) -> 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);
|
|
|
|
new_response(
|
|
|
|
&bank,
|
|
|
|
bank.get_account(pubkey)
|
|
|
|
.map(|account| UiAccount::encode(account, encoding)),
|
|
|
|
)
|
2018-10-25 16:58:40 -07:00
|
|
|
}
|
2019-02-26 12:25:46 -08: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-07-03 17:39:14 -06:00
|
|
|
) -> 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-07-03 17:39:14 -06:00
|
|
|
bank.get_program_accounts(Some(&program_id))
|
2019-06-29 10:59:07 -06:00
|
|
|
.into_iter()
|
2020-07-03 01:46:29 -06:00
|
|
|
.filter(|(_, account)| {
|
|
|
|
filters.iter().all(|filter_type| match filter_type {
|
|
|
|
RpcFilterType::DataSize(size) => account.data.len() as u64 == *size,
|
|
|
|
RpcFilterType::Memcmp(compare) => compare.bytes_match(&account.data),
|
|
|
|
})
|
|
|
|
})
|
2020-01-15 00:25:45 -07:00
|
|
|
.map(|(pubkey, account)| RpcKeyedAccount {
|
|
|
|
pubkey: pubkey.to_string(),
|
2020-06-30 22:55:11 -06:00
|
|
|
account: UiAccount::encode(account, encoding.clone()),
|
2020-01-15 00:25:45 -07:00
|
|
|
})
|
2020-07-03 17:39:14 -06:00
|
|
|
.collect()
|
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-05-29 12:50:25 -06:00
|
|
|
let year =
|
|
|
|
(bank.epoch_schedule().get_last_slot_in_epoch(epoch)) as f64 / bank.slots_per_year();
|
|
|
|
|
2020-07-03 17:39:14 -06:00
|
|
|
RpcInflationRate {
|
2020-05-29 12:50:25 -06:00
|
|
|
total: inflation.total(year),
|
|
|
|
validator: inflation.validator(year),
|
|
|
|
foundation: inflation.foundation(year),
|
|
|
|
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
|
2020-07-03 17:39:14 -06:00
|
|
|
let bank = self.bank(Some(CommitmentConfig::root()));
|
|
|
|
*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
|
|
|
}
|
|
|
|
|
2020-07-03 17:39:14 -06:00
|
|
|
fn get_slot(&self, commitment: Option<CommitmentConfig>) -> u64 {
|
|
|
|
self.bank(commitment).slot()
|
2019-06-12 16:43:05 -07:00
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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);
|
2020-05-12 21:05:05 -06:00
|
|
|
let (addresses, address_filter) = if let Some(filter) = config.filter {
|
2020-05-20 20:04:07 -07:00
|
|
|
let non_circulating_supply = calculate_non_circulating_supply(&bank);
|
2020-05-12 21:05:05 -06:00
|
|
|
let addresses = non_circulating_supply.accounts.into_iter().collect();
|
|
|
|
let address_filter = match filter {
|
|
|
|
RpcLargestAccountsFilter::Circulating => AccountAddressFilter::Exclude,
|
|
|
|
RpcLargestAccountsFilter::NonCirculating => AccountAddressFilter::Include,
|
|
|
|
};
|
|
|
|
(addresses, address_filter)
|
|
|
|
} else {
|
|
|
|
(HashSet::new(), AccountAddressFilter::Exclude)
|
|
|
|
};
|
2020-05-04 17:46:10 -06:00
|
|
|
new_response(
|
|
|
|
&bank,
|
2020-05-12 21:05:05 -06:00
|
|
|
bank.get_largest_accounts(NUM_LARGEST_ACCOUNTS, &addresses, address_filter)
|
|
|
|
.into_iter()
|
|
|
|
.map(|(address, lamports)| RpcAccountBalance {
|
|
|
|
address: address.to_string(),
|
|
|
|
lamports,
|
|
|
|
})
|
|
|
|
.collect(),
|
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)?;
|
|
|
|
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))| {
|
|
|
|
let vote_state = VoteState::from(&account).unwrap_or_default();
|
|
|
|
let last_vote = if let Some(vote) = vote_state.votes.iter().last() {
|
|
|
|
vote.slot
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
|
|
|
let epoch_vote_account = epoch_vote_accounts
|
|
|
|
.iter()
|
|
|
|
.any(|(epoch_vote_pubkey, _)| epoch_vote_pubkey == pubkey);
|
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(),
|
2019-08-16 17:02:19 -06:00
|
|
|
epoch_vote_account,
|
|
|
|
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-07-03 17:39:14 -06:00
|
|
|
pub fn set_log_filter(&self, filter: String) {
|
2020-03-06 17:03:10 -07:00
|
|
|
if self.config.enable_set_log_filter {
|
|
|
|
solana_logger::setup_with(&filter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-03 17:39:14 -06:00
|
|
|
pub fn validator_exit(&self) -> bool {
|
2019-10-11 13:30:52 -06:00
|
|
|
if self.config.enable_validator_exit {
|
|
|
|
warn!("validator_exit request...");
|
2019-08-20 23:59:31 -07:00
|
|
|
if let Some(x) = self.validator_exit.write().unwrap().take() {
|
|
|
|
x.exit()
|
|
|
|
}
|
2020-07-03 17:39:14 -06:00
|
|
|
true
|
2019-03-05 21:12:30 -08:00
|
|
|
} else {
|
2019-10-11 13:30:52 -06:00
|
|
|
debug!("validator_exit ignored");
|
2020-07-03 17:39:14 -06:00
|
|
|
false
|
2019-03-03 22:01:09 -08:00
|
|
|
}
|
|
|
|
}
|
2019-11-11 13:18:34 -05:00
|
|
|
|
2020-05-11 15:47:40 -06:00
|
|
|
fn check_slot_cleaned_up<T>(
|
|
|
|
&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(())
|
|
|
|
}
|
|
|
|
|
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-03-26 13:29:30 -07:00
|
|
|
) -> Result<Option<ConfirmedBlock>> {
|
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
|
|
|
{
|
2020-05-11 15:47:40 -06:00
|
|
|
let result = self.blockstore.get_confirmed_block(slot, encoding);
|
|
|
|
self.check_slot_cleaned_up(&result, slot)?;
|
|
|
|
Ok(result.ok())
|
2020-02-11 18:01:49 -07:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
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-04-22 14:33:06 -06:00
|
|
|
Ok(self
|
|
|
|
.blockstore
|
2020-04-28 10:22:10 -06:00
|
|
|
.rooted_slot_iterator(max(start_slot, self.blockstore.lowest_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
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
// This calculation currently assumes that bank.slots_per_year will remain unchanged after
|
|
|
|
// genesis (ie. that this bank's slot_per_year will be applicable to any rooted slot being
|
|
|
|
// queried). If these values will be variable in the future, those timing parameters will
|
|
|
|
// need to be stored persistently, and the slot_duration calculation will likely need to be
|
|
|
|
// moved upstream into blockstore. Also, an explicit commitment level will need to be set.
|
2020-07-03 17:39:14 -06:00
|
|
|
let bank = self.bank(None);
|
2020-05-04 19:39:27 -06:00
|
|
|
let slot_duration = slot_duration_from_slots_per_year(bank.slots_per_year());
|
|
|
|
let epoch = bank.epoch_schedule().get_epoch(slot);
|
|
|
|
let stakes = HashMap::new();
|
|
|
|
let stakes = bank.epoch_vote_accounts(epoch).unwrap_or(&stakes);
|
2019-11-26 00:40:36 -07:00
|
|
|
|
2020-05-11 15:47:40 -06:00
|
|
|
let result = self.blockstore.get_block_time(slot, slot_duration, stakes);
|
|
|
|
self.check_slot_cleaned_up(&result, slot)?;
|
|
|
|
Ok(result.ok().unwrap_or(None))
|
2020-05-04 19:39:27 -06:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
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);
|
2020-07-03 17:39:14 -06:00
|
|
|
let bank = self.bank(Some(CommitmentConfig::recent()));
|
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,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2020-03-23 11:25:39 -06:00
|
|
|
statuses.push(status);
|
|
|
|
}
|
2020-03-26 19:21:01 -06:00
|
|
|
Ok(Response {
|
|
|
|
context: RpcResponseContext { slot: bank.slot() },
|
|
|
|
value: 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();
|
|
|
|
|
|
|
|
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,
|
|
|
|
})
|
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-07-03 17:39:14 -06:00
|
|
|
) -> Option<ConfirmedTransaction> {
|
2020-04-09 00:57:30 -06:00
|
|
|
if self.config.enable_rpc_transaction_history {
|
2020-07-03 17:39:14 -06:00
|
|
|
self.blockstore
|
2020-04-09 00:57:30 -06:00
|
|
|
.get_confirmed_transaction(signature, encoding)
|
2020-05-04 19:39:27 -06:00
|
|
|
.unwrap_or(None)
|
|
|
|
.filter(|confirmed_transaction| {
|
|
|
|
confirmed_transaction.slot
|
|
|
|
<= self
|
|
|
|
.block_commitment_cache
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2020-07-07 17:59:46 -06:00
|
|
|
.highest_confirmed_root()
|
2020-07-03 17:39:14 -06:00
|
|
|
})
|
2020-04-09 00:57:30 -06:00
|
|
|
} else {
|
2020-07-03 17:39:14 -06: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-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-03 17:39:14 -06:00
|
|
|
pub fn get_first_available_block(&self) -> Slot {
|
|
|
|
self.blockstore
|
2020-04-22 14:33:06 -06:00
|
|
|
.get_first_available_block()
|
2020-07-03 17:39:14 -06:00
|
|
|
.unwrap_or_default()
|
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 =
|
|
|
|
StakeHistory::from_account(&stake_history_account).ok_or_else(Error::internal_error)?;
|
|
|
|
|
|
|
|
let (active, activating, deactivating) =
|
|
|
|
delegation.stake_activating_and_deactivating(epoch, Some(&stake_history));
|
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
2019-02-17 10:29:08 -07:00
|
|
|
}
|
2018-10-25 16:58:40 -07:00
|
|
|
|
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-05-29 23:16:35 -07:00
|
|
|
/// Run transactions against a frozen bank without committing the results
|
2020-06-06 10:18:28 -07:00
|
|
|
fn run_transaction_simulation(
|
|
|
|
bank: &Bank,
|
|
|
|
transaction: Transaction,
|
|
|
|
) -> (transaction::Result<()>, Vec<String>) {
|
2020-06-01 13:53:37 -07:00
|
|
|
assert!(bank.is_frozen(), "simulation bank must be frozen");
|
2020-05-29 23:16:35 -07:00
|
|
|
|
2020-06-05 10:06:01 +08:00
|
|
|
let txs = &[transaction];
|
|
|
|
let batch = bank.prepare_simulation_batch(txs);
|
2020-06-13 13:20:08 -07:00
|
|
|
let log_collector = Rc::new(LogCollector::default());
|
|
|
|
let (_loaded_accounts, executed, _retryable_transactions, _transaction_count, _signature_count) = {
|
2020-06-06 10:18:28 -07:00
|
|
|
bank.load_and_execute_transactions(
|
|
|
|
&batch,
|
|
|
|
solana_sdk::clock::MAX_PROCESSING_AGE,
|
2020-06-13 13:20:08 -07:00
|
|
|
Some(log_collector.clone()),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
(
|
|
|
|
executed[0].0.clone().map(|_| ()),
|
|
|
|
Rc::try_unwrap(log_collector).unwrap_or_default().into(),
|
|
|
|
)
|
2020-05-29 23:16:35 -07:00
|
|
|
}
|
|
|
|
|
2020-06-11 16:51:25 -06:00
|
|
|
#[rpc]
|
2019-02-04 17:41:03 -07:00
|
|
|
pub trait RpcSol {
|
|
|
|
type Metadata;
|
2018-08-10 17:05:23 -06:00
|
|
|
|
2020-04-05 14:31:24 +08:00
|
|
|
// DEPRECATED
|
2019-02-04 17:41:03 -07:00
|
|
|
#[rpc(meta, name = "confirmTransaction")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn confirm_transaction(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
signature_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<bool>>;
|
2018-08-10 17:05:23 -06:00
|
|
|
|
2020-04-05 14:31:24 +08:00
|
|
|
// 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>>;
|
|
|
|
|
2019-02-04 17:41:03 -07:00
|
|
|
#[rpc(meta, name = "getAccountInfo")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_account_info(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
pubkey_str: String,
|
2020-06-30 22:55:11 -06:00
|
|
|
config: Option<RpcAccountInfoConfig>,
|
|
|
|
) -> Result<RpcResponse<Option<UiAccount>>>;
|
2018-09-20 23:27:06 -06:00
|
|
|
|
2019-06-29 10:59:07 -06:00
|
|
|
#[rpc(meta, name = "getProgramAccounts")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_program_accounts(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
program_id_str: String,
|
2020-07-03 01:46:29 -06:00
|
|
|
config: Option<RpcProgramAccountsConfig>,
|
2020-01-15 00:25:45 -07:00
|
|
|
) -> Result<Vec<RpcKeyedAccount>>;
|
2019-06-29 10:59:07 -06:00
|
|
|
|
2019-09-26 23:27:13 +05:30
|
|
|
#[rpc(meta, name = "getMinimumBalanceForRentExemption")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_minimum_balance_for_rent_exemption(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
data_len: usize,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<u64>;
|
2019-09-26 23:27:13 +05:30
|
|
|
|
2020-05-29 12:50:25 -06:00
|
|
|
#[rpc(meta, name = "getInflationGovernor")]
|
|
|
|
fn get_inflation_governor(
|
2019-11-06 14:15:00 -07:00
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-05-29 12:50:25 -06:00
|
|
|
) -> Result<RpcInflationGovernor>;
|
|
|
|
|
|
|
|
#[rpc(meta, name = "getInflationRate")]
|
2020-07-01 15:43:25 -07:00
|
|
|
fn get_inflation_rate(&self, meta: Self::Metadata) -> Result<RpcInflationRate>;
|
2019-08-27 18:17:03 -04:00
|
|
|
|
2019-10-22 16:41:18 -04:00
|
|
|
#[rpc(meta, name = "getEpochSchedule")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_epoch_schedule(&self, meta: Self::Metadata) -> Result<EpochSchedule>;
|
2019-10-22 16:41:18 -04:00
|
|
|
|
2019-02-04 17:41:03 -07:00
|
|
|
#[rpc(meta, name = "getBalance")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_balance(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
pubkey_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<u64>>;
|
2018-08-14 18:03:48 -06:00
|
|
|
|
2019-04-23 14:46:41 -07:00
|
|
|
#[rpc(meta, name = "getClusterNodes")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>>;
|
2019-04-23 14:46:41 -07:00
|
|
|
|
2019-07-19 07:31:18 -07:00
|
|
|
#[rpc(meta, name = "getEpochInfo")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_epoch_info(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-05-20 16:42:46 -07:00
|
|
|
) -> Result<EpochInfo>;
|
2019-07-19 07:31:18 -07:00
|
|
|
|
2019-11-04 16:44:27 -07:00
|
|
|
#[rpc(meta, name = "getBlockCommitment")]
|
|
|
|
fn get_block_commitment(
|
2019-10-14 16:24:10 -06:00
|
|
|
&self,
|
2019-11-06 14:15:00 -07:00
|
|
|
meta: Self::Metadata,
|
2019-12-17 16:26:31 -07:00
|
|
|
block: Slot,
|
2020-04-20 23:25:49 -06:00
|
|
|
) -> Result<RpcBlockCommitment<BlockCommitmentArray>>;
|
2019-10-14 16:24:10 -06:00
|
|
|
|
2019-11-08 23:56:57 -05:00
|
|
|
#[rpc(meta, name = "getGenesisHash")]
|
|
|
|
fn get_genesis_hash(&self, meta: Self::Metadata) -> Result<String>;
|
2019-08-21 18:16:40 -07:00
|
|
|
|
2019-07-19 07:31:18 -07:00
|
|
|
#[rpc(meta, name = "getLeaderSchedule")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_leader_schedule(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2019-12-17 16:26:31 -07:00
|
|
|
slot: Option<Slot>,
|
2019-11-06 14:15:00 -07:00
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-12-18 12:42:58 -07:00
|
|
|
) -> Result<Option<RpcLeaderSchedule>>;
|
2019-07-19 07:31:18 -07:00
|
|
|
|
2019-03-02 10:25:16 -08:00
|
|
|
#[rpc(meta, name = "getRecentBlockhash")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_recent_blockhash(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<RpcBlockhashFeeCalculator>>;
|
2018-08-13 12:52:37 -06:00
|
|
|
|
2020-05-26 13:06:21 -06:00
|
|
|
#[rpc(meta, name = "getFees")]
|
|
|
|
fn get_fees(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<RpcFees>>;
|
2020-05-26 13:06:21 -06:00
|
|
|
|
2020-03-06 17:01:31 -07:00
|
|
|
#[rpc(meta, name = "getFeeCalculatorForBlockhash")]
|
|
|
|
fn get_fee_calculator_for_blockhash(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
blockhash: String,
|
2020-05-26 17:23:58 -06:00
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<Option<RpcFeeCalculator>>>;
|
2020-03-06 17:01:31 -07:00
|
|
|
|
2020-02-28 13:27:01 -07:00
|
|
|
#[rpc(meta, name = "getFeeRateGovernor")]
|
2020-06-11 16:51:25 -06:00
|
|
|
fn get_fee_rate_governor(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
) -> Result<RpcResponse<RpcFeeRateGovernor>>;
|
2020-02-28 13:27:01 -07:00
|
|
|
|
2020-04-02 02:30:58 +08:00
|
|
|
#[rpc(meta, name = "getSignatureStatuses")]
|
2020-04-06 04:04:54 -06:00
|
|
|
fn get_signature_statuses(
|
2019-04-05 19:07:30 -06:00
|
|
|
&self,
|
2019-11-06 14:15:00 -07:00
|
|
|
meta: Self::Metadata,
|
2020-03-23 11:25:39 -06:00
|
|
|
signature_strs: Vec<String>,
|
2020-04-06 04:04:54 -06:00
|
|
|
config: Option<RpcSignatureStatusConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<Vec<Option<TransactionStatus>>>>;
|
2018-09-26 17:12:40 -07:00
|
|
|
|
2019-06-12 16:43:05 -07:00
|
|
|
#[rpc(meta, name = "getSlot")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64>;
|
2019-06-12 16:43:05 -07:00
|
|
|
|
2019-02-04 17:41:03 -07:00
|
|
|
#[rpc(meta, name = "getTransactionCount")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_transaction_count(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<u64>;
|
2018-08-10 17:05:23 -06:00
|
|
|
|
2020-05-09 12:05:29 -06:00
|
|
|
// DEPRECATED
|
2019-06-21 22:00:26 -06:00
|
|
|
#[rpc(meta, name = "getTotalSupply")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_total_supply(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<u64>;
|
2019-06-21 22:00:26 -06:00
|
|
|
|
2020-05-04 17:46:10 -06:00
|
|
|
#[rpc(meta, name = "getLargestAccounts")]
|
|
|
|
fn get_largest_accounts(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2020-05-12 21:05:05 -06:00
|
|
|
config: Option<RpcLargestAccountsConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<Vec<RpcAccountBalance>>>;
|
2020-05-04 17:46:10 -06:00
|
|
|
|
2020-05-09 12:05:29 -06:00
|
|
|
#[rpc(meta, name = "getSupply")]
|
|
|
|
fn get_supply(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<RpcSupply>>;
|
2020-05-09 12:05:29 -06:00
|
|
|
|
2019-02-04 17:41:03 -07:00
|
|
|
#[rpc(meta, name = "requestAirdrop")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn request_airdrop(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
pubkey_str: String,
|
|
|
|
lamports: u64,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<String>;
|
2018-08-22 11:54:37 -06:00
|
|
|
|
2019-02-04 17:41:03 -07:00
|
|
|
#[rpc(meta, name = "sendTransaction")]
|
2020-05-29 23:16:35 -07:00
|
|
|
fn send_transaction(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
data: String,
|
|
|
|
config: Option<RpcSendTransactionConfig>,
|
|
|
|
) -> Result<String>;
|
2018-11-02 08:40:29 -07:00
|
|
|
|
2020-05-19 12:08:19 -07:00
|
|
|
#[rpc(meta, name = "simulateTransaction")]
|
|
|
|
fn simulate_transaction(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
data: String,
|
|
|
|
config: Option<RpcSimulateTransactionConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<RpcSimulateTransactionResult>>;
|
2020-05-19 12:08:19 -07:00
|
|
|
|
2019-04-23 14:46:41 -07:00
|
|
|
#[rpc(meta, name = "getSlotLeader")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_slot_leader(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<String>;
|
2019-04-23 14:46:41 -07:00
|
|
|
|
2020-01-21 13:05:04 -07:00
|
|
|
#[rpc(meta, name = "minimumLedgerSlot")]
|
|
|
|
fn minimum_ledger_slot(&self, meta: Self::Metadata) -> Result<Slot>;
|
|
|
|
|
2019-08-16 17:02:19 -06:00
|
|
|
#[rpc(meta, name = "getVoteAccounts")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_vote_accounts(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<RpcVoteAccountStatus>;
|
2019-05-20 22:21:13 -07:00
|
|
|
|
2019-10-11 13:30:52 -06:00
|
|
|
#[rpc(meta, name = "validatorExit")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn validator_exit(&self, meta: Self::Metadata) -> Result<bool>;
|
2019-03-21 07:43:21 -07:00
|
|
|
|
2020-03-04 14:44:21 -08:00
|
|
|
#[rpc(meta, name = "getIdentity")]
|
|
|
|
fn get_identity(&self, meta: Self::Metadata) -> Result<RpcIdentity>;
|
|
|
|
|
2019-08-07 20:06:27 -06:00
|
|
|
#[rpc(meta, name = "getVersion")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_version(&self, meta: Self::Metadata) -> Result<RpcVersionInfo>;
|
2019-08-10 22:54:46 -07:00
|
|
|
|
|
|
|
#[rpc(meta, name = "setLogFilter")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn set_log_filter(&self, _meta: Self::Metadata, filter: String) -> Result<()>;
|
2019-11-11 13:18:34 -05:00
|
|
|
|
2019-11-19 09:39:55 -07:00
|
|
|
#[rpc(meta, name = "getConfirmedBlock")]
|
2019-11-14 14:14:42 -07:00
|
|
|
fn get_confirmed_block(
|
2019-11-11 13:18:34 -05:00
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
slot: Slot,
|
2020-07-01 14:06:40 -06:00
|
|
|
encoding: Option<UiTransactionEncoding>,
|
2020-03-26 13:29:30 -07:00
|
|
|
) -> Result<Option<ConfirmedBlock>>;
|
2019-11-26 00:40:36 -07:00
|
|
|
|
|
|
|
#[rpc(meta, name = "getBlockTime")]
|
|
|
|
fn get_block_time(&self, meta: Self::Metadata, slot: Slot) -> Result<Option<UnixTimestamp>>;
|
2019-12-18 16:51:47 -07:00
|
|
|
|
|
|
|
#[rpc(meta, name = "getConfirmedBlocks")]
|
|
|
|
fn get_confirmed_blocks(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
start_slot: Slot,
|
|
|
|
end_slot: Option<Slot>,
|
|
|
|
) -> Result<Vec<Slot>>;
|
2020-04-09 00:57:30 -06:00
|
|
|
|
|
|
|
#[rpc(meta, name = "getConfirmedTransaction")]
|
|
|
|
fn get_confirmed_transaction(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
signature_str: String,
|
2020-07-01 14:06:40 -06:00
|
|
|
encoding: Option<UiTransactionEncoding>,
|
2020-04-09 00:57:30 -06:00
|
|
|
) -> Result<Option<ConfirmedTransaction>>;
|
2020-04-09 21:21:31 -06:00
|
|
|
|
|
|
|
#[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>>;
|
2020-04-22 14:33:06 -06:00
|
|
|
|
|
|
|
#[rpc(meta, name = "getFirstAvailableBlock")]
|
|
|
|
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot>;
|
2020-07-06 13:28:40 -06:00
|
|
|
|
|
|
|
#[rpc(meta, name = "getStakeActivation")]
|
|
|
|
fn get_stake_activation(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
pubkey_str: String,
|
|
|
|
config: Option<RpcStakeConfig>,
|
|
|
|
) -> Result<RpcStakeActivation>;
|
2018-08-10 17:05:23 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct RpcSolImpl;
|
|
|
|
impl RpcSol for RpcSolImpl {
|
2020-06-07 21:54:03 -06:00
|
|
|
type Metadata = JsonRpcRequestProcessor;
|
2018-08-10 17:05:23 -06:00
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn confirm_transaction(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2019-11-12 14:49:41 -05:00
|
|
|
id: String,
|
2019-11-06 14:15:00 -07:00
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<bool>> {
|
2019-11-12 14:49:41 -05:00
|
|
|
debug!("confirm_transaction rpc request received: {:?}", id);
|
2020-06-25 17:08:55 -06:00
|
|
|
let signature = verify_signature(&id)?;
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.confirm_transaction(&signature, commitment))
|
2018-08-10 17:05:23 -06:00
|
|
|
}
|
2018-09-26 17:12:40 -07:00
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_account_info(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
pubkey_str: String,
|
2020-06-30 22:55:11 -06:00
|
|
|
config: Option<RpcAccountInfoConfig>,
|
|
|
|
) -> Result<RpcResponse<Option<UiAccount>>> {
|
2019-11-06 14:15:00 -07:00
|
|
|
debug!("get_account_info rpc request received: {:?}", pubkey_str);
|
2020-06-25 17:08:55 -06:00
|
|
|
let pubkey = verify_pubkey(pubkey_str)?;
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_account_info(&pubkey, config))
|
2018-09-20 23:27:06 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2019-09-26 23:27:13 +05:30
|
|
|
fn get_minimum_balance_for_rent_exemption(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
data_len: usize,
|
2019-11-06 14:15:00 -07:00
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-09-26 23:27:13 +05:30
|
|
|
) -> Result<u64> {
|
|
|
|
debug!(
|
|
|
|
"get_minimum_balance_for_rent_exemption rpc request received: {:?}",
|
|
|
|
data_len
|
|
|
|
);
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_minimum_balance_for_rent_exemption(data_len, commitment))
|
2019-09-26 23:27:13 +05:30
|
|
|
}
|
|
|
|
|
2019-06-29 10:59:07 -06:00
|
|
|
fn get_program_accounts(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2019-11-06 14:15:00 -07:00
|
|
|
program_id_str: String,
|
2020-07-03 01:46:29 -06:00
|
|
|
config: Option<RpcProgramAccountsConfig>,
|
2020-01-15 00:25:45 -07:00
|
|
|
) -> Result<Vec<RpcKeyedAccount>> {
|
2019-11-06 14:15:00 -07:00
|
|
|
debug!(
|
|
|
|
"get_program_accounts rpc request received: {:?}",
|
|
|
|
program_id_str
|
|
|
|
);
|
|
|
|
let program_id = verify_pubkey(program_id_str)?;
|
2020-07-03 01:46:29 -06:00
|
|
|
let (config, filters) = if let Some(config) = config {
|
|
|
|
(
|
|
|
|
Some(config.account_config),
|
|
|
|
config.filters.unwrap_or_default(),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
(None, vec![])
|
|
|
|
};
|
|
|
|
for filter in &filters {
|
|
|
|
verify_filter(filter)?;
|
|
|
|
}
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_program_accounts(&program_id, config, filters))
|
2019-06-29 10:59:07 -06:00
|
|
|
}
|
|
|
|
|
2020-05-29 12:50:25 -06:00
|
|
|
fn get_inflation_governor(
|
2019-11-06 14:15:00 -07:00
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-05-29 12:50:25 -06:00
|
|
|
) -> Result<RpcInflationGovernor> {
|
|
|
|
debug!("get_inflation_governor rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_inflation_governor(commitment))
|
2020-05-29 12:50:25 -06:00
|
|
|
}
|
|
|
|
|
2020-07-01 15:43:25 -07:00
|
|
|
fn get_inflation_rate(&self, meta: Self::Metadata) -> Result<RpcInflationRate> {
|
2020-05-29 12:50:25 -06:00
|
|
|
debug!("get_inflation_rate rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_inflation_rate())
|
2019-08-27 18:17:03 -04:00
|
|
|
}
|
|
|
|
|
2019-10-22 16:41:18 -04:00
|
|
|
fn get_epoch_schedule(&self, meta: Self::Metadata) -> Result<EpochSchedule> {
|
|
|
|
debug!("get_epoch_schedule rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_epoch_schedule())
|
2019-10-22 16:41:18 -04:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_balance(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
pubkey_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<u64>> {
|
2019-11-06 14:15:00 -07:00
|
|
|
debug!("get_balance rpc request received: {:?}", pubkey_str);
|
2020-06-25 17:08:55 -06:00
|
|
|
let pubkey = verify_pubkey(pubkey_str)?;
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_balance(&pubkey, commitment))
|
2018-08-10 17:05:23 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2019-04-23 14:46:41 -07:00
|
|
|
fn get_cluster_nodes(&self, meta: Self::Metadata) -> Result<Vec<RpcContactInfo>> {
|
2020-04-21 12:54:45 -07:00
|
|
|
let cluster_info = &meta.cluster_info;
|
2019-04-23 14:46:41 -07:00
|
|
|
fn valid_address_or_none(addr: &SocketAddr) -> Option<SocketAddr> {
|
|
|
|
if ContactInfo::is_valid_address(addr) {
|
|
|
|
Some(*addr)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2020-04-21 12:54:45 -07:00
|
|
|
let my_shred_version = cluster_info.my_shred_version();
|
2019-04-23 14:46:41 -07:00
|
|
|
Ok(cluster_info
|
|
|
|
.all_peers()
|
|
|
|
.iter()
|
2019-04-29 13:19:24 -07:00
|
|
|
.filter_map(|(contact_info, _)| {
|
2020-04-21 12:54:45 -07:00
|
|
|
if my_shred_version == contact_info.shred_version
|
2020-01-28 11:14:25 -07:00
|
|
|
&& ContactInfo::is_valid_address(&contact_info.gossip)
|
|
|
|
{
|
2019-04-23 14:46:41 -07:00
|
|
|
Some(RpcContactInfo {
|
2019-06-12 14:12:08 -07:00
|
|
|
pubkey: contact_info.id.to_string(),
|
2019-04-23 14:46:41 -07:00
|
|
|
gossip: Some(contact_info.gossip),
|
|
|
|
tpu: valid_address_or_none(&contact_info.tpu),
|
|
|
|
rpc: valid_address_or_none(&contact_info.rpc),
|
2020-05-11 21:30:01 -07:00
|
|
|
version: cluster_info
|
|
|
|
.get_node_version(&contact_info.id)
|
|
|
|
.map(|v| v.to_string()),
|
2019-04-23 14:46:41 -07:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None // Exclude spy nodes
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect())
|
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_epoch_info(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-05-20 16:42:46 -07:00
|
|
|
) -> Result<EpochInfo> {
|
2020-07-03 17:39:14 -06:00
|
|
|
let bank = meta.bank(commitment);
|
2020-05-20 16:42:46 -07:00
|
|
|
Ok(bank.get_epoch_info())
|
2019-07-19 07:31:18 -07:00
|
|
|
}
|
|
|
|
|
2019-11-04 16:44:27 -07:00
|
|
|
fn get_block_commitment(
|
2019-10-14 16:24:10 -06:00
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2019-11-06 14:15:00 -07:00
|
|
|
block: Slot,
|
2020-04-20 23:25:49 -06:00
|
|
|
) -> Result<RpcBlockCommitment<BlockCommitmentArray>> {
|
2020-06-07 21:54:03 -06:00
|
|
|
Ok(meta.get_block_commitment(block))
|
2019-10-14 16:24:10 -06:00
|
|
|
}
|
|
|
|
|
2019-11-08 23:56:57 -05:00
|
|
|
fn get_genesis_hash(&self, meta: Self::Metadata) -> Result<String> {
|
|
|
|
debug!("get_genesis_hash rpc request received");
|
|
|
|
Ok(meta.genesis_hash.to_string())
|
2019-08-21 18:16:40 -07:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_leader_schedule(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2019-12-17 16:26:31 -07:00
|
|
|
slot: Option<Slot>,
|
2019-11-06 14:15:00 -07:00
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-12-18 12:42:58 -07:00
|
|
|
) -> Result<Option<RpcLeaderSchedule>> {
|
2020-07-03 17:39:14 -06:00
|
|
|
let bank = meta.bank(commitment);
|
2019-12-17 16:26:31 -07:00
|
|
|
let slot = slot.unwrap_or_else(|| bank.slot());
|
|
|
|
let epoch = bank.epoch_schedule().get_epoch(slot);
|
2019-12-18 12:42:58 -07:00
|
|
|
|
2019-07-19 07:31:18 -07:00
|
|
|
Ok(
|
2019-12-17 16:26:31 -07:00
|
|
|
solana_ledger::leader_schedule_utils::leader_schedule(epoch, &bank).map(
|
2019-07-19 07:31:18 -07:00
|
|
|
|leader_schedule| {
|
2019-12-18 12:42:58 -07:00
|
|
|
let mut map = HashMap::new();
|
|
|
|
|
|
|
|
for (slot_index, pubkey) in
|
|
|
|
leader_schedule.get_slot_leaders().iter().enumerate()
|
|
|
|
{
|
|
|
|
let pubkey = pubkey.to_string();
|
2020-06-09 01:38:14 +01:00
|
|
|
map.entry(pubkey).or_insert_with(Vec::new).push(slot_index);
|
2019-12-18 12:42:58 -07:00
|
|
|
}
|
|
|
|
map
|
2019-07-19 07:31:18 -07:00
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_recent_blockhash(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<RpcBlockhashFeeCalculator>> {
|
2019-03-28 11:45:34 -07:00
|
|
|
debug!("get_recent_blockhash rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_recent_blockhash(commitment))
|
2018-08-13 12:52:37 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2020-05-26 13:06:21 -06:00
|
|
|
fn get_fees(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<RpcFees>> {
|
2020-05-26 13:06:21 -06:00
|
|
|
debug!("get_fees rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_fees(commitment))
|
2020-05-26 13:06:21 -06:00
|
|
|
}
|
|
|
|
|
2020-03-06 17:01:31 -07:00
|
|
|
fn get_fee_calculator_for_blockhash(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
blockhash: String,
|
2020-05-26 17:23:58 -06:00
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<Option<RpcFeeCalculator>>> {
|
2020-03-06 17:01:31 -07:00
|
|
|
debug!("get_fee_calculator_for_blockhash rpc request received");
|
|
|
|
let blockhash =
|
|
|
|
Hash::from_str(&blockhash).map_err(|e| Error::invalid_params(format!("{:?}", e)))?;
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_fee_calculator_for_blockhash(&blockhash, commitment))
|
2020-03-06 17:01:31 -07:00
|
|
|
}
|
|
|
|
|
2020-06-11 16:51:25 -06:00
|
|
|
fn get_fee_rate_governor(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
) -> Result<RpcResponse<RpcFeeRateGovernor>> {
|
2020-02-28 13:27:01 -07:00
|
|
|
debug!("get_fee_rate_governor rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_fee_rate_governor())
|
2020-02-28 13:27:01 -07:00
|
|
|
}
|
|
|
|
|
2020-04-01 17:56:18 -06: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)?;
|
2020-06-07 21:54:03 -06:00
|
|
|
Ok(meta.get_signature_confirmation_status(signature, commitment))
|
2020-04-01 17:56:18 -06:00
|
|
|
}
|
|
|
|
|
2019-04-05 19:07:30 -06:00
|
|
|
fn get_signature_status(
|
2020-04-02 02:30:58 +08:00
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
signature_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Option<transaction::Result<()>>> {
|
|
|
|
let signature = verify_signature(&signature_str)?;
|
2020-06-07 21:54:03 -06:00
|
|
|
Ok(meta.get_signature_status(signature, commitment))
|
2020-04-02 02:30:58 +08:00
|
|
|
}
|
|
|
|
|
2020-04-06 04:04:54 -06:00
|
|
|
fn get_signature_statuses(
|
2019-04-05 19:07:30 -06:00
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2020-03-23 11:25:39 -06:00
|
|
|
signature_strs: Vec<String>,
|
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-04-20 22:01:09 -07:00
|
|
|
if signature_strs.len() > MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS {
|
2020-04-06 04:04:54 -06:00
|
|
|
return Err(Error::invalid_params(format!(
|
|
|
|
"Too many inputs provided; max {}",
|
2020-04-20 22:01:09 -07:00
|
|
|
MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS
|
2020-04-06 04:04:54 -06:00
|
|
|
)));
|
|
|
|
}
|
2020-03-23 11:25:39 -06:00
|
|
|
let mut signatures: Vec<Signature> = vec![];
|
|
|
|
for signature_str in signature_strs {
|
|
|
|
signatures.push(verify_signature(&signature_str)?);
|
|
|
|
}
|
2020-06-07 21:54:03 -06:00
|
|
|
meta.get_signature_statuses(signatures, config)
|
2019-03-21 07:43:21 -07:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_slot(&self, meta: Self::Metadata, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_slot(commitment))
|
2019-06-12 16:43:05 -07:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_transaction_count(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<u64> {
|
2019-03-28 11:45:34 -07:00
|
|
|
debug!("get_transaction_count rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_transaction_count(commitment))
|
2018-08-14 18:03:48 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_total_supply(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<u64> {
|
2019-06-21 22:00:26 -06:00
|
|
|
debug!("get_total_supply rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_total_supply(commitment))
|
2019-06-21 22:00:26 -06:00
|
|
|
}
|
|
|
|
|
2020-05-04 17:46:10 -06:00
|
|
|
fn get_largest_accounts(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2020-05-12 21:05:05 -06:00
|
|
|
config: Option<RpcLargestAccountsConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<Vec<RpcAccountBalance>>> {
|
2020-05-04 17:46:10 -06:00
|
|
|
debug!("get_largest_accounts rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_largest_accounts(config))
|
2020-05-04 17:46:10 -06:00
|
|
|
}
|
|
|
|
|
2020-05-09 12:05:29 -06:00
|
|
|
fn get_supply(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<RpcSupply>> {
|
2020-05-09 12:05:29 -06:00
|
|
|
debug!("get_supply rpc request received");
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_supply(commitment))
|
2020-05-09 12:05:29 -06:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn request_airdrop(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
pubkey_str: String,
|
|
|
|
lamports: u64,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<String> {
|
2019-11-10 12:20:52 -05:00
|
|
|
trace!(
|
|
|
|
"request_airdrop id={} lamports={} commitment: {:?}",
|
|
|
|
pubkey_str,
|
|
|
|
lamports,
|
|
|
|
&commitment
|
|
|
|
);
|
2019-03-06 09:26:12 -08:00
|
|
|
|
2020-06-07 21:54:03 -06:00
|
|
|
let faucet_addr = meta.config.faucet_addr.ok_or_else(Error::invalid_request)?;
|
2019-11-06 14:15:00 -07:00
|
|
|
let pubkey = verify_pubkey(pubkey_str)?;
|
2018-10-15 11:01:40 -06:00
|
|
|
|
2020-06-05 21:23:13 -07:00
|
|
|
let (blockhash, last_valid_slot) = {
|
2020-07-03 17:39:14 -06:00
|
|
|
let bank = meta.bank(commitment);
|
2020-06-05 21:23:13 -07:00
|
|
|
|
|
|
|
let blockhash = bank.confirmed_last_blockhash().0;
|
|
|
|
(
|
|
|
|
blockhash,
|
|
|
|
bank.get_blockhash_last_valid_slot(&blockhash).unwrap_or(0),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2019-12-16 14:05:17 -07:00
|
|
|
let transaction = request_airdrop_transaction(&faucet_addr, &pubkey, lamports, blockhash)
|
2019-03-06 09:26:12 -08:00
|
|
|
.map_err(|err| {
|
2019-12-16 14:05:17 -07:00
|
|
|
info!("request_airdrop_transaction failed: {:?}", err);
|
|
|
|
Error::internal_error()
|
|
|
|
})?;
|
2020-06-05 21:23:13 -07:00
|
|
|
let signature = transaction.signatures[0];
|
2018-11-14 18:57:34 -08:00
|
|
|
|
2020-06-05 21:23:13 -07:00
|
|
|
let wire_transaction = serialize(&transaction).map_err(|err| {
|
2018-11-14 18:57:34 -08:00
|
|
|
info!("request_airdrop: serialize error: {:?}", err);
|
2018-10-23 10:59:43 -07:00
|
|
|
Error::internal_error()
|
2018-11-14 18:57:34 -08:00
|
|
|
})?;
|
2018-10-15 11:01:40 -06:00
|
|
|
|
2020-06-05 21:23:13 -07:00
|
|
|
meta.send_transaction_service
|
|
|
|
.send(signature, wire_transaction, last_valid_slot);
|
2018-11-14 18:57:34 -08:00
|
|
|
|
2020-06-05 21:23:13 -07:00
|
|
|
Ok(signature.to_string())
|
2018-08-22 11:54:37 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2020-05-29 23:16:35 -07:00
|
|
|
fn send_transaction(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
data: String,
|
|
|
|
config: Option<RpcSendTransactionConfig>,
|
|
|
|
) -> Result<String> {
|
|
|
|
let config = config.unwrap_or_default();
|
2020-05-19 12:08:19 -07:00
|
|
|
let (wire_transaction, transaction) = deserialize_bs58_transaction(data)?;
|
2020-06-05 21:23:13 -07:00
|
|
|
let signature = transaction.signatures[0];
|
2020-07-03 17:39:14 -06:00
|
|
|
let bank = &*meta.bank(None);
|
2020-06-05 21:23:13 -07:00
|
|
|
let last_valid_slot = bank
|
|
|
|
.get_blockhash_last_valid_slot(&transaction.message.recent_blockhash)
|
|
|
|
.unwrap_or(0);
|
2020-05-29 23:16:35 -07:00
|
|
|
|
|
|
|
if !config.skip_preflight {
|
|
|
|
if transaction.verify().is_err() {
|
|
|
|
return Err(RpcCustomError::SendTransactionPreflightFailure {
|
|
|
|
message: "Transaction signature verification failed".into(),
|
|
|
|
}
|
|
|
|
.into());
|
|
|
|
}
|
|
|
|
|
2020-06-07 21:54:03 -06:00
|
|
|
if meta.health.check() != RpcHealthStatus::Ok {
|
2020-05-30 00:39:24 -07:00
|
|
|
return Err(RpcCustomError::SendTransactionPreflightFailure {
|
|
|
|
message: "RPC node is unhealthy, unable to simulate transaction".into(),
|
|
|
|
}
|
|
|
|
.into());
|
|
|
|
}
|
|
|
|
|
2020-06-06 10:18:28 -07:00
|
|
|
if let (Err(err), _log_output) = run_transaction_simulation(&bank, transaction) {
|
2020-05-29 23:16:35 -07:00
|
|
|
// Note: it's possible that the transaction simulation failed but the actual
|
2020-06-01 13:53:37 -07:00
|
|
|
// transaction would succeed, such as when a transaction depends on an earlier
|
|
|
|
// transaction that has yet to reach max confirmations. In these cases the user
|
|
|
|
// should use the config.skip_preflight flag, and potentially in the future
|
|
|
|
// additional controls over what bank is used for preflight should be exposed.
|
2020-05-29 23:16:35 -07:00
|
|
|
return Err(RpcCustomError::SendTransactionPreflightFailure {
|
|
|
|
message: format!("Transaction simulation failed: {}", err),
|
|
|
|
}
|
|
|
|
.into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-05 21:23:13 -07:00
|
|
|
meta.send_transaction_service
|
|
|
|
.send(signature, wire_transaction, last_valid_slot);
|
|
|
|
Ok(signature.to_string())
|
2018-08-22 11:53:24 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2020-05-19 12:08:19 -07:00
|
|
|
fn simulate_transaction(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
data: String,
|
|
|
|
config: Option<RpcSimulateTransactionConfig>,
|
2020-06-11 16:51:25 -06:00
|
|
|
) -> Result<RpcResponse<RpcSimulateTransactionResult>> {
|
2020-05-19 12:08:19 -07:00
|
|
|
let (_, transaction) = deserialize_bs58_transaction(data)?;
|
2020-05-29 23:16:35 -07:00
|
|
|
let config = config.unwrap_or_default();
|
2020-05-19 12:08:19 -07:00
|
|
|
|
|
|
|
let mut result = if config.sig_verify {
|
|
|
|
transaction.verify()
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
};
|
|
|
|
|
2020-07-03 17:39:14 -06:00
|
|
|
let bank = &*meta.bank(None);
|
2020-06-06 10:18:28 -07:00
|
|
|
let logs = if result.is_ok() {
|
|
|
|
let sim_result = run_transaction_simulation(&bank, transaction);
|
|
|
|
result = sim_result.0;
|
|
|
|
Some(sim_result.1)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2020-05-19 12:08:19 -07:00
|
|
|
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(new_response(
|
2020-05-19 12:08:19 -07:00
|
|
|
&bank,
|
2020-06-06 10:18:28 -07:00
|
|
|
RpcSimulateTransactionResult {
|
2020-05-19 12:08:19 -07:00
|
|
|
err: result.err(),
|
2020-06-06 10:18:28 -07:00
|
|
|
logs,
|
2020-05-19 12:08:19 -07:00
|
|
|
},
|
2020-07-03 17:39:14 -06:00
|
|
|
))
|
2020-05-19 12:08:19 -07:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_slot_leader(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<String> {
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_slot_leader(commitment))
|
2019-04-23 14:46:41 -07:00
|
|
|
}
|
|
|
|
|
2020-01-21 13:05:04 -07:00
|
|
|
fn minimum_ledger_slot(&self, meta: Self::Metadata) -> Result<Slot> {
|
2020-06-07 21:54:03 -06:00
|
|
|
meta.minimum_ledger_slot()
|
2020-01-21 13:05:04 -07:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_vote_accounts(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<RpcVoteAccountStatus> {
|
2020-06-07 21:54:03 -06:00
|
|
|
meta.get_vote_accounts(commitment)
|
2019-05-20 22:21:13 -07:00
|
|
|
}
|
|
|
|
|
2019-10-11 13:30:52 -06:00
|
|
|
fn validator_exit(&self, meta: Self::Metadata) -> Result<bool> {
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.validator_exit())
|
2019-03-03 22:01:09 -08:00
|
|
|
}
|
2019-08-07 20:06:27 -06:00
|
|
|
|
2020-03-04 14:44:21 -08:00
|
|
|
fn get_identity(&self, meta: Self::Metadata) -> Result<RpcIdentity> {
|
|
|
|
Ok(RpcIdentity {
|
2020-06-07 21:54:03 -06:00
|
|
|
identity: meta.config.identity_pubkey.to_string(),
|
2020-03-04 14:44:21 -08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:06:27 -06:00
|
|
|
fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
|
|
|
|
Ok(RpcVersionInfo {
|
2020-05-11 15:02:01 -07:00
|
|
|
solana_core: solana_version::Version::default().to_string(),
|
2019-08-07 20:06:27 -06:00
|
|
|
})
|
|
|
|
}
|
2019-08-10 22:54:46 -07:00
|
|
|
|
2020-03-06 17:03:10 -07:00
|
|
|
fn set_log_filter(&self, meta: Self::Metadata, filter: String) -> Result<()> {
|
2020-07-03 17:39:14 -06:00
|
|
|
meta.set_log_filter(filter);
|
|
|
|
Ok(())
|
2019-08-10 22:54:46 -07:00
|
|
|
}
|
2019-11-11 13:18:34 -05:00
|
|
|
|
2019-11-14 14:14:42 -07:00
|
|
|
fn get_confirmed_block(
|
2019-11-11 13:18:34 -05:00
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
slot: Slot,
|
2020-07-01 14:06:40 -06:00
|
|
|
encoding: Option<UiTransactionEncoding>,
|
2020-03-26 13:29:30 -07:00
|
|
|
) -> Result<Option<ConfirmedBlock>> {
|
2020-06-07 21:54:03 -06:00
|
|
|
meta.get_confirmed_block(slot, encoding)
|
2019-11-11 13:18:34 -05:00
|
|
|
}
|
2019-11-26 00:40:36 -07:00
|
|
|
|
2019-12-18 16:51:47 -07:00
|
|
|
fn get_confirmed_blocks(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
start_slot: Slot,
|
|
|
|
end_slot: Option<Slot>,
|
|
|
|
) -> Result<Vec<Slot>> {
|
2020-06-07 21:54:03 -06:00
|
|
|
meta.get_confirmed_blocks(start_slot, end_slot)
|
2019-12-18 16:51:47 -07:00
|
|
|
}
|
|
|
|
|
2019-11-26 00:40:36 -07:00
|
|
|
fn get_block_time(&self, meta: Self::Metadata, slot: Slot) -> Result<Option<UnixTimestamp>> {
|
2020-06-07 21:54:03 -06:00
|
|
|
meta.get_block_time(slot)
|
2019-11-26 00:40:36 -07:00
|
|
|
}
|
2020-04-09 00:57:30 -06:00
|
|
|
|
|
|
|
fn get_confirmed_transaction(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
signature_str: String,
|
2020-07-01 14:06:40 -06:00
|
|
|
encoding: Option<UiTransactionEncoding>,
|
2020-04-09 00:57:30 -06:00
|
|
|
) -> Result<Option<ConfirmedTransaction>> {
|
|
|
|
let signature = verify_signature(&signature_str)?;
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_confirmed_transaction(signature, encoding))
|
2020-04-09 00:57:30 -06:00
|
|
|
}
|
2020-04-09 21:21:31 -06:00
|
|
|
|
|
|
|
fn get_confirmed_signatures_for_address(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
pubkey_str: String,
|
|
|
|
start_slot: Slot,
|
|
|
|
end_slot: Slot,
|
|
|
|
) -> Result<Vec<String>> {
|
|
|
|
let pubkey = verify_pubkey(pubkey_str)?;
|
2020-04-22 01:08:06 +08:00
|
|
|
if end_slot < start_slot {
|
2020-04-09 21:21:31 -06:00
|
|
|
return Err(Error::invalid_params(format!(
|
2020-04-22 01:08:06 +08:00
|
|
|
"start_slot {} must be less than or equal to end_slot {}",
|
2020-04-09 21:21:31 -06:00
|
|
|
start_slot, end_slot
|
|
|
|
)));
|
|
|
|
}
|
2020-04-20 22:01:09 -07:00
|
|
|
if end_slot - start_slot > MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE {
|
2020-04-09 21:21:31 -06:00
|
|
|
return Err(Error::invalid_params(format!(
|
|
|
|
"Slot range too large; max {}",
|
2020-04-20 22:01:09 -07:00
|
|
|
MAX_GET_CONFIRMED_SIGNATURES_FOR_ADDRESS_SLOT_RANGE
|
2020-04-09 21:21:31 -06:00
|
|
|
)));
|
|
|
|
}
|
2020-07-03 17:39:14 -06:00
|
|
|
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
|
|
|
|
|
|
|
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot> {
|
2020-07-03 17:39:14 -06:00
|
|
|
Ok(meta.get_first_available_block())
|
2020-04-22 14:33:06 -06:00
|
|
|
}
|
2020-07-06 13:28:40 -06: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)
|
|
|
|
}
|
2019-11-11 13:18:34 -05:00
|
|
|
}
|
|
|
|
|
2020-05-19 12:08:19 -07:00
|
|
|
fn deserialize_bs58_transaction(bs58_transaction: String) -> Result<(Vec<u8>, Transaction)> {
|
2020-05-21 18:30:02 -06:00
|
|
|
let wire_transaction = bs58::decode(bs58_transaction)
|
|
|
|
.into_vec()
|
|
|
|
.map_err(|e| Error::invalid_params(format!("{:?}", e)))?;
|
2020-05-19 12:08:19 -07: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
|
|
|
})
|
|
|
|
.map(|transaction| (wire_transaction, transaction))
|
|
|
|
}
|
|
|
|
|
2020-06-16 23:30:59 -06:00
|
|
|
pub(crate) fn create_validator_exit(exit: &Arc<AtomicBool>) -> Arc<RwLock<Option<ValidatorExit>>> {
|
|
|
|
let mut validator_exit = ValidatorExit::default();
|
|
|
|
let exit_ = exit.clone();
|
|
|
|
validator_exit.register_exit(Box::new(move || exit_.store(true, Ordering::Relaxed)));
|
|
|
|
Arc::new(RwLock::new(Some(validator_exit)))
|
|
|
|
}
|
|
|
|
|
2018-08-13 11:24:39 -06:00
|
|
|
#[cfg(test)]
|
2019-08-20 23:59:31 -07:00
|
|
|
pub mod tests {
|
2018-08-13 11:24:39 -06:00
|
|
|
use super::*;
|
2019-10-14 16:24:10 -06:00
|
|
|
use crate::{
|
2020-06-25 22:06:58 -06:00
|
|
|
contact_info::ContactInfo, non_circulating_supply::non_circulating_accounts,
|
2020-01-13 14:13:52 -07:00
|
|
|
replay_stage::tests::create_test_transactions_and_populate_blockstore,
|
2019-10-14 16:24:10 -06:00
|
|
|
};
|
2020-01-12 22:34:30 -07:00
|
|
|
use bincode::deserialize;
|
2020-06-11 16:51:25 -06:00
|
|
|
use jsonrpc_core::{
|
|
|
|
futures::future::Future, ErrorCode, MetaIoHandler, Output, Response, Value,
|
|
|
|
};
|
|
|
|
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-03-21 10:54:40 -07:00
|
|
|
blockstore::entries_to_test_shreds,
|
|
|
|
blockstore_processor::fill_blockstore_slot_with_ticks,
|
|
|
|
entry::next_entry_mut,
|
|
|
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
2019-12-14 12:23:02 -07:00
|
|
|
};
|
2020-06-25 22:06:58 -06:00
|
|
|
use solana_runtime::commitment::BlockCommitment;
|
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-07-03 01:46:29 -06:00
|
|
|
system_instruction, system_program, system_transaction,
|
2020-03-23 11:25:39 -06:00
|
|
|
transaction::{self, TransactionError},
|
2019-10-14 16:24:10 -06:00
|
|
|
};
|
2020-07-01 14:06:40 -06:00
|
|
|
use solana_transaction_status::{EncodedTransaction, TransactionWithStatusMeta, UiMessage};
|
2019-12-11 22:04:54 -08:00
|
|
|
use solana_vote_program::{
|
|
|
|
vote_instruction,
|
|
|
|
vote_state::{Vote, VoteInit, MAX_LOCKOUT_HISTORY},
|
|
|
|
};
|
2020-06-16 23:30:59 -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,
|
2019-12-11 22:04:54 -08:00
|
|
|
leader_vote_keypair: 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-01-13 14:13:52 -07:00
|
|
|
start_rpc_handler_with_tx_and_blockstore(pubkey, vec![], 0)
|
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
|
|
|
default_timestamp: i64,
|
|
|
|
) -> 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();
|
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-04-22 12:22:09 -06:00
|
|
|
0,
|
2020-03-30 17:53:25 -06:00
|
|
|
10,
|
2020-07-08 18:50:13 -06:00
|
|
|
bank.slot(),
|
2020-03-30 11:29:30 -06:00
|
|
|
0,
|
2020-05-18 12:49:01 -06:00
|
|
|
0,
|
2020-03-30 11:29:30 -06:00
|
|
|
)));
|
|
|
|
|
2020-01-13 14:13:52 -07:00
|
|
|
// Add timestamp vote to blockstore
|
2019-12-14 12:23:02 -07:00
|
|
|
let vote = Vote {
|
|
|
|
slots: vec![1],
|
|
|
|
hash: Hash::default(),
|
|
|
|
timestamp: Some(default_timestamp),
|
|
|
|
};
|
|
|
|
let vote_ix = vote_instruction::vote(
|
|
|
|
&leader_vote_keypair.pubkey(),
|
|
|
|
&leader_vote_keypair.pubkey(),
|
|
|
|
vote,
|
|
|
|
);
|
2020-06-24 14:52:38 -06:00
|
|
|
let vote_msg = Message::new(&[vote_ix], Some(&leader_vote_keypair.pubkey()));
|
2020-05-30 00:17:44 -06:00
|
|
|
let vote_tx = Transaction::new(&[&leader_vote_keypair], vote_msg, Hash::default());
|
2019-12-14 12:23:02 -07:00
|
|
|
let shreds = entries_to_test_shreds(
|
|
|
|
vec![next_entry_mut(&mut Hash::default(), 0, vec![vote_tx])],
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
true,
|
|
|
|
0,
|
|
|
|
);
|
2020-01-13 14:13:52 -07:00
|
|
|
blockstore.insert_shreds(shreds, None, false).unwrap();
|
|
|
|
blockstore.set_roots(&[1]).unwrap();
|
2019-12-18 16:51:47 -07: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() {
|
|
|
|
bank_forks.write().unwrap().set_root(*root, &None, Some(0));
|
|
|
|
}
|
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"),
|
|
|
|
));
|
|
|
|
|
|
|
|
let meta = 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()
|
|
|
|
},
|
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(),
|
2020-07-08 19:13:42 -06:00
|
|
|
Arc::new(SendTransactionService::new(tpu_address, &bank_forks, &exit)),
|
2020-06-07 21:54:03 -06:00
|
|
|
);
|
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();
|
|
|
|
let rpc = RpcSolImpl;
|
|
|
|
io.extend_with(rpc.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() {
|
2019-03-30 21:37:33 -06:00
|
|
|
let bob_pubkey = 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();
|
|
|
|
io.extend_with(RpcSolImpl.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();
|
|
|
|
io.extend_with(RpcSolImpl.to_delegate());
|
|
|
|
|
2020-06-11 16:51:25 -06:00
|
|
|
let fut = {
|
|
|
|
let (client, server) =
|
2020-06-16 23:30:59 -06:00
|
|
|
local::connect_with_metadata::<gen_client::Client, _, _>(&io, meta);
|
2020-06-11 16:51:25 -06:00
|
|
|
client
|
2020-06-16 23:30:59 -06:00
|
|
|
.get_balance(mint_pubkey.to_string(), None)
|
2020-06-11 16:51:25 -06:00
|
|
|
.join(server)
|
|
|
|
};
|
2020-06-16 23:30:59 -06:00
|
|
|
let (response, _) = fut.wait().unwrap();
|
|
|
|
assert_eq!(response.value, 20);
|
2020-06-11 16:51:25 -06:00
|
|
|
}
|
|
|
|
|
2019-04-23 14:46:41 -07:00
|
|
|
#[test]
|
|
|
|
fn test_rpc_get_cluster_nodes() {
|
|
|
|
let bob_pubkey = 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-05-11 21:30:01 -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}}],"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);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rpc_get_slot_leader() {
|
|
|
|
let bob_pubkey = 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() {
|
2019-03-30 21:37:33 -06:00
|
|
|
let bob_pubkey = 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();
|
|
|
|
io.extend_with(RpcSolImpl.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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
|
|
|
let bob_pubkey = 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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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-05-12 21:05:05 -06:00
|
|
|
assert_eq!(largest_accounts.len(), 19);
|
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");
|
|
|
|
assert_eq!(largest_accounts.len(), 18);
|
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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
|
|
|
let bob_pubkey = 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();
|
|
|
|
let year =
|
|
|
|
(bank.epoch_schedule().get_last_slot_in_epoch(epoch)) as f64 / bank.slots_per_year();
|
2020-05-29 12:50:25 -06:00
|
|
|
let expected_inflation_rate = RpcInflationRate {
|
|
|
|
total: inflation.total(year),
|
|
|
|
validator: inflation.validator(year),
|
|
|
|
foundation: inflation.foundation(year),
|
|
|
|
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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
2019-03-30 21:37:33 -06:00
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
2019-10-14 16:24:10 -06:00
|
|
|
let RpcHandler { io, meta, .. } = 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
|
|
|
|
);
|
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":{
|
2020-01-15 15:33:53 -07:00
|
|
|
"owner": "11111111111111111111111111111111",
|
2019-03-05 16:28:14 -08:00
|
|
|
"lamports": 20,
|
2020-01-15 15:33:53 -07:00
|
|
|
"data": "",
|
2019-08-23 14:04:53 -07:00
|
|
|
"executable": false,
|
2020-01-15 00:25:45 -07:00
|
|
|
"rentEpoch": 0
|
2018-09-20 13:20:37 -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);
|
|
|
|
}
|
2018-09-20 13:20:37 -07:00
|
|
|
|
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
|
|
|
|
|
|
|
let new_program_id = Pubkey::new_rand();
|
|
|
|
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();
|
|
|
|
let authority = Pubkey::new_rand();
|
|
|
|
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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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-06-06 10:18:28 -07:00
|
|
|
"value":{"err":null, "logs":[]}
|
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!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"result": {
|
|
|
|
"context":{"slot":0},
|
2020-06-06 10:18:28 -07:00
|
|
|
"value":{"err":"SignatureFailure", "logs":null}
|
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=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-06-06 10:18:28 -07:00
|
|
|
"value":{"err":null, "logs":[]}
|
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-06-06 10:18:28 -07:00
|
|
|
"value":{"err":null, "logs":[]}
|
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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
2019-03-30 21:37:33 -06:00
|
|
|
let bob_pubkey = 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-04-02 02:30:58 +08:00
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
2019-03-30 21:37:33 -06:00
|
|
|
let bob_pubkey = 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() {
|
2019-03-30 21:37:33 -06:00
|
|
|
let bob_pubkey = 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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
2019-03-30 21:37:33 -06:00
|
|
|
let bob_pubkey = 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() {
|
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);
|
2019-11-11 13:18:34 -05:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
2020-04-22 12:22:09 -06:00
|
|
|
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()));
|
2018-08-15 10:37:02 -06:00
|
|
|
|
2018-08-13 11:24:39 -06:00
|
|
|
let mut io = MetaIoHandler::default();
|
|
|
|
let rpc = RpcSolImpl;
|
|
|
|
io.extend_with(rpc.to_delegate());
|
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-06-05 21:23:13 -07:00
|
|
|
let bank_forks = new_bank_forks().0;
|
2020-06-07 21:54:03 -06:00
|
|
|
let meta = JsonRpcRequestProcessor::new(
|
|
|
|
JsonRpcConfig::default(),
|
|
|
|
new_bank_forks().0,
|
|
|
|
block_commitment_cache,
|
|
|
|
blockstore,
|
|
|
|
validator_exit,
|
|
|
|
RpcHealth::stub(),
|
2020-07-08 19:13:42 -06:00
|
|
|
cluster_info,
|
2020-06-07 21:54:03 -06:00
|
|
|
Hash::default(),
|
2020-07-08 19:13:42 -06:00
|
|
|
Arc::new(SendTransactionService::new(tpu_address, &bank_forks, &exit)),
|
2020-06-07 21:54:03 -06:00
|
|
|
);
|
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-06-01 13:53:37 -07:00
|
|
|
let bank_forks = new_bank_forks().0;
|
|
|
|
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();
|
|
|
|
let rpc = RpcSolImpl;
|
|
|
|
io.extend_with(rpc.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-06-07 21:54:03 -06:00
|
|
|
let meta = JsonRpcRequestProcessor::new(
|
|
|
|
JsonRpcConfig::default(),
|
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(),
|
2020-07-08 19:13:42 -06:00
|
|
|
Arc::new(SendTransactionService::new(tpu_address, &bank_forks, &exit)),
|
2020-06-07 21:54:03 -06:00
|
|
|
);
|
2020-06-01 13:53:37 -07:00
|
|
|
|
|
|
|
let mut bad_transaction =
|
|
|
|
system_transaction::transfer(&Keypair::new(), &Pubkey::default(), 42, Hash::default());
|
|
|
|
|
|
|
|
// 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(
|
|
|
|
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found"},"id":1}"#.to_string(),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// sendTransaction will fail due to poor node health
|
|
|
|
health.stub_set_health_status(Some(RpcHealthStatus::Behind));
|
|
|
|
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(
|
|
|
|
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"RPC node is unhealthy, unable to simulate transaction"},"id":1}"#.to_string(),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
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(
|
|
|
|
r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction signature verification failed"},"id":1}"#.to_string(),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
// 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()
|
|
|
|
);
|
|
|
|
let res = io.handle_request_sync(&req, meta);
|
|
|
|
assert_eq!(
|
|
|
|
res,
|
|
|
|
Some(
|
|
|
|
r#"{"jsonrpc":"2.0","result":"1111111111111111111111111111111111111111111111111111111111111111","id":1}"#.to_string(),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
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() {
|
2019-03-30 21:37:33 -06:00
|
|
|
let pubkey = 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() {
|
2019-05-20 10:03:19 -07:00
|
|
|
let tx = system_transaction::transfer(&Keypair::new(), &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-08 19:13:42 -06:00
|
|
|
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair, 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,
|
2019-12-11 22:04:54 -08:00
|
|
|
voting_keypair,
|
2019-03-18 14:18:43 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-03-03 22:01:09 -08:00
|
|
|
#[test]
|
2019-10-11 13:30:52 -06:00
|
|
|
fn test_rpc_request_processor_config_default_trait_validator_exit_fails() {
|
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);
|
2019-11-11 13:18:34 -05:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
2020-04-22 12:22:09 -06:00
|
|
|
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-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-06-05 21:23:13 -07:00
|
|
|
let bank_forks = new_bank_forks().0;
|
2019-03-18 14:18:43 -07:00
|
|
|
let request_processor = JsonRpcRequestProcessor::new(
|
|
|
|
JsonRpcConfig::default(),
|
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(),
|
2020-07-08 19:13:42 -06:00
|
|
|
Arc::new(SendTransactionService::new(tpu_address, &bank_forks, &exit)),
|
2019-03-18 14:18:43 -07:00
|
|
|
);
|
2020-07-03 17:39:14 -06:00
|
|
|
assert_eq!(request_processor.validator_exit(), false);
|
2019-03-03 22:01:09 -08:00
|
|
|
assert_eq!(exit.load(Ordering::Relaxed), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-10-11 13:30:52 -06:00
|
|
|
fn test_rpc_request_processor_allow_validator_exit_config() {
|
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);
|
2019-11-11 13:18:34 -05:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
2020-04-22 12:22:09 -06:00
|
|
|
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()));
|
2019-03-05 21:12:30 -08:00
|
|
|
let mut config = JsonRpcConfig::default();
|
2019-10-11 13:30:52 -06:00
|
|
|
config.enable_validator_exit = true;
|
2020-06-05 21:23:13 -07:00
|
|
|
let bank_forks = new_bank_forks().0;
|
|
|
|
let cluster_info = Arc::new(ClusterInfo::default());
|
2020-07-08 19:13:42 -06:00
|
|
|
let tpu_address = cluster_info.my_contact_info().tpu;
|
2019-03-18 14:18:43 -07:00
|
|
|
let request_processor = JsonRpcRequestProcessor::new(
|
|
|
|
config,
|
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(),
|
2020-07-08 19:13:42 -06:00
|
|
|
Arc::new(SendTransactionService::new(tpu_address, &bank_forks, &exit)),
|
2019-03-18 14:18:43 -07:00
|
|
|
);
|
2020-07-03 17:39:14 -06:00
|
|
|
assert_eq!(request_processor.validator_exit(), true);
|
2019-03-03 22:01:09 -08:00
|
|
|
assert_eq!(exit.load(Ordering::Relaxed), true);
|
|
|
|
}
|
2019-08-07 20:06:27 -06:00
|
|
|
|
2020-03-04 14:44:21 -08:00
|
|
|
#[test]
|
|
|
|
fn test_rpc_get_identity() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-08-07 20:06:27 -06:00
|
|
|
#[test]
|
|
|
|
fn test_rpc_get_version() {
|
|
|
|
let bob_pubkey = 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);
|
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"result": {
|
2020-05-11 15:02:01 -07:00
|
|
|
"solana-core": solana_version::version!().to_string()
|
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,
|
2020-04-22 12:22:09 -06:00
|
|
|
0,
|
2020-03-30 11:29:30 -06:00
|
|
|
42,
|
2020-07-08 18:50:13 -06:00
|
|
|
bank_forks.read().unwrap().highest_slot(),
|
2020-03-30 11:29:30 -06:00
|
|
|
0,
|
2020-05-18 12:49:01 -06:00
|
|
|
0,
|
2020-03-30 11:29:30 -06:00
|
|
|
)));
|
2019-10-14 16:24:10 -06:00
|
|
|
|
|
|
|
let mut config = JsonRpcConfig::default();
|
|
|
|
config.enable_validator_exit = true;
|
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;
|
2019-10-14 16:24:10 -06:00
|
|
|
let request_processor = JsonRpcRequestProcessor::new(
|
|
|
|
config,
|
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(),
|
2020-07-08 19:13:42 -06:00
|
|
|
Arc::new(SendTransactionService::new(tpu_address, &bank_forks, &exit)),
|
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() {
|
2019-10-14 16:24:10 -06:00
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
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-03-26 13:29:30 -07:00
|
|
|
let confirmed_block: Option<ConfirmedBlock> =
|
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-03-26 13:29:30 -07:00
|
|
|
for TransactionWithStatusMeta { 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-03-26 13:29:30 -07:00
|
|
|
let confirmed_block: Option<ConfirmedBlock> =
|
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-03-26 13:29:30 -07:00
|
|
|
for TransactionWithStatusMeta { 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::Binary(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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
|
|
|
let roots = vec![0, 1, 3, 4, 8];
|
2020-04-28 11:20:43 -06:00
|
|
|
let RpcHandler {
|
|
|
|
io,
|
|
|
|
meta,
|
|
|
|
block_commitment_cache,
|
|
|
|
..
|
|
|
|
} = start_rpc_handler_with_tx_and_blockstore(&bob_pubkey, roots.clone(), 0);
|
|
|
|
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]}"#;
|
2019-12-18 16:51:47 -07:00
|
|
|
let res = io.handle_request_sync(&req, meta);
|
|
|
|
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
|
|
|
.expect("actual response deserialization");
|
|
|
|
let 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() {
|
|
|
|
let bob_pubkey = Pubkey::new_rand();
|
2020-05-15 17:35:43 +01:00
|
|
|
let base_timestamp = 1_576_183_541;
|
2020-05-04 19:39:27 -06:00
|
|
|
let RpcHandler {
|
|
|
|
io,
|
|
|
|
meta,
|
|
|
|
bank,
|
|
|
|
block_commitment_cache,
|
|
|
|
..
|
|
|
|
} = start_rpc_handler_with_tx_and_blockstore(
|
2019-12-14 12:23:02 -07:00
|
|
|
&bob_pubkey,
|
|
|
|
vec![1, 2, 3, 4, 5, 6, 7],
|
|
|
|
base_timestamp,
|
|
|
|
);
|
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}}"#,
|
2019-12-14 12:23:02 -07:00
|
|
|
base_timestamp + (5 * 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-05-15 17:35:43 +01:00
|
|
|
let expected = r#"{"jsonrpc":"2.0","result":null,"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
|
|
|
|
|
|
|
#[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,
|
2019-12-07 00:12:25 -07:00
|
|
|
..
|
|
|
|
} = start_rpc_handler_with_tx(&Pubkey::new_rand());
|
|
|
|
|
|
|
|
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,
|
|
|
|
));
|
|
|
|
|
|
|
|
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":{}}}"#,
|
|
|
|
json!([CommitmentConfig::recent()])
|
|
|
|
);
|
|
|
|
|
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,
|
|
|
|
));
|
|
|
|
|
|
|
|
// 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":{}}}"#,
|
|
|
|
json!([CommitmentConfig::recent()])
|
|
|
|
);
|
|
|
|
|
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,
|
|
|
|
highest_confirmed_root,
|
|
|
|
50,
|
2020-07-08 18:50:13 -06:00
|
|
|
bank.slot(),
|
2020-07-07 20:13:30 -06:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
);
|
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
|
|
|
|
));
|
|
|
|
}
|
2018-08-13 11:24:39 -06:00
|
|
|
}
|