Add move to bench-tps (#5250)

This commit is contained in:
sakridge 2019-07-27 15:28:00 -07:00 committed by GitHub
parent 8d296d0969
commit a642168369
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 279 additions and 40 deletions

6
Cargo.lock generated
View File

@ -3098,10 +3098,13 @@ dependencies = [
"solana-ed25519-dalek 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-exchange-program 0.18.0-pre0",
"solana-kvstore 0.18.0-pre0",
"solana-librapay-api 0.18.0-pre0",
"solana-logger 0.18.0-pre0",
"solana-measure 0.18.0-pre0",
"solana-merkle-tree 0.18.0-pre0",
"solana-metrics 0.18.0-pre0",
"solana-move-loader-api 0.18.0-pre0",
"solana-move-loader-program 0.18.0-pre0",
"solana-netutil 0.18.0-pre0",
"solana-runtime 0.18.0-pre0",
"solana-sdk 0.18.0-pre0",
@ -3164,6 +3167,7 @@ dependencies = [
name = "solana-bench-tps"
version = "0.18.0-pre0"
dependencies = [
"bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3174,7 +3178,9 @@ dependencies = [
"solana 0.18.0-pre0",
"solana-client 0.18.0-pre0",
"solana-drone 0.18.0-pre0",
"solana-librapay-api 0.18.0-pre0",
"solana-logger 0.18.0-pre0",
"solana-measure 0.18.0-pre0",
"solana-metrics 0.18.0-pre0",
"solana-netutil 0.18.0-pre0",
"solana-runtime 0.18.0-pre0",

View File

@ -8,6 +8,7 @@ license = "Apache-2.0"
homepage = "https://solana.com/"
[dependencies]
bincode = "1.1.4"
clap = "2.33.0"
log = "0.4.7"
rayon = "1.1.0"
@ -18,8 +19,10 @@ serde_yaml = "0.8.9"
solana = { path = "../core", version = "0.18.0-pre0" }
solana-client = { path = "../client", version = "0.18.0-pre0" }
solana-drone = { path = "../drone", version = "0.18.0-pre0" }
solana-librapay-api = { path = "../programs/librapay_api", version = "0.18.0-pre0" }
solana-logger = { path = "../logger", version = "0.18.0-pre0" }
solana-metrics = { path = "../metrics", version = "0.18.0-pre0" }
solana-measure = { path = "../measure", version = "0.18.0-pre0" }
solana-netutil = { path = "../netutil", version = "0.18.0-pre0" }
solana-runtime = { path = "../runtime", version = "0.18.0-pre0" }
solana-sdk = { path = "../sdk", version = "0.18.0-pre0" }

View File

@ -1,13 +1,16 @@
use solana_metrics;
use bincode;
use log::*;
use rayon::prelude::*;
use solana::gen_keys::GenKeys;
use solana_client::perf_utils::{sample_txs, SampleStats};
use solana_drone::drone::request_airdrop_transaction;
use solana_measure::measure::Measure;
use solana_metrics::datapoint_info;
use solana_sdk::client::Client;
use solana_sdk::hash::Hash;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction;
use solana_sdk::system_transaction;
@ -24,6 +27,8 @@ use std::thread::Builder;
use std::time::Duration;
use std::time::Instant;
use solana_librapay_api::librapay_transaction;
pub const MAX_SPENDS_PER_TX: u64 = 4;
pub const NUM_LAMPORTS_PER_ACCOUNT: u64 = 128;
@ -32,6 +37,8 @@ pub enum BenchTpsError {
AirdropFailure,
}
const USE_MOVE: bool = false;
pub type Result<T> = std::result::Result<T, BenchTpsError>;
pub type SharedTransactions = Arc<RwLock<VecDeque<Vec<(Transaction, u64)>>>>;
@ -63,6 +70,8 @@ pub fn do_bench_tps<T>(
config: Config,
gen_keypairs: Vec<Keypair>,
keypair0_balance: u64,
program_id: &Pubkey,
libra_mint_id: &Pubkey,
) -> u64
where
T: 'static + Client + Send + Sync,
@ -165,6 +174,8 @@ where
&keypairs[len..],
threads,
reclaim_lamports_back_to_source_account,
&program_id,
&libra_mint_id,
);
// In sustained mode overlap the transfers with generation
// this has higher average performance but lower peak performance
@ -228,6 +239,8 @@ fn generate_txs(
dest: &[Keypair],
threads: usize,
reclaim: bool,
program_id: &Pubkey,
libra_mint_id: &Pubkey,
) {
let tx_count = source.len();
println!("Signing transactions... {} (reclaim={})", tx_count, reclaim);
@ -241,10 +254,25 @@ fn generate_txs(
let transactions: Vec<_> = pairs
.par_iter()
.map(|(id, keypair)| {
(
system_transaction::create_user_account(id, &keypair.pubkey(), 1, *blockhash),
timestamp(),
)
if USE_MOVE {
(
librapay_transaction::transfer(
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();
@ -392,13 +420,10 @@ pub fn fund_keys<T: Client>(
let mut to_fund_txs: Vec<_> = chunk
.par_iter()
.map(|(k, m)| {
(
k.clone(),
Transaction::new_unsigned_instructions(system_instruction::transfer_many(
&k.pubkey(),
&m,
)),
)
let tx = Transaction::new_unsigned_instructions(
system_instruction::transfer_many(&k.pubkey(), &m),
);
(k.clone(), tx)
})
.collect();
@ -599,18 +624,148 @@ pub fn generate_keypairs(seed_keypair: &Keypair, count: u64) -> (Vec<Keypair>, u
delta *= MAX_SPENDS_PER_TX;
total_keys += delta;
}
(rnd.gen_n_keypairs(total_keys), extra)
if USE_MOVE {
// 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>(
client: &T,
funding_key: &Keypair,
keypairs: &[Keypair],
total: u64,
libra_pay_program_id: &Pubkey,
libra_mint_program_id: &Pubkey,
libra_mint_key: &Keypair,
) {
let (mut blockhash, _fee_calculator) = client.get_recent_blockhash().unwrap();
info!("creating the libra funding account..");
let libra_funding_key = Keypair::new();
let tx = librapay_transaction::create_account(
funding_key,
&libra_funding_key.pubkey(),
1,
blockhash,
);
let sig = client
.async_send_transaction(tx)
.expect("create_account in generate_and_fund_keypairs");
client.poll_for_signature(&sig).unwrap();
info!("minting to funding keypair");
let tx = librapay_transaction::mint_tokens(
&libra_mint_program_id,
funding_key,
libra_mint_key,
&libra_funding_key.pubkey(),
total,
blockhash,
);
let sig = client
.async_send_transaction(tx)
.expect("create_account in generate_and_fund_keypairs");
client.poll_for_signature(&sig).unwrap();
info!("creating move accounts.. {}", keypairs.len());
let create_len = 8;
let mut funding_time = Measure::start("funding_time");
for (i, keys) in keypairs.chunks(create_len).enumerate() {
let mut tx_send = Measure::start("poll");
let pubkeys: Vec<_> = keys.iter().map(|k| k.pubkey()).collect();
let tx = librapay_transaction::create_accounts(funding_key, &pubkeys, 1, blockhash);
let ser_size = bincode::serialized_size(&tx).unwrap();
let sig = client
.async_send_transaction(tx)
.expect("create_account in generate_and_fund_keypairs");
tx_send.stop();
let mut poll = Measure::start("poll");
client.poll_for_signature(&sig).unwrap();
poll.stop();
if i % 10 == 0 {
blockhash = client.get_recent_blockhash().unwrap().0;
info!(
"size: {} created {} accounts of {} sig: {}us send: {}us",
ser_size,
i,
(keypairs.len() / create_len),
poll.as_us(),
tx_send.as_us()
);
}
}
funding_time.stop();
info!("funding accounts {}ms", funding_time.as_ms());
let mut sigs = vec![];
let tx_count = keypairs.len();
let amount = total / (tx_count as u64);
for (i, key) in keypairs[..tx_count].iter().enumerate() {
let tx = librapay_transaction::transfer(
libra_pay_program_id,
&libra_mint_key.pubkey(),
funding_key,
&libra_funding_key,
&key.pubkey(),
amount,
blockhash,
);
let sig = client
.async_send_transaction(tx.clone())
.expect("create_account in generate_and_fund_keypairs");
sigs.push((sig, key));
if i % 50 == 0 {
blockhash = client.get_recent_blockhash().unwrap().0;
}
}
for (i, (sig, key)) in sigs.iter().enumerate() {
let mut times = 0;
loop {
match client.poll_for_signature(&sig) {
Ok(_) => {
break;
}
Err(e) => {
info!("e :{:?} waiting times: {} sig: {}", e, times, sig);
times += 1;
sleep(Duration::from_secs(1));
}
}
}
times = 0;
loop {
let balance = librapay_transaction::get_libra_balance(client, &key.pubkey()).unwrap();
if amount != balance {
info!("i: {} balance: {} times: {}", i, balance, times);
times += 1;
sleep(Duration::from_secs(1));
} else {
break;
}
}
if i % 10 == 0 {
info!("funding {} of {}", i, tx_count);
}
}
info!("done..");
}
pub fn generate_and_fund_keypairs<T: Client>(
client: &T,
drone_addr: Option<SocketAddr>,
funding_pubkey: &Keypair,
funding_key: &Keypair,
tx_count: usize,
lamports_per_account: u64,
libra_keys: Option<(&Pubkey, &Pubkey, &Keypair)>,
) -> Result<(Vec<Keypair>, u64)> {
info!("Creating {} keypairs...", tx_count * 2);
let (mut keypairs, extra) = generate_keypairs(funding_pubkey, tx_count as u64 * 2);
let (mut keypairs, extra) = generate_keypairs(funding_key, tx_count as u64 * 2);
info!("Get lamports...");
// Sample the first keypair, see if it has lamports, if so then resume.
@ -620,23 +775,35 @@ pub fn generate_and_fund_keypairs<T: Client>(
.unwrap_or(0);
if lamports_per_account > last_keypair_balance {
let (_, fee_calculator) = client.get_recent_blockhash().unwrap();
let (_blockhash, fee_calculator) = client.get_recent_blockhash().unwrap();
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 total = account_desired_balance * (1 + keypairs.len() as u64) + extra_fees;
if client.get_balance(&funding_pubkey.pubkey()).unwrap_or(0) < total {
airdrop_lamports(client, &drone_addr.unwrap(), funding_pubkey, total)?;
if client.get_balance(&funding_key.pubkey()).unwrap_or(0) < total {
airdrop_lamports(client, &drone_addr.unwrap(), funding_key, total)?;
}
if USE_MOVE {
let (libra_pay_program_id, libra_mint_program_id, libra_mint_key) = libra_keys.unwrap();
fund_move_keys(
client,
funding_key,
&keypairs,
total,
libra_pay_program_id,
libra_mint_program_id,
libra_mint_key,
);
} else {
fund_keys(
client,
funding_key,
&keypairs,
total,
fee_calculator.max_lamports_per_signature,
extra,
);
}
info!("adding more lamports {}", account_desired_balance);
fund_keys(
client,
funding_pubkey,
&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.
@ -653,6 +820,7 @@ mod tests {
use solana::validator::ValidatorConfig;
use solana_client::thin_client::create_client;
use solana_drone::drone::run_local_drone;
use solana_librapay_api::{upload_mint_program, upload_payment_program};
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_sdk::client::SyncClient;
@ -681,13 +849,30 @@ mod tests {
const NUM_NODES: usize = 1;
let cluster = LocalCluster::new(&ClusterConfig {
node_stakes: vec![999_990; NUM_NODES],
cluster_lamports: 2_000_000,
cluster_lamports: 200_000_000,
validator_configs: vec![ValidatorConfig::default(); NUM_NODES],
..ClusterConfig::default()
});
let drone_keypair = Keypair::new();
cluster.transfer(&cluster.funding_keypair, &drone_keypair.pubkey(), 1_000_000);
cluster.transfer(
&cluster.funding_keypair,
&drone_keypair.pubkey(),
100_000_000,
);
let client = create_client(
(cluster.entry_point_info.rpc, cluster.entry_point_info.tpu),
FULLNODE_PORT_RANGE,
);
let (libra_mint_id, libra_pay_program_id) = if USE_MOVE {
let libra_mint_id = upload_mint_program(&drone_keypair, &client);
let libra_pay_program_id = upload_payment_program(&drone_keypair, &client);
(libra_mint_id, libra_pay_program_id)
} else {
(Pubkey::default(), Pubkey::default())
};
let (addr_sender, addr_receiver) = channel();
run_local_drone(drone_keypair, addr_sender, None);
@ -695,24 +880,32 @@ mod tests {
let mut config = Config::default();
config.tx_count = 100;
config.duration = Duration::from_secs(5);
let client = create_client(
(cluster.entry_point_info.rpc, cluster.entry_point_info.tpu),
FULLNODE_PORT_RANGE,
);
config.duration = Duration::from_secs(10);
let lamports_per_account = 100;
let (keypairs, _keypair_balance) = generate_and_fund_keypairs(
&client,
Some(drone_addr),
&config.id,
config.tx_count,
lamports_per_account,
Some((
&libra_pay_program_id,
&libra_mint_id,
&cluster.libra_mint_keypair,
)),
)
.unwrap();
let total = do_bench_tps(vec![client], config, keypairs, 0);
let total = do_bench_tps(
vec![client],
config,
keypairs,
0,
&libra_pay_program_id,
&cluster.libra_mint_keypair.pubkey(),
);
assert!(total > 100);
}
@ -728,9 +921,17 @@ mod tests {
config.duration = Duration::from_secs(5);
let (keypairs, _keypair_balance) =
generate_and_fund_keypairs(&clients[0], None, &config.id, config.tx_count, 20).unwrap();
generate_and_fund_keypairs(&clients[0], None, &config.id, config.tx_count, 20, None)
.unwrap();
do_bench_tps(clients, config, keypairs, 0);
do_bench_tps(
clients,
config,
keypairs,
0,
&Pubkey::default(),
&Pubkey::default(),
);
}
#[test]
@ -742,7 +943,7 @@ mod tests {
let lamports = 20;
let (keypairs, _keypair_balance) =
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports).unwrap();
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, None).unwrap();
for kp in &keypairs {
assert_eq!(client.get_balance(&kp.pubkey()).unwrap(), lamports);
@ -760,7 +961,7 @@ mod tests {
let lamports = 20;
let (keypairs, _keypair_balance) =
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports).unwrap();
generate_and_fund_keypairs(&client, None, &id, tx_count, lamports, None).unwrap();
let max_fee = client
.get_recent_blockhash()

View File

@ -6,6 +6,7 @@ use crate::bench::{
};
use solana::gossip_service::{discover_cluster, get_multi_client};
use solana_sdk::fee_calculator::FeeCalculator;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use std::collections::HashMap;
use std::fs::File;
@ -103,6 +104,7 @@ fn main() {
&id,
tx_count,
NUM_LAMPORTS_PER_ACCOUNT,
None,
)
.unwrap_or_else(|e| {
eprintln!("Error could not fund keys: {:?}", e);
@ -119,5 +121,12 @@ fn main() {
sustained,
};
do_bench_tps(vec![client], config, keypairs, keypair_balance);
do_bench_tps(
vec![client],
config,
keypairs,
keypair_balance,
&Pubkey::new_rand(),
&Pubkey::new_rand(),
);
}

View File

@ -69,6 +69,9 @@ solana-storage-program = { path = "../programs/storage_program", version = "0.18
solana-vote-api = { path = "../programs/vote_api", version = "0.18.0-pre0" }
solana-vote-program = { path = "../programs/vote_program", version = "0.18.0-pre0" }
solana-vote-signer = { path = "../vote-signer", version = "0.18.0-pre0" }
solana-move-loader-program = { path = "../programs/move_loader_program", version = "0.18.0-pre0" }
solana-move-loader-api = { path = "../programs/move_loader_api", version = "0.18.0-pre0" }
solana-librapay-api = { path = "../programs/librapay_api", version = "0.18.0-pre0" }
sys-info = "0.5.7"
tokio = "0.1"
tokio-codec = "0.1"

View File

@ -101,3 +101,6 @@ extern crate solana_metrics;
extern crate matches;
extern crate crossbeam_channel;
#[macro_use]
extern crate solana_move_loader_program;

View File

@ -29,6 +29,9 @@ use std::fs::remove_dir_all;
use std::io::{Error, ErrorKind, Result};
use std::sync::Arc;
use solana_librapay_api::librapay_transaction;
use solana_move_loader_api;
pub struct ValidatorInfo {
pub keypair: Arc<Keypair>,
pub voting_keypair: Arc<Keypair>,
@ -115,6 +118,7 @@ pub struct LocalCluster {
pub genesis_block: GenesisBlock,
replicators: Vec<Replicator>,
pub replicator_infos: HashMap<Pubkey, ReplicatorInfo>,
pub libra_mint_keypair: Arc<Keypair>,
}
impl LocalCluster {
@ -161,13 +165,22 @@ impl LocalCluster {
storage_keypair.pubkey(),
storage_contract::create_validator_storage_account(leader_pubkey, 1),
));
let libra_mint_keypair = Keypair::new();
genesis_block.accounts.push((
libra_mint_keypair.pubkey(),
librapay_transaction::create_libra_genesis_account(10_000),
));
genesis_block
.native_instruction_processors
.push(solana_storage_program!());
genesis_block
.native_instruction_processors
.push(solana_move_loader_program!());
let (leader_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_block);
let leader_contact_info = leader_node.info.clone();
let leader_storage_keypair = Arc::new(storage_keypair);
let libra_mint_keypair = Arc::new(libra_mint_keypair);
let leader_voting_keypair = Arc::new(voting_keypair);
let leader_server = Validator::new(
leader_node,
@ -206,6 +219,7 @@ impl LocalCluster {
fullnode_infos,
replicator_infos: HashMap::new(),
listener_infos: HashMap::new(),
libra_mint_keypair,
};
for (stake, validator_config) in (&config.node_stakes[1..])