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::{
|
|
|
|
cluster_info::ClusterInfo,
|
2019-11-04 16:44:27 -07:00
|
|
|
commitment::{BlockCommitment, BlockCommitmentCache},
|
2019-10-14 16:24:10 -06:00
|
|
|
contact_info::ContactInfo,
|
|
|
|
packet::PACKET_DATA_SIZE,
|
|
|
|
storage_stage::StorageState,
|
|
|
|
validator::ValidatorExit,
|
|
|
|
};
|
2019-11-06 00:07:57 -08:00
|
|
|
use bincode::serialize;
|
2019-03-18 14:18:43 -07:00
|
|
|
use jsonrpc_core::{Error, Metadata, Result};
|
2019-02-04 17:41:03 -07:00
|
|
|
use jsonrpc_derive::rpc;
|
2019-10-07 12:30:22 +09:00
|
|
|
use solana_client::rpc_request::{RpcEpochInfo, RpcVoteAccountInfo, RpcVoteAccountStatus};
|
2019-01-04 17:20:51 -08:00
|
|
|
use solana_drone::drone::request_airdrop_transaction;
|
2019-10-20 09:54:38 -06:00
|
|
|
use solana_ledger::bank_forks::BankForks;
|
2019-04-05 10:42:54 -06:00
|
|
|
use solana_runtime::bank::Bank;
|
2019-10-14 16:24:10 -06:00
|
|
|
use solana_sdk::{
|
|
|
|
account::Account,
|
2019-11-02 00:38:30 -07:00
|
|
|
clock::Slot,
|
2019-11-06 14:15:00 -07:00
|
|
|
commitment_config::{CommitmentConfig, CommitmentLevel},
|
2019-10-22 16:41:18 -04:00
|
|
|
epoch_schedule::EpochSchedule,
|
2019-10-14 16:24:10 -06:00
|
|
|
fee_calculator::FeeCalculator,
|
|
|
|
hash::Hash,
|
|
|
|
inflation::Inflation,
|
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::Signature,
|
|
|
|
transaction::{self, Transaction},
|
|
|
|
};
|
2019-08-16 17:02:19 -06:00
|
|
|
use solana_vote_api::vote_state::{VoteState, MAX_LOCKOUT_HISTORY};
|
2019-10-14 16:24:10 -06:00
|
|
|
use std::{
|
|
|
|
net::{SocketAddr, UdpSocket},
|
|
|
|
sync::{Arc, RwLock},
|
|
|
|
thread::sleep,
|
|
|
|
time::{Duration, Instant},
|
|
|
|
};
|
2018-08-10 17:05:23 -06:00
|
|
|
|
2019-03-06 09:26:12 -08:00
|
|
|
#[derive(Debug, Clone)]
|
2019-03-05 21:12:30 -08:00
|
|
|
pub struct JsonRpcConfig {
|
2019-10-11 13:30:52 -06:00
|
|
|
pub enable_validator_exit: bool, // Enable the 'validatorExit' command
|
2019-03-06 09:26:12 -08:00
|
|
|
pub drone_addr: Option<SocketAddr>,
|
2019-03-03 22:01:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for JsonRpcConfig {
|
|
|
|
fn default() -> Self {
|
2019-03-05 21:12:30 -08:00
|
|
|
Self {
|
2019-10-11 13:30:52 -06:00
|
|
|
enable_validator_exit: false,
|
2019-03-06 09:26:12 -08:00
|
|
|
drone_addr: None,
|
2019-03-05 21:12:30 -08:00
|
|
|
}
|
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>>,
|
2019-02-17 10:29:08 -07:00
|
|
|
storage_state: StorageState,
|
2019-03-03 22:01:09 -08:00
|
|
|
config: JsonRpcConfig,
|
2019-08-20 23:59:31 -07:00
|
|
|
validator_exit: Arc<RwLock<Option<ValidatorExit>>>,
|
2018-08-14 18:03:48 -06:00
|
|
|
}
|
|
|
|
|
2019-02-17 10:29:08 -07:00
|
|
|
impl JsonRpcRequestProcessor {
|
2019-11-06 14:15:00 -07:00
|
|
|
fn bank(&self, commitment: Option<CommitmentConfig>) -> Arc<Bank> {
|
|
|
|
debug!("RPC commitment_config: {:?}", commitment);
|
|
|
|
let r_bank_forks = self.bank_forks.read().unwrap();
|
|
|
|
if commitment.is_some() && commitment.unwrap().commitment == CommitmentLevel::Recent {
|
|
|
|
let bank = r_bank_forks.working_bank();
|
|
|
|
debug!("RPC using working_bank: {:?}", bank.slot());
|
|
|
|
bank
|
|
|
|
} else {
|
|
|
|
let slot = r_bank_forks.root();
|
|
|
|
debug!("RPC using block: {:?}", slot);
|
|
|
|
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(
|
|
|
|
storage_state: StorageState,
|
|
|
|
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>>,
|
2019-08-20 23:59:31 -07:00
|
|
|
validator_exit: &Arc<RwLock<Option<ValidatorExit>>>,
|
2019-03-03 22:01:09 -08:00
|
|
|
) -> Self {
|
2019-02-17 10:29:08 -07:00
|
|
|
JsonRpcRequestProcessor {
|
2019-03-18 14:18:43 -07:00
|
|
|
bank_forks,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache,
|
2019-01-28 14:53:50 -08:00
|
|
|
storage_state,
|
2019-03-03 22:01:09 -08:00
|
|
|
config,
|
2019-08-20 23:59:31 -07:00
|
|
|
validator_exit: validator_exit.clone(),
|
2019-01-15 12:20:07 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
pub fn get_account_info(
|
|
|
|
&self,
|
|
|
|
pubkey: &Pubkey,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Account> {
|
|
|
|
self.bank(commitment)
|
2019-02-17 10:29:08 -07:00
|
|
|
.get_account(&pubkey)
|
|
|
|
.ok_or_else(Error::invalid_request)
|
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>,
|
|
|
|
) -> Result<u64> {
|
|
|
|
Ok(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,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Vec<(String, Account)>> {
|
2019-06-29 10:59:07 -06:00
|
|
|
Ok(self
|
2019-11-06 14:15:00 -07:00
|
|
|
.bank(commitment)
|
2019-07-11 12:58:28 -06:00
|
|
|
.get_program_accounts(&program_id)
|
2019-06-29 10:59:07 -06:00
|
|
|
.into_iter()
|
|
|
|
.map(|(pubkey, account)| (pubkey.to_string(), account))
|
|
|
|
.collect())
|
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
pub fn get_inflation(&self, commitment: Option<CommitmentConfig>) -> Result<Inflation> {
|
|
|
|
Ok(self.bank(commitment).inflation())
|
2019-08-27 18:17:03 -04:00
|
|
|
}
|
|
|
|
|
2019-10-22 16:41:18 -04:00
|
|
|
pub fn get_epoch_schedule(&self) -> Result<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
|
|
|
|
Ok(*self.bank(None).epoch_schedule())
|
2019-10-22 16:41:18 -04:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
pub fn get_balance(&self, pubkey: &Pubkey, commitment: Option<CommitmentConfig>) -> u64 {
|
|
|
|
self.bank(commitment).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>,
|
|
|
|
) -> (String, FeeCalculator) {
|
|
|
|
let (blockhash, fee_calculator) = self.bank(commitment).confirmed_last_blockhash();
|
2019-06-10 22:18:32 -07:00
|
|
|
(blockhash.to_string(), fee_calculator)
|
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_block_commitment(&self, block: Slot) -> (Option<BlockCommitment>, u64) {
|
2019-11-04 16:44:27 -07:00
|
|
|
let r_block_commitment = self.block_commitment_cache.read().unwrap();
|
2019-10-14 16:24:10 -06:00
|
|
|
(
|
2019-11-04 16:44:27 -07:00
|
|
|
r_block_commitment.get_block_commitment(block).cloned(),
|
|
|
|
r_block_commitment.total_stake(),
|
2019-10-14 16:24:10 -06:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-03-21 07:43:21 -07:00
|
|
|
pub fn get_signature_confirmation_status(
|
|
|
|
&self,
|
|
|
|
signature: Signature,
|
2019-11-06 14:15:00 -07:00
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-04-05 10:42:54 -06:00
|
|
|
) -> Option<(usize, transaction::Result<()>)> {
|
2019-11-06 14:15:00 -07:00
|
|
|
self.bank(commitment)
|
|
|
|
.get_signature_confirmation_status(&signature)
|
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_slot(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
|
|
|
Ok(self.bank(commitment).slot())
|
2019-06-12 16:43:05 -07:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_slot_leader(&self, commitment: Option<CommitmentConfig>) -> Result<String> {
|
|
|
|
Ok(self.bank(commitment).collector_id().to_string())
|
2019-07-09 22:06:47 -07:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_transaction_count(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
|
|
|
Ok(self.bank(commitment).transaction_count() as u64)
|
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_total_supply(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
|
|
|
Ok(self.bank(commitment).capitalization())
|
2019-06-21 22:00:26 -06:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_vote_accounts(
|
|
|
|
&self,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<RpcVoteAccountStatus> {
|
|
|
|
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-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| {
|
2019-09-26 19:40:18 -06:00
|
|
|
if bank.slot() >= MAX_LOCKOUT_HISTORY as u64 {
|
|
|
|
vote_account_info.last_vote > bank.slot() - MAX_LOCKOUT_HISTORY as u64
|
|
|
|
} else {
|
|
|
|
vote_account_info.last_vote > 0
|
|
|
|
}
|
2019-08-16 17:02:19 -06:00
|
|
|
});
|
|
|
|
Ok(RpcVoteAccountStatus {
|
|
|
|
current: current_vote_accounts,
|
|
|
|
delinquent: delinquent_vote_accounts,
|
|
|
|
})
|
2019-05-20 22:21:13 -07:00
|
|
|
}
|
|
|
|
|
2019-07-10 13:33:29 -07:00
|
|
|
fn get_storage_turn_rate(&self) -> Result<u64> {
|
|
|
|
Ok(self.storage_state.get_storage_turn_rate())
|
2018-10-25 16:58:40 -07:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2019-07-10 13:33:29 -07:00
|
|
|
fn get_storage_turn(&self) -> Result<(String, u64)> {
|
|
|
|
Ok((
|
|
|
|
self.storage_state.get_storage_blockhash().to_string(),
|
|
|
|
self.storage_state.get_slot(),
|
|
|
|
))
|
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_slots_per_segment(&self, commitment: Option<CommitmentConfig>) -> Result<u64> {
|
|
|
|
Ok(self.bank(commitment).slots_per_segment())
|
2019-07-09 16:48:40 -07:00
|
|
|
}
|
|
|
|
|
2019-11-02 00:38:30 -07:00
|
|
|
fn get_storage_pubkeys_for_slot(&self, slot: Slot) -> Result<Vec<Pubkey>> {
|
2019-06-11 18:27:47 -07:00
|
|
|
Ok(self
|
|
|
|
.storage_state
|
|
|
|
.get_pubkeys_for_slot(slot, &self.bank_forks))
|
2019-02-17 10:29:08 -07:00
|
|
|
}
|
2019-03-03 22:01:09 -08:00
|
|
|
|
2019-10-11 13:30:52 -06:00
|
|
|
pub fn validator_exit(&self) -> Result<bool> {
|
|
|
|
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()
|
|
|
|
}
|
2019-03-05 21:12:30 -08:00
|
|
|
Ok(true)
|
|
|
|
} else {
|
2019-10-11 13:30:52 -06:00
|
|
|
debug!("validator_exit ignored");
|
2019-03-05 21:12:30 -08:00
|
|
|
Ok(false)
|
2019-03-03 22:01:09 -08:00
|
|
|
}
|
|
|
|
}
|
2019-02-17 10:29:08 -07:00
|
|
|
}
|
2018-10-25 16:58:40 -07:00
|
|
|
|
2019-03-08 09:48:21 -08:00
|
|
|
fn get_tpu_addr(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<SocketAddr> {
|
2019-03-08 17:23:07 -08:00
|
|
|
let contact_info = cluster_info.read().unwrap().my_data();
|
|
|
|
Ok(contact_info.tpu)
|
2018-09-10 22:41:44 -07:00
|
|
|
}
|
2018-08-14 18:03:48 -06:00
|
|
|
|
2019-02-17 10:29:08 -07:00
|
|
|
fn verify_pubkey(input: String) -> Result<Pubkey> {
|
2019-05-20 22:21:13 -07:00
|
|
|
input.parse().map_err(|_e| Error::invalid_request())
|
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> {
|
2019-05-20 22:21:13 -07:00
|
|
|
input.parse().map_err(|_e| Error::invalid_request())
|
2018-08-14 18:03:48 -06:00
|
|
|
}
|
|
|
|
|
2018-08-10 17:05:23 -06:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Meta {
|
2019-01-15 12:20:07 -08:00
|
|
|
pub request_processor: Arc<RwLock<JsonRpcRequestProcessor>>,
|
2018-10-12 14:25:56 -06:00
|
|
|
pub cluster_info: Arc<RwLock<ClusterInfo>>,
|
2019-11-08 23:56:57 -05:00
|
|
|
pub genesis_hash: Hash,
|
2018-08-10 17:05:23 -06:00
|
|
|
}
|
|
|
|
impl Metadata for Meta {}
|
|
|
|
|
2019-04-23 14:46:41 -07:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
|
|
pub struct RpcContactInfo {
|
2019-06-12 14:12:08 -07:00
|
|
|
/// Pubkey of the node as a base-58 string
|
|
|
|
pub pubkey: String,
|
2019-04-23 14:46:41 -07:00
|
|
|
/// Gossip port
|
|
|
|
pub gossip: Option<SocketAddr>,
|
|
|
|
/// Tpu port
|
|
|
|
pub tpu: Option<SocketAddr>,
|
|
|
|
/// JSON RPC port
|
|
|
|
pub rpc: Option<SocketAddr>,
|
|
|
|
}
|
2019-06-12 14:12:08 -07:00
|
|
|
|
2019-08-07 20:06:27 -06:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
|
|
#[serde(rename_all = "kebab-case")]
|
|
|
|
pub struct RpcVersionInfo {
|
|
|
|
/// The current version of solana-core
|
|
|
|
pub solana_core: String,
|
|
|
|
}
|
|
|
|
|
2019-04-05 12:20:22 -06:00
|
|
|
#[rpc(server)]
|
2019-02-04 17:41:03 -07:00
|
|
|
pub trait RpcSol {
|
|
|
|
type Metadata;
|
2018-08-10 17:05:23 -06:00
|
|
|
|
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>,
|
|
|
|
) -> Result<bool>;
|
2018-08-10 17:05:23 -06:00
|
|
|
|
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,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Account>;
|
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,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Vec<(String, Account)>>;
|
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
|
|
|
|
2019-08-27 18:17:03 -04:00
|
|
|
#[rpc(meta, name = "getInflation")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_inflation(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Inflation>;
|
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>,
|
|
|
|
) -> Result<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>,
|
|
|
|
) -> Result<RpcEpochInfo>;
|
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,
|
|
|
|
block: u64,
|
2019-11-04 16:44:27 -07:00
|
|
|
) -> Result<(Option<BlockCommitment>, u64)>;
|
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,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Option<Vec<String>>>;
|
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>,
|
|
|
|
) -> Result<(String, FeeCalculator)>;
|
2018-08-13 12:52:37 -06:00
|
|
|
|
2019-02-04 17:41:03 -07:00
|
|
|
#[rpc(meta, name = "getSignatureStatus")]
|
2019-04-05 19:07:30 -06:00
|
|
|
fn get_signature_status(
|
|
|
|
&self,
|
2019-11-06 14:15:00 -07:00
|
|
|
meta: Self::Metadata,
|
|
|
|
signature_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-04-05 19:07:30 -06:00
|
|
|
) -> Result<Option<transaction::Result<()>>>;
|
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
|
|
|
|
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
|
|
|
|
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")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn send_transaction(&self, meta: Self::Metadata, data: Vec<u8>) -> Result<String>;
|
2018-11-02 08:40:29 -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
|
|
|
|
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-07-10 13:33:29 -07:00
|
|
|
#[rpc(meta, name = "getStorageTurnRate")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_storage_turn_rate(&self, meta: Self::Metadata) -> Result<u64>;
|
2018-12-10 11:38:29 -08:00
|
|
|
|
2019-07-10 13:33:29 -07:00
|
|
|
#[rpc(meta, name = "getStorageTurn")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_storage_turn(&self, meta: Self::Metadata) -> Result<(String, u64)>;
|
2018-12-10 11:38:29 -08:00
|
|
|
|
2019-07-09 16:48:40 -07:00
|
|
|
#[rpc(meta, name = "getSlotsPerSegment")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_slots_per_segment(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<u64>;
|
2019-07-09 16:48:40 -07:00
|
|
|
|
2019-05-03 16:27:53 -07:00
|
|
|
#[rpc(meta, name = "getStoragePubkeysForSlot")]
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_storage_pubkeys_for_slot(&self, meta: Self::Metadata, slot: u64) -> Result<Vec<Pubkey>>;
|
2019-03-03 22:01:09 -08: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
|
|
|
|
|
|
|
#[rpc(meta, name = "getNumBlocksSinceSignatureConfirmation")]
|
|
|
|
fn get_num_blocks_since_signature_confirmation(
|
|
|
|
&self,
|
2019-11-06 14:15:00 -07:00
|
|
|
meta: Self::Metadata,
|
|
|
|
signature_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-04-05 19:07:30 -06:00
|
|
|
) -> Result<Option<usize>>;
|
2019-03-21 07:43:21 -07:00
|
|
|
|
|
|
|
#[rpc(meta, name = "getSignatureConfirmation")]
|
|
|
|
fn get_signature_confirmation(
|
|
|
|
&self,
|
2019-11-06 14:15:00 -07:00
|
|
|
meta: Self::Metadata,
|
|
|
|
signature_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-04-05 19:07:30 -06:00
|
|
|
) -> Result<Option<(usize, transaction::Result<()>)>>;
|
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<()>;
|
2018-08-10 17:05:23 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct RpcSolImpl;
|
|
|
|
impl RpcSol for RpcSolImpl {
|
|
|
|
type Metadata = Meta;
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn confirm_transaction(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
signature_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<bool> {
|
|
|
|
debug!(
|
|
|
|
"confirm_transaction rpc request received: {:?}",
|
|
|
|
signature_str
|
|
|
|
);
|
|
|
|
self.get_signature_status(meta, signature_str, commitment)
|
|
|
|
.map(|status_option| {
|
|
|
|
if status_option.is_none() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
status_option.unwrap().is_ok()
|
|
|
|
})
|
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,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Account> {
|
|
|
|
debug!("get_account_info rpc request received: {:?}", pubkey_str);
|
|
|
|
let pubkey = verify_pubkey(pubkey_str)?;
|
2019-01-15 12:20:07 -08:00
|
|
|
meta.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.get_account_info(&pubkey, commitment)
|
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
|
|
|
|
);
|
|
|
|
meta.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.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,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-06-29 10:59:07 -06:00
|
|
|
) -> Result<Vec<(String, Account)>> {
|
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)?;
|
2019-06-29 10:59:07 -06:00
|
|
|
meta.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.get_program_accounts(&program_id, commitment)
|
2019-06-29 10:59:07 -06:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_inflation(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Inflation> {
|
2019-08-27 18:17:03 -04:00
|
|
|
debug!("get_inflation rpc request received");
|
|
|
|
Ok(meta
|
|
|
|
.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.get_inflation(commitment)
|
2019-08-27 18:17:03 -04:00
|
|
|
.unwrap())
|
|
|
|
}
|
|
|
|
|
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");
|
|
|
|
Ok(meta
|
|
|
|
.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get_epoch_schedule()
|
|
|
|
.unwrap())
|
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_balance(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
pubkey_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<u64> {
|
|
|
|
debug!("get_balance rpc request received: {:?}", pubkey_str);
|
|
|
|
let pubkey = verify_pubkey(pubkey_str)?;
|
|
|
|
Ok(meta
|
|
|
|
.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.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>> {
|
|
|
|
let cluster_info = meta.cluster_info.read().unwrap();
|
|
|
|
fn valid_address_or_none(addr: &SocketAddr) -> Option<SocketAddr> {
|
|
|
|
if ContactInfo::is_valid_address(addr) {
|
|
|
|
Some(*addr)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(cluster_info
|
|
|
|
.all_peers()
|
|
|
|
.iter()
|
2019-04-29 13:19:24 -07:00
|
|
|
.filter_map(|(contact_info, _)| {
|
2019-04-23 14:46:41 -07:00
|
|
|
if ContactInfo::is_valid_address(&contact_info.gossip) {
|
|
|
|
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),
|
|
|
|
})
|
|
|
|
} 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>,
|
|
|
|
) -> Result<RpcEpochInfo> {
|
|
|
|
let bank = meta.request_processor.read().unwrap().bank(commitment);
|
2019-07-19 07:31:18 -07:00
|
|
|
let epoch_schedule = bank.epoch_schedule();
|
|
|
|
let (epoch, slot_index) = epoch_schedule.get_epoch_and_slot_index(bank.slot());
|
2019-09-02 12:21:06 -07:00
|
|
|
let slot = bank.slot();
|
2019-07-19 07:31:18 -07:00
|
|
|
Ok(RpcEpochInfo {
|
|
|
|
epoch,
|
|
|
|
slot_index,
|
2019-07-19 11:45:04 -06:00
|
|
|
slots_in_epoch: epoch_schedule.get_slots_in_epoch(epoch),
|
2019-09-02 12:21:06 -07:00
|
|
|
absolute_slot: slot,
|
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,
|
2019-11-04 16:44:27 -07:00
|
|
|
) -> Result<(Option<BlockCommitment>, u64)> {
|
2019-10-14 16:24:10 -06:00
|
|
|
Ok(meta
|
|
|
|
.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-04 16:44:27 -07:00
|
|
|
.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,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<Option<Vec<String>>> {
|
|
|
|
let bank = meta.request_processor.read().unwrap().bank(commitment);
|
2019-07-19 07:31:18 -07:00
|
|
|
Ok(
|
2019-10-18 10:28:51 -06:00
|
|
|
solana_ledger::leader_schedule_utils::leader_schedule(bank.epoch(), &bank).map(
|
2019-07-19 07:31:18 -07:00
|
|
|
|leader_schedule| {
|
|
|
|
leader_schedule
|
|
|
|
.get_slot_leaders()
|
|
|
|
.iter()
|
|
|
|
.map(|pubkey| pubkey.to_string())
|
|
|
|
.collect()
|
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_recent_blockhash(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<(String, FeeCalculator)> {
|
2019-03-28 11:45:34 -07:00
|
|
|
debug!("get_recent_blockhash rpc request received");
|
2019-03-18 14:18:43 -07:00
|
|
|
Ok(meta
|
|
|
|
.request_processor
|
2019-03-02 10:20:10 -08:00
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.get_recent_blockhash(commitment))
|
2018-08-13 12:52:37 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2019-04-05 19:07:30 -06:00
|
|
|
fn get_signature_status(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2019-11-06 14:15:00 -07:00
|
|
|
signature_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-04-05 19:07:30 -06:00
|
|
|
) -> Result<Option<transaction::Result<()>>> {
|
2019-11-06 14:15:00 -07:00
|
|
|
self.get_signature_confirmation(meta, signature_str, commitment)
|
2019-04-05 19:07:30 -06:00
|
|
|
.map(|res| res.map(|x| x.1))
|
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> {
|
|
|
|
meta.request_processor.read().unwrap().get_slot(commitment)
|
2019-06-12 16:43:05 -07:00
|
|
|
}
|
|
|
|
|
2019-03-21 07:43:21 -07:00
|
|
|
fn get_num_blocks_since_signature_confirmation(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2019-11-06 14:15:00 -07:00
|
|
|
signature_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-04-05 19:07:30 -06:00
|
|
|
) -> Result<Option<usize>> {
|
2019-11-06 14:15:00 -07:00
|
|
|
self.get_signature_confirmation(meta, signature_str, commitment)
|
2019-04-05 19:07:30 -06:00
|
|
|
.map(|res| res.map(|x| x.0))
|
2019-03-21 07:43:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_signature_confirmation(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
2019-11-06 14:15:00 -07:00
|
|
|
signature_str: String,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
2019-04-05 19:07:30 -06:00
|
|
|
) -> Result<Option<(usize, transaction::Result<()>)>> {
|
2019-11-06 14:15:00 -07:00
|
|
|
debug!(
|
|
|
|
"get_signature_confirmation rpc request received: {:?}",
|
|
|
|
signature_str
|
|
|
|
);
|
|
|
|
let signature = verify_signature(&signature_str)?;
|
2019-04-05 19:07:30 -06:00
|
|
|
Ok(meta
|
2019-01-15 12:20:07 -08:00
|
|
|
.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.get_signature_confirmation_status(signature, commitment))
|
2018-09-26 17:12:40 -07:00
|
|
|
}
|
2019-02-26 12:25:46 -08: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");
|
2019-01-15 12:20:07 -08:00
|
|
|
meta.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.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");
|
2019-11-06 14:15:00 -07:00
|
|
|
meta.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get_total_supply(commitment)
|
2019-06-21 22:00:26 -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
|
|
|
|
|
|
|
let drone_addr = meta
|
|
|
|
.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.config
|
|
|
|
.drone_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
|
|
|
|
2019-03-02 10:25:16 -08:00
|
|
|
let blockhash = meta
|
2019-03-02 10:20:10 -08:00
|
|
|
.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.bank(commitment.clone())
|
2019-06-10 22:18:32 -07:00
|
|
|
.confirmed_last_blockhash()
|
|
|
|
.0;
|
2019-03-06 09:26:12 -08:00
|
|
|
let transaction = request_airdrop_transaction(&drone_addr, &pubkey, lamports, blockhash)
|
|
|
|
.map_err(|err| {
|
|
|
|
info!("request_airdrop_transaction failed: {:?}", err);
|
|
|
|
Error::internal_error()
|
2019-08-23 22:47:54 -07:00
|
|
|
})?;
|
2018-11-14 18:57:34 -08:00
|
|
|
|
|
|
|
let data = serialize(&transaction).map_err(|err| {
|
|
|
|
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
|
|
|
|
2018-11-14 18:57:34 -08:00
|
|
|
let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
2019-09-06 09:07:40 -07:00
|
|
|
let tpu_addr = get_tpu_addr(&meta.cluster_info)?;
|
2018-11-14 18:57:34 -08:00
|
|
|
transactions_socket
|
2019-09-06 09:07:40 -07:00
|
|
|
.send_to(&data, tpu_addr)
|
2018-11-14 18:57:34 -08:00
|
|
|
.map_err(|err| {
|
|
|
|
info!("request_airdrop: send_to error: {:?}", err);
|
|
|
|
Error::internal_error()
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let signature = transaction.signatures[0];
|
2018-08-22 12:25:21 -06:00
|
|
|
let now = Instant::now();
|
2018-08-26 22:32:51 -06:00
|
|
|
let mut signature_status;
|
2019-11-10 12:20:52 -05:00
|
|
|
let signature_timeout = match &commitment {
|
|
|
|
Some(config) if config.commitment == CommitmentLevel::Recent => 5,
|
|
|
|
_ => 30,
|
|
|
|
};
|
2018-08-22 12:25:21 -06:00
|
|
|
loop {
|
2019-01-15 12:20:07 -08:00
|
|
|
signature_status = meta
|
|
|
|
.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.get_signature_confirmation_status(signature, commitment.clone())
|
|
|
|
.map(|x| x.1);
|
2018-08-26 22:32:51 -06:00
|
|
|
|
2019-01-31 06:53:52 -08:00
|
|
|
if signature_status == Some(Ok(())) {
|
2018-11-14 18:57:34 -08:00
|
|
|
info!("airdrop signature ok");
|
2019-05-20 22:21:13 -07:00
|
|
|
return Ok(signature.to_string());
|
2019-11-10 12:20:52 -05:00
|
|
|
} else if now.elapsed().as_secs() > signature_timeout {
|
2018-10-23 10:59:43 -07:00
|
|
|
info!("airdrop signature timeout");
|
2018-08-22 12:25:21 -06:00
|
|
|
return Err(Error::internal_error());
|
|
|
|
}
|
|
|
|
sleep(Duration::from_millis(100));
|
|
|
|
}
|
2018-08-22 11:54:37 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2018-08-22 11:53:24 -06:00
|
|
|
fn send_transaction(&self, meta: Self::Metadata, data: Vec<u8>) -> Result<String> {
|
2018-10-24 14:06:45 -07:00
|
|
|
if data.len() >= PACKET_DATA_SIZE {
|
|
|
|
info!(
|
|
|
|
"send_transaction: transaction too large: {} bytes (max: {} bytes)",
|
|
|
|
data.len(),
|
|
|
|
PACKET_DATA_SIZE
|
|
|
|
);
|
|
|
|
return Err(Error::invalid_request());
|
|
|
|
}
|
2019-11-06 00:07:57 -08:00
|
|
|
let tx: Transaction = bincode::config()
|
|
|
|
.limit(PACKET_DATA_SIZE as u64)
|
|
|
|
.deserialize(&data)
|
|
|
|
.map_err(|err| {
|
|
|
|
info!("send_transaction: deserialize error: {:?}", err);
|
|
|
|
Error::invalid_request()
|
|
|
|
})?;
|
|
|
|
|
2018-08-22 11:53:24 -06:00
|
|
|
let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
2019-09-06 09:07:40 -07:00
|
|
|
let tpu_addr = get_tpu_addr(&meta.cluster_info)?;
|
|
|
|
trace!("send_transaction: leader is {:?}", &tpu_addr);
|
2018-08-22 11:53:24 -06:00
|
|
|
transactions_socket
|
2019-09-06 09:07:40 -07:00
|
|
|
.send_to(&data, tpu_addr)
|
2018-09-18 11:31:21 -07:00
|
|
|
.map_err(|err| {
|
2018-10-23 10:59:43 -07:00
|
|
|
info!("send_transaction: send_to error: {:?}", err);
|
2018-09-18 11:31:21 -07:00
|
|
|
Error::internal_error()
|
|
|
|
})?;
|
2019-05-20 22:21:13 -07:00
|
|
|
let signature = tx.signatures[0].to_string();
|
2018-10-24 14:06:45 -07:00
|
|
|
trace!(
|
|
|
|
"send_transaction: sent {} bytes, signature={}",
|
|
|
|
data.len(),
|
|
|
|
signature
|
|
|
|
);
|
|
|
|
Ok(signature)
|
2018-08-22 11:53:24 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_slot_leader(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<String> {
|
|
|
|
meta.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get_slot_leader(commitment)
|
2019-04-23 14:46:41 -07:00
|
|
|
}
|
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_vote_accounts(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<RpcVoteAccountStatus> {
|
|
|
|
meta.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get_vote_accounts(commitment)
|
2019-05-20 22:21:13 -07:00
|
|
|
}
|
|
|
|
|
2019-07-10 13:33:29 -07:00
|
|
|
fn get_storage_turn_rate(&self, meta: Self::Metadata) -> Result<u64> {
|
2019-01-15 12:20:07 -08:00
|
|
|
meta.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-07-10 13:33:29 -07:00
|
|
|
.get_storage_turn_rate()
|
2018-11-02 08:40:29 -07:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2019-07-10 13:33:29 -07:00
|
|
|
fn get_storage_turn(&self, meta: Self::Metadata) -> Result<(String, u64)> {
|
|
|
|
meta.request_processor.read().unwrap().get_storage_turn()
|
2018-12-10 11:38:29 -08:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn get_slots_per_segment(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
commitment: Option<CommitmentConfig>,
|
|
|
|
) -> Result<u64> {
|
2019-07-09 16:48:40 -07:00
|
|
|
meta.request_processor
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-11-06 14:15:00 -07:00
|
|
|
.get_slots_per_segment(commitment)
|
2019-07-09 16:48:40 -07:00
|
|
|
}
|
|
|
|
|
2019-11-02 00:38:30 -07:00
|
|
|
fn get_storage_pubkeys_for_slot(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
slot: Slot,
|
|
|
|
) -> Result<Vec<Pubkey>> {
|
2018-12-10 11:38:29 -08:00
|
|
|
meta.request_processor
|
2019-01-15 12:20:07 -08:00
|
|
|
.read()
|
|
|
|
.unwrap()
|
2019-05-03 16:27:53 -07:00
|
|
|
.get_storage_pubkeys_for_slot(slot)
|
2018-12-10 11:38:29 -08:00
|
|
|
}
|
2019-03-03 22:01:09 -08:00
|
|
|
|
2019-10-11 13:30:52 -06:00
|
|
|
fn validator_exit(&self, meta: Self::Metadata) -> Result<bool> {
|
|
|
|
meta.request_processor.read().unwrap().validator_exit()
|
2019-03-03 22:01:09 -08:00
|
|
|
}
|
2019-08-07 20:06:27 -06:00
|
|
|
|
|
|
|
fn get_version(&self, _: Self::Metadata) -> Result<RpcVersionInfo> {
|
|
|
|
Ok(RpcVersionInfo {
|
2019-11-10 22:39:13 -07:00
|
|
|
solana_core: crate::version!().to_string(),
|
2019-08-07 20:06:27 -06:00
|
|
|
})
|
|
|
|
}
|
2019-08-10 22:54:46 -07:00
|
|
|
|
2019-11-06 14:15:00 -07:00
|
|
|
fn set_log_filter(&self, _meta: Self::Metadata, filter: String) -> Result<()> {
|
2019-08-10 22:54:46 -07:00
|
|
|
solana_logger::setup_with_filter(&filter);
|
|
|
|
Ok(())
|
|
|
|
}
|
2018-08-14 18:03:48 -06:00
|
|
|
}
|
2019-02-26 12:25:46 -08:00
|
|
|
|
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::{
|
|
|
|
contact_info::ContactInfo,
|
2019-11-08 23:56:57 -05:00
|
|
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
2019-10-14 16:24:10 -06:00
|
|
|
};
|
2019-06-21 22:00:26 -06:00
|
|
|
use jsonrpc_core::{MetaIoHandler, Output, Response, Value};
|
2019-10-14 16:24:10 -06:00
|
|
|
use solana_sdk::{
|
|
|
|
fee_calculator::DEFAULT_BURN_PERCENT,
|
|
|
|
hash::{hash, Hash},
|
|
|
|
instruction::InstructionError,
|
|
|
|
signature::{Keypair, KeypairUtil},
|
|
|
|
system_transaction,
|
|
|
|
transaction::TransactionError,
|
|
|
|
};
|
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
sync::atomic::{AtomicBool, Ordering},
|
|
|
|
thread,
|
|
|
|
};
|
2018-08-13 11:24:39 -06:00
|
|
|
|
2019-06-21 22:00:26 -06:00
|
|
|
const TEST_MINT_LAMPORTS: u64 = 10_000;
|
|
|
|
|
2019-10-14 16:24:10 -06:00
|
|
|
struct RpcHandler {
|
|
|
|
io: MetaIoHandler<Meta>,
|
|
|
|
meta: Meta,
|
|
|
|
bank: Arc<Bank>,
|
|
|
|
blockhash: Hash,
|
|
|
|
alice: Keypair,
|
|
|
|
leader_pubkey: Pubkey,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
2019-10-14 16:24:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn start_rpc_handler_with_tx(pubkey: &Pubkey) -> RpcHandler {
|
2019-03-18 14:18:43 -07:00
|
|
|
let (bank_forks, alice) = new_bank_forks();
|
|
|
|
let bank = bank_forks.read().unwrap().working_bank();
|
2019-10-14 16:24:10 -06:00
|
|
|
|
2019-11-04 16:44:27 -07:00
|
|
|
let commitment_slot0 = BlockCommitment::new([8; MAX_LOCKOUT_HISTORY]);
|
|
|
|
let commitment_slot1 = BlockCommitment::new([9; MAX_LOCKOUT_HISTORY]);
|
|
|
|
let mut block_commitment: HashMap<u64, BlockCommitment> = HashMap::new();
|
|
|
|
block_commitment
|
|
|
|
.entry(0)
|
|
|
|
.or_insert(commitment_slot0.clone());
|
|
|
|
block_commitment
|
|
|
|
.entry(1)
|
|
|
|
.or_insert(commitment_slot1.clone());
|
|
|
|
let block_commitment_cache =
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new(block_commitment, 42)));
|
2019-10-14 16:24:10 -06: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");
|
|
|
|
|
2019-05-20 10:03:19 -07:00
|
|
|
let tx = system_transaction::transfer(&alice, &alice.pubkey(), 20, blockhash);
|
2019-04-05 19:07:30 -06:00
|
|
|
let _ = bank.process_transaction(&tx);
|
|
|
|
|
2019-01-28 14:53:50 -08:00
|
|
|
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
|
|
|
StorageState::default(),
|
2019-03-03 22:01:09 -08:00
|
|
|
JsonRpcConfig::default(),
|
2019-03-18 14:18:43 -07:00
|
|
|
bank_forks,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache.clone(),
|
2019-08-20 23:59:31 -07:00
|
|
|
&validator_exit,
|
2019-01-28 14:53:50 -08:00
|
|
|
)));
|
2019-03-06 19:09:37 -08:00
|
|
|
let cluster_info = Arc::new(RwLock::new(ClusterInfo::new_with_invalid_keypair(
|
2019-03-08 17:23:07 -08:00
|
|
|
ContactInfo::default(),
|
2019-03-06 19:09:37 -08:00
|
|
|
)));
|
2018-11-02 08:40:29 -07:00
|
|
|
|
2019-07-09 22:06:47 -07:00
|
|
|
cluster_info
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.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());
|
2018-08-22 11:54:37 -06:00
|
|
|
let meta = Meta {
|
|
|
|
request_processor,
|
2018-10-12 14:25:56 -06:00
|
|
|
cluster_info,
|
2019-11-08 23:56:57 -05:00
|
|
|
genesis_hash: Hash::default(),
|
2018-08-22 11:54:37 -06:00
|
|
|
};
|
2019-10-14 16:24:10 -06:00
|
|
|
RpcHandler {
|
|
|
|
io,
|
|
|
|
meta,
|
|
|
|
bank,
|
|
|
|
blockhash,
|
|
|
|
alice,
|
|
|
|
leader_pubkey,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache,
|
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();
|
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-03-18 14:18:43 -07:00
|
|
|
let (bank_forks, alice) = new_bank_forks();
|
|
|
|
let bank = bank_forks.read().unwrap().working_bank();
|
2019-11-04 16:44:27 -07:00
|
|
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
|
2019-03-18 14:18:43 -07:00
|
|
|
let request_processor = JsonRpcRequestProcessor::new(
|
|
|
|
StorageState::default(),
|
|
|
|
JsonRpcConfig::default(),
|
|
|
|
bank_forks,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache,
|
2019-08-20 23:59:31 -07:00
|
|
|
&validator_exit,
|
2019-03-18 14:18:43 -07:00
|
|
|
);
|
2018-10-15 11:01:40 -06:00
|
|
|
thread::spawn(move || {
|
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, &bob_pubkey, 20, blockhash);
|
2019-02-20 21:23:44 -08:00
|
|
|
bank.process_transaction(&tx).expect("process transaction");
|
2018-12-07 20:01:28 -07:00
|
|
|
})
|
|
|
|
.join()
|
2018-10-15 11:01:40 -06:00
|
|
|
.unwrap();
|
2019-11-06 14:15:00 -07:00
|
|
|
assert_eq!(request_processor.get_transaction_count(None).unwrap(), 1);
|
2018-10-15 11:01:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_rpc_get_balance() {
|
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-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":["{}"]}}"#,
|
2018-08-13 11:24:39 -06:00
|
|
|
bob_pubkey
|
|
|
|
);
|
2018-10-15 11:01:40 -06:00
|
|
|
let res = io.handle_request_sync(&req, meta);
|
2018-08-20 14:20:20 -07:00
|
|
|
let expected = format!(r#"{{"jsonrpc":"2.0","result":20,"id":1}}"#);
|
2018-08-13 11:24:39 -06:00
|
|
|
let expected: Response =
|
2018-08-14 18:03:48 -06:00
|
|
|
serde_json::from_str(&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
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getClusterNodes"}}"#);
|
|
|
|
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!(
|
2019-06-12 14:12:08 -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:8899"}}],"id":1}}"#,
|
2019-05-23 23:20:04 -07:00
|
|
|
leader_pubkey,
|
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
|
|
|
|
|
|
|
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getSlotLeader"}}"#);
|
|
|
|
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();
|
2019-10-14 16:24:10 -06:00
|
|
|
let RpcHandler { io, meta, .. } = start_rpc_handler_with_tx(&bob_pubkey);
|
2018-08-13 11:24:39 -06:00
|
|
|
|
2018-08-15 12:41:39 -06:00
|
|
|
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}}"#);
|
2018-10-15 11:01:40 -06:00
|
|
|
let res = io.handle_request_sync(&req, meta);
|
2018-08-14 18:03:48 -06:00
|
|
|
let expected = format!(r#"{{"jsonrpc":"2.0","result":1,"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
|
|
|
|
|
|
|
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getTotalSupply"}}"#);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
|
|
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getInflation"}}"#);
|
|
|
|
let rep = io.handle_request_sync(&req, meta);
|
|
|
|
let res: Response = serde_json::from_str(&rep.expect("actual response"))
|
|
|
|
.expect("actual response deserialization");
|
|
|
|
let inflation: Inflation = 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!(inflation, bank.inflation());
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getEpochSchedule"}}"#);
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
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);
|
2018-09-20 13:20:37 -07:00
|
|
|
let expected = r#"{
|
|
|
|
"jsonrpc":"2.0",
|
|
|
|
"result":{
|
2018-11-12 09:29:17 -08:00
|
|
|
"owner": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
|
2019-03-05 16:28:14 -08:00
|
|
|
"lamports": 20,
|
2019-03-14 10:48:27 -06:00
|
|
|
"data": [],
|
2019-08-23 14:04:53 -07:00
|
|
|
"executable": false,
|
|
|
|
"rent_epoch": 0
|
2018-09-20 13:20:37 -07:00
|
|
|
},
|
|
|
|
"id":1}
|
|
|
|
"#;
|
|
|
|
let expected: Response =
|
|
|
|
serde_json::from_str(&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,
|
|
|
|
..
|
|
|
|
} = 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
|
|
|
|
);
|
|
|
|
let res = io.handle_request_sync(&req, meta);
|
|
|
|
let expected = format!(
|
|
|
|
r#"{{
|
|
|
|
"jsonrpc":"2.0",
|
|
|
|
"result":[["{}", {{
|
|
|
|
"owner": {:?},
|
|
|
|
"lamports": 20,
|
|
|
|
"data": [],
|
2019-08-23 14:04:53 -07:00
|
|
|
"executable": false,
|
|
|
|
"rent_epoch": 0
|
2019-06-29 10:59:07 -06:00
|
|
|
}}]],
|
|
|
|
"id":1}}
|
|
|
|
"#,
|
|
|
|
bob.pubkey(),
|
|
|
|
new_program_id.as_ref()
|
|
|
|
);
|
|
|
|
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_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);
|
|
|
|
let expected = format!(r#"{{"jsonrpc":"2.0","result":true,"id":1}}"#);
|
|
|
|
let expected: Response =
|
|
|
|
serde_json::from_str(&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() {
|
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-08-15 10:37:02 -06:00
|
|
|
|
2018-10-15 11:01:40 -06:00
|
|
|
let req = format!(
|
|
|
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","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.clone());
|
2019-04-05 19:07:30 -06:00
|
|
|
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
|
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"result": expected_res,
|
|
|
|
"id": 1
|
|
|
|
});
|
2018-10-15 11:01:40 -06:00
|
|
|
let expected: Response =
|
2019-04-05 19:07:30 -06: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-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!(
|
|
|
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","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());
|
|
|
|
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
|
2019-05-20 10:03:19 -07:00
|
|
|
let tx = system_transaction::transfer(&alice, &alice.pubkey(), 20, blockhash);
|
2019-04-05 19:07:30 -06:00
|
|
|
let req = format!(
|
|
|
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"#,
|
|
|
|
tx.signatures[0]
|
|
|
|
);
|
2018-10-15 11:01:40 -06:00
|
|
|
let res = io.handle_request_sync(&req, meta);
|
2019-04-05 19:07:30 -06:00
|
|
|
let expected_res: Option<transaction::Result<()>> = Some(Err(
|
|
|
|
TransactionError::InstructionError(0, InstructionError::DuplicateAccountIndex),
|
|
|
|
));
|
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"result": expected_res,
|
|
|
|
"id": 1
|
|
|
|
});
|
2018-08-13 11:24:39 -06:00
|
|
|
let expected: Response =
|
2019-04-05 19:07:30 -06: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);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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
|
|
|
|
2019-03-02 10:25:16 -08:00
|
|
|
let req = format!(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",
|
|
|
|
"result": [ blockhash.to_string(), {
|
2019-08-09 13:58:46 -07:00
|
|
|
"burnPercent": DEFAULT_BURN_PERCENT,
|
2019-06-10 22:18:32 -07:00
|
|
|
"lamportsPerSignature": 0,
|
2019-06-21 17:23:26 -07:00
|
|
|
"maxLamportsPerSignature": 0,
|
|
|
|
"minLamportsPerSignature": 0,
|
2019-06-10 22:18:32 -07:00
|
|
|
"targetLamportsPerSignature": 0,
|
|
|
|
"targetSignaturesPerSlot": 0
|
|
|
|
}],
|
|
|
|
"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-03-06 09:26:12 -08:00
|
|
|
// Expect internal error because no drone 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-04 16:44:27 -07: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());
|
|
|
|
let meta = Meta {
|
2019-02-22 17:15:15 -08:00
|
|
|
request_processor: {
|
2019-03-18 14:18:43 -07:00
|
|
|
let request_processor = JsonRpcRequestProcessor::new(
|
2019-03-03 22:01:09 -08:00
|
|
|
StorageState::default(),
|
|
|
|
JsonRpcConfig::default(),
|
2019-03-18 14:18:43 -07:00
|
|
|
new_bank_forks().0,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache,
|
2019-08-20 23:59:31 -07:00
|
|
|
&validator_exit,
|
2019-03-03 22:01:09 -08:00
|
|
|
);
|
2019-02-22 17:15:15 -08:00
|
|
|
Arc::new(RwLock::new(request_processor))
|
|
|
|
},
|
2019-03-06 19:09:37 -08:00
|
|
|
cluster_info: Arc::new(RwLock::new(ClusterInfo::new_with_invalid_keypair(
|
2019-03-08 17:23:07 -08:00
|
|
|
ContactInfo::default(),
|
2019-03-06 19:09:37 -08:00
|
|
|
))),
|
2019-11-08 23:56:57 -05:00
|
|
|
genesis_hash: Hash::default(),
|
2018-08-13 11:24:39 -06:00
|
|
|
};
|
|
|
|
|
2018-10-15 11:01:40 -06:00
|
|
|
let req =
|
|
|
|
r#"{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":[[0,0,0,0,0,0,0,0]]}"#;
|
|
|
|
let res = io.handle_request_sync(req, meta.clone());
|
2018-08-13 11:24:39 -06:00
|
|
|
let expected =
|
|
|
|
r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"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"))
|
|
|
|
.expect("actual response deserialization");
|
|
|
|
assert_eq!(expected, result);
|
|
|
|
}
|
2018-10-15 11:01:40 -06:00
|
|
|
|
2018-10-12 14:25:56 -06:00
|
|
|
#[test]
|
2019-03-08 09:48:21 -08:00
|
|
|
fn test_rpc_get_tpu_addr() {
|
2019-03-06 19:09:37 -08:00
|
|
|
let cluster_info = Arc::new(RwLock::new(ClusterInfo::new_with_invalid_keypair(
|
2019-03-08 17:23:07 -08:00
|
|
|
ContactInfo::new_with_socketaddr(&socketaddr!("127.0.0.1:1234")),
|
2019-03-06 19:09:37 -08:00
|
|
|
)));
|
2018-10-12 14:25:56 -06:00
|
|
|
assert_eq!(
|
2019-03-08 09:48:21 -08:00
|
|
|
get_tpu_addr(&cluster_info),
|
2018-10-12 14:25:56 -06:00
|
|
|
Ok(socketaddr!("127.0.0.1:1234"))
|
|
|
|
);
|
|
|
|
}
|
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()),
|
|
|
|
Err(Error::invalid_request())
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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()),
|
2018-10-15 11:01:40 -06:00
|
|
|
Err(Error::invalid_request())
|
|
|
|
);
|
|
|
|
}
|
2019-03-03 22:01:09 -08:00
|
|
|
|
2019-03-18 14:18:43 -07:00
|
|
|
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, 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-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-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
|
|
|
(
|
|
|
|
Arc::new(RwLock::new(BankForks::new(bank.slot(), bank))),
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair,
|
2019-03-18 14:18:43 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-08-20 23:59:31 -07:00
|
|
|
pub 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)))
|
|
|
|
}
|
|
|
|
|
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-04 16:44:27 -07:00
|
|
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
|
2019-03-18 14:18:43 -07:00
|
|
|
let request_processor = JsonRpcRequestProcessor::new(
|
|
|
|
StorageState::default(),
|
|
|
|
JsonRpcConfig::default(),
|
|
|
|
new_bank_forks().0,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache,
|
2019-08-20 23:59:31 -07:00
|
|
|
&validator_exit,
|
2019-03-18 14:18:43 -07:00
|
|
|
);
|
2019-10-11 13:30:52 -06:00
|
|
|
assert_eq!(request_processor.validator_exit(), Ok(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-04 16:44:27 -07: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;
|
2019-03-18 14:18:43 -07:00
|
|
|
let request_processor = JsonRpcRequestProcessor::new(
|
|
|
|
StorageState::default(),
|
|
|
|
config,
|
|
|
|
new_bank_forks().0,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache,
|
2019-08-20 23:59:31 -07:00
|
|
|
&validator_exit,
|
2019-03-18 14:18:43 -07:00
|
|
|
);
|
2019-10-11 13:30:52 -06:00
|
|
|
assert_eq!(request_processor.validator_exit(), Ok(true));
|
2019-03-03 22:01:09 -08:00
|
|
|
assert_eq!(exit.load(Ordering::Relaxed), true);
|
|
|
|
}
|
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
|
|
|
|
|
|
|
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getVersion"}}"#);
|
|
|
|
let res = io.handle_request_sync(&req, meta);
|
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"result": {
|
2019-11-10 22:39:13 -07:00
|
|
|
"solana-core": crate::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);
|
2019-11-04 16:44:27 -07:00
|
|
|
let commitment_slot0 = BlockCommitment::new([8; MAX_LOCKOUT_HISTORY]);
|
|
|
|
let commitment_slot1 = BlockCommitment::new([9; MAX_LOCKOUT_HISTORY]);
|
|
|
|
let mut block_commitment: HashMap<u64, BlockCommitment> = HashMap::new();
|
|
|
|
block_commitment
|
|
|
|
.entry(0)
|
|
|
|
.or_insert(commitment_slot0.clone());
|
|
|
|
block_commitment
|
|
|
|
.entry(1)
|
|
|
|
.or_insert(commitment_slot1.clone());
|
|
|
|
let block_commitment_cache =
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new(block_commitment, 42)));
|
2019-10-14 16:24:10 -06:00
|
|
|
|
|
|
|
let mut config = JsonRpcConfig::default();
|
|
|
|
config.enable_validator_exit = true;
|
|
|
|
let request_processor = JsonRpcRequestProcessor::new(
|
|
|
|
StorageState::default(),
|
|
|
|
config,
|
|
|
|
new_bank_forks().0,
|
2019-11-04 16:44:27 -07:00
|
|
|
block_commitment_cache,
|
2019-10-14 16:24:10 -06:00
|
|
|
&validator_exit,
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2019-11-04 16:44:27 -07:00
|
|
|
request_processor.get_block_commitment(0),
|
|
|
|
(Some(commitment_slot0), 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),
|
|
|
|
(Some(commitment_slot1), 42)
|
2019-10-14 16:24:10 -06:00
|
|
|
);
|
2019-11-04 16:44:27 -07:00
|
|
|
assert_eq!(request_processor.get_block_commitment(2), (None, 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);
|
|
|
|
|
|
|
|
let req =
|
2019-11-04 16:44:27 -07:00
|
|
|
format!(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");
|
2019-11-04 16:44:27 -07:00
|
|
|
let (commitment, total_staked): (Option<BlockCommitment>, u64) =
|
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");
|
|
|
|
};
|
|
|
|
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)
|
2019-10-14 16:24:10 -06:00
|
|
|
.cloned()
|
|
|
|
);
|
|
|
|
assert_eq!(total_staked, 42);
|
|
|
|
|
|
|
|
let req =
|
2019-11-04 16:44:27 -07:00
|
|
|
format!(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");
|
2019-11-04 16:44:27 -07:00
|
|
|
let (commitment, total_staked): (Option<BlockCommitment>, u64) =
|
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");
|
|
|
|
};
|
2019-11-04 16:44:27 -07:00
|
|
|
assert_eq!(commitment, None);
|
2019-10-14 16:24:10 -06:00
|
|
|
assert_eq!(total_staked, 42);
|
|
|
|
}
|
2018-08-13 11:24:39 -06:00
|
|
|
}
|