2021-02-16 13:48:20 -08:00
#![ allow(clippy::integer_arithmetic) ]
2022-08-05 01:51:15 -07:00
2021-12-03 09:00:31 -08:00
use {
2022-05-01 00:14:47 -07:00
clap ::value_t ,
2021-12-03 09:00:31 -08:00
log ::* ,
solana_bench_tps ::{
2022-09-23 13:00:31 -07:00
bench ::{ do_bench_tps , max_lamports_for_prioritization } ,
2022-08-05 01:51:15 -07:00
bench_tps_client ::BenchTpsClient ,
2022-04-12 08:43:29 -07:00
cli ::{ self , ExternalClientType } ,
keypairs ::get_keypairs ,
2022-08-13 04:01:25 -07:00
send_batch ::{ generate_durable_nonce_accounts , generate_keypairs } ,
2022-04-12 08:43:29 -07:00
} ,
2021-12-03 09:00:31 -08:00
solana_genesis ::Base64Account ,
solana_gossip ::gossip_service ::{ discover_cluster , get_client , get_multi_client } ,
2022-08-24 09:47:02 -07:00
solana_rpc_client ::rpc_client ::RpcClient ,
2021-12-03 09:00:31 -08:00
solana_sdk ::{
2022-08-05 01:51:15 -07:00
commitment_config ::CommitmentConfig , fee_calculator ::FeeRateGovernor , pubkey ::Pubkey ,
system_program ,
2021-12-03 09:00:31 -08:00
} ,
solana_streamer ::socket ::SocketAddrSpace ,
2022-08-24 09:47:02 -07:00
solana_thin_client ::thin_client ::ThinClient ,
solana_tpu_client ::{
connection_cache ::ConnectionCache ,
tpu_client ::{ TpuClient , TpuClientConfig } ,
} ,
2022-08-05 01:51:15 -07:00
std ::{
collections ::HashMap , fs ::File , io ::prelude ::* , net ::SocketAddr , path ::Path , process ::exit ,
sync ::Arc ,
} ,
2021-12-03 09:00:31 -08:00
} ;
2018-03-04 00:21:40 -08:00
2019-06-18 14:44:53 -07:00
/// Number of signatures for all transactions in ~1 week at ~100K TPS
pub const NUM_SIGNATURES_FOR_TXS : u64 = 100_000 * 60 * 60 * 24 * 7 ;
2022-08-05 01:51:15 -07:00
#[ allow(clippy::too_many_arguments) ]
fn create_client (
external_client_type : & ExternalClientType ,
entrypoint_addr : & SocketAddr ,
json_rpc_url : & str ,
websocket_url : & str ,
multi_client : bool ,
use_quic : bool ,
tpu_connection_pool_size : usize ,
rpc_tpu_sockets : Option < ( SocketAddr , SocketAddr ) > ,
num_nodes : usize ,
target_node : Option < Pubkey > ,
) -> Arc < dyn BenchTpsClient + Send + Sync > {
match external_client_type {
ExternalClientType ::RpcClient = > Arc ::new ( RpcClient ::new_with_commitment (
json_rpc_url . to_string ( ) ,
CommitmentConfig ::confirmed ( ) ,
) ) ,
ExternalClientType ::ThinClient = > {
let connection_cache = match use_quic {
true = > Arc ::new ( ConnectionCache ::new ( tpu_connection_pool_size ) ) ,
false = > Arc ::new ( ConnectionCache ::with_udp ( tpu_connection_pool_size ) ) ,
} ;
if let Some ( ( rpc , tpu ) ) = rpc_tpu_sockets {
Arc ::new ( ThinClient ::new ( rpc , tpu , connection_cache ) )
} else {
let nodes =
discover_cluster ( entrypoint_addr , num_nodes , SocketAddrSpace ::Unspecified )
. unwrap_or_else ( | err | {
eprintln! ( " Failed to discover {} nodes: {:?} " , num_nodes , err ) ;
exit ( 1 ) ;
} ) ;
if multi_client {
let ( client , num_clients ) =
get_multi_client ( & nodes , & SocketAddrSpace ::Unspecified , connection_cache ) ;
if nodes . len ( ) < num_clients {
eprintln! (
" Error: Insufficient nodes discovered. Expecting {} or more " ,
num_nodes
) ;
exit ( 1 ) ;
}
Arc ::new ( client )
} else if let Some ( target_node ) = target_node {
info! ( " Searching for target_node: {:?} " , target_node ) ;
let mut target_client = None ;
for node in nodes {
if node . id = = target_node {
target_client = Some ( get_client (
& [ node ] ,
& SocketAddrSpace ::Unspecified ,
connection_cache ,
) ) ;
break ;
}
}
Arc ::new ( target_client . unwrap_or_else ( | | {
eprintln! ( " Target node {} not found " , target_node ) ;
exit ( 1 ) ;
} ) )
} else {
Arc ::new ( get_client (
& nodes ,
& SocketAddrSpace ::Unspecified ,
connection_cache ,
) )
}
}
}
ExternalClientType ::TpuClient = > {
let rpc_client = Arc ::new ( RpcClient ::new_with_commitment (
json_rpc_url . to_string ( ) ,
CommitmentConfig ::confirmed ( ) ,
) ) ;
let connection_cache = match use_quic {
true = > ConnectionCache ::new ( tpu_connection_pool_size ) ,
false = > ConnectionCache ::with_udp ( tpu_connection_pool_size ) ,
} ;
Arc ::new (
TpuClient ::new_with_connection_cache (
rpc_client ,
websocket_url ,
TpuClientConfig ::default ( ) ,
Arc ::new ( connection_cache ) ,
)
. unwrap_or_else ( | err | {
eprintln! ( " Could not create TpuClient {:?} " , err ) ;
exit ( 1 ) ;
} ) ,
)
}
}
}
2018-02-28 09:07:54 -08:00
fn main ( ) {
2020-01-08 09:19:12 -08:00
solana_logger ::setup_with_default ( " solana=info " ) ;
2022-02-11 10:04:10 -08:00
solana_metrics ::set_panic_hook ( " bench-tps " , /* version: */ None ) ;
2018-03-03 20:15:42 -08:00
2020-05-11 15:02:01 -07:00
let matches = cli ::build_args ( solana_version ::version! ( ) ) . get_matches ( ) ;
2019-04-19 14:04:36 -07:00
let cli_config = cli ::extract_args ( & matches ) ;
2018-12-12 11:27:21 -08:00
2019-04-19 14:04:36 -07:00
let cli ::Config {
2019-05-03 15:00:19 -07:00
entrypoint_addr ,
2022-04-12 08:43:29 -07:00
json_rpc_url ,
websocket_url ,
2019-04-19 14:04:36 -07:00
id ,
num_nodes ,
tx_count ,
2019-12-18 20:50:17 -08:00
keypair_multiplier ,
2019-06-11 18:47:35 -07:00
client_ids_and_stake_file ,
write_to_client_file ,
read_from_client_file ,
2019-06-18 14:44:53 -07:00
target_lamports_per_signature ,
2019-10-30 14:43:30 -07:00
multi_client ,
2019-09-10 16:24:43 -07:00
num_lamports_per_account ,
2020-07-01 21:10:12 -07:00
target_node ,
2022-04-12 08:43:29 -07:00
external_client_type ,
2022-04-13 11:17:10 -07:00
use_quic ,
2022-06-10 09:25:24 -07:00
tpu_connection_pool_size ,
2022-08-11 18:59:17 -07:00
use_randomized_compute_unit_price ,
2022-08-13 04:01:25 -07:00
use_durable_nonce ,
2022-09-22 12:37:40 -07:00
instruction_padding_config ,
2019-09-10 16:24:43 -07:00
..
} = & cli_config ;
2018-12-12 11:27:21 -08:00
2019-12-18 20:50:17 -08:00
let keypair_count = * tx_count * keypair_multiplier ;
2019-09-10 16:24:43 -07:00
if * write_to_client_file {
2019-12-18 20:50:17 -08:00
info! ( " Generating {} keypairs " , keypair_count ) ;
2021-06-18 06:34:46 -07:00
let ( keypairs , _ ) = generate_keypairs ( id , keypair_count as u64 ) ;
2019-06-18 14:44:53 -07:00
let num_accounts = keypairs . len ( ) as u64 ;
2022-08-11 18:59:17 -07:00
let max_fee = FeeRateGovernor ::new ( * target_lamports_per_signature , 0 )
. max_lamports_per_signature
2022-09-23 13:00:31 -07:00
. saturating_add ( max_lamports_for_prioritization (
2022-08-11 18:59:17 -07:00
* use_randomized_compute_unit_price ,
) ) ;
2019-06-18 14:44:53 -07:00
let num_lamports_per_account = ( num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee )
/ num_accounts
2019-09-10 16:24:43 -07:00
+ num_lamports_per_account ;
2019-06-11 18:47:35 -07:00
let mut accounts = HashMap ::new ( ) ;
keypairs . iter ( ) . for_each ( | keypair | {
accounts . insert (
serde_json ::to_string ( & keypair . to_bytes ( ) . to_vec ( ) ) . unwrap ( ) ,
2019-10-15 12:52:44 -07:00
Base64Account {
2019-09-09 16:17:10 -07:00
balance : num_lamports_per_account ,
executable : false ,
owner : system_program ::id ( ) . to_string ( ) ,
data : String ::new ( ) ,
} ,
2019-06-11 18:47:35 -07:00
) ;
} ) ;
2019-10-04 01:16:07 -07:00
info! ( " Writing {} " , client_ids_and_stake_file ) ;
2019-06-11 18:47:35 -07:00
let serialized = serde_yaml ::to_string ( & accounts ) . unwrap ( ) ;
let path = Path ::new ( & client_ids_and_stake_file ) ;
let mut file = File ::create ( path ) . unwrap ( ) ;
file . write_all ( & serialized . into_bytes ( ) ) . unwrap ( ) ;
return ;
}
2019-10-04 01:16:07 -07:00
info! ( " Connecting to the cluster " ) ;
2022-08-05 01:51:15 -07:00
let rpc_tpu_sockets : Option < ( SocketAddr , SocketAddr ) > =
if let Ok ( rpc_addr ) = value_t! ( matches , " rpc_addr " , String ) {
let rpc = rpc_addr . parse ( ) . unwrap_or_else ( | e | {
eprintln! ( " RPC address should parse as socketaddr {:?} " , e ) ;
exit ( 1 ) ;
} ) ;
let tpu = value_t! ( matches , " tpu_addr " , String )
. unwrap ( )
. parse ( )
. unwrap_or_else ( | e | {
eprintln! ( " TPU address should parse to a socket: {:?} " , e ) ;
2022-04-12 08:43:29 -07:00
exit ( 1 ) ;
} ) ;
2022-08-05 01:51:15 -07:00
Some ( ( rpc , tpu ) )
} else {
None
} ;
2022-05-01 00:14:47 -07:00
2022-08-05 01:51:15 -07:00
let client = create_client (
external_client_type ,
entrypoint_addr ,
json_rpc_url ,
websocket_url ,
* multi_client ,
* use_quic ,
* tpu_connection_pool_size ,
rpc_tpu_sockets ,
* num_nodes ,
* target_node ,
) ;
2022-09-22 12:37:40 -07:00
if let Some ( instruction_padding_config ) = instruction_padding_config {
info! (
" Checking for existence of instruction padding program: {} " ,
instruction_padding_config . program_id
) ;
client
. get_account ( & instruction_padding_config . program_id )
. expect ( " Instruction padding program must be deployed to this cluster. Deploy the program using `solana program deploy ./bench-tps/tests/fixtures/spl_instruction_padding.so` and pass the resulting program id with `--instruction-padding-program-id` " ) ;
}
2022-08-05 01:51:15 -07:00
let keypairs = get_keypairs (
client . clone ( ) ,
id ,
keypair_count ,
* num_lamports_per_account ,
client_ids_and_stake_file ,
* read_from_client_file ,
) ;
2022-08-13 04:01:25 -07:00
let nonce_keypairs = if * use_durable_nonce {
Some ( generate_durable_nonce_accounts ( client . clone ( ) , & keypairs ) )
} else {
None
} ;
do_bench_tps ( client , cli_config , keypairs , nonce_keypairs ) ;
2018-09-06 14:20:01 -07:00
}