2021-02-16 13:48:20 -08:00
#![ allow(clippy::integer_arithmetic) ]
2021-12-03 09:00:31 -08:00
#[ cfg(not(target_env = " msvc " )) ]
use jemallocator ::Jemalloc ;
2021-03-04 13:01:11 -08:00
use {
2022-11-18 21:39:20 -08:00
clap ::{ crate_name , value_t , value_t_or_exit , values_t , values_t_or_exit , ArgMatches } ,
2021-03-04 13:01:11 -08:00
console ::style ,
log ::* ,
2021-10-03 11:13:16 -07:00
rand ::{ seq ::SliceRandom , thread_rng } ,
2022-11-18 21:39:20 -08:00
solana_clap_utils ::input_parsers ::{ keypair_of , keypairs_of , pubkey_of , value_of } ,
2021-03-04 13:01:11 -08:00
solana_core ::{
2021-05-26 08:15:46 -07:00
ledger_cleanup_service ::{ DEFAULT_MAX_LEDGER_SHREDS , DEFAULT_MIN_MAX_LEDGER_SHREDS } ,
2022-01-20 12:38:42 -08:00
system_monitor_service ::SystemMonitorService ,
2021-08-10 13:09:52 -07:00
tower_storage ,
2021-03-04 13:01:11 -08:00
tpu ::DEFAULT_TPU_COALESCE_MS ,
2021-09-07 07:31:54 -07:00
validator ::{ is_snapshot_config_valid , Validator , ValidatorConfig , ValidatorStartProgress } ,
2021-03-04 13:01:11 -08:00
} ,
2023-01-08 08:00:55 -08:00
solana_gossip ::{ cluster_info ::Node , legacy_contact_info ::LegacyContactInfo as ContactInfo } ,
2022-06-07 00:24:58 -07:00
solana_ledger ::blockstore_options ::{
2022-06-07 16:58:58 -07:00
BlockstoreCompressionType , BlockstoreRecoveryMode , LedgerColumnOptions , ShredStorageType ,
2022-03-03 12:43:58 -08:00
} ,
2021-03-04 13:01:11 -08:00
solana_perf ::recycler ::enable_recycler_warming ,
2021-06-04 08:23:06 -07:00
solana_poh ::poh_service ,
2022-03-18 11:36:52 -07:00
solana_rpc ::{
2022-11-18 21:39:20 -08:00
rpc ::{ JsonRpcConfig , RpcBigtableConfig } ,
2022-03-18 11:36:52 -07:00
rpc_pubsub_service ::PubSubConfig ,
} ,
2022-08-24 09:47:02 -07:00
solana_rpc_client ::rpc_client ::RpcClient ,
2022-11-18 21:39:20 -08:00
solana_rpc_client_api ::config ::RpcLeaderScheduleConfig ,
2021-03-04 13:01:11 -08:00
solana_runtime ::{
2023-01-12 07:43:50 -08:00
accounts_db ::{ AccountShrinkThreshold , AccountsDb , AccountsDbConfig , FillerAccountsConfig } ,
2021-05-11 15:06:22 -07:00
accounts_index ::{
AccountIndex , AccountSecondaryIndexes , AccountSecondaryIndexesIncludeExclude ,
2022-04-12 07:38:09 -07:00
AccountsIndexConfig , IndexLimitMb ,
2021-05-11 15:06:22 -07:00
} ,
2022-04-11 17:28:10 -07:00
runtime_config ::RuntimeConfig ,
2022-09-02 05:56:23 -07:00
snapshot_config ::{ SnapshotConfig , SnapshotUsage } ,
2022-11-18 21:39:20 -08:00
snapshot_utils ::{ self , ArchiveFormat , SnapshotVersion } ,
2021-03-04 13:01:11 -08:00
} ,
solana_sdk ::{
clock ::{ Slot , DEFAULT_S_PER_SLOT } ,
commitment_config ::CommitmentConfig ,
hash ::Hash ,
pubkey ::Pubkey ,
2022-06-24 09:21:03 -07:00
signature ::{ read_keypair , Keypair , Signer } ,
2021-03-04 13:01:11 -08:00
} ,
2022-11-18 21:39:20 -08:00
solana_send_transaction_service ::send_transaction_service ::{ self } ,
2021-07-23 08:25:03 -07:00
solana_streamer ::socket ::SocketAddrSpace ,
2022-11-18 21:39:20 -08:00
solana_tpu_client ::tpu_connection_cache ::DEFAULT_TPU_ENABLE_UDP ,
2021-03-04 13:01:11 -08:00
solana_validator ::{
2022-08-11 14:34:04 -07:00
admin_rpc_service ,
admin_rpc_service ::{ load_staked_nodes_overrides , StakedNodesOverrides } ,
bootstrap ,
2022-11-18 21:39:20 -08:00
cli ::{ app , warn_for_deprecated_arguments , DefaultArgs } ,
2022-08-11 14:34:04 -07:00
dashboard ::Dashboard ,
ledger_lockfile , lock_ledger , new_spinner_progress_bar , println_name_value ,
redirect_stderr_to_file ,
2021-03-04 13:01:11 -08:00
} ,
std ::{
collections ::{ HashSet , VecDeque } ,
env ,
fs ::{ self , File } ,
2021-10-03 11:13:16 -07:00
net ::{ IpAddr , SocketAddr } ,
2021-03-04 13:01:11 -08:00
path ::{ Path , PathBuf } ,
process ::exit ,
str ::FromStr ,
2021-10-03 11:13:16 -07:00
sync ::{ Arc , RwLock } ,
time ::{ Duration , SystemTime } ,
2019-11-18 20:43:14 -08:00
} ,
} ;
2019-11-04 07:11:40 -08:00
2021-09-24 07:26:25 -07:00
#[ cfg(not(target_env = " msvc " )) ]
#[ global_allocator ]
static GLOBAL : Jemalloc = Jemalloc ;
2022-05-22 18:00:42 -07:00
#[ derive(Debug, PartialEq, Eq) ]
2021-01-29 18:01:27 -08:00
enum Operation {
Initialize ,
Run ,
2021-02-19 11:31:16 -08:00
}
2022-04-21 12:43:08 -07:00
const MILLIS_PER_SECOND : u64 = 1000 ;
2021-05-11 15:06:22 -07:00
2021-03-10 15:28:42 -08:00
fn monitor_validator ( ledger_path : & Path ) {
let dashboard = Dashboard ::new ( ledger_path , None , None ) . unwrap_or_else ( | err | {
println! (
" Error: Unable to connect to validator at {}: {:?} " ,
ledger_path . display ( ) ,
err ,
) ;
exit ( 1 ) ;
} ) ;
dashboard . run ( Duration ::from_secs ( 2 ) ) ;
}
2021-02-19 11:31:16 -08:00
fn wait_for_restart_window (
ledger_path : & Path ,
2021-07-14 18:24:43 -07:00
identity : Option < Pubkey > ,
2021-02-19 11:31:16 -08:00
min_idle_time_in_minutes : usize ,
2021-10-01 12:52:28 -07:00
max_delinquency_percentage : u8 ,
2022-02-15 13:42:23 -08:00
skip_new_snapshot_check : bool ,
2021-02-19 11:31:16 -08:00
) -> Result < ( ) , Box < dyn std ::error ::Error > > {
2021-02-26 12:09:55 -08:00
let sleep_interval = Duration ::from_secs ( 5 ) ;
2021-02-19 11:31:16 -08:00
let min_idle_slots = ( min_idle_time_in_minutes as f64 * 60. / DEFAULT_S_PER_SLOT ) as Slot ;
2021-06-18 06:34:46 -07:00
let admin_client = admin_rpc_service ::connect ( ledger_path ) ;
2021-02-26 21:42:09 -08:00
let rpc_addr = admin_rpc_service ::runtime ( )
. block_on ( async move { admin_client . await ? . rpc_addr ( ) . await } )
2022-12-06 06:30:06 -08:00
. map_err ( | err | format! ( " Unable to get validator RPC address: {err} " ) ) ? ;
2021-02-19 11:31:16 -08:00
let rpc_client = match rpc_addr {
None = > return Err ( " RPC not available " . into ( ) ) ,
Some ( rpc_addr ) = > RpcClient ::new_socket ( rpc_addr ) ,
} ;
2021-07-14 18:24:43 -07:00
let my_identity = rpc_client . get_identity ( ) ? ;
let identity = identity . unwrap_or ( my_identity ) ;
let monitoring_another_validator = identity ! = my_identity ;
2021-02-19 11:31:16 -08:00
println_name_value ( " Identity: " , & identity . to_string ( ) ) ;
println_name_value (
" Minimum Idle Time: " ,
2022-12-06 06:30:06 -08:00
& format! ( " {min_idle_slots} slots (~ {min_idle_time_in_minutes} minutes) " ) ,
2021-02-19 11:31:16 -08:00
) ;
2022-12-06 06:30:06 -08:00
println! ( " Maximum permitted delinquency: {max_delinquency_percentage} % " ) ;
2021-10-01 12:52:28 -07:00
2021-02-19 11:31:16 -08:00
let mut current_epoch = None ;
let mut leader_schedule = VecDeque ::new ( ) ;
let mut restart_snapshot = None ;
2021-04-02 18:19:15 -07:00
let mut upcoming_idle_windows = vec! [ ] ; // Vec<(starting slot, idle window length in slots)>
2021-02-19 11:31:16 -08:00
let progress_bar = new_spinner_progress_bar ( ) ;
let monitor_start_time = SystemTime ::now ( ) ;
2022-08-30 08:13:08 -07:00
let mut seen_incremential_snapshot = false ;
2021-02-19 11:31:16 -08:00
loop {
2021-09-02 13:25:42 -07:00
let snapshot_slot_info = rpc_client . get_highest_snapshot_slot ( ) . ok ( ) ;
2022-08-30 08:13:08 -07:00
let snapshot_slot_info_has_incremential = snapshot_slot_info
. as_ref ( )
. map ( | snapshot_slot_info | snapshot_slot_info . incremental . is_some ( ) )
. unwrap_or_default ( ) ;
seen_incremential_snapshot | = snapshot_slot_info_has_incremential ;
2021-02-19 11:31:16 -08:00
let epoch_info = rpc_client . get_epoch_info_with_commitment ( CommitmentConfig ::processed ( ) ) ? ;
let healthy = rpc_client . get_health ( ) . ok ( ) . is_some ( ) ;
2021-02-26 12:09:55 -08:00
let delinquent_stake_percentage = {
let vote_accounts = rpc_client . get_vote_accounts ( ) ? ;
let current_stake : u64 = vote_accounts
. current
. iter ( )
. map ( | va | va . activated_stake )
. sum ( ) ;
let delinquent_stake : u64 = vote_accounts
. delinquent
. iter ( )
. map ( | va | va . activated_stake )
. sum ( ) ;
let total_stake = current_stake + delinquent_stake ;
delinquent_stake as f64 / total_stake as f64
} ;
2021-02-19 11:31:16 -08:00
if match current_epoch {
None = > true ,
Some ( current_epoch ) = > current_epoch ! = epoch_info . epoch ,
} {
2021-06-01 10:38:02 -07:00
progress_bar . set_message ( format! (
2021-02-19 11:31:16 -08:00
" Fetching leader schedule for epoch {}... " ,
epoch_info . epoch
) ) ;
let first_slot_in_epoch = epoch_info . absolute_slot - epoch_info . slot_index ;
leader_schedule = rpc_client
2021-04-21 14:13:41 -07:00
. get_leader_schedule_with_config (
Some ( first_slot_in_epoch ) ,
RpcLeaderScheduleConfig {
identity : Some ( identity . to_string ( ) ) ,
.. RpcLeaderScheduleConfig ::default ( )
} ,
) ?
2021-02-19 11:31:16 -08:00
. ok_or_else ( | | {
2022-12-06 06:30:06 -08:00
format! ( " Unable to get leader schedule from slot {first_slot_in_epoch} " )
2021-02-19 11:31:16 -08:00
} ) ?
. get ( & identity . to_string ( ) )
. cloned ( )
. unwrap_or_default ( )
. into_iter ( )
. map ( | slot_index | first_slot_in_epoch . saturating_add ( slot_index as u64 ) )
2021-04-02 18:19:15 -07:00
. filter ( | slot | * slot > epoch_info . absolute_slot )
2021-02-19 11:31:16 -08:00
. collect ::< VecDeque < _ > > ( ) ;
2021-04-02 18:19:15 -07:00
upcoming_idle_windows . clear ( ) ;
{
let mut leader_schedule = leader_schedule . clone ( ) ;
let mut max_idle_window = 0 ;
let mut idle_window_start_slot = epoch_info . absolute_slot ;
while let Some ( next_leader_slot ) = leader_schedule . pop_front ( ) {
let idle_window = next_leader_slot - idle_window_start_slot ;
max_idle_window = max_idle_window . max ( idle_window ) ;
if idle_window > min_idle_slots {
upcoming_idle_windows . push ( ( idle_window_start_slot , idle_window ) ) ;
}
idle_window_start_slot = next_leader_slot ;
}
2021-04-04 08:09:19 -07:00
if ! leader_schedule . is_empty ( ) & & upcoming_idle_windows . is_empty ( ) {
2021-04-02 18:19:15 -07:00
return Err ( format! (
" Validator has no idle window of at least {} slots. Largest idle window for epoch {} is {} slots " ,
min_idle_slots , epoch_info . epoch , max_idle_window
)
. into ( ) ) ;
}
}
2021-02-19 11:31:16 -08:00
current_epoch = Some ( epoch_info . epoch ) ;
}
let status = {
if ! healthy {
style ( " Node is unhealthy " ) . red ( ) . to_string ( )
} else {
// Wait until a hole in the leader schedule before restarting the node
2022-11-09 11:39:38 -08:00
let in_leader_schedule_hole = if epoch_info . slot_index + min_idle_slots
2021-04-02 18:19:15 -07:00
> epoch_info . slots_in_epoch
{
Err ( " Current epoch is almost complete " . to_string ( ) )
} else {
while leader_schedule
. get ( 0 )
. map ( | slot | * slot < epoch_info . absolute_slot )
. unwrap_or ( false )
{
leader_schedule . pop_front ( ) ;
}
while upcoming_idle_windows
2022-06-21 13:26:51 -07:00
. first ( )
2021-04-02 18:19:15 -07:00
. map ( | ( slot , _ ) | * slot < epoch_info . absolute_slot )
. unwrap_or ( false )
{
upcoming_idle_windows . pop ( ) ;
}
match leader_schedule . get ( 0 ) {
None = > {
Ok ( ( ) ) // Validator has no leader slots
2021-02-19 11:31:16 -08:00
}
2021-04-02 18:19:15 -07:00
Some ( next_leader_slot ) = > {
let idle_slots =
next_leader_slot . saturating_sub ( epoch_info . absolute_slot ) ;
if idle_slots > = min_idle_slots {
Ok ( ( ) )
} else {
2022-06-21 13:26:51 -07:00
Err ( match upcoming_idle_windows . first ( ) {
2021-04-02 18:19:15 -07:00
Some ( ( starting_slot , length_in_slots ) ) = > {
format! (
" Next idle window in {} slots, for {} slots " ,
starting_slot . saturating_sub ( epoch_info . absolute_slot ) ,
length_in_slots
)
}
None = > format! (
2022-12-06 06:30:06 -08:00
" Validator will be leader soon. Next leader slot is {next_leader_slot} "
2021-04-02 18:19:15 -07:00
) ,
} )
2021-02-19 11:31:16 -08:00
}
}
2021-04-02 18:19:15 -07:00
}
} ;
2021-02-19 11:31:16 -08:00
match in_leader_schedule_hole {
Ok ( _ ) = > {
2022-02-15 13:42:23 -08:00
if skip_new_snapshot_check {
break ; // Restart!
}
2022-08-30 08:13:08 -07:00
let snapshot_slot = snapshot_slot_info . map ( | snapshot_slot_info | {
snapshot_slot_info
. incremental
. unwrap_or ( snapshot_slot_info . full )
} ) ;
2022-09-07 08:45:52 -07:00
if restart_snapshot . is_none ( ) {
2021-09-03 09:42:22 -07:00
restart_snapshot = snapshot_slot ;
2021-02-19 11:31:16 -08:00
}
2021-09-03 09:42:22 -07:00
if restart_snapshot = = snapshot_slot & & ! monitoring_another_validator {
2021-02-19 11:31:16 -08:00
" Waiting for a new snapshot " . to_string ( )
2021-10-01 12:52:28 -07:00
} else if delinquent_stake_percentage
> = ( max_delinquency_percentage as f64 / 100. )
{
2021-02-26 12:09:55 -08:00
style ( " Delinquency too high " ) . red ( ) . to_string ( )
2022-08-30 08:13:08 -07:00
} else if seen_incremential_snapshot & & ! snapshot_slot_info_has_incremential
{
// Restarts using just a full snapshot will put the node significantly
// further behind than if an incremental snapshot is also used, as full
// snapshots are larger and take much longer to create.
//
// Therefore if the node just created a new full snapshot, wait a
// little longer until it creates the first incremental snapshot for
// the full snapshot.
" Waiting for incremental snapshot " . to_string ( )
2021-02-19 11:31:16 -08:00
} else {
break ; // Restart!
}
}
2021-03-10 15:28:42 -08:00
Err ( why ) = > style ( why ) . yellow ( ) . to_string ( ) ,
2021-02-19 11:31:16 -08:00
}
}
} ;
2021-06-01 10:38:02 -07:00
progress_bar . set_message ( format! (
2021-07-14 18:24:43 -07:00
" {} | Processed Slot: {} {} | {:.2}% delinquent stake | {} " ,
2021-02-19 11:31:16 -08:00
{
let elapsed =
chrono ::Duration ::from_std ( monitor_start_time . elapsed ( ) . unwrap ( ) ) . unwrap ( ) ;
format! (
" {:02}:{:02}:{:02} " ,
elapsed . num_hours ( ) ,
elapsed . num_minutes ( ) % 60 ,
elapsed . num_seconds ( ) % 60
)
} ,
epoch_info . absolute_slot ,
2021-07-14 18:24:43 -07:00
if monitoring_another_validator {
" " . to_string ( )
} else {
format! (
2021-09-03 09:42:22 -07:00
" | Full Snapshot Slot: {} | Incremental Snapshot Slot: {} " ,
2021-09-02 13:25:42 -07:00
snapshot_slot_info
2021-09-03 09:42:22 -07:00
. as_ref ( )
2021-09-02 13:25:42 -07:00
. map ( | snapshot_slot_info | snapshot_slot_info . full . to_string ( ) )
. unwrap_or_else ( | | '-' . to_string ( ) ) ,
2021-09-03 09:42:22 -07:00
snapshot_slot_info
. as_ref ( )
2022-01-21 16:01:22 -08:00
. and_then ( | snapshot_slot_info | snapshot_slot_info
2021-09-03 09:42:22 -07:00
. incremental
. map ( | incremental | incremental . to_string ( ) ) )
. unwrap_or_else ( | | '-' . to_string ( ) ) ,
2021-07-14 18:24:43 -07:00
)
} ,
2021-03-13 09:34:43 -08:00
delinquent_stake_percentage * 100. ,
2021-02-19 11:31:16 -08:00
status
) ) ;
2021-02-26 12:09:55 -08:00
std ::thread ::sleep ( sleep_interval ) ;
2021-02-19 11:31:16 -08:00
}
drop ( progress_bar ) ;
println! ( " {} " , style ( " Ready to restart " ) . green ( ) ) ;
Ok ( ( ) )
2021-01-29 18:01:27 -08:00
}
2022-12-15 19:24:23 -08:00
fn set_repair_whitelist (
ledger_path : & Path ,
whitelist : Vec < Pubkey > ,
) -> Result < ( ) , Box < dyn std ::error ::Error > > {
let admin_client = admin_rpc_service ::connect ( ledger_path ) ;
admin_rpc_service ::runtime ( )
. block_on ( async move { admin_client . await ? . set_repair_whitelist ( whitelist ) . await } )
. map_err ( | err | {
std ::io ::Error ::new (
std ::io ::ErrorKind ::Other ,
2022-12-19 14:26:38 -08:00
format! ( " setRepairWhitelist request failed: {err} " ) ,
2022-12-15 19:24:23 -08:00
)
} ) ? ;
Ok ( ( ) )
}
2022-10-04 10:38:40 -07:00
/// Returns the default fifo shred storage size (include both data and coding
2022-09-28 00:32:27 -07:00
/// shreds) based on the validator config.
2022-10-04 10:38:40 -07:00
fn default_fifo_shred_storage_size ( vc : & ValidatorConfig ) -> Option < u64 > {
2022-09-28 00:32:27 -07:00
// The max shred size is around 1228 bytes.
// Here we reserve a little bit more than that to give extra storage for FIFO
// to prevent it from purging data that have not yet being marked as obsoleted
// by LedgerCleanupService.
const RESERVED_BYTES_PER_SHRED : u64 = 1500 ;
2022-10-04 10:38:40 -07:00
vc . max_ledger_shreds . map ( | max_ledger_shreds | {
2022-09-28 00:32:27 -07:00
// x2 as we have data shred and coding shred.
2022-10-04 10:38:40 -07:00
max_ledger_shreds * RESERVED_BYTES_PER_SHRED * 2
} )
2022-09-28 00:32:27 -07:00
}
2020-01-24 17:27:04 -08:00
// This function is duplicated in ledger-tool/src/main.rs...
fn hardforks_of ( matches : & ArgMatches < '_ > , name : & str ) -> Option < Vec < Slot > > {
if matches . is_present ( name ) {
Some ( values_t_or_exit! ( matches , name , Slot ) )
} else {
None
}
}
2020-08-21 00:35:11 -07:00
fn validators_set (
identity_pubkey : & Pubkey ,
matches : & ArgMatches < '_ > ,
matches_name : & str ,
arg_name : & str ,
) -> Option < HashSet < Pubkey > > {
if matches . is_present ( matches_name ) {
let validators_set : HashSet < _ > = values_t_or_exit! ( matches , matches_name , Pubkey )
. into_iter ( )
. collect ( ) ;
if validators_set . contains ( identity_pubkey ) {
2022-12-06 06:30:06 -08:00
eprintln! ( " The validator's identity pubkey cannot be a {arg_name} : {identity_pubkey} " ) ;
2020-08-21 00:35:11 -07:00
exit ( 1 ) ;
}
Some ( validators_set )
} else {
None
}
}
2021-06-20 08:39:20 -07:00
fn get_cluster_shred_version ( entrypoints : & [ SocketAddr ] ) -> Option < u16 > {
let entrypoints = {
let mut index : Vec < _ > = ( 0 .. entrypoints . len ( ) ) . collect ( ) ;
index . shuffle ( & mut rand ::thread_rng ( ) ) ;
index . into_iter ( ) . map ( | i | & entrypoints [ i ] )
} ;
for entrypoint in entrypoints {
match solana_net_utils ::get_cluster_shred_version ( entrypoint ) {
2022-12-06 06:30:06 -08:00
Err ( err ) = > eprintln! ( " get_cluster_shred_version failed: {entrypoint} , {err} " ) ,
Ok ( 0 ) = > eprintln! ( " zero shred-version from entrypoint: {entrypoint} " ) ,
2021-06-20 08:39:20 -07:00
Ok ( shred_version ) = > {
info! (
" obtained shred-version {} from {} " ,
shred_version , entrypoint
) ;
return Some ( shred_version ) ;
}
}
}
None
}
2019-11-04 07:11:40 -08:00
pub fn main ( ) {
2022-11-18 21:39:20 -08:00
let default_args = DefaultArgs ::new ( ) ;
let solana_version = solana_version ::version! ( ) ;
let cli_app = app ( solana_version , & default_args ) ;
let matches = cli_app . get_matches ( ) ;
2022-10-06 12:27:32 -07:00
warn_for_deprecated_arguments ( & matches ) ;
2019-11-04 07:11:40 -08:00
2021-07-23 08:25:03 -07:00
let socket_addr_space = SocketAddrSpace ::new ( matches . is_present ( " allow_private_addr " ) ) ;
2021-03-06 09:29:02 -08:00
let ledger_path = PathBuf ::from ( matches . value_of ( " ledger_path " ) . unwrap ( ) ) ;
2021-02-19 11:31:16 -08:00
let operation = match matches . subcommand ( ) {
( " " , _ ) | ( " run " , _ ) = > Operation ::Run ,
2021-04-11 20:38:30 -07:00
( " authorized-voter " , Some ( authorized_voter_subcommand_matches ) ) = > {
match authorized_voter_subcommand_matches . subcommand ( ) {
( " add " , Some ( subcommand_matches ) ) = > {
2022-06-24 09:21:03 -07:00
if let Some ( authorized_voter_keypair ) =
value_t! ( subcommand_matches , " authorized_voter_keypair " , String ) . ok ( )
{
let authorized_voter_keypair = fs ::canonicalize ( & authorized_voter_keypair )
. unwrap_or_else ( | err | {
println! (
2022-12-06 06:30:06 -08:00
" Unable to access path: {authorized_voter_keypair}: {err:?} "
2022-06-24 09:21:03 -07:00
) ;
exit ( 1 ) ;
} ) ;
println! (
" Adding authorized voter path: {} " ,
authorized_voter_keypair . display ( )
) ;
2021-04-12 16:33:14 -07:00
2022-06-24 09:21:03 -07:00
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
admin_rpc_service ::runtime ( )
. block_on ( async move {
admin_client
. await ?
. add_authorized_voter (
authorized_voter_keypair . display ( ) . to_string ( ) ,
)
. await
} )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " addAuthorizedVoter request failed: {err} " ) ;
2022-06-24 09:21:03 -07:00
exit ( 1 ) ;
} ) ;
} else {
let mut stdin = std ::io ::stdin ( ) ;
let authorized_voter_keypair =
read_keypair ( & mut stdin ) . unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " Unable to read JSON keypair from stdin: {err:?} " ) ;
2022-06-24 09:21:03 -07:00
exit ( 1 ) ;
} ) ;
println! (
" Adding authorized voter: {} " ,
authorized_voter_keypair . pubkey ( )
) ;
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
admin_rpc_service ::runtime ( )
. block_on ( async move {
admin_client
. await ?
. add_authorized_voter_from_bytes ( Vec ::from (
authorized_voter_keypair . to_bytes ( ) ,
) )
. await
} )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " addAuthorizedVoterFromBytes request failed: {err} " ) ;
2022-06-24 09:21:03 -07:00
exit ( 1 ) ;
} ) ;
}
2021-04-11 20:38:30 -07:00
return ;
}
( " remove-all " , _ ) = > {
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
admin_rpc_service ::runtime ( )
. block_on ( async move {
admin_client . await ? . remove_all_authorized_voters ( ) . await
} )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " removeAllAuthorizedVoters request failed: {err} " ) ;
2021-04-11 20:38:30 -07:00
exit ( 1 ) ;
} ) ;
println! ( " All authorized voters removed " ) ;
return ;
}
_ = > unreachable! ( ) ,
}
}
2021-12-22 23:56:16 -08:00
( " contact-info " , Some ( subcommand_matches ) ) = > {
let output_mode = subcommand_matches . value_of ( " output " ) ;
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
let contact_info = admin_rpc_service ::runtime ( )
. block_on ( async move { admin_client . await ? . contact_info ( ) . await } )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
eprintln! ( " Contact info query failed: {err} " ) ;
2021-12-22 23:56:16 -08:00
exit ( 1 ) ;
} ) ;
if let Some ( mode ) = output_mode {
match mode {
" json " = > println! ( " {} " , serde_json ::to_string_pretty ( & contact_info ) . unwrap ( ) ) ,
" json-compact " = > print! ( " {} " , serde_json ::to_string ( & contact_info ) . unwrap ( ) ) ,
_ = > unreachable! ( ) ,
}
} else {
2022-12-06 06:30:06 -08:00
print! ( " {contact_info} " ) ;
2021-12-22 23:56:16 -08:00
}
return ;
}
2021-02-19 11:31:16 -08:00
( " init " , _ ) = > Operation ::Initialize ,
2021-03-10 15:28:42 -08:00
( " exit " , Some ( subcommand_matches ) ) = > {
let min_idle_time = value_t_or_exit! ( subcommand_matches , " min_idle_time " , usize ) ;
let force = subcommand_matches . is_present ( " force " ) ;
let monitor = subcommand_matches . is_present ( " monitor " ) ;
2022-02-15 13:42:23 -08:00
let skip_new_snapshot_check = subcommand_matches . is_present ( " skip_new_snapshot_check " ) ;
2021-10-01 12:52:28 -07:00
let max_delinquent_stake =
value_t_or_exit! ( subcommand_matches , " max_delinquent_stake " , u8 ) ;
2021-03-10 15:28:42 -08:00
if ! force {
2022-02-15 13:42:23 -08:00
wait_for_restart_window (
& ledger_path ,
None ,
min_idle_time ,
max_delinquent_stake ,
skip_new_snapshot_check ,
)
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " {err} " ) ;
2022-02-15 13:42:23 -08:00
exit ( 1 ) ;
} ) ;
2021-03-10 15:28:42 -08:00
}
2021-03-06 09:29:02 -08:00
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
admin_rpc_service ::runtime ( )
. block_on ( async move { admin_client . await ? . exit ( ) . await } )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " exit request failed: {err} " ) ;
2021-03-06 09:29:02 -08:00
exit ( 1 ) ;
} ) ;
2021-03-10 15:28:42 -08:00
println! ( " Exit request sent " ) ;
if monitor {
monitor_validator ( & ledger_path ) ;
}
2021-03-06 09:29:02 -08:00
return ;
}
( " monitor " , _ ) = > {
2021-03-10 15:28:42 -08:00
monitor_validator ( & ledger_path ) ;
2021-03-06 09:29:02 -08:00
return ;
}
2022-08-11 14:34:04 -07:00
( " staked-nodes-overrides " , Some ( subcommand_matches ) ) = > {
if ! subcommand_matches . is_present ( " path " ) {
println! (
" staked-nodes-overrides requires argument of location of the configuration "
) ;
exit ( 1 ) ;
}
let path = subcommand_matches . value_of ( " path " ) . unwrap ( ) ;
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
admin_rpc_service ::runtime ( )
. block_on ( async move {
admin_client
. await ?
. set_staked_nodes_overrides ( path . to_string ( ) )
. await
} )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " setStakedNodesOverrides request failed: {err} " ) ;
2022-08-11 14:34:04 -07:00
exit ( 1 ) ;
} ) ;
return ;
}
2021-06-17 13:51:06 -07:00
( " set-identity " , Some ( subcommand_matches ) ) = > {
2022-02-14 10:27:11 -08:00
let require_tower = subcommand_matches . is_present ( " require_tower " ) ;
2021-06-17 13:51:06 -07:00
2022-06-24 09:21:03 -07:00
if let Some ( identity_keypair ) = value_t! ( subcommand_matches , " identity " , String ) . ok ( ) {
let identity_keypair = fs ::canonicalize ( & identity_keypair ) . unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " Unable to access path: {identity_keypair} : {err:?} " ) ;
2022-06-24 09:21:03 -07:00
exit ( 1 ) ;
} ) ;
println! (
" New validator identity path: {} " ,
identity_keypair . display ( )
) ;
2021-06-17 13:51:06 -07:00
2022-06-24 09:21:03 -07:00
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
admin_rpc_service ::runtime ( )
. block_on ( async move {
admin_client
. await ?
. set_identity ( identity_keypair . display ( ) . to_string ( ) , require_tower )
. await
} )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " setIdentity request failed: {err} " ) ;
2022-06-24 09:21:03 -07:00
exit ( 1 ) ;
} ) ;
} else {
let mut stdin = std ::io ::stdin ( ) ;
let identity_keypair = read_keypair ( & mut stdin ) . unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " Unable to read JSON keypair from stdin: {err:?} " ) ;
2021-06-17 13:51:06 -07:00
exit ( 1 ) ;
} ) ;
2022-06-24 09:21:03 -07:00
println! ( " New validator identity: {} " , identity_keypair . pubkey ( ) ) ;
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
admin_rpc_service ::runtime ( )
. block_on ( async move {
admin_client
. await ?
. set_identity_from_bytes (
Vec ::from ( identity_keypair . to_bytes ( ) ) ,
require_tower ,
)
. await
} )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " setIdentityFromBytes request failed: {err} " ) ;
2022-06-24 09:21:03 -07:00
exit ( 1 ) ;
} ) ;
} ;
2021-06-17 13:51:06 -07:00
return ;
}
2021-03-06 09:29:02 -08:00
( " set-log-filter " , Some ( subcommand_matches ) ) = > {
let filter = value_t_or_exit! ( subcommand_matches , " filter " , String ) ;
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
admin_rpc_service ::runtime ( )
. block_on ( async move { admin_client . await ? . set_log_filter ( filter ) . await } )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " set log filter failed: {err} " ) ;
2021-03-06 09:29:02 -08:00
exit ( 1 ) ;
} ) ;
return ;
}
( " wait-for-restart-window " , Some ( subcommand_matches ) ) = > {
2021-03-10 15:28:42 -08:00
let min_idle_time = value_t_or_exit! ( subcommand_matches , " min_idle_time " , usize ) ;
2021-07-14 18:24:43 -07:00
let identity = pubkey_of ( subcommand_matches , " identity " ) ;
2021-10-01 12:52:28 -07:00
let max_delinquent_stake =
value_t_or_exit! ( subcommand_matches , " max_delinquent_stake " , u8 ) ;
2022-02-15 13:42:23 -08:00
let skip_new_snapshot_check = subcommand_matches . is_present ( " skip_new_snapshot_check " ) ;
2021-10-01 12:52:28 -07:00
2022-02-15 13:42:23 -08:00
wait_for_restart_window (
& ledger_path ,
identity ,
min_idle_time ,
max_delinquent_stake ,
skip_new_snapshot_check ,
)
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
println! ( " {err} " ) ;
2022-02-15 13:42:23 -08:00
exit ( 1 ) ;
} ) ;
2021-03-06 09:29:02 -08:00
return ;
}
2022-12-15 19:24:23 -08:00
( " repair-whitelist " , Some ( repair_whitelist_subcommand_matches ) ) = > {
match repair_whitelist_subcommand_matches . subcommand ( ) {
( " get " , Some ( subcommand_matches ) ) = > {
let output_mode = subcommand_matches . value_of ( " output " ) ;
let admin_client = admin_rpc_service ::connect ( & ledger_path ) ;
let repair_whitelist = admin_rpc_service ::runtime ( )
. block_on ( async move { admin_client . await ? . repair_whitelist ( ) . await } )
. unwrap_or_else ( | err | {
2022-12-19 14:26:38 -08:00
eprintln! ( " Repair whitelist query failed: {err} " ) ;
2022-12-15 19:24:23 -08:00
exit ( 1 ) ;
} ) ;
if let Some ( mode ) = output_mode {
match mode {
" json " = > println! (
" {} " ,
serde_json ::to_string_pretty ( & repair_whitelist ) . unwrap ( )
) ,
" json-compact " = > {
print! ( " {} " , serde_json ::to_string ( & repair_whitelist ) . unwrap ( ) )
}
_ = > unreachable! ( ) ,
}
} else {
2022-12-19 14:26:38 -08:00
print! ( " {repair_whitelist} " ) ;
2022-12-15 19:24:23 -08:00
}
return ;
}
( " set " , Some ( subcommand_matches ) ) = > {
let whitelist = if subcommand_matches . is_present ( " whitelist " ) {
let validators_set : HashSet < _ > =
values_t_or_exit! ( subcommand_matches , " whitelist " , Pubkey )
. into_iter ( )
. collect ( ) ;
validators_set . into_iter ( ) . collect ::< Vec < _ > > ( )
} else {
return ;
} ;
set_repair_whitelist ( & ledger_path , whitelist ) . unwrap_or_else ( | err | {
eprintln! ( " {err} " ) ;
exit ( 1 ) ;
} ) ;
return ;
}
( " remove-all " , _ ) = > {
set_repair_whitelist ( & ledger_path , Vec ::default ( ) ) . unwrap_or_else ( | err | {
eprintln! ( " {err} " ) ;
exit ( 1 ) ;
} ) ;
return ;
}
_ = > unreachable! ( ) ,
}
}
2021-01-29 18:01:27 -08:00
_ = > unreachable! ( ) ,
} ;
2021-06-17 13:51:06 -07:00
let identity_keypair = keypair_of ( & matches , " identity " ) . unwrap_or_else ( | | {
2021-03-06 09:29:02 -08:00
clap ::Error ::with_description (
" The --identity <KEYPAIR> argument is required " ,
clap ::ErrorKind ::ArgumentNotFound ,
)
. exit ( ) ;
2021-06-17 13:51:06 -07:00
} ) ;
2020-03-06 21:22:23 -08:00
2021-07-28 00:54:54 -07:00
let logfile = {
let logfile = matches
. value_of ( " logfile " )
. map ( | s | s . into ( ) )
. unwrap_or_else ( | | format! ( " solana-validator- {} .log " , identity_keypair . pubkey ( ) ) ) ;
if logfile = = " - " {
None
} else {
2022-12-06 06:30:06 -08:00
println! ( " log file: {logfile} " ) ;
2021-07-28 00:54:54 -07:00
Some ( logfile )
}
} ;
let use_progress_bar = logfile . is_none ( ) ;
let _logger_thread = redirect_stderr_to_file ( logfile ) ;
info! ( " {} {} " , crate_name! ( ) , solana_version ::version! ( ) ) ;
info! ( " Starting validator with: {:#?} " , std ::env ::args_os ( ) ) ;
2021-07-28 00:55:27 -07:00
let cuda = matches . is_present ( " cuda " ) ;
if cuda {
solana_perf ::perf_libs ::init_cuda ( ) ;
enable_recycler_warming ( ) ;
}
solana_core ::validator ::report_target_features ( ) ;
2020-03-31 08:23:42 -07:00
let authorized_voter_keypairs = keypairs_of ( & matches , " authorized_voter_keypairs " )
. map ( | keypairs | keypairs . into_iter ( ) . map ( Arc ::new ) . collect ( ) )
2021-06-17 13:51:06 -07:00
. unwrap_or_else ( | | {
vec! [ Arc ::new (
keypair_of ( & matches , " identity " ) . expect ( " identity " ) ,
) ]
} ) ;
2021-04-11 20:38:30 -07:00
let authorized_voter_keypairs = Arc ::new ( RwLock ::new ( authorized_voter_keypairs ) ) ;
2020-03-06 21:22:23 -08:00
2022-08-11 14:34:04 -07:00
let staked_nodes_overrides_path = matches
. value_of ( " staked_nodes_overrides " )
. map ( str ::to_string ) ;
let staked_nodes_overrides = Arc ::new ( RwLock ::new (
match staked_nodes_overrides_path {
None = > StakedNodesOverrides ::default ( ) ,
Some ( p ) = > load_staked_nodes_overrides ( & p ) . unwrap_or_else ( | err | {
error! ( " Failed to load stake-nodes-overrides from {}: {} " , & p , err ) ;
clap ::Error ::with_description (
" Failed to load configuration of stake-nodes-overrides argument " ,
clap ::ErrorKind ::InvalidValue ,
)
. exit ( )
} ) ,
}
. staked_map_id ,
) ) ;
2019-11-06 10:34:31 -08:00
let init_complete_file = matches . value_of ( " init_complete_file " ) ;
2020-09-18 14:35:20 -07:00
2021-10-03 11:13:16 -07:00
let rpc_bootstrap_config = bootstrap ::RpcBootstrapConfig {
2020-09-18 14:35:20 -07:00
no_genesis_fetch : matches . is_present ( " no_genesis_fetch " ) ,
no_snapshot_fetch : matches . is_present ( " no_snapshot_fetch " ) ,
2022-02-14 22:50:17 -08:00
check_vote_account : matches
. value_of ( " check_vote_account " )
. map ( | url | url . to_string ( ) ) ,
2021-11-12 19:13:59 -08:00
only_known_rpc : matches . is_present ( " only_known_rpc " ) ,
2020-09-18 14:35:20 -07:00
max_genesis_archive_unpacked_size : value_t_or_exit ! (
matches ,
" max_genesis_archive_unpacked_size " ,
u64
) ,
2022-02-09 11:26:35 -08:00
incremental_snapshot_fetch : ! matches . is_present ( " no_incremental_snapshots " ) ,
2020-09-18 14:35:20 -07:00
} ;
2020-01-30 09:17:01 -08:00
let private_rpc = matches . is_present ( " private_rpc " ) ;
2021-10-19 14:35:42 -07:00
let do_port_check = ! matches . is_present ( " no_port_check " ) ;
2021-02-26 09:15:45 -08:00
let tpu_coalesce_ms =
value_t! ( matches , " tpu_coalesce_ms " , u64 ) . unwrap_or ( DEFAULT_TPU_COALESCE_MS ) ;
2020-07-06 12:43:45 -07:00
let wal_recovery_mode = matches
. value_of ( " wal_recovery_mode " )
. map ( BlockstoreRecoveryMode ::from ) ;
2019-11-04 07:11:40 -08:00
2019-12-05 11:58:02 -08:00
// Canonicalize ledger path to avoid issues with symlink creation
2020-01-20 07:58:03 -08:00
let _ = fs ::create_dir_all ( & ledger_path ) ;
2019-12-05 11:58:02 -08:00
let ledger_path = fs ::canonicalize ( & ledger_path ) . unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
eprintln! ( " Unable to access ledger path: {err:?} " ) ;
2019-12-05 11:58:02 -08:00
exit ( 1 ) ;
} ) ;
2020-09-23 18:46:42 -07:00
let debug_keys : Option < Arc < HashSet < _ > > > = if matches . is_present ( " debug_key " ) {
Some ( Arc ::new (
values_t_or_exit! ( matches , " debug_key " , Pubkey )
. into_iter ( )
. collect ( ) ,
) )
} else {
None
} ;
2021-11-12 10:57:55 -08:00
let known_validators = validators_set (
2020-08-21 00:35:11 -07:00
& identity_keypair . pubkey ( ) ,
& matches ,
2021-11-12 10:57:55 -08:00
" known_validators " ,
2021-08-17 21:17:46 -07:00
" --known-validator " ,
2020-08-21 00:35:11 -07:00
) ;
let repair_validators = validators_set (
& identity_keypair . pubkey ( ) ,
& matches ,
" repair_validators " ,
" --repair-validator " ,
) ;
2022-12-15 19:24:23 -08:00
let repair_whitelist = validators_set (
& identity_keypair . pubkey ( ) ,
& matches ,
" repair_whitelist " ,
" --repair-whitelist " ,
) ;
let repair_whitelist = Arc ::new ( RwLock ::new ( repair_whitelist . unwrap_or_default ( ) ) ) ;
2020-09-11 12:00:16 -07:00
let gossip_validators = validators_set (
& identity_keypair . pubkey ( ) ,
& matches ,
" gossip_validators " ,
" --gossip-validator " ,
) ;
2020-02-21 18:42:24 -08:00
2020-09-10 08:56:26 -07:00
let bind_address = solana_net_utils ::parse_host ( matches . value_of ( " bind_address " ) . unwrap ( ) )
. expect ( " invalid bind_address " ) ;
let rpc_bind_address = if matches . is_present ( " rpc_bind_address " ) {
solana_net_utils ::parse_host ( matches . value_of ( " rpc_bind_address " ) . unwrap ( ) )
. expect ( " invalid rpc_bind_address " )
2021-10-04 11:40:54 -07:00
} else if private_rpc {
solana_net_utils ::parse_host ( " 127.0.0.1 " ) . unwrap ( )
2020-09-10 08:56:26 -07:00
} else {
bind_address
} ;
2020-11-20 14:47:37 -08:00
let contact_debug_interval = value_t_or_exit! ( matches , " contact_debug_interval " , u64 ) ;
2021-05-11 15:06:22 -07:00
let account_indexes = process_account_indexes ( & matches ) ;
2020-12-31 18:06:03 -08:00
2020-09-10 13:15:22 -07:00
let restricted_repair_only_mode = matches . is_present ( " restricted_repair_only_mode " ) ;
2021-06-09 21:21:32 -07:00
let accounts_shrink_optimize_total_space =
value_t_or_exit! ( matches , " accounts_shrink_optimize_total_space " , bool ) ;
2022-08-19 07:15:15 -07:00
let tpu_use_quic = ! matches . is_present ( " tpu_disable_quic " ) ;
2022-09-07 13:19:14 -07:00
let tpu_enable_udp = if matches . is_present ( " tpu_enable_udp " ) {
true
} else {
DEFAULT_TPU_ENABLE_UDP
} ;
2022-06-10 09:25:24 -07:00
let tpu_connection_pool_size = value_t_or_exit! ( matches , " tpu_connection_pool_size " , usize ) ;
2022-03-21 09:31:37 -07:00
2021-06-09 21:21:32 -07:00
let shrink_ratio = value_t_or_exit! ( matches , " accounts_shrink_ratio " , f64 ) ;
if ! ( 0. 0 ..= 1.0 ) . contains ( & shrink_ratio ) {
eprintln! (
2022-12-06 06:30:06 -08:00
" The specified account-shrink-ratio is invalid, it must be between 0. and 1.0 inclusive: {shrink_ratio} "
2021-06-09 21:21:32 -07:00
) ;
exit ( 1 ) ;
}
let accounts_shrink_ratio = if accounts_shrink_optimize_total_space {
AccountShrinkThreshold ::TotalSpace { shrink_ratio }
} else {
2022-03-05 18:46:46 -08:00
AccountShrinkThreshold ::IndividualStore { shrink_ratio }
2021-06-09 21:21:32 -07:00
} ;
2021-06-20 08:39:20 -07:00
let entrypoint_addrs = values_t! ( matches , " entrypoint " , String )
. unwrap_or_default ( )
. into_iter ( )
. map ( | entrypoint | {
solana_net_utils ::parse_host_port ( & entrypoint ) . unwrap_or_else ( | e | {
2022-12-06 06:30:06 -08:00
eprintln! ( " failed to parse entrypoint address: {e} " ) ;
2021-06-20 08:39:20 -07:00
exit ( 1 ) ;
} )
} )
. collect ::< HashSet < _ > > ( )
. into_iter ( )
. collect ::< Vec < _ > > ( ) ;
2022-03-11 06:15:05 -08:00
for addr in & entrypoint_addrs {
if ! socket_addr_space . check ( addr ) {
2022-12-06 06:30:06 -08:00
eprintln! ( " invalid entrypoint address: {addr} " ) ;
2022-03-11 06:15:05 -08:00
exit ( 1 ) ;
}
}
2021-06-20 08:39:20 -07:00
// TODO: Once entrypoints are updated to return shred-version, this should
// abort if it fails to obtain a shred-version, so that nodes always join
// gossip with a valid shred-version. The code to adopt entrypoint shred
// version can then be deleted from gossip and get_rpc_node above.
let expected_shred_version = value_t! ( matches , " expected_shred_version " , u16 )
. ok ( )
. or_else ( | | get_cluster_shred_version ( & entrypoint_addrs ) ) ;
2021-06-09 21:21:32 -07:00
2021-08-10 13:09:52 -07:00
let tower_storage : Arc < dyn solana_core ::tower_storage ::TowerStorage > =
match value_t_or_exit! ( matches , " tower_storage " , String ) . as_str ( ) {
" file " = > {
let tower_path = value_t! ( matches , " tower " , PathBuf )
. ok ( )
. unwrap_or_else ( | | ledger_path . clone ( ) ) ;
Arc ::new ( tower_storage ::FileTowerStorage ::new ( tower_path ) )
}
" etcd " = > {
let endpoints = values_t_or_exit! ( matches , " etcd_endpoint " , String ) ;
let domain_name = value_t_or_exit! ( matches , " etcd_domain_name " , String ) ;
let ca_certificate_file = value_t_or_exit! ( matches , " etcd_cacert_file " , String ) ;
let identity_certificate_file = value_t_or_exit! ( matches , " etcd_cert_file " , String ) ;
let identity_private_key_file = value_t_or_exit! ( matches , " etcd_key_file " , String ) ;
let read = | file | {
fs ::read ( & file ) . unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
eprintln! ( " Unable to read {file} : {err} " ) ;
2021-08-10 13:09:52 -07:00
exit ( 1 )
} )
} ;
let tls_config = tower_storage ::EtcdTlsConfig {
domain_name ,
ca_certificate : read ( ca_certificate_file ) ,
identity_certificate : read ( identity_certificate_file ) ,
identity_private_key : read ( identity_private_key_file ) ,
} ;
Arc ::new (
tower_storage ::EtcdTowerStorage ::new ( endpoints , Some ( tls_config ) )
. unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
eprintln! ( " Failed to connect to etcd: {err} " ) ;
2021-08-10 13:09:52 -07:00
exit ( 1 ) ;
} ) ,
)
}
_ = > unreachable! ( ) ,
} ;
2021-07-20 22:25:13 -07:00
2022-02-22 07:40:12 -08:00
let mut accounts_index_config = AccountsIndexConfig {
started_from_validator : true , // this is the only place this is set
.. AccountsIndexConfig ::default ( )
} ;
2021-09-17 11:12:06 -07:00
if let Some ( bins ) = value_t! ( matches , " accounts_index_bins " , usize ) . ok ( ) {
accounts_index_config . bins = Some ( bins ) ;
}
2021-09-13 18:39:26 -07:00
2022-04-12 07:38:09 -07:00
accounts_index_config . index_limit_mb =
if let Some ( limit ) = value_t! ( matches , " accounts_index_memory_limit_mb " , usize ) . ok ( ) {
IndexLimitMb ::Limit ( limit )
} else if matches . is_present ( " disable_accounts_disk_index " ) {
IndexLimitMb ::InMemOnly
} else {
IndexLimitMb ::Unspecified
} ;
2021-09-19 16:00:15 -07:00
2021-09-18 07:54:57 -07:00
{
2021-09-28 09:07:47 -07:00
let mut accounts_index_paths : Vec < PathBuf > = if matches . is_present ( " accounts_index_path " ) {
values_t_or_exit! ( matches , " accounts_index_path " , String )
. into_iter ( )
. map ( PathBuf ::from )
. collect ( )
} else {
vec! [ ]
} ;
2021-09-18 07:54:57 -07:00
if accounts_index_paths . is_empty ( ) {
accounts_index_paths = vec! [ ledger_path . join ( " accounts_index " ) ] ;
}
accounts_index_config . drives = Some ( accounts_index_paths ) ;
}
2021-11-19 07:00:19 -08:00
const MB : usize = 1_024 * 1_024 ;
accounts_index_config . scan_results_limit_bytes =
value_t! ( matches , " accounts_index_scan_results_limit_mb " , usize )
. ok ( )
. map ( | mb | mb * MB ) ;
2022-04-11 11:10:09 -07:00
let filler_accounts_config = FillerAccountsConfig {
count : value_t_or_exit ! ( matches , " accounts_filler_count " , usize ) ,
size : value_t_or_exit ! ( matches , " accounts_filler_size " , usize ) ,
} ;
2022-11-29 16:47:51 -08:00
let accounts_db_config = AccountsDbConfig {
2021-09-17 11:12:06 -07:00
index : Some ( accounts_index_config ) ,
2023-01-12 07:43:50 -08:00
accounts_hash_cache_path : Some ( ledger_path . join ( AccountsDb ::ACCOUNTS_HASH_CACHE_DIR ) ) ,
2022-04-11 11:10:09 -07:00
filler_accounts_config ,
2021-12-01 11:10:48 -08:00
write_cache_limit_bytes : value_t ! ( matches , " accounts_db_cache_limit_mb " , u64 )
. ok ( )
. map ( | mb | mb * MB as u64 ) ,
2023-01-10 05:33:43 -08:00
ancient_append_vec_offset : value_t ! ( matches , " accounts_db_ancient_append_vecs " , i64 ) . ok ( ) ,
2022-09-06 09:39:39 -07:00
exhaustively_verify_refcounts : matches . is_present ( " accounts_db_verify_refcounts " ) ,
2021-10-25 07:45:46 -07:00
.. AccountsDbConfig ::default ( )
} ;
let accounts_db_config = Some ( accounts_db_config ) ;
2021-08-17 12:50:01 -07:00
2022-03-14 18:18:46 -07:00
let geyser_plugin_config_files = if matches . is_present ( " geyser_plugin_config " ) {
2021-10-08 20:06:58 -07:00
Some (
2022-03-14 18:18:46 -07:00
values_t_or_exit! ( matches , " geyser_plugin_config " , String )
2021-10-08 20:06:58 -07:00
. into_iter ( )
. map ( PathBuf ::from )
. collect ( ) ,
)
} else {
None
} ;
2021-09-30 14:26:17 -07:00
2022-03-18 11:36:52 -07:00
let rpc_bigtable_config = if matches . is_present ( " enable_rpc_bigtable_ledger_storage " )
| | matches . is_present ( " enable_bigtable_ledger_upload " )
{
Some ( RpcBigtableConfig {
enable_bigtable_ledger_upload : matches . is_present ( " enable_bigtable_ledger_upload " ) ,
2022-03-19 00:04:17 -07:00
bigtable_instance_name : value_t_or_exit ! ( matches , " rpc_bigtable_instance_name " , String ) ,
2022-06-15 17:58:16 -07:00
bigtable_app_profile_id : value_t_or_exit ! (
matches ,
" rpc_bigtable_app_profile_id " ,
String
) ,
2022-03-18 11:36:52 -07:00
timeout : value_t ! ( matches , " rpc_bigtable_timeout " , u64 )
. ok ( )
. map ( Duration ::from_secs ) ,
} )
} else {
None
} ;
2022-04-21 12:43:08 -07:00
let rpc_send_retry_rate_ms = value_t_or_exit! ( matches , " rpc_send_transaction_retry_ms " , u64 ) ;
let rpc_send_batch_size = value_t_or_exit! ( matches , " rpc_send_transaction_batch_size " , usize ) ;
let rpc_send_batch_send_rate_ms =
value_t_or_exit! ( matches , " rpc_send_transaction_batch_ms " , u64 ) ;
if rpc_send_batch_send_rate_ms > rpc_send_retry_rate_ms {
eprintln! (
2022-12-06 06:30:06 -08:00
" The specified rpc-send-batch-ms ({rpc_send_batch_send_rate_ms}) is invalid, it must be <= rpc-send-retry-ms ({rpc_send_retry_rate_ms}) "
2022-04-21 12:43:08 -07:00
) ;
exit ( 1 ) ;
}
let tps = rpc_send_batch_size as u64 * MILLIS_PER_SECOND / rpc_send_batch_send_rate_ms ;
if tps > send_transaction_service ::MAX_TRANSACTION_SENDS_PER_SECOND {
eprintln! (
" Either the specified rpc-send-batch-size ({}) or rpc-send-batch-ms ({}) is invalid, \
' rpc - send - batch - size * 1000 / rpc - send - batch - ms ' must be smaller than ( { } ) . " ,
rpc_send_batch_size ,
rpc_send_batch_send_rate_ms ,
send_transaction_service ::MAX_TRANSACTION_SENDS_PER_SECOND
) ;
exit ( 1 ) ;
}
2022-05-17 20:23:51 -07:00
let full_api = matches . is_present ( " full_rpc_api " ) ;
2022-04-21 12:43:08 -07:00
2020-01-24 17:27:04 -08:00
let mut validator_config = ValidatorConfig {
2020-09-18 22:03:54 -07:00
require_tower : matches . is_present ( " require_tower " ) ,
2021-08-10 13:09:52 -07:00
tower_storage ,
2022-04-19 15:06:30 -07:00
halt_at_slot : value_t ! ( matches , " dev_halt_at_slot " , Slot ) . ok ( ) ,
2020-01-24 17:27:04 -08:00
expected_genesis_hash : matches
. value_of ( " expected_genesis_hash " )
2021-06-18 06:34:46 -07:00
. map ( | s | Hash ::from_str ( s ) . unwrap ( ) ) ,
2020-06-30 12:43:48 -07:00
expected_bank_hash : matches
. value_of ( " expected_bank_hash " )
2021-06-18 06:34:46 -07:00
. map ( | s | Hash ::from_str ( s ) . unwrap ( ) ) ,
2021-06-20 08:39:20 -07:00
expected_shred_version ,
2020-01-24 17:27:04 -08:00
new_hard_forks : hardforks_of ( & matches , " hard_forks " ) ,
rpc_config : JsonRpcConfig {
2020-03-23 10:25:39 -07:00
enable_rpc_transaction_history : matches . is_present ( " enable_rpc_transaction_history " ) ,
2022-03-22 15:17:05 -07:00
enable_extended_tx_metadata_storage : matches . is_present ( " enable_cpi_and_log_storage " )
| | matches . is_present ( " enable_extended_tx_metadata_storage " ) ,
2022-03-18 11:36:52 -07:00
rpc_bigtable_config ,
2020-01-24 17:27:04 -08:00
faucet_addr : matches . value_of ( " rpc_faucet_addr " ) . map ( | address | {
solana_net_utils ::parse_host_port ( address ) . expect ( " failed to parse faucet address " )
} ) ,
2022-05-17 20:23:51 -07:00
full_api ,
2021-04-12 19:33:40 -07:00
obsolete_v1_7_api : matches . is_present ( " obsolete_v1_7_rpc_api " ) ,
2020-12-07 09:22:35 -08:00
max_multiple_accounts : Some ( value_t_or_exit! (
matches ,
" rpc_max_multiple_accounts " ,
usize
) ) ,
2020-05-29 15:31:52 -07:00
health_check_slot_distance : value_t_or_exit ! (
matches ,
" health_check_slot_distance " ,
u64
) ,
2021-01-12 17:13:47 -08:00
rpc_threads : value_t_or_exit ! ( matches , " rpc_threads " , usize ) ,
2021-10-26 20:13:19 -07:00
rpc_niceness_adj : value_t_or_exit ! ( matches , " rpc_niceness_adj " , i8 ) ,
2021-05-13 14:04:21 -07:00
account_indexes : account_indexes . clone ( ) ,
2021-05-24 12:24:47 -07:00
rpc_scan_and_fix_roots : matches . is_present ( " rpc_scan_and_fix_roots " ) ,
2022-08-08 05:50:05 -07:00
max_request_body_size : Some ( value_t_or_exit! (
matches ,
" rpc_max_request_body_size " ,
usize
) ) ,
2020-01-24 17:27:04 -08:00
} ,
2022-03-14 18:18:46 -07:00
geyser_plugin_config_files ,
2020-09-10 08:56:26 -07:00
rpc_addrs : value_t ! ( matches , " rpc_port " , u16 ) . ok ( ) . map ( | rpc_port | {
(
SocketAddr ::new ( rpc_bind_address , rpc_port ) ,
SocketAddr ::new ( rpc_bind_address , rpc_port + 1 ) ,
2020-12-01 19:25:09 -08:00
// If additional ports are added, +2 needs to be skipped to avoid a conflict with
// the websocket port (which is +2) in web3.js This odd port shifting is tracked at
// https://github.com/solana-labs/solana/issues/12250
2020-09-10 08:56:26 -07:00
)
} ) ,
2020-10-01 12:36:58 -07:00
pubsub_config : PubSubConfig {
2021-12-17 15:03:09 -08:00
enable_block_subscription : matches . is_present ( " rpc_pubsub_enable_block_subscription " ) ,
2020-11-14 09:29:51 -08:00
enable_vote_subscription : matches . is_present ( " rpc_pubsub_enable_vote_subscription " ) ,
2021-09-17 12:40:14 -07:00
max_active_subscriptions : value_t_or_exit ! (
2020-10-01 12:36:58 -07:00
matches ,
2021-09-17 12:40:14 -07:00
" rpc_pubsub_max_active_subscriptions " ,
2020-10-01 12:36:58 -07:00
usize
) ,
2021-09-17 12:40:14 -07:00
queue_capacity_items : value_t_or_exit ! (
2020-10-01 12:36:58 -07:00
matches ,
2021-09-17 12:40:14 -07:00
" rpc_pubsub_queue_capacity_items " ,
2020-10-01 12:36:58 -07:00
usize
) ,
2021-09-17 12:40:14 -07:00
queue_capacity_bytes : value_t_or_exit ! (
2021-06-16 21:28:23 -07:00
matches ,
2021-09-17 12:40:14 -07:00
" rpc_pubsub_queue_capacity_bytes " ,
2021-06-16 21:28:23 -07:00
usize
) ,
2021-10-31 23:17:24 -07:00
worker_threads : value_t_or_exit ! ( matches , " rpc_pubsub_worker_threads " , usize ) ,
2022-05-17 20:23:51 -07:00
notification_threads : if full_api {
value_of ( & matches , " rpc_pubsub_notification_threads " )
} else {
Some ( 0 )
} ,
2020-10-01 12:36:58 -07:00
} ,
2020-09-10 13:15:22 -07:00
voting_disabled : matches . is_present ( " no_voting " ) | | restricted_repair_only_mode ,
2020-03-02 10:47:58 -08:00
wait_for_supermajority : value_t ! ( matches , " wait_for_supermajority " , Slot ) . ok ( ) ,
2021-11-12 10:57:55 -08:00
known_validators ,
2020-08-21 00:35:11 -07:00
repair_validators ,
2022-12-15 19:24:23 -08:00
repair_whitelist : repair_whitelist . clone ( ) ,
2020-09-11 12:00:16 -07:00
gossip_validators ,
2020-07-06 12:43:45 -07:00
wal_recovery_mode ,
2020-09-18 14:35:20 -07:00
poh_verify : ! matches . is_present ( " skip_poh_verify " ) ,
2020-09-23 18:46:42 -07:00
debug_keys ,
2020-11-20 14:47:37 -08:00
contact_debug_interval ,
2021-10-19 16:11:46 -07:00
send_transaction_service_config : send_transaction_service ::Config {
2022-04-21 12:43:08 -07:00
retry_rate_ms : rpc_send_retry_rate_ms ,
2021-10-19 16:11:46 -07:00
leader_forward_count : value_t_or_exit ! (
matches ,
" rpc_send_transaction_leader_forward_count " ,
u64
) ,
2021-10-19 22:17:06 -07:00
default_max_retries : value_t ! (
matches ,
" rpc_send_transaction_default_max_retries " ,
usize
)
. ok ( ) ,
service_max_retries : value_t_or_exit ! (
matches ,
" rpc_send_transaction_service_max_retries " ,
usize
) ,
2022-04-21 12:43:08 -07:00
batch_send_rate_ms : rpc_send_batch_send_rate_ms ,
batch_size : rpc_send_batch_size ,
2021-10-19 16:11:46 -07:00
} ,
2020-12-29 09:35:57 -08:00
no_poh_speed_test : matches . is_present ( " no_poh_speed_test " ) ,
2022-03-14 19:38:04 -07:00
no_os_memory_stats_reporting : matches . is_present ( " no_os_memory_stats_reporting " ) ,
2021-11-16 10:26:03 -08:00
no_os_network_stats_reporting : matches . is_present ( " no_os_network_stats_reporting " ) ,
2022-06-07 11:34:25 -07:00
no_os_cpu_stats_reporting : matches . is_present ( " no_os_cpu_stats_reporting " ) ,
2022-08-02 14:29:53 -07:00
no_os_disk_stats_reporting : matches . is_present ( " no_os_disk_stats_reporting " ) ,
2020-12-29 11:09:47 -08:00
poh_pinned_cpu_core : value_of ( & matches , " poh_pinned_cpu_core " )
. unwrap_or ( poh_service ::DEFAULT_PINNED_CPU_CORE ) ,
2021-03-05 16:01:21 -08:00
poh_hashes_per_batch : value_of ( & matches , " poh_hashes_per_batch " )
. unwrap_or ( poh_service ::DEFAULT_HASHES_PER_BATCH ) ,
2022-09-11 05:40:49 -07:00
process_ledger_before_services : matches . is_present ( " process_ledger_before_services " ) ,
2020-12-31 18:06:03 -08:00
account_indexes ,
2021-02-04 07:00:33 -08:00
accounts_db_test_hash_calculation : matches . is_present ( " accounts_db_test_hash_calculation " ) ,
2021-09-07 21:30:38 -07:00
accounts_db_config ,
2021-08-04 15:28:33 -07:00
accounts_db_skip_shrink : matches . is_present ( " accounts_db_skip_shrink " ) ,
2021-02-26 09:15:45 -08:00
tpu_coalesce_ms ,
2021-03-25 18:54:51 -07:00
no_wait_for_vote_to_start_leader : matches . is_present ( " no_wait_for_vote_to_start_leader " ) ,
2021-06-09 21:21:32 -07:00
accounts_shrink_ratio ,
2022-04-11 17:28:10 -07:00
runtime_config : RuntimeConfig {
bpf_jit : ! matches . is_present ( " no_bpf_jit " ) ,
2022-07-19 22:01:35 -07:00
log_messages_bytes_limit : value_of ( & matches , " log_messages_bytes_limit " ) ,
2022-04-11 17:28:10 -07:00
.. RuntimeConfig ::default ( )
} ,
2022-08-11 14:34:04 -07:00
staked_nodes_overrides : staked_nodes_overrides . clone ( ) ,
2022-08-26 12:36:02 -07:00
replay_slots_concurrently : matches . is_present ( " replay_slots_concurrently " ) ,
2020-01-24 17:27:04 -08:00
.. ValidatorConfig ::default ( )
} ;
2019-11-04 07:11:40 -08:00
2020-03-15 10:19:07 -07:00
let vote_account = pubkey_of ( & matches , " vote_account " ) . unwrap_or_else ( | | {
2020-09-10 13:15:22 -07:00
if ! validator_config . voting_disabled {
warn! ( " --vote-account not specified, validator will not vote " ) ;
validator_config . voting_disabled = true ;
}
2020-03-31 08:23:42 -07:00
Keypair ::new ( ) . pubkey ( )
2020-03-15 10:19:07 -07:00
} ) ;
2019-11-04 07:11:40 -08:00
let dynamic_port_range =
2019-11-12 12:37:13 -08:00
solana_net_utils ::parse_port_range ( matches . value_of ( " dynamic_port_range " ) . unwrap ( ) )
2019-11-04 07:11:40 -08:00
. expect ( " invalid dynamic_port_range " ) ;
2020-12-20 21:36:27 -08:00
let account_paths : Vec < PathBuf > =
if let Ok ( account_paths ) = values_t! ( matches , " account_paths " , String ) {
account_paths
. join ( " , " )
. split ( ',' )
. map ( PathBuf ::from )
. collect ( )
} else {
vec! [ ledger_path . join ( " accounts " ) ]
} ;
2020-12-21 21:33:37 -08:00
let account_shrink_paths : Option < Vec < PathBuf > > =
values_t! ( matches , " account_shrink_path " , String )
. map ( | shrink_paths | shrink_paths . into_iter ( ) . map ( PathBuf ::from ) . collect ( ) )
. ok ( ) ;
2019-12-05 18:41:29 -08:00
// Create and canonicalize account paths to avoid issues with symlink creation
validator_config . account_paths = account_paths
. into_iter ( )
. map ( | account_path | {
match fs ::create_dir_all ( & account_path ) . and_then ( | _ | fs ::canonicalize ( & account_path ) ) {
Ok ( account_path ) = > account_path ,
Err ( err ) = > {
2022-12-06 06:30:06 -08:00
eprintln! ( " Unable to access account path: {account_path:?} , err: {err:?} " ) ;
2019-12-05 18:41:29 -08:00
exit ( 1 ) ;
}
}
} )
. collect ( ) ;
2019-11-04 07:11:40 -08:00
2020-12-21 21:33:37 -08:00
validator_config . account_shrink_paths = account_shrink_paths . map ( | paths | {
paths
. into_iter ( )
. map ( | account_path | {
match fs ::create_dir_all ( & account_path )
. and_then ( | _ | fs ::canonicalize ( & account_path ) )
{
Ok ( account_path ) = > account_path ,
Err ( err ) = > {
2022-12-06 06:30:06 -08:00
eprintln! ( " Unable to access account path: {account_path:?} , err: {err:?} " ) ;
2020-12-21 21:33:37 -08:00
exit ( 1 ) ;
}
}
} )
. collect ( )
} ) ;
2020-11-27 22:38:45 -08:00
let maximum_local_snapshot_age = value_t_or_exit! ( matches , " maximum_local_snapshot_age " , u64 ) ;
2021-09-03 09:28:10 -07:00
let maximum_full_snapshot_archives_to_retain =
2021-09-10 13:59:26 -07:00
value_t_or_exit! ( matches , " maximum_full_snapshots_to_retain " , usize ) ;
let maximum_incremental_snapshot_archives_to_retain =
value_t_or_exit! ( matches , " maximum_incremental_snapshots_to_retain " , usize ) ;
2021-10-26 18:56:16 -07:00
let snapshot_packager_niceness_adj =
value_t_or_exit! ( matches , " snapshot_packager_niceness_adj " , i8 ) ;
2021-05-25 09:32:12 -07:00
let minimal_snapshot_download_speed =
value_t_or_exit! ( matches , " minimal_snapshot_download_speed " , f32 ) ;
let maximum_snapshot_download_abort =
value_t_or_exit! ( matches , " maximum_snapshot_download_abort " , u64 ) ;
2022-05-10 13:37:41 -07:00
let full_snapshot_archives_dir = if matches . is_present ( " snapshots " ) {
2021-03-17 04:36:48 -07:00
PathBuf ::from ( matches . value_of ( " snapshots " ) . unwrap ( ) )
2021-03-13 13:48:26 -08:00
} else {
ledger_path . clone ( )
} ;
2022-05-10 13:37:41 -07:00
let incremental_snapshot_archives_dir =
if matches . is_present ( " incremental_snapshot_archive_path " ) {
let incremental_snapshot_archives_dir = PathBuf ::from (
matches
. value_of ( " incremental_snapshot_archive_path " )
. unwrap ( ) ,
) ;
fs ::create_dir_all ( & incremental_snapshot_archives_dir ) . unwrap_or_else ( | err | {
eprintln! (
" Failed to create incremental snapshot archives directory {:?}: {} " ,
incremental_snapshot_archives_dir . display ( ) ,
err
) ;
exit ( 1 ) ;
} ) ;
incremental_snapshot_archives_dir
} else {
full_snapshot_archives_dir . clone ( )
} ;
let bank_snapshots_dir = incremental_snapshot_archives_dir . join ( " snapshot " ) ;
2021-08-21 13:41:03 -07:00
fs ::create_dir_all ( & bank_snapshots_dir ) . unwrap_or_else ( | err | {
2019-11-22 07:20:40 -08:00
eprintln! (
2019-11-04 07:11:40 -08:00
" Failed to create snapshots directory {:?}: {} " ,
2022-05-10 13:37:41 -07:00
bank_snapshots_dir . display ( ) ,
err
2019-11-04 07:11:40 -08:00
) ;
exit ( 1 ) ;
} ) ;
2021-01-07 22:45:42 -08:00
let archive_format = {
let archive_format_str = value_t_or_exit! ( matches , " snapshot_archive_format " , String ) ;
2022-05-16 10:44:15 -07:00
ArchiveFormat ::from_cli_arg ( & archive_format_str )
2022-12-06 06:30:06 -08:00
. unwrap_or_else ( | | panic! ( " Archive format not recognized: {archive_format_str} " ) )
2020-09-10 13:15:22 -07:00
} ;
2020-06-18 22:38:37 -07:00
let snapshot_version =
matches
. value_of ( " snapshot_version " )
. map_or ( SnapshotVersion ::default ( ) , | s | {
s . parse ::< SnapshotVersion > ( ) . unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
eprintln! ( " Error: {err} " ) ;
2020-06-18 22:38:37 -07:00
exit ( 1 )
} )
} ) ;
2021-09-10 13:59:26 -07:00
let incremental_snapshot_interval_slots =
value_t_or_exit! ( matches , " incremental_snapshot_interval_slots " , u64 ) ;
let ( full_snapshot_archive_interval_slots , incremental_snapshot_archive_interval_slots ) =
if incremental_snapshot_interval_slots > 0 {
2022-02-09 11:26:35 -08:00
if ! matches . is_present ( " no_incremental_snapshots " ) {
2021-09-10 13:59:26 -07:00
(
value_t_or_exit! ( matches , " full_snapshot_interval_slots " , u64 ) ,
incremental_snapshot_interval_slots ,
)
} else {
( incremental_snapshot_interval_slots , Slot ::MAX )
}
2019-11-04 07:11:40 -08:00
} else {
2021-09-10 13:59:26 -07:00
( Slot ::MAX , Slot ::MAX )
} ;
2022-12-06 14:47:55 -08:00
validator_config . snapshot_config = SnapshotConfig {
2022-09-02 05:56:23 -07:00
usage : if full_snapshot_archive_interval_slots = = Slot ::MAX {
SnapshotUsage ::LoadOnly
} else {
SnapshotUsage ::LoadAndGenerate
} ,
2021-09-10 13:59:26 -07:00
full_snapshot_archive_interval_slots ,
incremental_snapshot_archive_interval_slots ,
2021-08-21 13:41:03 -07:00
bank_snapshots_dir ,
2022-05-10 13:37:41 -07:00
full_snapshot_archives_dir : full_snapshot_archives_dir . clone ( ) ,
incremental_snapshot_archives_dir : incremental_snapshot_archives_dir . clone ( ) ,
2021-01-07 22:45:42 -08:00
archive_format ,
2020-06-18 22:38:37 -07:00
snapshot_version ,
2021-09-03 09:28:10 -07:00
maximum_full_snapshot_archives_to_retain ,
2021-09-10 13:59:26 -07:00
maximum_incremental_snapshot_archives_to_retain ,
2021-09-13 06:27:50 -07:00
accounts_hash_debug_verify : validator_config . accounts_db_test_hash_calculation ,
2021-10-26 18:56:16 -07:00
packager_thread_niceness_adj : snapshot_packager_niceness_adj ,
2022-12-06 14:47:55 -08:00
} ;
2019-11-04 07:11:40 -08:00
2020-04-16 15:12:20 -07:00
validator_config . accounts_hash_interval_slots =
2021-09-10 13:59:26 -07:00
value_t_or_exit! ( matches , " accounts-hash-interval-slots " , u64 ) ;
2021-09-07 07:31:54 -07:00
if ! is_snapshot_config_valid (
2022-12-06 14:47:55 -08:00
& validator_config . snapshot_config ,
2020-04-16 15:12:20 -07:00
validator_config . accounts_hash_interval_slots ,
) {
2021-09-10 13:59:26 -07:00
eprintln! ( " Invalid snapshot configuration provided: snapshot intervals are incompatible. \
\ n \ t - full snapshot interval MUST be a multiple of accounts hash interval ( if enabled ) \
\ n \ t - incremental snapshot interval MUST be a multiple of accounts hash interval ( if enabled ) \
\ n \ t - full snapshot interval MUST be larger than incremental snapshot interval ( if enabled ) \
\ nSnapshot configuration values : \
\ n \ tfull snapshot interval : { } \
\ n \ tincremental snapshot interval : { } \
\ n \ taccounts hash interval : { } " ,
if full_snapshot_archive_interval_slots = = Slot ::MAX { " disabled " . to_string ( ) } else { full_snapshot_archive_interval_slots . to_string ( ) } ,
if incremental_snapshot_archive_interval_slots = = Slot ::MAX { " disabled " . to_string ( ) } else { incremental_snapshot_archive_interval_slots . to_string ( ) } ,
validator_config . accounts_hash_interval_slots ) ;
2020-04-16 15:12:20 -07:00
exit ( 1 ) ;
}
2019-11-04 07:11:40 -08:00
if matches . is_present ( " limit_ledger_size " ) {
2020-08-20 01:10:39 -07:00
let limit_ledger_size = match matches . value_of ( " limit_ledger_size " ) {
Some ( _ ) = > value_t_or_exit! ( matches , " limit_ledger_size " , u64 ) ,
None = > DEFAULT_MAX_LEDGER_SHREDS ,
} ;
2020-04-09 16:36:44 -07:00
if limit_ledger_size < DEFAULT_MIN_MAX_LEDGER_SHREDS {
2020-01-20 11:41:05 -08:00
eprintln! (
2022-12-06 06:30:06 -08:00
" The provided --limit-ledger-size value was too small, the minimum value is {DEFAULT_MIN_MAX_LEDGER_SHREDS} "
2020-01-20 11:41:05 -08:00
) ;
exit ( 1 ) ;
}
2020-03-31 17:21:19 -07:00
validator_config . max_ledger_shreds = Some ( limit_ledger_size ) ;
2019-11-04 07:11:40 -08:00
}
2022-03-18 11:13:35 -07:00
validator_config . ledger_column_options = LedgerColumnOptions {
2022-03-22 02:27:09 -07:00
compression_type : match matches . value_of ( " rocksdb_ledger_compression " ) {
None = > BlockstoreCompressionType ::default ( ) ,
Some ( ledger_compression_string ) = > match ledger_compression_string {
" none " = > BlockstoreCompressionType ::None ,
" snappy " = > BlockstoreCompressionType ::Snappy ,
" lz4 " = > BlockstoreCompressionType ::Lz4 ,
" zlib " = > BlockstoreCompressionType ::Zlib ,
2022-12-06 06:30:06 -08:00
_ = > panic! ( " Unsupported ledger_compression: {ledger_compression_string} " ) ,
2022-03-22 02:27:09 -07:00
} ,
} ,
2022-03-11 15:17:34 -08:00
shred_storage_type : match matches . value_of ( " rocksdb_shred_compaction " ) {
None = > ShredStorageType ::default ( ) ,
Some ( shred_compaction_string ) = > match shred_compaction_string {
" level " = > ShredStorageType ::RocksLevel ,
2022-09-28 00:32:27 -07:00
" fifo " = > match matches . value_of ( " rocksdb_fifo_shred_storage_size " ) {
None = > ShredStorageType ::rocks_fifo ( default_fifo_shred_storage_size (
& validator_config ,
) ) ,
2022-10-04 10:38:40 -07:00
Some ( _ ) = > ShredStorageType ::rocks_fifo ( Some ( value_t_or_exit! (
2022-09-28 00:32:27 -07:00
matches ,
" rocksdb_fifo_shred_storage_size " ,
u64
2022-10-04 10:38:40 -07:00
) ) ) ,
2022-09-28 00:32:27 -07:00
} ,
2022-12-06 06:30:06 -08:00
_ = > panic! ( " Unrecognized rocksdb-shred-compaction: {shred_compaction_string} " ) ,
2022-03-11 15:17:34 -08:00
} ,
2022-03-03 12:43:58 -08:00
} ,
2022-04-29 15:28:50 -07:00
rocks_perf_sample_interval : value_t_or_exit ! (
matches ,
" rocksdb_perf_sample_interval " ,
usize
) ,
2022-03-03 12:43:58 -08:00
} ;
2021-11-12 10:57:55 -08:00
if matches . is_present ( " halt_on_known_validators_accounts_hash_mismatch " ) {
validator_config . halt_on_known_validators_accounts_hash_mismatch = true ;
2020-03-16 08:37:31 -07:00
}
2020-10-21 20:31:48 -07:00
let public_rpc_addr = matches . value_of ( " public_rpc_addr " ) . map ( | addr | {
solana_net_utils ::parse_host_port ( addr ) . unwrap_or_else ( | e | {
2022-12-06 06:30:06 -08:00
eprintln! ( " failed to parse public rpc address: {e} " ) ;
2020-10-21 20:31:48 -07:00
exit ( 1 ) ;
} )
} ) ;
2021-10-25 18:25:55 -07:00
if ! matches . is_present ( " no_os_network_limits_test " ) {
2022-01-20 12:38:42 -08:00
if SystemMonitorService ::check_os_network_limits ( ) {
info! ( " OS network limits test passed. " ) ;
} else {
eprintln! ( " OS network limit test failed. solana-sys-tuner may be used to configure OS network limits. Bypass check with --no-os-network-limits-test. " ) ;
2022-02-14 07:48:30 -08:00
exit ( 1 ) ;
2022-01-20 12:38:42 -08:00
}
2021-10-25 18:25:55 -07:00
}
2021-09-22 14:10:35 -07:00
let mut ledger_lock = ledger_lockfile ( & ledger_path ) ;
let _ledger_write_guard = lock_ledger ( & ledger_path , & mut ledger_lock ) ;
2021-02-05 22:39:23 -08:00
2021-03-04 13:01:11 -08:00
let start_progress = Arc ::new ( RwLock ::new ( ValidatorStartProgress ::default ( ) ) ) ;
2022-02-14 10:27:11 -08:00
let admin_service_post_init = Arc ::new ( RwLock ::new ( None ) ) ;
2021-02-26 21:42:09 -08:00
admin_rpc_service ::run (
& ledger_path ,
admin_rpc_service ::AdminRpcRequestMetadata {
rpc_addr : validator_config . rpc_addrs . map ( | ( rpc_addr , _ ) | rpc_addr ) ,
start_time : std ::time ::SystemTime ::now ( ) ,
validator_exit : validator_config . validator_exit . clone ( ) ,
2021-03-04 13:01:11 -08:00
start_progress : start_progress . clone ( ) ,
2021-04-11 20:38:30 -07:00
authorized_voter_keypairs : authorized_voter_keypairs . clone ( ) ,
2022-02-14 10:27:11 -08:00
post_init : admin_service_post_init . clone ( ) ,
2021-07-20 22:25:13 -07:00
tower_storage : validator_config . tower_storage . clone ( ) ,
2022-08-11 14:34:04 -07:00
staked_nodes_overrides ,
2021-02-26 21:42:09 -08:00
} ,
) ;
2020-12-18 10:54:48 -08:00
let gossip_host : IpAddr = matches
2020-11-12 21:04:15 -08:00
. value_of ( " gossip_host " )
. map ( | gossip_host | {
solana_net_utils ::parse_host ( gossip_host ) . unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
eprintln! ( " Failed to parse --gossip-host: {err} " ) ;
2019-11-12 12:37:13 -08:00
exit ( 1 ) ;
2019-11-20 14:21:34 -08:00
} )
2020-11-12 21:04:15 -08:00
} )
. unwrap_or_else ( | | {
2020-12-18 10:54:48 -08:00
if ! entrypoint_addrs . is_empty ( ) {
let mut order : Vec < _ > = ( 0 .. entrypoint_addrs . len ( ) ) . collect ( ) ;
order . shuffle ( & mut thread_rng ( ) ) ;
let gossip_host = order . into_iter ( ) . find_map ( | i | {
let entrypoint_addr = & entrypoint_addrs [ i ] ;
info! (
" Contacting {} to determine the validator's public IP address " ,
entrypoint_addr
2020-11-12 21:04:15 -08:00
) ;
2020-12-18 10:54:48 -08:00
solana_net_utils ::get_public_ip_addr ( entrypoint_addr ) . map_or_else (
| err | {
eprintln! (
2022-12-06 06:30:06 -08:00
" Failed to contact cluster entrypoint {entrypoint_addr}: {err} "
2020-12-18 10:54:48 -08:00
) ;
None
} ,
Some ,
)
} ) ;
gossip_host . unwrap_or_else ( | | {
eprintln! ( " Unable to determine the validator's public IP address " ) ;
2020-11-12 21:04:15 -08:00
exit ( 1 ) ;
} )
} else {
std ::net ::IpAddr ::V4 ( std ::net ::Ipv4Addr ::new ( 127 , 0 , 0 , 1 ) )
}
} ) ;
2019-11-06 10:34:31 -08:00
2019-11-20 14:21:34 -08:00
let gossip_addr = SocketAddr ::new (
gossip_host ,
value_t! ( matches , " gossip_port " , u16 ) . unwrap_or_else ( | _ | {
2020-03-04 21:46:43 -08:00
solana_net_utils ::find_available_port_in_range ( bind_address , ( 0 , 1 ) ) . unwrap_or_else (
| err | {
2022-12-06 06:30:06 -08:00
eprintln! ( " Unable to find an available gossip port: {err} " ) ;
2020-03-04 21:46:43 -08:00
exit ( 1 ) ;
} ,
)
2019-11-20 14:21:34 -08:00
} ) ,
) ;
2022-03-02 00:42:14 -08:00
let overwrite_tpu_addr = matches . value_of ( " tpu_host_addr " ) . map ( | tpu_addr | {
solana_net_utils ::parse_host_port ( tpu_addr ) . unwrap_or_else ( | err | {
2022-12-06 06:30:06 -08:00
eprintln! ( " Failed to parse --overwrite-tpu-addr: {err} " ) ;
2022-03-02 00:42:14 -08:00
exit ( 1 ) ;
} )
} ) ;
2020-12-18 10:54:48 -08:00
let cluster_entrypoints = entrypoint_addrs
. iter ( )
. map ( ContactInfo ::new_gossip_entry_point )
. collect ::< Vec < _ > > ( ) ;
2019-11-04 07:11:40 -08:00
2020-03-04 21:46:43 -08:00
let mut node = Node ::new_with_external_ip (
& identity_keypair . pubkey ( ) ,
& gossip_addr ,
dynamic_port_range ,
bind_address ,
2022-03-02 00:42:14 -08:00
overwrite_tpu_addr ,
2020-03-04 21:46:43 -08:00
) ;
2020-01-30 09:17:01 -08:00
2020-09-10 13:15:22 -07:00
if restricted_repair_only_mode {
let any = SocketAddr ::new ( std ::net ::IpAddr ::V4 ( std ::net ::Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 0 ) ;
// When in --restricted_repair_only_mode is enabled only the gossip and repair ports
// need to be reachable by the entrypoint to respond to gossip pull requests and repair
// requests initiated by the node. All other ports are unused.
node . info . tpu = any ;
node . info . tpu_forwards = any ;
node . info . tvu = any ;
node . info . tvu_forwards = any ;
node . info . serve_repair = any ;
2020-09-18 14:35:20 -07:00
// A node in this configuration shouldn't be an entrypoint to other nodes
node . sockets . ip_echo = None ;
2020-09-10 13:15:22 -07:00
}
2020-01-30 09:17:01 -08:00
if ! private_rpc {
2020-10-21 20:31:48 -07:00
if let Some ( public_rpc_addr ) = public_rpc_addr {
node . info . rpc = public_rpc_addr ;
node . info . rpc_pubsub = public_rpc_addr ;
2020-12-01 19:25:09 -08:00
} else if let Some ( ( rpc_addr , rpc_pubsub_addr ) ) = validator_config . rpc_addrs {
2020-09-10 08:56:26 -07:00
node . info . rpc = SocketAddr ::new ( node . info . gossip . ip ( ) , rpc_addr . port ( ) ) ;
node . info . rpc_pubsub = SocketAddr ::new ( node . info . gossip . ip ( ) , rpc_pubsub_addr . port ( ) ) ;
2020-01-30 09:17:01 -08:00
}
}
2019-11-04 07:11:40 -08:00
2020-09-18 14:35:20 -07:00
solana_metrics ::set_host_id ( identity_keypair . pubkey ( ) . to_string ( ) ) ;
2022-02-11 10:04:10 -08:00
solana_metrics ::set_panic_hook ( " validator " , {
2022-12-06 06:30:06 -08:00
let version = format! ( " {solana_version:?} " ) ;
2022-02-11 10:04:10 -08:00
Some ( version )
} ) ;
2021-07-14 05:16:29 -07:00
solana_entry ::entry ::init_poh ( ) ;
2022-05-10 13:37:41 -07:00
snapshot_utils ::remove_tmp_snapshot_archives ( & full_snapshot_archives_dir ) ;
snapshot_utils ::remove_tmp_snapshot_archives ( & incremental_snapshot_archives_dir ) ;
2021-01-29 18:01:27 -08:00
2021-06-17 13:51:06 -07:00
let identity_keypair = Arc ::new ( identity_keypair ) ;
2021-02-03 08:26:17 -08:00
let should_check_duplicate_instance = ! matches . is_present ( " no_duplicate_instance_check " ) ;
2021-01-29 18:01:27 -08:00
if ! cluster_entrypoints . is_empty ( ) {
2021-10-03 11:13:16 -07:00
bootstrap ::rpc_bootstrap (
2021-01-29 18:01:27 -08:00
& node ,
& identity_keypair ,
& ledger_path ,
2022-05-10 13:37:41 -07:00
& full_snapshot_archives_dir ,
& incremental_snapshot_archives_dir ,
2021-01-29 18:01:27 -08:00
& vote_account ,
2021-04-11 20:38:30 -07:00
authorized_voter_keypairs . clone ( ) ,
2021-01-29 18:01:27 -08:00
& cluster_entrypoints ,
& mut validator_config ,
rpc_bootstrap_config ,
2021-10-19 14:35:42 -07:00
do_port_check ,
2021-01-29 18:01:27 -08:00
use_progress_bar ,
maximum_local_snapshot_age ,
2021-02-03 08:26:17 -08:00
should_check_duplicate_instance ,
2021-03-04 13:01:11 -08:00
& start_progress ,
2021-05-25 09:32:12 -07:00
minimal_snapshot_download_speed ,
maximum_snapshot_download_abort ,
2021-07-23 08:25:03 -07:00
socket_addr_space ,
2021-01-29 18:01:27 -08:00
) ;
2021-03-04 13:01:11 -08:00
* start_progress . write ( ) . unwrap ( ) = ValidatorStartProgress ::Initializing ;
2021-01-29 18:01:27 -08:00
}
if operation = = Operation ::Initialize {
info! ( " Validator ledger initialization complete " ) ;
return ;
}
2021-04-11 20:38:30 -07:00
2021-01-29 18:01:27 -08:00
let validator = Validator ::new (
2019-11-04 07:11:40 -08:00
node ,
2021-06-17 13:51:06 -07:00
identity_keypair ,
2019-11-04 07:11:40 -08:00
& ledger_path ,
& vote_account ,
2020-03-31 08:23:42 -07:00
authorized_voter_keypairs ,
2020-12-18 10:54:48 -08:00
cluster_entrypoints ,
2021-01-29 18:01:27 -08:00
& validator_config ,
2021-02-03 08:26:17 -08:00
should_check_duplicate_instance ,
2021-03-04 13:01:11 -08:00
start_progress ,
2021-07-23 08:25:03 -07:00
socket_addr_space ,
2022-04-30 20:52:38 -07:00
tpu_use_quic ,
2022-06-10 09:25:24 -07:00
tpu_connection_pool_size ,
2022-09-07 13:19:14 -07:00
tpu_enable_udp ,
2022-08-11 23:25:20 -07:00
)
. unwrap_or_else ( | e | {
error! ( " Failed to start validator: {:?} " , e ) ;
exit ( 1 ) ;
} ) ;
2022-02-14 10:27:11 -08:00
* admin_service_post_init . write ( ) . unwrap ( ) =
Some ( admin_rpc_service ::AdminRpcRequestMetadataPostInit {
bank_forks : validator . bank_forks . clone ( ) ,
cluster_info : validator . cluster_info . clone ( ) ,
vote_account ,
2022-12-15 19:24:23 -08:00
repair_whitelist ,
2022-02-14 10:27:11 -08:00
} ) ;
2019-11-04 07:11:40 -08:00
if let Some ( filename ) = init_complete_file {
File ::create ( filename ) . unwrap_or_else ( | _ | {
error! ( " Unable to create: {} " , filename ) ;
exit ( 1 ) ;
} ) ;
}
info! ( " Validator initialized " ) ;
2020-12-10 17:28:52 -08:00
validator . join ( ) ;
2019-11-04 07:11:40 -08:00
info! ( " Validator exiting.. " ) ;
2018-05-23 13:03:19 -07:00
}
2021-05-11 15:06:22 -07:00
fn process_account_indexes ( matches : & ArgMatches ) -> AccountSecondaryIndexes {
let account_indexes : HashSet < AccountIndex > = matches
. values_of ( " account_indexes " )
. unwrap_or_default ( )
. map ( | value | match value {
" program-id " = > AccountIndex ::ProgramId ,
" spl-token-mint " = > AccountIndex ::SplTokenMint ,
" spl-token-owner " = > AccountIndex ::SplTokenOwner ,
_ = > unreachable! ( ) ,
} )
. collect ( ) ;
let account_indexes_include_keys : HashSet < Pubkey > =
values_t! ( matches , " account_index_include_key " , Pubkey )
. unwrap_or_default ( )
. iter ( )
. cloned ( )
. collect ( ) ;
let account_indexes_exclude_keys : HashSet < Pubkey > =
values_t! ( matches , " account_index_exclude_key " , Pubkey )
. unwrap_or_default ( )
. iter ( )
. cloned ( )
. collect ( ) ;
let exclude_keys = ! account_indexes_exclude_keys . is_empty ( ) ;
let include_keys = ! account_indexes_include_keys . is_empty ( ) ;
let keys = if ! account_indexes . is_empty ( ) & & ( exclude_keys | | include_keys ) {
let account_indexes_keys = AccountSecondaryIndexesIncludeExclude {
exclude : exclude_keys ,
keys : if exclude_keys {
account_indexes_exclude_keys
} else {
account_indexes_include_keys
} ,
} ;
Some ( account_indexes_keys )
} else {
None
} ;
AccountSecondaryIndexes {
keys ,
indexes : account_indexes ,
}
}