| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -21,8 +21,7 @@ use solana_sdk::{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    transaction::Transaction,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				use std::{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    cmp,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    collections::VecDeque,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    collections::{HashSet, VecDeque},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    net::SocketAddr,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    process::exit,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    sync::{
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -66,10 +65,9 @@ fn get_recent_blockhash<T: Client>(client: &T) -> (Hash, FeeCalculator) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				pub fn do_bench_tps<T>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    clients: Vec<T>,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    client: Arc<T>,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    config: Config,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    gen_keypairs: Vec<Keypair>,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    keypair0_balance: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    libra_args: Option<LibraKeys>,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				) -> u64
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				where
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -82,13 +80,9 @@ where
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        duration,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        tx_count,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        sustained,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        num_lamports_per_account,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ..
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    } = config;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let clients: Vec<_> = clients.into_iter().map(Arc::new).collect();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let client = &clients[0];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut source_keypair_chunks: Vec<Vec<&Keypair>> = Vec::new();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut dest_keypair_chunks: Vec<VecDeque<&Keypair>> = Vec::new();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    assert!(gen_keypairs.len() >= 2 * tx_count);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -115,9 +109,7 @@ where
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let maxes = Arc::new(RwLock::new(Vec::new()));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let sample_period = 1; // in seconds
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    info!("Sampling TPS every {} second...", sample_period);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let v_threads: Vec<_> = clients
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        .iter()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        .map(|client| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let sample_thread = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let exit_signal = exit_signal.clone();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let maxes = maxes.clone();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let client = client.clone();
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -127,8 +119,7 @@ where
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                sample_txs(&exit_signal, &maxes, sample_period, &client);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            })
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .unwrap()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        })
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        .collect();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let shared_txs: SharedTransactions = Arc::new(RwLock::new(VecDeque::new()));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -174,11 +165,10 @@ where
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // generate and send transactions for the specified duration
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let start = Instant::now();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let keypair_chunks = source_keypair_chunks.len() as u64;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let keypair_chunks = source_keypair_chunks.len();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut reclaim_lamports_back_to_source_account = false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut i = keypair0_balance;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut chunk_index = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    while start.elapsed() < duration {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let chunk_index = (i % keypair_chunks) as usize;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        generate_txs(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            &shared_txs,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            &recent_blockhash,
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -206,8 +196,11 @@ where
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // transaction signatures even when blockhash is reused.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        dest_keypair_chunks[chunk_index].rotate_left(1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        i += 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if should_switch_directions(num_lamports_per_account, keypair_chunks, i) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Move on to next chunk
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        chunk_index = (chunk_index + 1) % keypair_chunks;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Switch directions after transfering for each "chunk"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if chunk_index == 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            reclaim_lamports_back_to_source_account = !reclaim_lamports_back_to_source_account;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -215,12 +208,10 @@ where
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Stop the sampling threads so it will collect the stats
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    exit_signal.store(true, Ordering::Relaxed);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    info!("Waiting for validator threads...");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for t in v_threads {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if let Err(err) = t.join() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    info!("Waiting for sampler threads...");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if let Err(err) = sample_thread.join() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        info!("  join() failed with: {:?}", err);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // join the tx send threads
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    info!("Waiting for transmit threads...");
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -500,86 +491,81 @@ fn do_tx_transfers<T: Client>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				fn verify_funding_transfer<T: Client>(client: &T, tx: &Transaction, amount: u64) -> bool {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				fn verify_funding_transfer<T: Client>(client: &Arc<T>, tx: &Transaction, amount: u64) -> bool {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for a in &tx.message().account_keys[1..] {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if client
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .get_balance_with_commitment(a, CommitmentConfig::recent())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .unwrap_or(0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            >= amount
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        match client.get_balance_with_commitment(a, CommitmentConfig::recent()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            Ok(balance) => return balance >= amount,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            Err(err) => error!("failed to get balance {:?}", err),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    false
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// 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<T: Client>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    client: &T,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    source: &Keypair,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    dests: &[Keypair],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    total: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    max_fee: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    mut extra: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut funded: Vec<(&Keypair, u64)> = vec![(source, total)];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut notfunded: Vec<&Keypair> = dests.iter().collect();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let lamports_per_account = (total - (extra * max_fee)) / (notfunded.len() as u64 + 1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    info!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        "funding keys {} with lamports: {:?} total: {}",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        dests.len(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        client.get_balance(&source.pubkey()),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        total
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				trait FundingTransactions<'a> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn fund<T: 'static + Client + Send + Sync>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        &mut self,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        client: &Arc<T>,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        to_lamports: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    while !notfunded.is_empty() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut new_funded: Vec<(&Keypair, u64)> = vec![];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut to_fund = vec![];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        info!("creating from... {}", funded.len());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut build_to_fund = Measure::start("build_to_fund");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        for f in &mut funded {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let max_units = cmp::min(notfunded.len() as u64, MAX_SPENDS_PER_TX);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if max_units == 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let start = notfunded.len() - max_units as usize;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let fees = if extra > 0 { max_fee } else { 0 };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let per_unit = (f.1 - lamports_per_account - fees) / max_units;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let moves: Vec<_> = notfunded[start..]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .iter()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .map(|k| (k.pubkey(), per_unit))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .collect();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            notfunded[start..]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .iter()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .for_each(|k| new_funded.push((k, per_unit)));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            notfunded.truncate(start);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if !moves.is_empty() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                to_fund.push((f.0, moves));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            extra -= 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        build_to_fund.stop();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        debug!("build to_fund vec: {}us", build_to_fund.as_us());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn make(&mut self, to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn sign(&mut self, blockhash: Hash);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn send<T: Client>(&self, client: &Arc<T>);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn verify<T: 'static + Client + Send + Sync>(&mut self, client: &Arc<T>, to_lamports: u64);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // try to transfer a "few" at a time with recent blockhash
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        //  assume 4MB network buffers, and 512 byte packets
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        const FUND_CHUNK_LEN: usize = 4 * 1024 * 1024 / 512;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				impl<'a> FundingTransactions<'a> for Vec<(&'a Keypair, Transaction)> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn fund<T: 'static + Client + Send + Sync>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        &mut self,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        client: &Arc<T>,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        to_lamports: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.make(to_fund);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        to_fund.chunks(FUND_CHUNK_LEN).for_each(|chunk| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut tries = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let mut make_txs = Measure::start("make_txs");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // this set of transactions just initializes us for bookkeeping
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            #[allow(clippy::clone_double_ref)] // sigh
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let mut to_fund_txs: Vec<_> = chunk
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .par_iter()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .map(|(k, m)| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    let tx = Transaction::new_unsigned_instructions(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        system_instruction::transfer_many(&k.pubkey(), &m),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        while !self.is_empty() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            info!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                "{} {} each to {} accounts in {} txs",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                if tries == 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    "transferring"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    " retrying"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                to_lamports,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                self.len() * MAX_SPENDS_PER_TX as usize,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                self.len(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    (k.clone(), tx)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let (blockhash, _fee_calculator) = get_recent_blockhash(client.as_ref());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // re-sign retained to_fund_txes with updated blockhash
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            self.sign(blockhash);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            self.send(&client);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // Sleep a few slots to allow transactions to process
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            sleep(Duration::from_secs(1));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            self.verify(&client, to_lamports);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // retry anything that seems to have dropped through cracks
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            //  again since these txs are all or nothing, they're fine to
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            //  retry
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            tries += 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        info!("transferred");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn make(&mut self, to_fund: &[(&'a Keypair, Vec<(Pubkey, u64)>)]) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut make_txs = Measure::start("make_txs");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let to_fund_txs: Vec<(&Keypair, Transaction)> = to_fund
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .par_iter()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .map(|(k, t)| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let tx = Transaction::new_unsigned_instructions(system_instruction::transfer_many(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    &k.pubkey(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    &t,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                ));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                (*k, tx)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            })
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .collect();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        make_txs.stop();
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -588,89 +574,135 @@ pub fn fund_keys<T: Client>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            to_fund_txs.len(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            make_txs.as_us()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.extend(to_fund_txs);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let amount = chunk[0].1[0].1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            while !to_fund_txs.is_empty() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let receivers = to_fund_txs
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    .iter()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    .fold(0, |len, (_, tx)| len + tx.message().instructions.len());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                info!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    "{} {} to {} in {} txs",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    if tries == 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        "transferring"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        " retrying"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    },
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    amount,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    receivers,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    to_fund_txs.len(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let (blockhash, _fee_calculator) = get_recent_blockhash(client);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // re-sign retained to_fund_txes with updated blockhash
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn sign(&mut self, blockhash: Hash) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut sign_txs = Measure::start("sign_txs");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                to_fund_txs.par_iter_mut().for_each(|(k, tx)| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.par_iter_mut().for_each(|(k, tx)| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            tx.sign(&[*k], blockhash);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        sign_txs.stop();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                debug!("sign {} txs: {}us", to_fund_txs.len(), sign_txs.as_us());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        debug!("sign {} txs: {}us", self.len(), sign_txs.as_us());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn send<T: Client>(&self, client: &Arc<T>) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut send_txs = Measure::start("send_txs");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                to_fund_txs.iter().for_each(|(_, tx)| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.iter().for_each(|(_, tx)| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            client.async_send_transaction(tx.clone()).expect("transfer");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        send_txs.stop();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                debug!("send {} txs: {}us", to_fund_txs.len(), send_txs.as_us());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        debug!("send {} txs: {}us", self.len(), send_txs.as_us());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let mut verify_txs = Measure::start("verify_txs");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let mut starting_txs = to_fund_txs.len();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let mut verified_txs = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let mut failed_verify = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn verify<T: 'static + Client + Send + Sync>(&mut self, client: &Arc<T>, 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));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let loops = if starting_txs < 1000 { 3 } else { 1 };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Only loop multiple times for small (quick) transaction batches
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                for _ in 0..(if starting_txs < 1000 { 3 } else { 1 }) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    let mut timer = Instant::now();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    to_fund_txs.retain(|(_, tx)| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        if timer.elapsed() >= Duration::from_secs(5) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            if failed_verify > 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                debug!("total txs failed verify: {}", failed_verify);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        for _ in 0..loops {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let failed_verify = Arc::new(AtomicUsize::new(0));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let client = client.clone();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let verified_txs = &verified_txs;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let failed_verify = &failed_verify;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let too_many_failures = &too_many_failures;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let verified_set: HashSet<Pubkey> = self
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .par_iter()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .filter_map(move |(k, tx)| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    if too_many_failures.load(Ordering::Relaxed) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        return None;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            info!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                "Verifying transfers... {} remaining",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                starting_txs - verified_txs
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            timer = Instant::now();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        let verified = verify_funding_transfer(client, &tx, amount);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        if verified {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            verified_txs += 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    let verified = if verify_funding_transfer(&client, &tx, to_lamports) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        verified_txs.fetch_add(1, Ordering::Relaxed);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        Some(k.pubkey())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    } else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            failed_verify += 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        failed_verify.fetch_add(1, Ordering::Relaxed);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        None
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    };
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    let verified_txs = verified_txs.load(Ordering::Relaxed);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    let failed_verify = failed_verify.load(Ordering::Relaxed);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    let remaining_count = starting_txs.saturating_sub(verified_txs + failed_verify);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    if failed_verify > 100 && failed_verify > verified_txs {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        too_many_failures.store(true, Ordering::Relaxed);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        warn!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            "Too many failed transfers... {} remaining, {} verified, {} failures",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            remaining_count, verified_txs, failed_verify
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        !verified
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    if to_fund_txs.is_empty() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    if remaining_count % 100 == 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        info!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            "Verifying transfers... {} remaining, {} verified, {} failures",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            remaining_count, verified_txs, failed_verify
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    verified
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                })
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .collect();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            self.retain(|(k, _)| !verified_set.contains(&k.pubkey()));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if self.is_empty() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    debug!("Looping verifications");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    info!("Verifying transfers... {} remaining", to_fund_txs.len());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            info!("Looping verifications");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let verified_txs = verified_txs.load(Ordering::Relaxed);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let failed_verify = failed_verify.load(Ordering::Relaxed);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let remaining_count = starting_txs.saturating_sub(verified_txs + failed_verify);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            info!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                "Verifying transfers... {} remaining, {} verified, {} failures",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                remaining_count, verified_txs, failed_verify
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            sleep(Duration::from_millis(100));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                starting_txs -= to_fund_txs.len();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                verify_txs.stop();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                debug!("verified {} txs: {}us", starting_txs, verify_txs.as_us());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // retry anything that seems to have dropped through cracks
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                //  again since these txs are all or nothing, they're fine to
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                //  retry
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                tries += 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            info!("transferred");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// 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<T: 'static + Client + Send + Sync>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    client: Arc<T>,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    source: &Keypair,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    dests: &[Keypair],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    total: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    max_fee: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    lamports_per_account: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut funded: Vec<&Keypair> = vec![source];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut funded_funds = total;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut not_funded: Vec<&Keypair> = dests.iter().collect();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    while !not_funded.is_empty() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Build to fund list and prepare funding sources for next iteration
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut new_funded: Vec<&Keypair> = vec![];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut to_fund: Vec<(&Keypair, Vec<(Pubkey, u64)>)> = vec![];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let to_lamports = (funded_funds - lamports_per_account - max_fee) / MAX_SPENDS_PER_TX;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        for f in funded {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let start = not_funded.len() - MAX_SPENDS_PER_TX as usize;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let dests: Vec<_> = not_funded.drain(start..).collect();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            let spends: Vec<_> = dests.iter().map(|k| (k.pubkey(), to_lamports)).collect();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            to_fund.push((f, spends));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            new_funded.extend(dests.into_iter());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // try to transfer a "few" at a time with recent blockhash
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        //  assume 4MB network buffers, and 512 byte packets
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        const FUND_CHUNK_LEN: usize = 4 * 1024 * 1024 / 512;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        to_fund.chunks(FUND_CHUNK_LEN).for_each(|chunk| {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            Vec::<(&Keypair, Transaction)>::with_capacity(chunk.len()).fund(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                &client,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                chunk,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                to_lamports,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        info!("funded: {} left: {}", new_funded.len(), notfunded.len());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        info!("funded: {} left: {}", new_funded.len(), not_funded.len());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        funded = new_funded;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        funded_funds = to_lamports;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -678,14 +710,14 @@ pub fn airdrop_lamports<T: Client>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    client: &T,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    faucet_addr: &SocketAddr,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    id: &Keypair,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    tx_count: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    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 < tx_count {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let airdrop_amount = tx_count - starting_balance;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if starting_balance < desired_balance {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let airdrop_amount = desired_balance - starting_balance;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        info!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            "Airdropping {:?} lamports from {} for {}",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            airdrop_amount,
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -810,17 +842,6 @@ fn compute_and_report_stats(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// First transfer 2/3 of the lamports to the dest accounts
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// then ping-pong 1/3 of the lamports back to the other account
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// this leaves 1/3 lamport buffer in each account
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				fn should_switch_directions(num_lamports_per_account: u64, keypair_chunks: u64, i: u64) -> bool {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if i < keypair_chunks * (2 * num_lamports_per_account) / 3 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return false;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    i % (keypair_chunks * num_lamports_per_account / 3) == 0
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				pub fn generate_keypairs(seed_keypair: &Keypair, count: u64) -> (Vec<Keypair>, u64) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut seed = [0u8; 32];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    seed.copy_from_slice(&seed_keypair.to_bytes()[..32]);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1004,23 +1025,25 @@ fn fund_move_keys<T: Client>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    info!("done funding keys, took {} ms", funding_time.as_ms());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				pub fn generate_and_fund_keypairs<T: Client>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    client: &T,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				pub fn generate_and_fund_keypairs<T: 'static + Client + Send + Sync>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    client: Arc<T>,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    faucet_addr: Option<SocketAddr>,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    funding_key: &Keypair,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    keypair_count: usize,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    lamports_per_account: u64,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    use_move: bool,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				) -> Result<(Vec<Keypair>, Option<LibraKeys>, u64)> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				) -> Result<(Vec<Keypair>, Option<LibraKeys>)> {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    info!("Creating {} keypairs...", keypair_count);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let (mut keypairs, extra) = generate_keypairs(funding_key, keypair_count as u64);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    info!("Get lamports...");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Sample the first keypair, see if it has lamports, if so then resume.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // This logic is to prevent lamport loss on repeated solana-bench-tps executions
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let last_keypair_balance = client
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        .get_balance(&keypairs[keypair_count - 1].pubkey())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        .unwrap_or(0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Sample the first keypair, to prevent lamport loss on repeated solana-bench-tps executions
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let first_key = keypairs[0].pubkey();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    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_keypair_balance = client.get_balance(&last_key).unwrap_or(0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #[cfg(feature = "move")]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let mut move_keypairs_ret = None;
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1028,31 +1051,38 @@ pub fn generate_and_fund_keypairs<T: Client>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #[cfg(not(feature = "move"))]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let move_keypairs_ret = None;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if lamports_per_account > last_keypair_balance {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (_blockhash, fee_calculator) = get_recent_blockhash(client);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let account_desired_balance =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            lamports_per_account - last_keypair_balance + fee_calculator.max_lamports_per_signature;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let extra_fees = extra * fee_calculator.max_lamports_per_signature;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut total = account_desired_balance * (1 + keypairs.len() as u64) + extra_fees;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Repeated runs will eat up keypair balances from transaction fees. In order to quickly
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    //   start another bench-tps run without re-funding all of the keypairs, check if the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    //   keypairs still have at least 80% of the expected funds. That should be enough to
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    //   pay for the transaction fees in a new run.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    let enough_lamports = 8 * lamports_per_account / 10;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if first_keypair_balance < enough_lamports || last_keypair_balance < enough_lamports {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (_blockhash, fee_calculator) = get_recent_blockhash(client.as_ref());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let max_fee = fee_calculator.max_lamports_per_signature;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let extra_fees = extra * max_fee;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let total_keypairs = keypairs.len() as u64 + 1; // Add one for funding keypair
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut total = lamports_per_account * total_keypairs + extra_fees;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if use_move {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            total *= 3;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        info!("Previous key balance: {} max_fee: {} lamports_per_account: {} extra: {} desired_balance: {} total: {}",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                 last_keypair_balance, fee_calculator.max_lamports_per_signature, lamports_per_account, extra,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                 account_desired_balance, total
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let funding_key_balance = client.get_balance(&funding_key.pubkey()).unwrap_or(0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        info!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            "Funding keypair balance: {} max_fee: {} lamports_per_account: {} extra: {} total: {}",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            funding_key_balance, max_fee, lamports_per_account, extra, total
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if client.get_balance(&funding_key.pubkey()).unwrap_or(0) < total {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            airdrop_lamports(client, &faucet_addr.unwrap(), funding_key, total)?;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            airdrop_lamports(client.as_ref(), &faucet_addr.unwrap(), funding_key, total)?;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        #[cfg(feature = "move")]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if use_move {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let libra_genesis_keypair = create_genesis(&funding_key, client, 10_000_000);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let libra_mint_program_id = upload_mint_script(&funding_key, client);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let libra_pay_program_id = upload_payment_script(&funding_key, client);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let libra_genesis_keypair =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    create_genesis(&funding_key, client.as_ref(), 10_000_000);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let libra_mint_program_id = upload_mint_script(&funding_key, client.as_ref());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let libra_pay_program_id = upload_payment_script(&funding_key, client.as_ref());
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // Generate another set of keypairs for move accounts.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                // Still fund the solana ones which will be used for fees.
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1060,7 +1090,7 @@ pub fn generate_and_fund_keypairs<T: Client>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let mut rnd = GenKeys::new(seed);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                let move_keypairs = rnd.gen_n_keypairs(keypair_count as u64);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                fund_move_keys(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    client,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    client.as_ref(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    funding_key,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    &move_keypairs,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                    total / 3,
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1085,15 +1115,15 @@ pub fn generate_and_fund_keypairs<T: Client>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            funding_key,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            &keypairs,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            total,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            fee_calculator.max_lamports_per_signature,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            extra,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            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, move_keypairs_ret, last_keypair_balance))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Ok((keypairs, move_keypairs_ret))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#[cfg(test)]
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1105,30 +1135,11 @@ mod tests {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    use solana_sdk::fee_calculator::FeeCalculator;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    use solana_sdk::genesis_config::create_genesis_config;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #[test]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn test_switch_directions() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 1, 0), false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 1, 1), false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 1, 20), true);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 1, 21), false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 1, 30), true);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 1, 90), true);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 1, 91), false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 2, 0), false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 2, 1), false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 2, 20), false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 2, 40), true);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 2, 90), false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 2, 100), true);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assert_eq!(should_switch_directions(30, 2, 101), false);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #[test]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn test_bench_tps_bank_client() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (genesis_config, id) = create_genesis_config(10_000);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let bank = Bank::new(&genesis_config);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let clients = vec![BankClient::new(bank)];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let client = Arc::new(BankClient::new(bank));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let mut config = Config::default();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        config.id = id;
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1136,23 +1147,24 @@ mod tests {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        config.duration = Duration::from_secs(5);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let keypair_count = config.tx_count * config.keypair_multiplier;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (keypairs, _move_keypairs, _keypair_balance) =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            generate_and_fund_keypairs(&clients[0], None, &config.id, keypair_count, 20, false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (keypairs, _move_keypairs) =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            generate_and_fund_keypairs(client.clone(), None, &config.id, keypair_count, 20, false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .unwrap();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        do_bench_tps(clients, config, keypairs, 0, None);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        do_bench_tps(client, config, keypairs, None);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #[test]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    fn test_bench_tps_fund_keys() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (genesis_config, id) = create_genesis_config(10_000);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let bank = Bank::new(&genesis_config);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let client = BankClient::new(bank);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let client = Arc::new(BankClient::new(bank));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let keypair_count = 20;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let lamports = 20;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (keypairs, _move_keypairs, _keypair_balance) =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            generate_and_fund_keypairs(&client, None, &id, keypair_count, lamports, false).unwrap();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (keypairs, _move_keypairs) =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            generate_and_fund_keypairs(client.clone(), None, &id, keypair_count, lamports, false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .unwrap();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        for kp in &keypairs {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            assert_eq!(
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -1170,23 +1182,16 @@ mod tests {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let fee_calculator = FeeCalculator::new(11, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        genesis_config.fee_calculator = fee_calculator;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let bank = Bank::new(&genesis_config);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let client = BankClient::new(bank);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let client = Arc::new(BankClient::new(bank));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let keypair_count = 20;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let lamports = 20;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (keypairs, _move_keypairs, _keypair_balance) =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            generate_and_fund_keypairs(&client, None, &id, keypair_count, lamports, false).unwrap();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let (keypairs, _move_keypairs) =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            generate_and_fund_keypairs(client.clone(), None, &id, keypair_count, lamports, false)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                .unwrap();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        let max_fee = client
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .get_recent_blockhash_with_commitment(CommitmentConfig::recent())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .unwrap()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            .max_lamports_per_signature;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        for kp in &keypairs {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            assert_eq!(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                client.get_balance(&kp.pubkey()).unwrap(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                lamports + max_fee
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            );
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            assert_eq!(client.get_balance(&kp.pubkey()).unwrap(), lamports);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				 
 |