From 8c204519d34c88231f1f061b57b80b542f36eacc Mon Sep 17 00:00:00 2001 From: Kirill Lykov Date: Mon, 15 Aug 2022 21:26:03 +0200 Subject: [PATCH 1/6] add use_durable_nonce option --- bench-tps/src/cli.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index a8affe4cc53148..bdc54a46eaedb6 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -313,6 +313,11 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> { .takes_value(false) .help("Sets random compute-unit-price in range [0..100] to transfer transactions"), ) + .arg( + Arg::with_name("use_durable_nonce") + .long("use-durable-nonce") + .help("Use durable transaction nonce instead of recent blockhash"), + ) } /// Parses a clap `ArgMatches` structure into a `Config` @@ -447,5 +452,9 @@ pub fn extract_args(matches: &ArgMatches) -> Config { args.use_randomized_compute_unit_price = true; } + if matches.is_present("use_durable_nonce") { + args.use_durable_nonce = true; + } + args } From f425233f3cb45b461cb1a010254c80b438ca6566 Mon Sep 17 00:00:00 2001 From: Kirill Lykov Date: Mon, 15 Aug 2022 22:11:45 +0200 Subject: [PATCH 2/6] log creating nonce account in bench-tps --- bench-tps/src/send_batch.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bench-tps/src/send_batch.rs b/bench-tps/src/send_batch.rs index cda4a45bba8034..a3a649e789311c 100644 --- a/bench-tps/src/send_batch.rs +++ b/bench-tps/src/send_batch.rs @@ -109,6 +109,7 @@ pub fn generate_durable_nonce_accounts = authority_keypairs .iter() .zip(nonce_keypairs.iter()) From b129eeec04e829c7fdd29233f1c058cbcd40c23a Mon Sep 17 00:00:00 2001 From: Kirill Lykov Date: Tue, 16 Aug 2022 10:33:04 +0200 Subject: [PATCH 3/6] try get account data in a loop --- bench-tps/src/bench.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index 8fd7f772266506..f60a6d656d7af6 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -543,12 +543,21 @@ fn get_nonce_blockhash( client: Arc, nonce_account_pubkey: Pubkey, ) -> Hash { - let nonce_account = client - .get_account(&nonce_account_pubkey) - .unwrap_or_else(|error| panic!("{:?}", error)); - let nonce_data = solana_rpc_client_nonce_utils::data_from_account(&nonce_account) - .unwrap_or_else(|error| panic!("{:?}", error)); - nonce_data.blockhash() + loop { + match client.get_account(&nonce_account_pubkey) { + Ok(nonce_account) => match nonce_utils::data_from_account(&nonce_account) { + Ok(nonce_data) => return nonce_data.blockhash(), + Err(err) => { + info!("Couldn't get data from durable nonce account: {:?}", err); + sleep(Duration::from_secs(1)); + } + }, + Err(err) => { + info!("Couldn't get durable nonce account: {:?}", err); + sleep(Duration::from_secs(1)); + } + } + } } fn generate_nonced_system_txs( From b0138f97c5057da4df30cfd96d765c6e2c5580a2 Mon Sep 17 00:00:00 2001 From: Kirill Lykov Date: Tue, 16 Aug 2022 15:19:06 +0200 Subject: [PATCH 4/6] Get account with commitment for nonce in bench-tps --- bench-tps/src/bench.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index f60a6d656d7af6..4dfcc0e5bf8528 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -11,6 +11,7 @@ use { solana_metrics::{self, datapoint_info}, solana_sdk::{ clock::{DEFAULT_MS_PER_SLOT, DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE}, + commitment_config::CommitmentConfig, compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::{AccountMeta, Instruction}, @@ -544,7 +545,9 @@ fn get_nonce_blockhash( nonce_account_pubkey: Pubkey, ) -> Hash { loop { - match client.get_account(&nonce_account_pubkey) { + match client + .get_account_with_commitment(&nonce_account_pubkey, CommitmentConfig::processed()) + { Ok(nonce_account) => match nonce_utils::data_from_account(&nonce_account) { Ok(nonce_data) => return nonce_data.blockhash(), Err(err) => { From 3da1fcb19ebf8ddb819d5df525ef73880a85bddd Mon Sep 17 00:00:00 2001 From: Kirill Lykov Date: Tue, 23 Aug 2022 14:46:47 +0200 Subject: [PATCH 5/6] use get_multiple_accounts in bench-tps --- bench-tps/src/bench.rs | 132 +++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 44 deletions(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index 4dfcc0e5bf8528..08eb7e2da6b2b9 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -10,8 +10,8 @@ use { rayon::prelude::*, solana_metrics::{self, datapoint_info}, solana_sdk::{ + account::Account, clock::{DEFAULT_MS_PER_SLOT, DEFAULT_S_PER_SLOT, MAX_PROCESSING_AGE}, - commitment_config::CommitmentConfig, compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::{AccountMeta, Instruction}, @@ -24,7 +24,7 @@ use { transaction::Transaction, }, std::{ - collections::VecDeque, + collections::{HashSet, VecDeque}, process::exit, sync::{ atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}, @@ -540,21 +540,15 @@ fn transfer_with_compute_unit_price( Transaction::new(&[from_keypair], message, recent_blockhash) } -fn get_nonce_blockhash( - client: Arc, - nonce_account_pubkey: Pubkey, -) -> Hash { +fn get_nonce_accounts( + client: &Arc, + nonce_pubkeys: &[Pubkey], +) -> Vec> { loop { - match client - .get_account_with_commitment(&nonce_account_pubkey, CommitmentConfig::processed()) - { - Ok(nonce_account) => match nonce_utils::data_from_account(&nonce_account) { - Ok(nonce_data) => return nonce_data.blockhash(), - Err(err) => { - info!("Couldn't get data from durable nonce account: {:?}", err); - sleep(Duration::from_secs(1)); - } - }, + match client.get_multiple_accounts(&nonce_pubkeys) { + Ok(nonce_account) => { + return nonce_account; + } Err(err) => { info!("Couldn't get durable nonce account: {:?}", err); sleep(Duration::from_secs(1)); @@ -563,6 +557,47 @@ fn get_nonce_blockhash( } } +fn get_nonce_blockhashes( + client: Arc, + nonce_pubkeys: &[Pubkey], +) -> Vec { + let num_accounts = nonce_pubkeys.len(); + let mut blockhashes = vec![Hash::default(); num_accounts]; + let mut unprocessed = HashSet::with_capacity(num_accounts); + for i in 0..num_accounts { + unprocessed.insert(i); + } + + let mut request_pubkeys = Vec::::with_capacity(num_accounts); + let mut request_indexes = Vec::::with_capacity(num_accounts); + + while !unprocessed.is_empty() { + for i in &unprocessed { + request_pubkeys.push(nonce_pubkeys[*i]); + request_indexes.push(*i); + } + + let num_unprocessed_before = unprocessed.len(); + info!("Request {} durable nonce accounts", num_unprocessed_before); + let accounts = get_nonce_accounts(&client, nonce_pubkeys); + for (account, index) in accounts.iter().zip(request_indexes.iter()) { + if let Some(nonce_account) = account { + let nonce_data = nonce_utils::data_from_account(nonce_account).unwrap(); + blockhashes[*index] = nonce_data.blockhash(); + unprocessed.remove(index); + } + } + let num_unprocessed_after = unprocessed.len(); + info!( + "Received {} durable nonce accounts", + num_unprocessed_before - num_unprocessed_after + ); + request_pubkeys.clear(); + request_indexes.clear(); + } + blockhashes +} + fn generate_nonced_system_txs( client: Arc, source: &[&Keypair], @@ -573,34 +608,43 @@ fn generate_nonced_system_txs Vec { let length = source.len(); let mut transactions: Vec = Vec::with_capacity(length); - for i in 0..length { - let (from, to, nonce, nonce_blockhash) = if !reclaim { - ( - source[i], - dest[i], - source_nonce[i], - get_nonce_blockhash(client.clone(), source_nonce[i].pubkey()), - ) - } else { - ( - dest[i], - source[i], - dest_nonce[i], - get_nonce_blockhash(client.clone(), dest_nonce[i].pubkey()), - ) - }; - - transactions.push(( - system_transaction::nonced_transfer( - from, - &to.pubkey(), - 1, - &nonce.pubkey(), - from, - nonce_blockhash, - ), - None, - )); + if !reclaim { + let pubkeys: Vec = source_nonce + .iter() + .map(|keypair| keypair.pubkey()) + .collect(); + let blockhashes = get_nonce_blockhashes(client, &pubkeys); + + for i in 0..length { + transactions.push(( + system_transaction::nonced_transfer( + source[i], + &dest[i].pubkey(), + 1, + &source_nonce[i].pubkey(), + source[i], + blockhashes[i], + ), + None, + )); + } + } else { + let pubkeys: Vec = dest_nonce.iter().map(|keypair| keypair.pubkey()).collect(); + let blockhashes = get_nonce_blockhashes(client, &pubkeys); + + for i in 0..length { + transactions.push(( + system_transaction::nonced_transfer( + dest[i], + &source[i].pubkey(), + 1, + &dest_nonce[i].pubkey(), + dest[i], + blockhashes[i], + ), + None, + )); + } } transactions } From bab6632eaa97b195bfff09aca19d25c38b1a3ab0 Mon Sep 17 00:00:00 2001 From: Kirill Lykov Date: Wed, 24 Aug 2022 10:43:46 +0200 Subject: [PATCH 6/6] split accounts request into chunks --- bench-tps/src/bench.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index 08eb7e2da6b2b9..c6b333d1926747 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -8,6 +8,7 @@ use { log::*, rand::distributions::{Distribution, Uniform}, rayon::prelude::*, + solana_client::{nonce_utils, rpc_request::MAX_MULTIPLE_ACCOUNTS}, solana_metrics::{self, datapoint_info}, solana_sdk::{ account::Account, @@ -544,10 +545,12 @@ fn get_nonce_accounts( client: &Arc, nonce_pubkeys: &[Pubkey], ) -> Vec> { + // get_multiple_accounts supports maximum MAX_MULTIPLE_ACCOUNTS pubkeys in request + assert!(nonce_pubkeys.len() <= MAX_MULTIPLE_ACCOUNTS); loop { - match client.get_multiple_accounts(&nonce_pubkeys) { - Ok(nonce_account) => { - return nonce_account; + match client.get_multiple_accounts(nonce_pubkeys) { + Ok(nonce_accounts) => { + return nonce_accounts; } Err(err) => { info!("Couldn't get durable nonce account: {:?}", err); @@ -558,15 +561,12 @@ fn get_nonce_accounts( } fn get_nonce_blockhashes( - client: Arc, + client: &Arc, nonce_pubkeys: &[Pubkey], ) -> Vec { let num_accounts = nonce_pubkeys.len(); let mut blockhashes = vec![Hash::default(); num_accounts]; - let mut unprocessed = HashSet::with_capacity(num_accounts); - for i in 0..num_accounts { - unprocessed.insert(i); - } + let mut unprocessed = (0..num_accounts).collect::>(); let mut request_pubkeys = Vec::::with_capacity(num_accounts); let mut request_indexes = Vec::::with_capacity(num_accounts); @@ -578,8 +578,11 @@ fn get_nonce_blockhashes( } let num_unprocessed_before = unprocessed.len(); - info!("Request {} durable nonce accounts", num_unprocessed_before); - let accounts = get_nonce_accounts(&client, nonce_pubkeys); + let accounts: Vec> = nonce_pubkeys + .chunks(MAX_MULTIPLE_ACCOUNTS) + .flat_map(|pubkeys| get_nonce_accounts(client, pubkeys)) + .collect(); + for (account, index) in accounts.iter().zip(request_indexes.iter()) { if let Some(nonce_account) = account { let nonce_data = nonce_utils::data_from_account(nonce_account).unwrap(); @@ -588,7 +591,7 @@ fn get_nonce_blockhashes( } } let num_unprocessed_after = unprocessed.len(); - info!( + debug!( "Received {} durable nonce accounts", num_unprocessed_before - num_unprocessed_after ); @@ -613,8 +616,8 @@ fn generate_nonced_system_txs = get_nonce_blockhashes(&client, &pubkeys); for i in 0..length { transactions.push(( system_transaction::nonced_transfer( @@ -630,7 +633,7 @@ fn generate_nonced_system_txs = dest_nonce.iter().map(|keypair| keypair.pubkey()).collect(); - let blockhashes = get_nonce_blockhashes(client, &pubkeys); + let blockhashes: Vec = get_nonce_blockhashes(&client, &pubkeys); for i in 0..length { transactions.push((