Handle paying for move transactions with unique solana system transactions (#5317)

This commit is contained in:
sakridge 2019-07-31 11:15:14 -07:00 committed by GitHub
parent f859243191
commit 05f3437601
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 133 additions and 98 deletions

View File

@ -70,8 +70,7 @@ pub fn do_bench_tps<T>(
config: Config, config: Config,
gen_keypairs: Vec<Keypair>, gen_keypairs: Vec<Keypair>,
keypair0_balance: u64, keypair0_balance: u64,
program_id: &Pubkey, libra_args: Option<(&Pubkey, &Pubkey, Vec<Keypair>)>,
libra_mint_id: &Pubkey,
) -> u64 ) -> u64
where where
T: 'static + Client + Send + Sync, T: 'static + Client + Send + Sync,
@ -82,8 +81,8 @@ where
thread_batch_sleep_ms, thread_batch_sleep_ms,
duration, duration,
tx_count, tx_count,
use_move,
sustained, sustained,
..
} = config; } = config;
let clients: Vec<_> = clients.into_iter().map(Arc::new).collect(); let clients: Vec<_> = clients.into_iter().map(Arc::new).collect();
@ -175,9 +174,7 @@ where
&keypairs[len..], &keypairs[len..],
threads, threads,
reclaim_lamports_back_to_source_account, reclaim_lamports_back_to_source_account,
use_move, &libra_args,
&program_id,
&libra_mint_id,
); );
// In sustained mode overlap the transfers with generation // In sustained mode overlap the transfers with generation
// this has higher average performance but lower peak performance // this has higher average performance but lower peak performance
@ -234,6 +231,74 @@ fn metrics_submit_lamport_balance(lamport_balance: u64) {
); );
} }
fn generate_move_txs(
source: &[Keypair],
dest: &[Keypair],
reclaim: bool,
move_keypairs: &[Keypair],
libra_pay_program_id: &Pubkey,
libra_mint_id: &Pubkey,
blockhash: &Hash,
) -> Vec<(Transaction, u64)> {
let count = move_keypairs.len() / 2;
let source_move = &move_keypairs[..count];
let dest_move = &move_keypairs[count..];
let pairs: Vec<_> = if !reclaim {
source_move
.iter()
.zip(dest_move.iter())
.zip(source.iter())
.collect()
} else {
dest_move
.iter()
.zip(source_move.iter())
.zip(dest.iter())
.collect()
};
pairs
.par_iter()
.map(|((from, to), payer)| {
(
librapay_transaction::transfer(
libra_pay_program_id,
libra_mint_id,
&payer,
&from,
&to.pubkey(),
1,
*blockhash,
),
timestamp(),
)
})
.collect()
}
fn generate_solana_txs(
source: &[Keypair],
dest: &[Keypair],
reclaim: bool,
blockhash: &Hash,
) -> Vec<(Transaction, u64)> {
let pairs: Vec<_> = if !reclaim {
source.iter().zip(dest.iter()).collect()
} else {
dest.iter().zip(source.iter()).collect()
};
pairs
.par_iter()
.map(|(from, to)| {
(
system_transaction::create_user_account(from, &to.pubkey(), 1, *blockhash),
timestamp(),
)
})
.collect()
}
fn generate_txs( fn generate_txs(
shared_txs: &SharedTransactions, shared_txs: &SharedTransactions,
blockhash: &Hash, blockhash: &Hash,
@ -241,43 +306,25 @@ fn generate_txs(
dest: &[Keypair], dest: &[Keypair],
threads: usize, threads: usize,
reclaim: bool, reclaim: bool,
use_move: bool, libra_args: &Option<(&Pubkey, &Pubkey, Vec<Keypair>)>,
libra_pay_program_id: &Pubkey,
libra_mint_id: &Pubkey,
) { ) {
let tx_count = source.len(); let tx_count = source.len();
println!("Signing transactions... {} (reclaim={})", tx_count, reclaim); println!("Signing transactions... {} (reclaim={})", tx_count, reclaim);
let signing_start = Instant::now(); let signing_start = Instant::now();
let pairs: Vec<_> = if !reclaim { let transactions = if let Some((libra_pay_program_id, libra_mint_id, libra_keys)) = libra_args {
source.iter().zip(dest.iter()).collect() generate_move_txs(
source,
dest,
reclaim,
&libra_keys,
libra_pay_program_id,
libra_mint_id,
blockhash,
)
} else { } else {
dest.iter().zip(source.iter()).collect() generate_solana_txs(source, dest, reclaim, blockhash)
}; };
let transactions: Vec<_> = pairs
.par_iter()
.map(|(id, keypair)| {
if use_move {
(
librapay_transaction::transfer(
libra_pay_program_id,
libra_mint_id,
&id,
&id,
&keypair.pubkey(),
1,
*blockhash,
),
timestamp(),
)
} else {
(
system_transaction::create_user_account(id, &keypair.pubkey(), 1, *blockhash),
timestamp(),
)
}
})
.collect();
let duration = signing_start.elapsed(); let duration = signing_start.elapsed();
let ns = duration.as_secs() * 1_000_000_000 + u64::from(duration.subsec_nanos()); let ns = duration.as_secs() * 1_000_000_000 + u64::from(duration.subsec_nanos());
@ -614,11 +661,7 @@ fn should_switch_directions(num_lamports_per_account: u64, i: u64) -> bool {
i % (num_lamports_per_account / 4) == 0 && (i >= (3 * num_lamports_per_account) / 4) i % (num_lamports_per_account / 4) == 0 && (i >= (3 * num_lamports_per_account) / 4)
} }
pub fn generate_keypairs( pub fn generate_keypairs(seed_keypair: &Keypair, count: u64) -> (Vec<Keypair>, u64) {
seed_keypair: &Keypair,
count: u64,
use_move: bool,
) -> (Vec<Keypair>, u64) {
let mut seed = [0u8; 32]; let mut seed = [0u8; 32];
seed.copy_from_slice(&seed_keypair.to_bytes()[..32]); seed.copy_from_slice(&seed_keypair.to_bytes()[..32]);
let mut rnd = GenKeys::new(seed); let mut rnd = GenKeys::new(seed);
@ -631,13 +674,7 @@ pub fn generate_keypairs(
delta *= MAX_SPENDS_PER_TX; delta *= MAX_SPENDS_PER_TX;
total_keys += delta; total_keys += delta;
} }
if use_move { (rnd.gen_n_keypairs(total_keys), extra)
// Move funding is a naive loop that doesn't
// need aligned number of keys.
(rnd.gen_n_keypairs(count), extra)
} else {
(rnd.gen_n_keypairs(total_keys), extra)
}
} }
fn fund_move_keys<T: Client>( fn fund_move_keys<T: Client>(
@ -770,10 +807,9 @@ pub fn generate_and_fund_keypairs<T: Client>(
tx_count: usize, tx_count: usize,
lamports_per_account: u64, lamports_per_account: u64,
libra_keys: Option<(&Pubkey, &Pubkey, &Arc<Keypair>)>, libra_keys: Option<(&Pubkey, &Pubkey, &Arc<Keypair>)>,
) -> Result<(Vec<Keypair>, u64)> { ) -> Result<(Vec<Keypair>, Option<Vec<Keypair>>, u64)> {
info!("Creating {} keypairs...", tx_count * 2); info!("Creating {} keypairs...", tx_count * 2);
let (mut keypairs, extra) = let (mut keypairs, extra) = generate_keypairs(funding_key, tx_count as u64 * 2);
generate_keypairs(funding_key, tx_count as u64 * 2, libra_keys.is_some());
info!("Get lamports..."); info!("Get lamports...");
// Sample the first keypair, see if it has lamports, if so then resume. // Sample the first keypair, see if it has lamports, if so then resume.
@ -782,41 +818,56 @@ pub fn generate_and_fund_keypairs<T: Client>(
.get_balance(&keypairs[tx_count * 2 - 1].pubkey()) .get_balance(&keypairs[tx_count * 2 - 1].pubkey())
.unwrap_or(0); .unwrap_or(0);
let mut move_keypairs_ret = None;
if lamports_per_account > last_keypair_balance { if lamports_per_account > last_keypair_balance {
let (_blockhash, fee_calculator) = client.get_recent_blockhash().unwrap(); let (_blockhash, fee_calculator) = client.get_recent_blockhash().unwrap();
let account_desired_balance = let account_desired_balance =
lamports_per_account - last_keypair_balance + fee_calculator.max_lamports_per_signature; lamports_per_account - last_keypair_balance + fee_calculator.max_lamports_per_signature;
let extra_fees = extra * fee_calculator.max_lamports_per_signature; let extra_fees = extra * fee_calculator.max_lamports_per_signature;
let total = account_desired_balance * (1 + keypairs.len() as u64) + extra_fees; let mut total = account_desired_balance * (1 + keypairs.len() as u64) + extra_fees;
if libra_keys.is_some() {
total *= 2;
}
if client.get_balance(&funding_key.pubkey()).unwrap_or(0) < total { if client.get_balance(&funding_key.pubkey()).unwrap_or(0) < total {
airdrop_lamports(client, &drone_addr.unwrap(), funding_key, total)?; airdrop_lamports(client, &drone_addr.unwrap(), funding_key, total)?;
} }
if let Some((libra_pay_program_id, libra_mint_program_id, libra_mint_key)) = libra_keys { if let Some((libra_pay_program_id, libra_mint_program_id, libra_mint_key)) = libra_keys {
// Generate another set of keypairs for move accounts.
// Still fund the solana ones which will be used for fees.
let seed = [0u8; 32];
let mut rnd = GenKeys::new(seed);
let move_keypairs = rnd.gen_n_keypairs(tx_count as u64 * 2);
fund_move_keys( fund_move_keys(
client, client,
funding_key, funding_key,
&keypairs, &move_keypairs,
total, total / 2,
libra_pay_program_id, libra_pay_program_id,
libra_mint_program_id, libra_mint_program_id,
libra_mint_key, libra_mint_key,
); );
} else { move_keypairs_ret = Some(move_keypairs);
fund_keys(
client, // Give solana keys half and move keys half the lamports.
funding_key, total /= 2;
&keypairs,
total,
fee_calculator.max_lamports_per_signature,
extra,
);
} }
fund_keys(
client,
funding_key,
&keypairs,
total,
fee_calculator.max_lamports_per_signature,
extra,
);
} }
// 'generate_keypairs' generates extra keys to be able to have size-aligned funding batches for fund_keys. // 'generate_keypairs' generates extra keys to be able to have size-aligned funding batches for fund_keys.
keypairs.truncate(2 * tx_count); keypairs.truncate(2 * tx_count);
Ok((keypairs, last_keypair_balance)) Ok((keypairs, move_keypairs_ret, last_keypair_balance))
} }
#[cfg(test)] #[cfg(test)]
@ -905,7 +956,7 @@ mod tests {
None None
}; };
let (keypairs, _keypair_balance) = generate_and_fund_keypairs( let (keypairs, move_keypairs, _keypair_balance) = generate_and_fund_keypairs(
&client, &client,
Some(drone_addr), Some(drone_addr),
&config.id, &config.id,
@ -915,14 +966,14 @@ mod tests {
) )
.unwrap(); .unwrap();
let total = do_bench_tps( let libra_mint_pubkey = libra_genesis_keypair.pubkey();
vec![client], let move_args = if let Some(keypairs) = move_keypairs {
config, Some((&libra_pay_program_id, &libra_mint_pubkey, keypairs))
keypairs, } else {
0, None
&libra_pay_program_id, };
&libra_genesis_keypair.pubkey(),
); let total = do_bench_tps(vec![client], config, keypairs, 0, move_args);
assert!(total > 100); assert!(total > 100);
} }
@ -936,11 +987,10 @@ mod tests {
} }
#[test] #[test]
#[ignore]
fn test_bench_tps_local_cluster_move() { fn test_bench_tps_local_cluster_move() {
let mut config = Config::default(); let mut config = Config::default();
config.tx_count = 100; config.tx_count = 100;
config.duration = Duration::from_secs(10); config.duration = Duration::from_secs(20);
config.use_move = true; config.use_move = true;
test_bench_tps_local_cluster(config); test_bench_tps_local_cluster(config);
@ -957,18 +1007,11 @@ mod tests {
config.tx_count = 10; config.tx_count = 10;
config.duration = Duration::from_secs(5); config.duration = Duration::from_secs(5);
let (keypairs, _keypair_balance) = let (keypairs, _move_keypairs, _keypair_balance) =
generate_and_fund_keypairs(&clients[0], None, &config.id, config.tx_count, 20, None) generate_and_fund_keypairs(&clients[0], None, &config.id, config.tx_count, 20, None)
.unwrap(); .unwrap();
do_bench_tps( do_bench_tps(clients, config, keypairs, 0, None);
clients,
config,
keypairs,
0,
&Pubkey::default(),
&Pubkey::default(),
);
} }
#[test] #[test]
@ -979,7 +1022,7 @@ mod tests {
let tx_count = 10; let tx_count = 10;
let lamports = 20; let lamports = 20;
let (keypairs, _keypair_balance) = let (keypairs, _move_keypairs, _keypair_balance) =
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, None).unwrap(); generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, None).unwrap();
for kp in &keypairs { for kp in &keypairs {
@ -997,7 +1040,7 @@ mod tests {
let tx_count = 10; let tx_count = 10;
let lamports = 20; let lamports = 20;
let (keypairs, _keypair_balance) = let (keypairs, _move_keypairs, _keypair_balance) =
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, None).unwrap(); generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, None).unwrap();
let max_fee = client let max_fee = client

View File

@ -6,7 +6,6 @@ use crate::bench::{
}; };
use solana::gossip_service::{discover_cluster, get_multi_client}; use solana::gossip_service::{discover_cluster, get_multi_client};
use solana_sdk::fee_calculator::FeeCalculator; use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
@ -42,7 +41,7 @@ fn main() {
} = cli_config; } = cli_config;
if write_to_client_file { if write_to_client_file {
let (keypairs, _) = generate_keypairs(&id, tx_count as u64 * 2, use_move); let (keypairs, _) = generate_keypairs(&id, tx_count as u64 * 2);
let num_accounts = keypairs.len() as u64; let num_accounts = keypairs.len() as u64;
let max_fee = FeeCalculator::new(target_lamports_per_signature).max_lamports_per_signature; let max_fee = FeeCalculator::new(target_lamports_per_signature).max_lamports_per_signature;
let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee) let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee)
@ -80,7 +79,7 @@ fn main() {
exit(1); exit(1);
} }
let (keypairs, keypair_balance) = if read_from_client_file { let (keypairs, _move_keypairs, keypair_balance) = if read_from_client_file {
let path = Path::new(&client_ids_and_stake_file); let path = Path::new(&client_ids_and_stake_file);
let file = File::open(path).unwrap(); let file = File::open(path).unwrap();
@ -97,7 +96,7 @@ fn main() {
// This prevents the amount of storage needed for bench-tps accounts from creeping up // This prevents the amount of storage needed for bench-tps accounts from creeping up
// across multiple runs. // across multiple runs.
keypairs.sort_by(|x, y| x.pubkey().to_string().cmp(&y.pubkey().to_string())); keypairs.sort_by(|x, y| x.pubkey().to_string().cmp(&y.pubkey().to_string()));
(keypairs, last_balance) (keypairs, None, last_balance)
} else { } else {
generate_and_fund_keypairs( generate_and_fund_keypairs(
&client, &client,
@ -123,12 +122,5 @@ fn main() {
use_move, use_move,
}; };
do_bench_tps( do_bench_tps(vec![client], config, keypairs, keypair_balance, None);
vec![client],
config,
keypairs,
keypair_balance,
&Pubkey::new_rand(),
&Pubkey::new_rand(),
);
} }