diff --git a/Cargo.lock b/Cargo.lock index ae4ca34df..543416c59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4446,10 +4446,12 @@ dependencies = [ "solana-measure", "solana-metrics", "solana-net-utils", + "solana-rpc", "solana-runtime", "solana-sdk", "solana-streamer", "solana-version", + "thiserror", ] [[package]] diff --git a/bench-tps/Cargo.toml b/bench-tps/Cargo.toml index 28f0fef15..0c6baa97c 100644 --- a/bench-tps/Cargo.toml +++ b/bench-tps/Cargo.toml @@ -24,10 +24,12 @@ solana-logger = { path = "../logger", version = "=1.11.0" } solana-measure = { path = "../measure", version = "=1.11.0" } solana-metrics = { path = "../metrics", version = "=1.11.0" } solana-net-utils = { path = "../net-utils", version = "=1.11.0" } +solana-rpc = { path = "../rpc", version = "=1.11.0" } solana-runtime = { path = "../runtime", version = "=1.11.0" } solana-sdk = { path = "../sdk", version = "=1.11.0" } solana-streamer = { path = "../streamer", version = "=1.11.0" } solana-version = { path = "../version", version = "=1.11.0" } +thiserror = "1.0" [dev-dependencies] serial_test = "0.6.0" diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index 0ee62109e..487d3922e 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -1,19 +1,21 @@ use { - crate::cli::Config, + crate::{ + bench_tps_client::*, + cli::Config, + perf_utils::{sample_txs, SampleStats}, + }, log::*, rayon::prelude::*, - solana_client::perf_utils::{sample_txs, SampleStats}, solana_core::gen_keys::GenKeys, - solana_faucet::faucet::request_airdrop_transaction, solana_measure::measure::Measure, solana_metrics::{self, datapoint_info}, solana_sdk::{ - client::Client, clock::{DEFAULT_MS_PER_SLOT, DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE}, commitment_config::CommitmentConfig, hash::Hash, instruction::{AccountMeta, Instruction}, message::Message, + native_token::Sol, pubkey::Pubkey, signature::{Keypair, Signer}, system_instruction, system_transaction, @@ -22,7 +24,6 @@ use { }, std::{ collections::{HashSet, VecDeque}, - net::SocketAddr, process::exit, sync::{ atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}, @@ -38,16 +39,9 @@ const MAX_TX_QUEUE_AGE: u64 = (MAX_PROCESSING_AGE as f64 * DEFAULT_S_PER_SLOT) a pub const MAX_SPENDS_PER_TX: u64 = 4; -#[derive(Debug)] -pub enum BenchTpsError { - AirdropFailure, -} - -pub type Result = std::result::Result; - pub type SharedTransactions = Arc>>>; -fn get_latest_blockhash(client: &T) -> Hash { +fn get_latest_blockhash(client: &T) -> Hash { loop { match client.get_latest_blockhash_with_commitment(CommitmentConfig::processed()) { Ok((blockhash, _)) => return blockhash, @@ -61,7 +55,7 @@ fn get_latest_blockhash(client: &T) -> Hash { fn wait_for_target_slots_per_epoch(target_slots_per_epoch: u64, client: &Arc) where - T: 'static + Client + Send + Sync, + T: 'static + BenchTpsClient + Send + Sync, { if target_slots_per_epoch != 0 { info!( @@ -91,7 +85,7 @@ fn create_sampler_thread( maxes: &Arc>>, ) -> JoinHandle<()> where - T: 'static + Client + Send + Sync, + T: 'static + BenchTpsClient + Send + Sync, { info!("Sampling TPS every {} second...", sample_period); let exit_signal = exit_signal.clone(); @@ -169,7 +163,7 @@ fn create_sender_threads( shared_tx_active_thread_count: &Arc, ) -> Vec> where - T: 'static + Client + Send + Sync, + T: 'static + BenchTpsClient + Send + Sync, { (0..threads) .map(|_| { @@ -197,7 +191,7 @@ where pub fn do_bench_tps(client: Arc, config: Config, gen_keypairs: Vec) -> u64 where - T: 'static + Client + Send + Sync, + T: 'static + BenchTpsClient + Send + Sync, { let Config { id, @@ -391,7 +385,7 @@ fn generate_txs( } } -fn get_new_latest_blockhash(client: &Arc, blockhash: &Hash) -> Option { +fn get_new_latest_blockhash(client: &Arc, blockhash: &Hash) -> Option { let start = Instant::now(); while start.elapsed().as_secs() < 5 { if let Ok(new_blockhash) = client.get_latest_blockhash() { @@ -407,7 +401,7 @@ fn get_new_latest_blockhash(client: &Arc, blockhash: &Hash) -> Opt None } -fn poll_blockhash( +fn poll_blockhash( exit_signal: &Arc, blockhash: &Arc>, client: &Arc, @@ -449,7 +443,7 @@ fn poll_blockhash( } } -fn do_tx_transfers( +fn do_tx_transfers( exit_signal: &Arc, shared_txs: &SharedTransactions, shared_tx_thread_count: &Arc, @@ -467,11 +461,7 @@ fn do_tx_transfers( }; if let Some(txs0) = txs { shared_tx_thread_count.fetch_add(1, Ordering::Relaxed); - info!( - "Transferring 1 unit {} times... to {}", - txs0.len(), - client.as_ref().tpu_addr(), - ); + info!("Transferring 1 unit {} times...", txs0.len()); let tx_len = txs0.len(); let transfer_start = Instant::now(); let mut old_transactions = false; @@ -487,7 +477,7 @@ fn do_tx_transfers( transactions.push(tx.0); } - if let Err(error) = client.async_send_batch(transactions) { + if let Err(error) = client.send_batch(transactions) { warn!("send_batch_sync in do_tx_transfers failed: {}", error); } @@ -514,7 +504,11 @@ fn do_tx_transfers( } } -fn verify_funding_transfer(client: &Arc, tx: &Transaction, amount: u64) -> bool { +fn verify_funding_transfer( + client: &Arc, + tx: &Transaction, + amount: u64, +) -> bool { for a in &tx.message().account_keys[1..] { match client.get_balance_with_commitment(a, CommitmentConfig::processed()) { Ok(balance) => return balance >= amount, @@ -525,7 +519,7 @@ fn verify_funding_transfer(client: &Arc, tx: &Transaction, amount: } trait FundingTransactions<'a> { - fn fund( + fn fund( &mut self, client: &Arc, to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)], @@ -533,12 +527,16 @@ trait FundingTransactions<'a> { ); fn make(&mut self, to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)]); fn sign(&mut self, blockhash: Hash); - fn send(&self, client: &Arc); - fn verify(&mut self, client: &Arc, to_lamports: u64); + fn send(&self, client: &Arc); + fn verify( + &mut self, + client: &Arc, + to_lamports: u64, + ); } impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> { - fn fund( + fn fund( &mut self, client: &Arc, to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)], @@ -607,16 +605,20 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> { debug!("sign {} txs: {}us", self.len(), sign_txs.as_us()); } - fn send(&self, client: &Arc) { + fn send(&self, client: &Arc) { let mut send_txs = Measure::start("send_txs"); self.iter().for_each(|(_, tx)| { - client.async_send_transaction(tx.clone()).expect("transfer"); + client.send_transaction(tx.clone()).expect("transfer"); }); send_txs.stop(); debug!("send {} txs: {}us", self.len(), send_txs.as_us()); } - fn verify(&mut self, client: &Arc, to_lamports: u64) { + fn verify( + &mut self, + client: &Arc, + to_lamports: u64, + ) { let starting_txs = self.len(); let verified_txs = Arc::new(AtomicUsize::new(0)); let too_many_failures = Arc::new(AtomicBool::new(false)); @@ -691,7 +693,7 @@ impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> { /// fund the dests keys by spending all of the source keys into MAX_SPENDS_PER_TX /// on every iteration. This allows us to replay the transfers because the source is either empty, /// or full -pub fn fund_keys( +pub fn fund_keys( client: Arc, source: &Keypair, dests: &[Keypair], @@ -733,75 +735,6 @@ pub fn fund_keys( } } -pub fn airdrop_lamports( - client: &T, - faucet_addr: &SocketAddr, - id: &Keypair, - desired_balance: u64, -) -> Result<()> { - let starting_balance = client.get_balance(&id.pubkey()).unwrap_or(0); - metrics_submit_lamport_balance(starting_balance); - info!("starting balance {}", starting_balance); - - if starting_balance < desired_balance { - let airdrop_amount = desired_balance - starting_balance; - info!( - "Airdropping {:?} lamports from {} for {}", - airdrop_amount, - faucet_addr, - id.pubkey(), - ); - - let blockhash = get_latest_blockhash(client); - match request_airdrop_transaction(faucet_addr, &id.pubkey(), airdrop_amount, blockhash) { - Ok(transaction) => { - let mut tries = 0; - loop { - tries += 1; - let signature = client.async_send_transaction(transaction.clone()).unwrap(); - let result = client.poll_for_signature_confirmation(&signature, 1); - - if result.is_ok() { - break; - } - if tries >= 5 { - panic!( - "Error requesting airdrop: to addr: {:?} amount: {} {:?}", - faucet_addr, airdrop_amount, result - ) - } - } - } - Err(err) => { - panic!( - "Error requesting airdrop: {:?} to addr: {:?} amount: {}", - err, faucet_addr, airdrop_amount - ); - } - }; - - let current_balance = client - .get_balance_with_commitment(&id.pubkey(), CommitmentConfig::processed()) - .unwrap_or_else(|e| { - info!("airdrop error {}", e); - starting_balance - }); - info!("current balance {}...", current_balance); - - metrics_submit_lamport_balance(current_balance); - if current_balance - starting_balance != airdrop_amount { - info!( - "Airdrop failed! {} {} {}", - id.pubkey(), - current_balance, - starting_balance - ); - return Err(BenchTpsError::AirdropFailure); - } - } - Ok(()) -} - fn compute_and_report_stats( maxes: &Arc>>, sample_period: u64, @@ -885,15 +818,33 @@ pub fn generate_keypairs(seed_keypair: &Keypair, count: u64) -> (Vec, u (rnd.gen_n_keypairs(total_keys), extra) } -pub fn generate_and_fund_keypairs( +pub fn generate_and_fund_keypairs( client: Arc, - faucet_addr: Option, funding_key: &Keypair, keypair_count: usize, lamports_per_account: u64, ) -> Result> { + let rent = client.get_minimum_balance_for_rent_exemption(0)?; + let lamports_per_account = lamports_per_account + rent; + info!("Creating {} keypairs...", keypair_count); let (mut keypairs, extra) = generate_keypairs(funding_key, keypair_count as u64); + fund_keypairs(client, funding_key, &keypairs, extra, lamports_per_account)?; + + // 'generate_keypairs' generates extra keys to be able to have size-aligned funding batches for fund_keys. + keypairs.truncate(keypair_count); + + Ok(keypairs) +} + +pub fn fund_keypairs( + client: Arc, + funding_key: &Keypair, + keypairs: &[Keypair], + extra: u64, + lamports_per_account: u64, +) -> Result<()> { + let rent = client.get_minimum_balance_for_rent_exemption(0)?; info!("Get lamports..."); // Sample the first keypair, to prevent lamport loss on repeated solana-bench-tps executions @@ -901,7 +852,7 @@ pub fn generate_and_fund_keypairs( let first_keypair_balance = client.get_balance(&first_key).unwrap_or(0); // Sample the last keypair, to check if funding was already completed - let last_key = keypairs[keypair_count - 1].pubkey(); + let last_key = keypairs[keypairs.len() - 1].pubkey(); let last_keypair_balance = client.get_balance(&last_key).unwrap_or(0); // Repeated runs will eat up keypair balances from transaction fees. In order to quickly @@ -930,24 +881,35 @@ pub fn generate_and_fund_keypairs( funding_key_balance, max_fee, lamports_per_account, extra, total ); - if client.get_balance(&funding_key.pubkey()).unwrap_or(0) < total { - airdrop_lamports(client.as_ref(), &faucet_addr.unwrap(), funding_key, total)?; + if funding_key_balance < total + rent { + error!( + "funder has {}, needed {}", + Sol(funding_key_balance), + Sol(total) + ); + let latest_blockhash = get_latest_blockhash(client.as_ref()); + if client + .request_airdrop_with_blockhash( + &funding_key.pubkey(), + total + rent - funding_key_balance, + &latest_blockhash, + ) + .is_err() + { + return Err(BenchTpsError::AirdropFailure); + } } fund_keys( client, funding_key, - &keypairs, + keypairs, total, max_fee, lamports_per_account, ); } - - // 'generate_keypairs' generates extra keys to be able to have size-aligned funding batches for fund_keys. - keypairs.truncate(keypair_count); - - Ok(keypairs) + Ok(()) } #[cfg(test)] @@ -956,14 +918,14 @@ mod tests { super::*, solana_runtime::{bank::Bank, bank_client::BankClient}, solana_sdk::{ - client::SyncClient, fee_calculator::FeeRateGovernor, - genesis_config::create_genesis_config, + fee_calculator::FeeRateGovernor, genesis_config::create_genesis_config, + native_token::sol_to_lamports, }, }; #[test] fn test_bench_tps_bank_client() { - let (genesis_config, id) = create_genesis_config(10_000); + let (genesis_config, id) = create_genesis_config(sol_to_lamports(10_000.0)); let bank = Bank::new_for_tests(&genesis_config); let client = Arc::new(BankClient::new(bank)); @@ -976,48 +938,49 @@ mod tests { let keypair_count = config.tx_count * config.keypair_multiplier; let keypairs = - generate_and_fund_keypairs(client.clone(), None, &config.id, keypair_count, 20) - .unwrap(); + generate_and_fund_keypairs(client.clone(), &config.id, keypair_count, 20).unwrap(); do_bench_tps(client, config, keypairs); } #[test] fn test_bench_tps_fund_keys() { - let (genesis_config, id) = create_genesis_config(10_000); + let (genesis_config, id) = create_genesis_config(sol_to_lamports(10_000.0)); let bank = Bank::new_for_tests(&genesis_config); let client = Arc::new(BankClient::new(bank)); let keypair_count = 20; let lamports = 20; + let rent = client.get_minimum_balance_for_rent_exemption(0).unwrap(); let keypairs = - generate_and_fund_keypairs(client.clone(), None, &id, keypair_count, lamports).unwrap(); + generate_and_fund_keypairs(client.clone(), &id, keypair_count, lamports).unwrap(); for kp in &keypairs { assert_eq!( client .get_balance_with_commitment(&kp.pubkey(), CommitmentConfig::processed()) .unwrap(), - lamports + lamports + rent ); } } #[test] fn test_bench_tps_fund_keys_with_fees() { - let (mut genesis_config, id) = create_genesis_config(10_000); + let (mut genesis_config, id) = create_genesis_config(sol_to_lamports(10_000.0)); let fee_rate_governor = FeeRateGovernor::new(11, 0); genesis_config.fee_rate_governor = fee_rate_governor; let bank = Bank::new_for_tests(&genesis_config); let client = Arc::new(BankClient::new(bank)); let keypair_count = 20; let lamports = 20; + let rent = client.get_minimum_balance_for_rent_exemption(0).unwrap(); let keypairs = - generate_and_fund_keypairs(client.clone(), None, &id, keypair_count, lamports).unwrap(); + generate_and_fund_keypairs(client.clone(), &id, keypair_count, lamports).unwrap(); for kp in &keypairs { - assert_eq!(client.get_balance(&kp.pubkey()).unwrap(), lamports); + assert_eq!(client.get_balance(&kp.pubkey()).unwrap(), lamports + rent); } } } diff --git a/bench-tps/src/bench_tps_client.rs b/bench-tps/src/bench_tps_client.rs new file mode 100644 index 000000000..5f0428487 --- /dev/null +++ b/bench-tps/src/bench_tps_client.rs @@ -0,0 +1,85 @@ +use { + solana_client::{client_error::ClientError, tpu_client::TpuSenderError}, + solana_sdk::{ + commitment_config::CommitmentConfig, epoch_info::EpochInfo, hash::Hash, message::Message, + pubkey::Pubkey, signature::Signature, transaction::Transaction, transport::TransportError, + }, + thiserror::Error, +}; + +#[derive(Error, Debug)] +pub enum BenchTpsError { + #[error("Airdrop failure")] + AirdropFailure, + #[error("IO error: {0:?}")] + IoError(#[from] std::io::Error), + #[error("Client error: {0:?}")] + ClientError(#[from] ClientError), + #[error("TpuClient error: {0:?}")] + TpuSenderError(#[from] TpuSenderError), + #[error("Transport error: {0:?}")] + TransportError(#[from] TransportError), + #[error("Custom error: {0}")] + Custom(String), +} + +pub(crate) type Result = std::result::Result; + +pub trait BenchTpsClient { + /// Send a signed transaction without confirmation + fn send_transaction(&self, transaction: Transaction) -> Result; + + /// Send a batch of signed transactions without confirmation. + fn send_batch(&self, transactions: Vec) -> Result<()>; + + /// Get latest blockhash + fn get_latest_blockhash(&self) -> Result; + + /// Get latest blockhash and its last valid block height, using explicit commitment + fn get_latest_blockhash_with_commitment( + &self, + commitment_config: CommitmentConfig, + ) -> Result<(Hash, u64)>; + + /// Get transaction count + fn get_transaction_count(&self) -> Result; + + /// Get transaction count, using explicit commitment + fn get_transaction_count_with_commitment( + &self, + commitment_config: CommitmentConfig, + ) -> Result; + + /// Get epoch info + fn get_epoch_info(&self) -> Result; + + /// Get account balance + fn get_balance(&self, pubkey: &Pubkey) -> Result; + + /// Get account balance, using explicit commitment + fn get_balance_with_commitment( + &self, + pubkey: &Pubkey, + commitment_config: CommitmentConfig, + ) -> Result; + + /// Calculate the fee for a `Message` + fn get_fee_for_message(&self, message: &Message) -> Result; + + /// Get the rent-exempt minimum for an account + fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result; + + /// Return the address of client + fn addr(&self) -> String; + + /// Request, submit, and confirm an airdrop transaction + fn request_airdrop_with_blockhash( + &self, + pubkey: &Pubkey, + lamports: u64, + recent_blockhash: &Hash, + ) -> Result; +} + +mod bank_client; +mod thin_client; diff --git a/bench-tps/src/bench_tps_client/bank_client.rs b/bench-tps/src/bench_tps_client/bank_client.rs new file mode 100644 index 000000000..2653fce31 --- /dev/null +++ b/bench-tps/src/bench_tps_client/bank_client.rs @@ -0,0 +1,85 @@ +use { + crate::bench_tps_client::{BenchTpsClient, BenchTpsError, Result}, + solana_runtime::bank_client::BankClient, + solana_sdk::{ + client::{AsyncClient, SyncClient}, + commitment_config::CommitmentConfig, + epoch_info::EpochInfo, + hash::Hash, + message::Message, + pubkey::Pubkey, + signature::Signature, + transaction::Transaction, + }, +}; + +impl BenchTpsClient for BankClient { + fn send_transaction(&self, transaction: Transaction) -> Result { + AsyncClient::async_send_transaction(self, transaction).map_err(|err| err.into()) + } + fn send_batch(&self, transactions: Vec) -> Result<()> { + AsyncClient::async_send_batch(self, transactions).map_err(|err| err.into()) + } + fn get_latest_blockhash(&self) -> Result { + SyncClient::get_latest_blockhash(self).map_err(|err| err.into()) + } + + fn get_latest_blockhash_with_commitment( + &self, + commitment_config: CommitmentConfig, + ) -> Result<(Hash, u64)> { + SyncClient::get_latest_blockhash_with_commitment(self, commitment_config) + .map_err(|err| err.into()) + } + + fn get_transaction_count(&self) -> Result { + SyncClient::get_transaction_count(self).map_err(|err| err.into()) + } + + fn get_transaction_count_with_commitment( + &self, + commitment_config: CommitmentConfig, + ) -> Result { + SyncClient::get_transaction_count_with_commitment(self, commitment_config) + .map_err(|err| err.into()) + } + + fn get_epoch_info(&self) -> Result { + SyncClient::get_epoch_info(self).map_err(|err| err.into()) + } + + fn get_balance(&self, pubkey: &Pubkey) -> Result { + SyncClient::get_balance(self, pubkey).map_err(|err| err.into()) + } + + fn get_balance_with_commitment( + &self, + pubkey: &Pubkey, + commitment_config: CommitmentConfig, + ) -> Result { + SyncClient::get_balance_with_commitment(self, pubkey, commitment_config) + .map_err(|err| err.into()) + } + + fn get_fee_for_message(&self, message: &Message) -> Result { + SyncClient::get_fee_for_message(self, message).map_err(|err| err.into()) + } + + fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result { + SyncClient::get_minimum_balance_for_rent_exemption(self, data_len).map_err(|err| err.into()) + } + + fn addr(&self) -> String { + "Local BankClient".to_string() + } + + fn request_airdrop_with_blockhash( + &self, + _pubkey: &Pubkey, + _lamports: u64, + _recent_blockhash: &Hash, + ) -> Result { + // BankClient doesn't support airdrops + Err(BenchTpsError::AirdropFailure) + } +} diff --git a/bench-tps/src/bench_tps_client/thin_client.rs b/bench-tps/src/bench_tps_client/thin_client.rs new file mode 100644 index 000000000..2ac7bca2e --- /dev/null +++ b/bench-tps/src/bench_tps_client/thin_client.rs @@ -0,0 +1,86 @@ +use { + crate::bench_tps_client::{BenchTpsClient, Result}, + solana_client::thin_client::ThinClient, + solana_sdk::{ + client::{AsyncClient, Client, SyncClient}, + commitment_config::CommitmentConfig, + epoch_info::EpochInfo, + hash::Hash, + message::Message, + pubkey::Pubkey, + signature::Signature, + transaction::Transaction, + }, +}; + +impl BenchTpsClient for ThinClient { + fn send_transaction(&self, transaction: Transaction) -> Result { + AsyncClient::async_send_transaction(self, transaction).map_err(|err| err.into()) + } + fn send_batch(&self, transactions: Vec) -> Result<()> { + AsyncClient::async_send_batch(self, transactions).map_err(|err| err.into()) + } + fn get_latest_blockhash(&self) -> Result { + SyncClient::get_latest_blockhash(self).map_err(|err| err.into()) + } + + fn get_latest_blockhash_with_commitment( + &self, + commitment_config: CommitmentConfig, + ) -> Result<(Hash, u64)> { + SyncClient::get_latest_blockhash_with_commitment(self, commitment_config) + .map_err(|err| err.into()) + } + + fn get_transaction_count(&self) -> Result { + SyncClient::get_transaction_count(self).map_err(|err| err.into()) + } + + fn get_transaction_count_with_commitment( + &self, + commitment_config: CommitmentConfig, + ) -> Result { + SyncClient::get_transaction_count_with_commitment(self, commitment_config) + .map_err(|err| err.into()) + } + + fn get_epoch_info(&self) -> Result { + SyncClient::get_epoch_info(self).map_err(|err| err.into()) + } + + fn get_balance(&self, pubkey: &Pubkey) -> Result { + SyncClient::get_balance(self, pubkey).map_err(|err| err.into()) + } + + fn get_balance_with_commitment( + &self, + pubkey: &Pubkey, + commitment_config: CommitmentConfig, + ) -> Result { + SyncClient::get_balance_with_commitment(self, pubkey, commitment_config) + .map_err(|err| err.into()) + } + + fn get_fee_for_message(&self, message: &Message) -> Result { + SyncClient::get_fee_for_message(self, message).map_err(|err| err.into()) + } + + fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result { + SyncClient::get_minimum_balance_for_rent_exemption(self, data_len).map_err(|err| err.into()) + } + + fn addr(&self) -> String { + Client::tpu_addr(self) + } + + fn request_airdrop_with_blockhash( + &self, + pubkey: &Pubkey, + lamports: u64, + recent_blockhash: &Hash, + ) -> Result { + self.rpc_client() + .request_airdrop_with_blockhash(pubkey, lamports, recent_blockhash) + .map_err(|err| err.into()) + } +} diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index c711406a7..1f289f052 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -1,6 +1,5 @@ use { clap::{crate_description, crate_name, App, Arg, ArgMatches}, - solana_faucet::faucet::FAUCET_PORT, solana_sdk::{ fee_calculator::FeeRateGovernor, pubkey::Pubkey, @@ -14,7 +13,6 @@ const NUM_LAMPORTS_PER_ACCOUNT_DEFAULT: u64 = solana_sdk::native_token::LAMPORTS /// Holds the configuration for a single run of the benchmark pub struct Config { pub entrypoint_addr: SocketAddr, - pub faucet_addr: SocketAddr, pub id: Keypair, pub threads: usize, pub num_nodes: usize, @@ -37,7 +35,6 @@ impl Default for Config { fn default() -> Config { Config { entrypoint_addr: SocketAddr::from(([127, 0, 0, 1], 8001)), - faucet_addr: SocketAddr::from(([127, 0, 0, 1], FAUCET_PORT)), id: Keypair::new(), threads: 4, num_nodes: 1, @@ -76,7 +73,8 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> { .long("faucet") .value_name("HOST:PORT") .takes_value(true) - .help("Location of the faucet; defaults to entrypoint:FAUCET_PORT"), + .hidden(true) + .help("Deprecated. BenchTps no longer queries the faucet directly"), ) .arg( Arg::with_name("identity") @@ -208,13 +206,6 @@ pub fn extract_args(matches: &ArgMatches) -> Config { }); } - if let Some(addr) = matches.value_of("faucet") { - args.faucet_addr = solana_net_utils::parse_host_port(addr).unwrap_or_else(|e| { - eprintln!("failed to parse faucet address: {}", e); - exit(1) - }); - } - if matches.is_present("identity") { args.id = read_keypair_file(matches.value_of("identity").unwrap()) .expect("can't read client identity"); diff --git a/bench-tps/src/lib.rs b/bench-tps/src/lib.rs index 48f769a29..6897b54d2 100644 --- a/bench-tps/src/lib.rs +++ b/bench-tps/src/lib.rs @@ -1,3 +1,5 @@ #![allow(clippy::integer_arithmetic)] pub mod bench; +mod bench_tps_client; pub mod cli; +mod perf_utils; diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index 888736bf6..88cd75d94 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -2,7 +2,7 @@ use { log::*, solana_bench_tps::{ - bench::{do_bench_tps, generate_and_fund_keypairs, generate_keypairs}, + bench::{do_bench_tps, fund_keypairs, generate_and_fund_keypairs, generate_keypairs}, cli, }, solana_genesis::Base64Account, @@ -28,7 +28,6 @@ fn main() { let cli::Config { entrypoint_addr, - faucet_addr, id, num_nodes, tx_count, @@ -138,19 +137,24 @@ fn main() { // This prevents the amount of storage needed for bench-tps accounts from creeping up // across multiple runs. keypairs.sort_by_key(|x| x.pubkey().to_string()); - keypairs - } else { - generate_and_fund_keypairs( + fund_keypairs( client.clone(), - Some(*faucet_addr), id, - keypair_count, - *num_lamports_per_account, + &keypairs, + keypairs.len().saturating_sub(keypair_count) as u64, + last_balance, ) .unwrap_or_else(|e| { eprintln!("Error could not fund keys: {:?}", e); exit(1); - }) + }); + keypairs + } else { + generate_and_fund_keypairs(client.clone(), id, keypair_count, *num_lamports_per_account) + .unwrap_or_else(|e| { + eprintln!("Error could not fund keys: {:?}", e); + exit(1); + }) }; do_bench_tps(client, cli_config, keypairs); diff --git a/client/src/perf_utils.rs b/bench-tps/src/perf_utils.rs similarity index 91% rename from client/src/perf_utils.rs rename to bench-tps/src/perf_utils.rs index d3f42d1db..7e31e6408 100644 --- a/client/src/perf_utils.rs +++ b/bench-tps/src/perf_utils.rs @@ -1,6 +1,7 @@ use { + crate::bench_tps_client::BenchTpsClient, log::*, - solana_sdk::{client::Client, commitment_config::CommitmentConfig, timing::duration_as_s}, + solana_sdk::{commitment_config::CommitmentConfig, timing::duration_as_s}, std::{ sync::{ atomic::{AtomicBool, Ordering}, @@ -27,7 +28,7 @@ pub fn sample_txs( sample_period: u64, client: &Arc, ) where - T: Client, + T: BenchTpsClient, { let mut max_tps = 0.0; let mut total_elapsed; @@ -81,10 +82,7 @@ pub fn sample_txs( elapsed: total_elapsed, txs: total_txs, }; - sample_stats - .write() - .unwrap() - .push((client.tpu_addr(), stats)); + sample_stats.write().unwrap().push((client.addr(), stats)); return; } sleep(Duration::from_secs(sample_period)); diff --git a/bench-tps/tests/bench_tps.rs b/bench-tps/tests/bench_tps.rs index c8ec22ee5..4665fe62b 100644 --- a/bench-tps/tests/bench_tps.rs +++ b/bench-tps/tests/bench_tps.rs @@ -13,6 +13,7 @@ use { local_cluster::{ClusterConfig, LocalCluster}, validator_configs::make_identical_validator_configs, }, + solana_rpc::rpc::JsonRpcConfig, solana_sdk::signature::{Keypair, Signer}, solana_streamer::socket::SocketAddrSpace, std::{sync::Arc, time::Duration}, @@ -22,13 +23,34 @@ fn test_bench_tps_local_cluster(config: Config) { let native_instruction_processors = vec![]; solana_logger::setup(); + + let faucet_keypair = Keypair::new(); + let faucet_pubkey = faucet_keypair.pubkey(); + let (addr_sender, addr_receiver) = unbounded(); + run_local_faucet_with_port(faucet_keypair, addr_sender, None, 0); + let faucet_addr = addr_receiver + .recv_timeout(Duration::from_secs(2)) + .expect("run_local_faucet") + .expect("faucet_addr"); + const NUM_NODES: usize = 1; + let mut validator_config = ValidatorConfig::default_for_test(); + validator_config.rpc_config = JsonRpcConfig { + faucet_addr: Some(faucet_addr), + ..JsonRpcConfig::default_for_test() + }; let cluster = LocalCluster::new( &mut ClusterConfig { node_stakes: vec![999_990; NUM_NODES], cluster_lamports: 200_000_000, validator_configs: make_identical_validator_configs( - &ValidatorConfig::default_for_test(), + &ValidatorConfig { + rpc_config: JsonRpcConfig { + faucet_addr: Some(faucet_addr), + ..JsonRpcConfig::default_for_test() + }, + ..ValidatorConfig::default_for_test() + }, NUM_NODES, ), native_instruction_processors, @@ -37,31 +59,18 @@ fn test_bench_tps_local_cluster(config: Config) { SocketAddrSpace::Unspecified, ); - let faucet_keypair = Keypair::new(); - cluster.transfer( - &cluster.funding_keypair, - &faucet_keypair.pubkey(), - 100_000_000, - ); + cluster.transfer(&cluster.funding_keypair, &faucet_pubkey, 100_000_000); let client = Arc::new(create_client( cluster.entry_point_info.rpc, cluster.entry_point_info.tpu, )); - let (addr_sender, addr_receiver) = unbounded(); - run_local_faucet_with_port(faucet_keypair, addr_sender, None, 0); - let faucet_addr = addr_receiver - .recv_timeout(Duration::from_secs(2)) - .expect("run_local_faucet") - .expect("faucet_addr"); - let lamports_per_account = 100; let keypair_count = config.tx_count * config.keypair_multiplier; let keypairs = generate_and_fund_keypairs( client.clone(), - Some(faucet_addr), &config.id, keypair_count, lamports_per_account, diff --git a/client/src/lib.rs b/client/src/lib.rs index 7dbd8b11f..6a169b1f3 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -9,7 +9,6 @@ pub(crate) mod http_sender; pub(crate) mod mock_sender; pub mod nonblocking; pub mod nonce_utils; -pub mod perf_utils; pub mod pubsub_client; pub mod quic_client; pub mod rpc_cache; diff --git a/client/src/thin_client.rs b/client/src/thin_client.rs index 68beb9f65..bb87945b1 100644 --- a/client/src/thin_client.rs +++ b/client/src/thin_client.rs @@ -171,7 +171,7 @@ impl ThinClient { &self.tpu_addrs[self.optimizer.best()] } - fn rpc_client(&self) -> &RpcClient { + pub fn rpc_client(&self) -> &RpcClient { &self.rpc_clients[self.optimizer.best()] }