2019-10-11 13:30:52 -06:00
//! The `validator` module hosts all the validator microservices.
2018-07-02 15:24:40 -07:00
2019-11-04 11:03:39 -07:00
use crate ::{
broadcast_stage ::BroadcastStageType ,
2020-09-09 09:33:14 -06:00
cache_block_time_service ::{ CacheBlockTimeSender , CacheBlockTimeService } ,
2020-12-25 22:31:25 -08:00
cluster_info ::{
ClusterInfo , Node , DEFAULT_CONTACT_DEBUG_INTERVAL_MILLIS ,
DEFAULT_CONTACT_SAVE_INTERVAL_MILLIS ,
} ,
2020-03-09 22:03:09 -07:00
cluster_info_vote_listener ::VoteTracker ,
2020-09-01 22:06:06 -07:00
completed_data_sets_service ::CompletedDataSetsService ,
2020-10-15 18:30:33 +09:00
consensus ::{ reconcile_blockstore_roots_with_tower , Tower } ,
2019-11-04 11:03:39 -07:00
contact_info ::ContactInfo ,
2020-09-18 22:21:44 -07:00
gossip_service ::GossipService ,
2021-02-23 13:06:33 -08:00
max_slots ::MaxSlots ,
2020-09-28 20:43:05 -06:00
optimistically_confirmed_bank_tracker ::{
OptimisticallyConfirmedBank , OptimisticallyConfirmedBankTracker ,
} ,
2020-02-26 13:35:50 -08:00
poh_recorder ::{ PohRecorder , GRACE_TICKS_FACTOR , MAX_GRACE_SLOTS } ,
2020-12-29 12:09:47 -07:00
poh_service ::{ self , PohService } ,
2020-07-14 21:14:48 -06:00
rewards_recorder_service ::{ RewardsRecorderSender , RewardsRecorderService } ,
2019-11-04 11:03:39 -07:00
rpc ::JsonRpcConfig ,
2020-10-01 12:36:58 -07:00
rpc_pubsub_service ::{ PubSubConfig , PubSubService } ,
2019-11-04 11:03:39 -07:00
rpc_service ::JsonRpcService ,
rpc_subscriptions ::RpcSubscriptions ,
2020-09-22 12:26:32 -07:00
sample_performance_service ::SamplePerformanceService ,
2020-01-31 14:23:51 -08:00
serve_repair ::ServeRepair ,
serve_repair_service ::ServeRepairService ,
2019-11-04 11:03:39 -07:00
sigverify ,
2021-01-11 10:21:15 -08:00
snapshot_packager_service ::{ PendingSnapshotPackage , SnapshotPackagerService } ,
2021-02-26 09:15:45 -08:00
tpu ::{ Tpu , DEFAULT_TPU_COALESCE_MS } ,
2019-11-20 16:43:10 -07:00
transaction_status_service ::TransactionStatusService ,
2020-03-16 08:37:31 -07:00
tvu ::{ Sockets , Tvu , TvuConfig } ,
2019-11-04 11:03:39 -07:00
} ;
2020-09-01 22:06:06 -07:00
use crossbeam_channel ::{ bounded , unbounded } ;
2020-06-22 20:27:25 -07:00
use rand ::{ thread_rng , Rng } ;
2019-11-04 11:03:39 -07:00
use solana_ledger ::{
2019-11-04 19:10:06 -07:00
bank_forks_utils ,
2020-09-01 22:06:06 -07:00
blockstore ::{ Blockstore , BlockstoreSignals , CompletedSlotsReceiver , PurgeType } ,
2020-07-06 12:43:45 -07:00
blockstore_db ::BlockstoreRecoveryMode ,
2020-08-07 11:21:35 -07:00
blockstore_processor ::{ self , TransactionStatusSender } ,
2019-12-03 16:31:59 -08:00
leader_schedule ::FixedSchedule ,
2019-11-04 11:03:39 -07:00
leader_schedule_cache ::LeaderScheduleCache ,
2020-12-29 09:35:57 -08:00
poh ::compute_hash_time_ns ,
2019-11-04 11:03:39 -07:00
} ;
2020-07-15 09:37:40 -07:00
use solana_measure ::measure ::Measure ;
2019-06-13 14:37:12 -07:00
use solana_metrics ::datapoint_info ;
2020-06-17 09:27:03 -06:00
use solana_runtime ::{
2020-12-31 18:06:03 -08:00
accounts_index ::AccountIndex ,
2020-06-17 09:27:03 -06:00
bank ::Bank ,
bank_forks ::{ BankForks , SnapshotConfig } ,
2020-06-25 22:06:58 -06:00
commitment ::BlockCommitmentCache ,
2020-06-17 09:27:03 -06:00
hardened_unpack ::{ open_genesis_config , MAX_GENESIS_ARCHIVE_UNPACKED_SIZE } ,
} ;
2019-11-04 11:03:39 -07:00
use solana_sdk ::{
2020-05-14 18:22:47 -07:00
clock ::Slot ,
2020-02-24 19:27:04 -08:00
epoch_schedule ::MAX_LEADER_SCHEDULE_EPOCH_OFFSET ,
2019-11-08 23:56:57 -05:00
genesis_config ::GenesisConfig ,
2020-02-07 09:57:54 -07:00
hash ::Hash ,
2019-11-04 11:03:39 -07:00
pubkey ::Pubkey ,
2020-02-24 10:18:08 -07:00
shred_version ::compute_shred_version ,
2020-02-20 14:28:55 -07:00
signature ::{ Keypair , Signer } ,
2019-11-04 11:03:39 -07:00
timing ::timestamp ,
} ;
2020-06-25 18:24:16 +09:00
use solana_vote_program ::vote_state ::VoteState ;
2020-11-12 14:01:13 -08:00
use std ::time ::Instant ;
2019-11-04 11:03:39 -07:00
use std ::{
2020-02-25 10:41:13 -07:00
collections ::HashSet ,
2021-03-01 13:20:04 -08:00
fmt ,
2020-09-10 08:56:26 -07:00
net ::SocketAddr ,
2020-12-27 13:28:05 +00:00
ops ::Deref ,
2019-11-04 11:03:39 -07:00
path ::{ Path , PathBuf } ,
sync ::atomic ::{ AtomicBool , Ordering } ,
2019-11-21 14:23:40 -07:00
sync ::mpsc ::Receiver ,
2021-01-11 10:21:15 -08:00
sync ::{ Arc , Mutex , RwLock } ,
2020-12-10 17:28:52 -08:00
thread ::sleep ,
2020-01-07 14:18:34 -07:00
time ::Duration ,
2019-11-04 11:03:39 -07:00
} ;
2018-07-02 11:20:35 -07:00
2020-09-18 14:35:20 -07:00
const MAX_COMPLETED_DATA_SETS_IN_CHANNEL : usize = 100_000 ;
2020-09-01 22:06:06 -07:00
2021-03-02 21:21:30 -07:00
#[ derive(Debug) ]
2019-05-23 22:05:16 -07:00
pub struct ValidatorConfig {
2019-08-08 09:14:30 -07:00
pub dev_halt_at_slot : Option < Slot > ,
2019-11-08 23:56:57 -05:00
pub expected_genesis_hash : Option < Hash > ,
2020-06-30 12:43:48 -07:00
pub expected_bank_hash : Option < Hash > ,
2020-01-28 16:56:55 -07:00
pub expected_shred_version : Option < u16 > ,
2019-01-30 17:16:55 -07:00
pub voting_disabled : bool ,
2019-12-05 21:41:29 -05:00
pub account_paths : Vec < PathBuf > ,
2020-12-21 21:33:37 -08:00
pub account_shrink_paths : Option < Vec < PathBuf > > ,
2019-03-03 22:01:09 -08:00
pub rpc_config : JsonRpcConfig ,
2020-12-01 20:25:09 -07:00
pub rpc_addrs : Option < ( SocketAddr , SocketAddr ) > , // (JsonRpc, JsonRpcPubSub)
2020-10-01 12:36:58 -07:00
pub pubsub_config : PubSubConfig ,
2019-07-31 17:58:10 -07:00
pub snapshot_config : Option < SnapshotConfig > ,
2020-03-31 17:21:19 -07:00
pub max_ledger_shreds : Option < u64 > ,
2019-06-19 00:13:19 -07:00
pub broadcast_stage_type : BroadcastStageType ,
2020-01-27 16:49:25 -08:00
pub enable_partition : Option < Arc < AtomicBool > > ,
2020-12-16 17:56:38 -08:00
pub enforce_ulimit_nofile : bool ,
2019-12-03 16:31:59 -08:00
pub fixed_leader_schedule : Option < FixedSchedule > ,
2020-03-02 11:47:58 -07:00
pub wait_for_supermajority : Option < Slot > ,
2020-01-24 18:27:04 -07:00
pub new_hard_forks : Option < Vec < Slot > > ,
2020-02-25 10:41:13 -07:00
pub trusted_validators : Option < HashSet < Pubkey > > , // None = trust all
2020-08-21 00:35:11 -07:00
pub repair_validators : Option < HashSet < Pubkey > > , // None = repair from all
2020-09-11 12:00:16 -07:00
pub gossip_validators : Option < HashSet < Pubkey > > , // None = gossip with all
2020-03-16 08:37:31 -07:00
pub halt_on_trusted_validators_accounts_hash_mismatch : bool ,
pub accounts_hash_fault_injection_slots : u64 , // 0 = no fault injection
2020-03-22 11:10:04 -07:00
pub frozen_accounts : Vec < Pubkey > ,
2020-03-23 08:42:32 -07:00
pub no_rocksdb_compaction : bool ,
2021-02-14 10:16:30 -08:00
pub rocksdb_compaction_interval : Option < u64 > ,
pub rocksdb_max_compaction_jitter : Option < u64 > ,
2020-04-16 15:12:20 -07:00
pub accounts_hash_interval_slots : u64 ,
2020-04-30 10:53:34 +09:00
pub max_genesis_archive_unpacked_size : u64 ,
2020-07-06 12:43:45 -07:00
pub wal_recovery_mode : Option < BlockstoreRecoveryMode > ,
2020-09-18 14:35:20 -07:00
pub poh_verify : bool , // Perform PoH verification during blockstore processing at boo
pub cuda : bool ,
2020-09-19 14:03:54 +09:00
pub require_tower : bool ,
2020-09-23 18:46:42 -07:00
pub debug_keys : Option < Arc < HashSet < Pubkey > > > ,
2020-11-20 14:47:37 -08:00
pub contact_debug_interval : u64 ,
2020-12-25 22:31:25 -08:00
pub contact_save_interval : u64 ,
2020-12-07 09:49:55 +01:00
pub bpf_jit : bool ,
2020-12-17 14:37:22 -08:00
pub send_transaction_retry_ms : u64 ,
pub send_transaction_leader_forward_count : u64 ,
2020-12-29 09:35:57 -08:00
pub no_poh_speed_test : bool ,
2020-12-29 12:09:47 -07:00
pub poh_pinned_cpu_core : usize ,
2020-12-31 18:06:03 -08:00
pub account_indexes : HashSet < AccountIndex > ,
2021-01-11 17:00:23 -08:00
pub accounts_db_caching_enabled : bool ,
2021-01-21 18:34:51 -08:00
pub warp_slot : Option < Slot > ,
2021-02-04 09:00:33 -06:00
pub accounts_db_test_hash_calculation : bool ,
2021-02-16 15:13:48 -06:00
pub accounts_db_use_index_hash_calculation : bool ,
2021-02-26 09:15:45 -08:00
pub tpu_coalesce_ms : u64 ,
2021-03-01 13:20:04 -08:00
pub validator_exit : Arc < RwLock < ValidatorExit > > ,
2019-01-29 08:51:01 -08:00
}
2019-06-19 00:13:19 -07:00
2019-05-23 22:05:16 -07:00
impl Default for ValidatorConfig {
2019-01-29 08:51:01 -08:00
fn default ( ) -> Self {
Self {
2019-08-08 09:14:30 -07:00
dev_halt_at_slot : None ,
2019-11-08 23:56:57 -05:00
expected_genesis_hash : None ,
2020-06-30 12:43:48 -07:00
expected_bank_hash : None ,
2020-01-28 16:56:55 -07:00
expected_shred_version : None ,
2019-01-30 17:16:55 -07:00
voting_disabled : false ,
2020-03-31 17:21:19 -07:00
max_ledger_shreds : None ,
2019-12-05 21:41:29 -05:00
account_paths : Vec ::new ( ) ,
2020-12-21 21:33:37 -08:00
account_shrink_paths : None ,
2019-03-03 22:01:09 -08:00
rpc_config : JsonRpcConfig ::default ( ) ,
2020-09-10 08:56:26 -07:00
rpc_addrs : None ,
2020-10-01 12:36:58 -07:00
pubsub_config : PubSubConfig ::default ( ) ,
2019-07-31 17:58:10 -07:00
snapshot_config : None ,
2019-06-19 00:13:19 -07:00
broadcast_stage_type : BroadcastStageType ::Standard ,
2020-01-27 16:49:25 -08:00
enable_partition : None ,
2020-12-16 17:56:38 -08:00
enforce_ulimit_nofile : true ,
2019-12-03 16:31:59 -08:00
fixed_leader_schedule : None ,
2020-03-02 11:47:58 -07:00
wait_for_supermajority : None ,
2020-01-24 18:27:04 -07:00
new_hard_forks : None ,
2020-02-25 10:41:13 -07:00
trusted_validators : None ,
2020-08-21 00:35:11 -07:00
repair_validators : None ,
2020-09-11 12:00:16 -07:00
gossip_validators : None ,
2020-03-16 08:37:31 -07:00
halt_on_trusted_validators_accounts_hash_mismatch : false ,
accounts_hash_fault_injection_slots : 0 ,
2020-03-22 11:10:04 -07:00
frozen_accounts : vec ! [ ] ,
2020-03-23 08:42:32 -07:00
no_rocksdb_compaction : false ,
2021-02-14 10:16:30 -08:00
rocksdb_compaction_interval : None ,
rocksdb_max_compaction_jitter : None ,
2020-04-16 15:12:20 -07:00
accounts_hash_interval_slots : std ::u64 ::MAX ,
2020-04-30 10:53:34 +09:00
max_genesis_archive_unpacked_size : MAX_GENESIS_ARCHIVE_UNPACKED_SIZE ,
2020-07-06 12:43:45 -07:00
wal_recovery_mode : None ,
2020-09-18 14:35:20 -07:00
poh_verify : true ,
cuda : false ,
2020-09-19 14:03:54 +09:00
require_tower : false ,
2020-09-23 18:46:42 -07:00
debug_keys : None ,
2020-12-25 22:31:25 -08:00
contact_debug_interval : DEFAULT_CONTACT_DEBUG_INTERVAL_MILLIS ,
contact_save_interval : DEFAULT_CONTACT_SAVE_INTERVAL_MILLIS ,
2020-12-07 09:49:55 +01:00
bpf_jit : false ,
2020-12-17 14:37:22 -08:00
send_transaction_retry_ms : 2000 ,
send_transaction_leader_forward_count : 2 ,
2020-12-29 09:35:57 -08:00
no_poh_speed_test : true ,
2020-12-29 12:09:47 -07:00
poh_pinned_cpu_core : poh_service ::DEFAULT_PINNED_CPU_CORE ,
2020-12-31 18:06:03 -08:00
account_indexes : HashSet ::new ( ) ,
2021-01-11 17:00:23 -08:00
accounts_db_caching_enabled : false ,
2021-01-21 18:34:51 -08:00
warp_slot : None ,
2021-02-04 09:00:33 -06:00
accounts_db_test_hash_calculation : false ,
2021-02-16 15:13:48 -06:00
accounts_db_use_index_hash_calculation : true ,
2021-02-26 09:15:45 -08:00
tpu_coalesce_ms : DEFAULT_TPU_COALESCE_MS ,
2021-03-01 13:20:04 -08:00
validator_exit : Arc ::new ( RwLock ::new ( ValidatorExit ::default ( ) ) ) ,
2019-01-29 08:51:01 -08:00
}
}
}
2019-08-20 23:59:31 -07:00
#[ derive(Default) ]
pub struct ValidatorExit {
2021-02-26 21:42:09 -08:00
exited : bool ,
2019-08-23 08:55:51 -07:00
exits : Vec < Box < dyn FnOnce ( ) + Send + Sync > > ,
2019-08-20 23:59:31 -07:00
}
impl ValidatorExit {
2020-06-09 01:38:14 +01:00
pub fn register_exit ( & mut self , exit : Box < dyn FnOnce ( ) + Send + Sync > ) {
2021-02-26 21:42:09 -08:00
if self . exited {
exit ( ) ;
} else {
self . exits . push ( exit ) ;
}
2019-08-20 23:59:31 -07:00
}
2021-03-01 13:20:04 -08:00
pub fn exit ( & mut self ) {
2021-02-26 21:42:09 -08:00
self . exited = true ;
2021-03-01 13:20:04 -08:00
for exit in self . exits . drain ( .. ) {
2019-08-20 23:59:31 -07:00
exit ( ) ;
}
}
}
2021-03-01 13:20:04 -08:00
impl fmt ::Debug for ValidatorExit {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
write! ( f , " {} exits " , self . exits . len ( ) )
}
}
2020-07-14 21:14:48 -06:00
#[ derive(Default) ]
struct TransactionHistoryServices {
transaction_status_sender : Option < TransactionStatusSender > ,
transaction_status_service : Option < TransactionStatusService > ,
rewards_recorder_sender : Option < RewardsRecorderSender > ,
rewards_recorder_service : Option < RewardsRecorderService > ,
2020-09-09 09:33:14 -06:00
cache_block_time_sender : Option < CacheBlockTimeSender > ,
cache_block_time_service : Option < CacheBlockTimeService > ,
2020-07-14 21:14:48 -06:00
}
2019-05-23 22:05:16 -07:00
pub struct Validator {
2019-03-03 16:44:06 -08:00
pub id : Pubkey ,
2021-03-01 13:20:04 -08:00
validator_exit : Arc < RwLock < ValidatorExit > > ,
2021-02-26 21:42:09 -08:00
json_rpc_service : Option < JsonRpcService > ,
pubsub_service : Option < PubSubService > ,
optimistically_confirmed_bank_tracker : Option < OptimisticallyConfirmedBankTracker > ,
2019-11-20 16:43:10 -07:00
transaction_status_service : Option < TransactionStatusService > ,
2020-02-04 19:50:24 -07:00
rewards_recorder_service : Option < RewardsRecorderService > ,
2020-09-09 09:33:14 -06:00
cache_block_time_service : Option < CacheBlockTimeService > ,
2020-09-22 12:26:32 -07:00
sample_performance_service : Option < SamplePerformanceService > ,
2018-12-06 13:52:47 -07:00
gossip_service : GossipService ,
2020-01-31 14:23:51 -08:00
serve_repair_service : ServeRepairService ,
2020-09-01 22:06:06 -07:00
completed_data_sets_service : CompletedDataSetsService ,
2020-03-05 23:52:31 -07:00
snapshot_packager_service : Option < SnapshotPackagerService > ,
2019-02-26 10:48:18 -08:00
poh_recorder : Arc < Mutex < PohRecorder > > ,
2019-03-04 19:02:03 -08:00
poh_service : PohService ,
tpu : Tpu ,
tvu : Tvu ,
2019-11-13 05:37:13 +09:00
ip_echo_server : solana_net_utils ::IpEchoServer ,
2018-07-02 15:24:40 -07:00
}
2018-07-02 11:20:35 -07:00
2020-12-08 01:43:03 +09:00
// in the distant future, get rid of ::new()/exit() and use Result properly...
2021-01-21 18:34:51 -08:00
pub ( crate ) fn abort ( ) -> ! {
2020-12-08 01:43:03 +09:00
#[ cfg(not(test)) ]
2021-01-21 18:34:51 -08:00
{
// standard error is usually redirected to a log file, cry for help on standard output as
// well
println! ( " Validator process aborted. The validator log may contain further details " ) ;
std ::process ::exit ( 1 ) ;
}
2020-12-08 01:43:03 +09:00
#[ cfg(test) ]
panic! ( " process::exit(1) is intercepted for friendly test failure... " ) ;
}
2019-05-23 22:05:16 -07:00
impl Validator {
2019-05-20 13:32:32 -07:00
pub fn new (
2019-01-29 18:12:32 -08:00
mut node : Node ,
2020-09-18 14:35:20 -07:00
identity_keypair : & Arc < Keypair > ,
2019-07-30 15:53:41 -07:00
ledger_path : & Path ,
2019-03-09 19:28:43 -08:00
vote_account : & Pubkey ,
2020-03-31 08:23:42 -07:00
mut authorized_voter_keypairs : Vec < Arc < Keypair > > ,
2020-12-18 10:54:48 -08:00
cluster_entrypoints : Vec < ContactInfo > ,
2019-05-23 22:05:16 -07:00
config : & ValidatorConfig ,
2021-02-03 16:26:17 +00:00
should_check_duplicate_instance : bool ,
2019-05-20 13:32:32 -07:00
) -> Self {
2020-09-18 14:35:20 -07:00
let id = identity_keypair . pubkey ( ) ;
2019-08-08 15:38:23 -07:00
assert_eq! ( id , node . info . id ) ;
2020-03-13 11:41:18 -07:00
warn! ( " identity: {} " , id ) ;
warn! ( " vote account: {} " , vote_account ) ;
2020-03-31 08:23:42 -07:00
if config . voting_disabled {
warn! ( " voting disabled " ) ;
authorized_voter_keypairs . clear ( ) ;
} else {
for authorized_voter_keypair in & authorized_voter_keypairs {
warn! ( " authorized voter: {} " , authorized_voter_keypair . pubkey ( ) ) ;
}
}
2020-01-07 14:33:39 -07:00
report_target_features ( ) ;
2019-11-04 11:03:39 -07:00
2020-12-18 10:54:48 -08:00
for cluster_entrypoint in & cluster_entrypoints {
info! ( " entrypoint: {:?} " , cluster_entrypoint ) ;
}
2019-09-14 12:32:57 -07:00
2020-06-16 23:03:26 -07:00
if solana_perf ::perf_libs ::api ( ) . is_some ( ) {
info! ( " Initializing sigverify, this could take a while... " ) ;
} else {
info! ( " Initializing sigverify... " ) ;
}
2019-09-14 12:32:57 -07:00
sigverify ::init ( ) ;
info! ( " Done. " ) ;
2019-02-06 19:21:31 -08:00
2020-09-18 14:35:20 -07:00
if ! ledger_path . is_dir ( ) {
error! (
" ledger directory does not exist or is not accessible: {:?} " ,
ledger_path
) ;
2020-12-08 01:43:03 +09:00
abort ( ) ;
2020-09-18 14:35:20 -07:00
}
2020-06-23 14:29:07 -07:00
if let Some ( shred_version ) = config . expected_shred_version {
if let Some ( wait_for_supermajority_slot ) = config . wait_for_supermajority {
backup_and_clear_blockstore (
ledger_path ,
wait_for_supermajority_slot + 1 ,
shred_version ,
) ;
}
}
2020-07-15 09:37:40 -07:00
info! ( " Cleaning accounts paths.. " ) ;
let mut start = Measure ::start ( " clean_accounts_paths " ) ;
2020-07-07 09:41:45 -07:00
for accounts_path in & config . account_paths {
cleanup_accounts_path ( accounts_path ) ;
}
2020-12-21 21:33:37 -08:00
if let Some ( ref shrink_paths ) = config . account_shrink_paths {
for accounts_path in shrink_paths {
cleanup_accounts_path ( accounts_path ) ;
}
}
2020-07-15 09:37:40 -07:00
start . stop ( ) ;
info! ( " done. {} " , start ) ;
2020-07-07 09:41:45 -07:00
2020-07-14 21:14:48 -06:00
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
2021-03-01 13:20:04 -08:00
{
let exit = exit . clone ( ) ;
config
. validator_exit
. write ( )
. unwrap ( )
. register_exit ( Box ::new ( move | | exit . store ( true , Ordering ::Relaxed ) ) ) ;
}
2020-07-14 21:14:48 -06:00
2020-08-07 11:21:35 -07:00
let ( replay_vote_sender , replay_vote_receiver ) = unbounded ( ) ;
2019-05-09 14:10:04 -07:00
let (
2020-02-20 19:53:26 -07:00
genesis_config ,
2019-05-09 14:10:04 -07:00
bank_forks ,
2020-01-13 14:13:52 -07:00
blockstore ,
2019-05-09 14:10:04 -07:00
ledger_signal_receiver ,
completed_slots_receiver ,
leader_schedule_cache ,
2020-02-20 19:53:26 -07:00
snapshot_hash ,
2020-07-14 21:14:48 -06:00
TransactionHistoryServices {
transaction_status_sender ,
transaction_status_service ,
rewards_recorder_sender ,
rewards_recorder_service ,
2020-09-09 09:33:14 -06:00
cache_block_time_sender ,
cache_block_time_service ,
2020-07-14 21:14:48 -06:00
} ,
2020-09-19 14:03:54 +09:00
tower ,
2020-09-18 14:35:20 -07:00
) = new_banks_from_ledger (
& id ,
vote_account ,
config ,
ledger_path ,
config . poh_verify ,
& exit ,
2020-12-16 17:56:38 -08:00
config . enforce_ulimit_nofile ,
2020-09-18 14:35:20 -07:00
) ;
2019-02-20 17:05:57 -08:00
2019-04-19 02:39:44 -07:00
let leader_schedule_cache = Arc ::new ( leader_schedule_cache ) ;
2020-05-06 08:24:59 -07:00
let bank = bank_forks . working_bank ( ) ;
2020-12-21 21:33:37 -08:00
if let Some ( ref shrink_paths ) = config . account_shrink_paths {
bank . set_shrink_paths ( shrink_paths . clone ( ) ) ;
}
2020-05-06 08:24:59 -07:00
let bank_forks = Arc ::new ( RwLock ::new ( bank_forks ) ) ;
2020-01-27 18:05:31 -07:00
2020-09-22 12:26:32 -07:00
let sample_performance_service =
if config . rpc_addrs . is_some ( ) & & config . rpc_config . enable_rpc_transaction_history {
Some ( SamplePerformanceService ::new (
& bank_forks ,
& blockstore ,
& exit ,
) )
} else {
None
} ;
2020-06-25 18:24:16 +09:00
info! ( " Starting validator with working bank slot {} " , bank . slot ( ) ) ;
2020-01-27 18:05:31 -07:00
{
let hard_forks : Vec < _ > = bank . hard_forks ( ) . read ( ) . unwrap ( ) . iter ( ) . copied ( ) . collect ( ) ;
if ! hard_forks . is_empty ( ) {
info! ( " Hard forks: {:?} " , hard_forks ) ;
}
}
2018-11-15 13:23:26 -08:00
node . info . wallclock = timestamp ( ) ;
2020-02-20 19:53:26 -07:00
node . info . shred_version = compute_shred_version (
& genesis_config . hash ( ) ,
Some ( & bank . hard_forks ( ) . read ( ) . unwrap ( ) ) ,
) ;
2020-06-25 18:24:16 +09:00
2020-01-13 15:59:31 -07:00
Self ::print_node_info ( & node ) ;
2020-01-28 16:56:55 -07:00
if let Some ( expected_shred_version ) = config . expected_shred_version {
if expected_shred_version ! = node . info . shred_version {
error! (
2020-06-30 12:43:48 -07:00
" shred version mismatch: expected {} found: {} " ,
expected_shred_version , node . info . shred_version ,
2020-01-28 16:56:55 -07:00
) ;
2020-12-08 01:43:03 +09:00
abort ( ) ;
2020-01-28 16:56:55 -07:00
}
}
2020-11-20 14:47:37 -08:00
let mut cluster_info = ClusterInfo ::new ( node . info . clone ( ) , identity_keypair . clone ( ) ) ;
cluster_info . set_contact_debug_interval ( config . contact_debug_interval ) ;
2020-12-25 22:31:25 -08:00
cluster_info . set_entrypoints ( cluster_entrypoints ) ;
cluster_info . restore_contact_info ( ledger_path , config . contact_save_interval ) ;
2020-11-20 14:47:37 -08:00
let cluster_info = Arc ::new ( cluster_info ) ;
2020-07-23 11:44:57 -06:00
let mut block_commitment_cache = BlockCommitmentCache ::default ( ) ;
block_commitment_cache . initialize_slots ( bank . slot ( ) ) ;
let block_commitment_cache = Arc ::new ( RwLock ::new ( block_commitment_cache ) ) ;
2019-11-11 13:18:34 -05:00
2020-09-28 20:43:05 -06:00
let optimistically_confirmed_bank =
OptimisticallyConfirmedBank ::locked_from_bank_forks_root ( & bank_forks ) ;
2020-11-14 09:29:51 -08:00
let subscriptions = Arc ::new ( RpcSubscriptions ::new_with_vote_subscription (
2020-05-07 00:23:06 -06:00
& exit ,
bank_forks . clone ( ) ,
block_commitment_cache . clone ( ) ,
2020-09-28 20:43:05 -06:00
optimistically_confirmed_bank . clone ( ) ,
2020-11-14 09:29:51 -08:00
config . pubsub_config . enable_vote_subscription ,
2020-05-07 00:23:06 -06:00
) ) ;
2020-01-30 10:17:01 -07:00
2021-02-23 13:06:33 -08:00
let max_slots = Arc ::new ( MaxSlots ::default ( ) ) ;
2020-09-01 22:06:06 -07:00
let ( completed_data_sets_sender , completed_data_sets_receiver ) =
bounded ( MAX_COMPLETED_DATA_SETS_IN_CHANNEL ) ;
let completed_data_sets_service = CompletedDataSetsService ::new (
completed_data_sets_receiver ,
blockstore . clone ( ) ,
subscriptions . clone ( ) ,
& exit ,
2021-02-23 13:06:33 -08:00
max_slots . clone ( ) ,
2020-09-01 22:06:06 -07:00
) ;
2019-08-16 16:20:20 -07:00
info! (
" Starting PoH: epoch={} slot={} tick_height={} blockhash={} leader={:?} " ,
bank . epoch ( ) ,
bank . slot ( ) ,
bank . tick_height ( ) ,
bank . last_blockhash ( ) ,
leader_schedule_cache . slot_leader_at ( bank . slot ( ) , Some ( & bank ) )
) ;
2020-09-08 02:00:49 -07:00
let poh_config = Arc ::new ( genesis_config . poh_config . clone ( ) ) ;
2019-08-08 09:14:30 -07:00
let ( mut poh_recorder , entry_receiver ) = PohRecorder ::new_with_clear_signal (
bank . tick_height ( ) ,
bank . last_blockhash ( ) ,
bank . slot ( ) ,
2020-02-26 13:35:50 -08:00
leader_schedule_cache . next_leader_slot (
& id ,
bank . slot ( ) ,
& bank ,
Some ( & blockstore ) ,
GRACE_TICKS_FACTOR * MAX_GRACE_SLOTS ,
) ,
2019-08-08 09:14:30 -07:00
bank . ticks_per_slot ( ) ,
& id ,
2020-01-13 14:13:52 -07:00
& blockstore ,
blockstore . new_shreds_signals . first ( ) . cloned ( ) ,
2019-08-08 09:14:30 -07:00
& leader_schedule_cache ,
& poh_config ,
) ;
if config . snapshot_config . is_some ( ) {
poh_recorder . set_bank ( & bank ) ;
}
let poh_recorder = Arc ::new ( Mutex ::new ( poh_recorder ) ) ;
2020-09-08 02:00:49 -07:00
let rpc_override_health_check = Arc ::new ( AtomicBool ::new ( false ) ) ;
2021-02-26 21:42:09 -08:00
let (
json_rpc_service ,
pubsub_service ,
optimistically_confirmed_bank_tracker ,
bank_notification_sender ,
) = if let Some ( ( rpc_addr , rpc_pubsub_addr ) ) = config . rpc_addrs {
2020-12-01 20:25:09 -07:00
if ContactInfo ::is_valid_address ( & node . info . rpc ) {
assert! ( ContactInfo ::is_valid_address ( & node . info . rpc_pubsub ) ) ;
2020-09-28 20:43:05 -06:00
} else {
2020-12-01 20:25:09 -07:00
assert! ( ! ContactInfo ::is_valid_address ( & node . info . rpc_pubsub ) ) ;
}
let ( bank_notification_sender , bank_notification_receiver ) = unbounded ( ) ;
(
2021-02-26 21:42:09 -08:00
Some ( JsonRpcService ::new (
rpc_addr ,
config . rpc_config . clone ( ) ,
config . snapshot_config . clone ( ) ,
bank_forks . clone ( ) ,
block_commitment_cache . clone ( ) ,
blockstore . clone ( ) ,
cluster_info . clone ( ) ,
Some ( poh_recorder . clone ( ) ) ,
genesis_config . hash ( ) ,
ledger_path ,
config . validator_exit . clone ( ) ,
config . trusted_validators . clone ( ) ,
rpc_override_health_check . clone ( ) ,
optimistically_confirmed_bank . clone ( ) ,
config . send_transaction_retry_ms ,
config . send_transaction_leader_forward_count ,
max_slots . clone ( ) ,
) ) ,
if config . rpc_config . minimal_api {
None
} else {
Some ( PubSubService ::new (
2020-12-01 20:25:09 -07:00
config . pubsub_config . clone ( ) ,
& subscriptions ,
rpc_pubsub_addr ,
& exit ,
2021-02-26 21:42:09 -08:00
) )
} ,
Some ( OptimisticallyConfirmedBankTracker ::new (
bank_notification_receiver ,
& exit ,
bank_forks . clone ( ) ,
optimistically_confirmed_bank ,
subscriptions . clone ( ) ,
) ) ,
2020-12-01 20:25:09 -07:00
Some ( bank_notification_sender ) ,
)
} else {
2021-02-26 21:42:09 -08:00
( None , None , None , None )
2020-12-01 20:25:09 -07:00
} ;
2020-09-08 02:00:49 -07:00
2020-10-19 15:16:13 -06:00
if config . dev_halt_at_slot . is_some ( ) {
2021-01-26 12:23:07 -07:00
// Simulate a confirmed root to avoid RPC errors with CommitmentConfig::finalized() and
2020-10-19 15:16:13 -06:00
// to ensure RPC endpoints like getConfirmedBlock, which require a confirmed root, work
block_commitment_cache
. write ( )
. unwrap ( )
. set_highest_confirmed_root ( bank_forks . read ( ) . unwrap ( ) . root ( ) ) ;
// Park with the RPC service running, ready for inspection!
warn! ( " Validator halted " ) ;
std ::thread ::park ( ) ;
}
2019-11-13 05:37:13 +09:00
let ip_echo_server = solana_net_utils ::ip_echo_server ( node . sockets . ip_echo . unwrap ( ) ) ;
2019-08-08 09:14:30 -07:00
2018-12-06 13:52:47 -07:00
let gossip_service = GossipService ::new (
2018-10-08 20:55:54 -06:00
& cluster_info ,
2019-02-20 21:36:08 -08:00
Some ( bank_forks . clone ( ) ) ,
2018-08-22 19:00:56 -06:00
node . sockets . gossip ,
2020-09-11 12:00:16 -07:00
config . gossip_validators . clone ( ) ,
2021-02-03 16:26:17 +00:00
should_check_duplicate_instance ,
2019-03-04 16:33:14 -08:00
& exit ,
2018-09-02 23:23:43 -10:00
) ;
2020-01-31 14:23:51 -08:00
let serve_repair = Arc ::new ( RwLock ::new ( ServeRepair ::new ( cluster_info . clone ( ) ) ) ) ;
let serve_repair_service = ServeRepairService ::new (
& serve_repair ,
Some ( blockstore . clone ( ) ) ,
node . sockets . serve_repair ,
& exit ,
) ;
2021-01-11 10:21:15 -08:00
let ( snapshot_packager_service , snapshot_config_and_pending_package ) =
2020-09-28 16:04:46 -07:00
if let Some ( snapshot_config ) = config . snapshot_config . clone ( ) {
2020-12-08 23:18:27 -08:00
if is_snapshot_config_invalid (
snapshot_config . snapshot_interval_slots ,
config . accounts_hash_interval_slots ,
) {
error! ( " Snapshot config is invalid " ) ;
}
2020-03-05 23:52:31 -07:00
// Start a snapshot packaging service
2021-01-11 10:21:15 -08:00
let pending_snapshot_package = PendingSnapshotPackage ::default ( ) ;
let snapshot_packager_service = SnapshotPackagerService ::new (
pending_snapshot_package . clone ( ) ,
snapshot_hash ,
& exit ,
& cluster_info ,
) ;
2020-09-28 16:04:46 -07:00
(
Some ( snapshot_packager_service ) ,
2021-01-11 10:21:15 -08:00
Some ( ( snapshot_config , pending_snapshot_package ) ) ,
2020-09-28 16:04:46 -07:00
)
2020-03-05 23:52:31 -07:00
} else {
( None , None )
} ;
2020-12-29 09:35:57 -08:00
if ! config . no_poh_speed_test {
check_poh_speed ( & genesis_config , None ) ;
}
2020-06-30 12:43:48 -07:00
if wait_for_supermajority ( config , & bank , & cluster_info , rpc_override_health_check ) {
2020-12-08 01:43:03 +09:00
abort ( ) ;
2020-06-30 12:43:48 -07:00
}
2018-12-03 00:10:43 -08:00
2020-12-29 09:35:57 -08:00
let poh_service = PohService ::new (
poh_recorder . clone ( ) ,
& poh_config ,
& exit ,
bank . ticks_per_slot ( ) ,
2020-12-29 12:09:47 -07:00
config . poh_pinned_cpu_core ,
2020-12-29 09:35:57 -08:00
) ;
2020-01-07 14:18:34 -07:00
assert_eq! (
2020-01-13 14:13:52 -07:00
blockstore . new_shreds_signals . len ( ) ,
2020-01-07 14:18:34 -07:00
1 ,
" New shred signal for the TVU should be the same as the clear bank signal. "
) ;
2020-12-27 13:28:05 +00:00
let vote_tracker = Arc ::new ( VoteTracker ::new (
bank_forks . read ( ) . unwrap ( ) . root_bank ( ) . deref ( ) ,
) ) ;
2020-03-09 22:03:09 -07:00
2020-03-19 23:35:01 -07:00
let ( retransmit_slots_sender , retransmit_slots_receiver ) = unbounded ( ) ;
2020-07-09 23:52:54 -06:00
let ( verified_vote_sender , verified_vote_receiver ) = unbounded ( ) ;
2019-02-11 17:56:52 -08:00
let tvu = Tvu ::new (
2019-03-08 18:29:08 -08:00
vote_account ,
2020-03-31 08:23:42 -07:00
authorized_voter_keypairs ,
2019-02-21 11:19:45 -08:00
& bank_forks ,
2019-01-26 13:58:08 +05:30
& cluster_info ,
2020-01-30 10:26:27 -07:00
Sockets {
repair : node
. sockets
. repair
. try_clone ( )
. expect ( " Failed to clone repair socket " ) ,
retransmit : node
. sockets
. retransmit_sockets
. iter ( )
. map ( | s | s . try_clone ( ) . expect ( " Failed to clone retransmit socket " ) )
. collect ( ) ,
fetch : node
. sockets
. tvu
. iter ( )
. map ( | s | s . try_clone ( ) . expect ( " Failed to clone TVU Sockets " ) )
. collect ( ) ,
forwards : node
. sockets
. tvu_forwards
. iter ( )
. map ( | s | s . try_clone ( ) . expect ( " Failed to clone TVU forwards Sockets " ) )
. collect ( ) ,
} ,
2020-01-13 14:13:52 -07:00
blockstore . clone ( ) ,
2019-02-04 15:33:43 -08:00
ledger_signal_receiver ,
2019-02-18 19:08:54 -07:00
& subscriptions ,
2019-03-03 16:44:06 -08:00
& poh_recorder ,
2020-09-19 14:03:54 +09:00
tower ,
2019-04-19 02:39:44 -07:00
& leader_schedule_cache ,
2019-03-04 16:33:14 -08:00
& exit ,
2019-05-09 14:10:04 -07:00
completed_slots_receiver ,
2019-11-04 16:44:27 -07:00
block_commitment_cache ,
2020-01-27 16:49:25 -08:00
config . enable_partition . clone ( ) ,
2019-11-20 16:43:10 -07:00
transaction_status_sender . clone ( ) ,
2020-02-11 18:01:49 -07:00
rewards_recorder_sender ,
2020-09-09 09:33:14 -06:00
cache_block_time_sender ,
2021-01-11 10:21:15 -08:00
snapshot_config_and_pending_package ,
2020-03-09 22:03:09 -07:00
vote_tracker . clone ( ) ,
2020-03-19 23:35:01 -07:00
retransmit_slots_sender ,
2020-07-09 23:52:54 -06:00
verified_vote_receiver ,
2020-08-07 11:21:35 -07:00
replay_vote_sender . clone ( ) ,
2020-09-01 22:06:06 -07:00
completed_data_sets_sender ,
2020-09-28 20:43:05 -06:00
bank_notification_sender . clone ( ) ,
2020-03-16 08:37:31 -07:00
TvuConfig {
2020-03-31 17:21:19 -07:00
max_ledger_shreds : config . max_ledger_shreds ,
2020-03-16 08:37:31 -07:00
halt_on_trusted_validators_accounts_hash_mismatch : config
. halt_on_trusted_validators_accounts_hash_mismatch ,
shred_version : node . info . shred_version ,
trusted_validators : config . trusted_validators . clone ( ) ,
2020-08-21 00:35:11 -07:00
repair_validators : config . repair_validators . clone ( ) ,
2020-03-16 08:37:31 -07:00
accounts_hash_fault_injection_slots : config . accounts_hash_fault_injection_slots ,
2021-01-11 17:00:23 -08:00
accounts_db_caching_enabled : config . accounts_db_caching_enabled ,
2021-02-04 09:00:33 -06:00
test_hash_calculation : config . accounts_db_test_hash_calculation ,
2021-02-16 15:13:48 -06:00
use_index_hash_calculation : config . accounts_db_use_index_hash_calculation ,
2021-02-14 10:16:30 -08:00
rocksdb_compaction_interval : config . rocksdb_compaction_interval ,
rocksdb_max_compaction_jitter : config . rocksdb_compaction_interval ,
2020-03-16 08:37:31 -07:00
} ,
2021-02-23 13:06:33 -08:00
& max_slots ,
2019-03-03 16:44:06 -08:00
) ;
2019-04-19 14:18:19 -07:00
2019-03-03 16:44:06 -08:00
let tpu = Tpu ::new (
& cluster_info ,
& poh_recorder ,
entry_receiver ,
2020-03-19 23:35:01 -07:00
retransmit_slots_receiver ,
2019-03-03 16:44:06 -08:00
node . sockets . tpu ,
2019-07-30 14:50:02 -07:00
node . sockets . tpu_forwards ,
2019-03-03 16:44:06 -08:00
node . sockets . broadcast ,
2020-05-17 22:01:08 +01:00
& subscriptions ,
2019-11-20 16:43:10 -07:00
transaction_status_sender ,
2020-01-13 14:13:52 -07:00
& blockstore ,
2019-06-19 00:13:19 -07:00
& config . broadcast_stage_type ,
2019-03-04 16:33:14 -08:00
& exit ,
2020-01-13 15:59:31 -07:00
node . info . shred_version ,
2020-03-09 22:03:09 -07:00
vote_tracker ,
bank_forks ,
2020-07-09 23:52:54 -06:00
verified_vote_sender ,
2020-08-07 11:21:35 -07:00
replay_vote_receiver ,
replay_vote_sender ,
2020-09-28 20:43:05 -06:00
bank_notification_sender ,
2021-02-26 09:15:45 -08:00
config . tpu_coalesce_ms ,
2019-01-26 13:58:08 +05:30
) ;
2018-12-12 12:38:00 -08:00
2019-07-30 16:18:33 -04:00
datapoint_info! ( " validator-new " , ( " id " , id . to_string ( ) , String ) ) ;
2019-02-21 11:37:48 -08:00
Self {
2019-01-30 20:02:35 -07:00
id ,
2018-12-06 13:52:47 -07:00
gossip_service ,
2020-01-31 14:23:51 -08:00
serve_repair_service ,
2021-02-26 21:42:09 -08:00
json_rpc_service ,
pubsub_service ,
optimistically_confirmed_bank_tracker ,
2019-11-20 16:43:10 -07:00
transaction_status_service ,
2020-02-04 19:50:24 -07:00
rewards_recorder_service ,
2020-09-09 09:33:14 -06:00
cache_block_time_service ,
2020-09-22 12:26:32 -07:00
sample_performance_service ,
2020-03-05 23:52:31 -07:00
snapshot_packager_service ,
2020-09-01 22:06:06 -07:00
completed_data_sets_service ,
2019-03-04 19:02:03 -08:00
tpu ,
tvu ,
2019-02-26 10:48:18 -08:00
poh_service ,
poh_recorder ,
2019-05-03 11:01:35 -07:00
ip_echo_server ,
2021-03-01 13:20:04 -08:00
validator_exit : config . validator_exit . clone ( ) ,
2019-02-01 18:09:38 -08:00
}
}
2019-01-28 20:10:38 -08:00
// Used for notifying many nodes in parallel to exit
2019-08-20 23:59:31 -07:00
pub fn exit ( & mut self ) {
2021-03-01 13:20:04 -08:00
self . validator_exit . write ( ) . unwrap ( ) . exit ( ) ;
2018-07-16 22:22:29 -07:00
}
2018-09-13 14:00:17 -07:00
2020-12-10 17:28:52 -08:00
pub fn close ( mut self ) {
2018-07-17 08:18:42 -07:00
self . exit ( ) ;
2020-12-10 17:28:52 -08:00
self . join ( ) ;
2018-07-02 15:24:40 -07:00
}
2019-09-14 12:32:57 -07:00
fn print_node_info ( node : & Node ) {
info! ( " {:?} " , node . info ) ;
info! (
" local gossip address: {} " ,
node . sockets . gossip . local_addr ( ) . unwrap ( )
) ;
info! (
" local broadcast address: {} " ,
2019-12-16 17:11:18 -08:00
node . sockets
. broadcast
. first ( )
. unwrap ( )
. local_addr ( )
. unwrap ( )
2019-09-14 12:32:57 -07:00
) ;
info! (
" local repair address: {} " ,
node . sockets . repair . local_addr ( ) . unwrap ( )
) ;
info! (
" local retransmit address: {} " ,
2019-10-10 13:24:03 -07:00
node . sockets . retransmit_sockets [ 0 ] . local_addr ( ) . unwrap ( )
2019-09-14 12:32:57 -07:00
) ;
}
2019-11-13 11:12:09 -07:00
2020-12-10 17:28:52 -08:00
pub fn join ( self ) {
2020-11-30 22:18:41 -08:00
self . poh_service . join ( ) . expect ( " poh_service " ) ;
2019-11-13 11:12:09 -07:00
drop ( self . poh_recorder ) ;
2021-02-26 21:42:09 -08:00
if let Some ( json_rpc_service ) = self . json_rpc_service {
2020-11-30 22:18:41 -08:00
json_rpc_service . join ( ) . expect ( " rpc_service " ) ;
2021-02-26 21:42:09 -08:00
}
if let Some ( pubsub_service ) = self . pubsub_service {
2020-11-30 22:18:41 -08:00
pubsub_service . join ( ) . expect ( " pubsub_service " ) ;
2021-02-26 21:42:09 -08:00
}
if let Some ( optimistically_confirmed_bank_tracker ) =
self . optimistically_confirmed_bank_tracker
{
2020-11-30 22:18:41 -08:00
optimistically_confirmed_bank_tracker
. join ( )
. expect ( " optimistically_confirmed_bank_tracker " ) ;
2019-11-13 11:12:09 -07:00
}
2021-02-26 21:42:09 -08:00
2019-11-20 16:43:10 -07:00
if let Some ( transaction_status_service ) = self . transaction_status_service {
2020-11-30 22:18:41 -08:00
transaction_status_service
. join ( )
. expect ( " transaction_status_service " ) ;
2019-11-20 16:43:10 -07:00
}
2019-11-13 11:12:09 -07:00
2020-02-04 19:50:24 -07:00
if let Some ( rewards_recorder_service ) = self . rewards_recorder_service {
2020-11-30 22:18:41 -08:00
rewards_recorder_service
. join ( )
. expect ( " rewards_recorder_service " ) ;
2020-02-04 19:50:24 -07:00
}
2020-09-09 09:33:14 -06:00
if let Some ( cache_block_time_service ) = self . cache_block_time_service {
2020-11-30 22:18:41 -08:00
cache_block_time_service
. join ( )
. expect ( " cache_block_time_service " ) ;
2020-09-09 09:33:14 -06:00
}
2020-09-22 12:26:32 -07:00
if let Some ( sample_performance_service ) = self . sample_performance_service {
2020-11-30 22:18:41 -08:00
sample_performance_service
. join ( )
. expect ( " sample_performance_service " ) ;
2020-09-22 12:26:32 -07:00
}
2020-03-05 23:52:31 -07:00
if let Some ( s ) = self . snapshot_packager_service {
2020-11-30 22:18:41 -08:00
s . join ( ) . expect ( " snapshot_packager_service " ) ;
2020-03-05 23:52:31 -07:00
}
2020-11-30 22:18:41 -08:00
self . gossip_service . join ( ) . expect ( " gossip_service " ) ;
self . serve_repair_service
. join ( )
. expect ( " serve_repair_service " ) ;
self . tpu . join ( ) . expect ( " tpu " ) ;
self . tvu . join ( ) . expect ( " tvu " ) ;
self . completed_data_sets_service
. join ( )
. expect ( " completed_data_sets_service " ) ;
2020-12-29 20:25:54 -08:00
self . ip_echo_server . shutdown_background ( ) ;
2019-11-13 11:12:09 -07:00
}
2019-02-06 19:47:55 -08:00
}
2018-09-14 01:53:18 -07:00
2020-09-19 14:03:54 +09:00
fn active_vote_account_exists_in_bank ( bank : & Arc < Bank > , vote_account : & Pubkey ) -> bool {
if let Some ( account ) = & bank . get_account ( vote_account ) {
if let Some ( vote_state ) = VoteState ::from ( & account ) {
return ! vote_state . votes . is_empty ( ) ;
}
}
false
}
2020-12-29 09:35:57 -08:00
fn check_poh_speed ( genesis_config : & GenesisConfig , maybe_hash_samples : Option < u64 > ) {
if let Some ( hashes_per_tick ) = genesis_config . hashes_per_tick ( ) {
let ticks_per_slot = genesis_config . ticks_per_slot ( ) ;
let hashes_per_slot = hashes_per_tick * ticks_per_slot ;
let hash_samples = maybe_hash_samples . unwrap_or ( hashes_per_slot ) ;
let hash_time_ns = compute_hash_time_ns ( hash_samples ) ;
let my_ns_per_slot = ( hash_time_ns * hashes_per_slot ) / hash_samples ;
debug! ( " computed: ns_per_slot: {} " , my_ns_per_slot ) ;
let target_ns_per_slot = genesis_config . ns_per_slot ( ) as u64 ;
debug! (
" cluster ns_per_hash: {}ns ns_per_slot: {} " ,
target_ns_per_slot / hashes_per_slot ,
target_ns_per_slot
) ;
if my_ns_per_slot < target_ns_per_slot {
let extra_ns = target_ns_per_slot - my_ns_per_slot ;
info! ( " PoH speed check: Will sleep {}ns per slot. " , extra_ns ) ;
} else {
error! (
2020-12-29 12:09:09 -07:00
" PoH is slower than cluster target tick rate! mine: {} cluster: {}. If you wish to continue, try --no-poh-speed-test " ,
2020-12-29 09:35:57 -08:00
my_ns_per_slot , target_ns_per_slot ,
) ;
abort ( ) ;
}
}
}
2020-09-19 14:03:54 +09:00
fn post_process_restored_tower (
restored_tower : crate ::consensus ::Result < Tower > ,
validator_identity : & Pubkey ,
vote_account : & Pubkey ,
config : & ValidatorConfig ,
ledger_path : & Path ,
bank_forks : & BankForks ,
) -> Tower {
2020-11-12 06:29:04 -08:00
let mut should_require_tower = config . require_tower ;
2020-09-19 14:03:54 +09:00
restored_tower
. and_then ( | tower | {
let root_bank = bank_forks . root_bank ( ) ;
let slot_history = root_bank . get_slot_history ( ) ;
2020-11-12 06:29:04 -08:00
let tower = tower . adjust_lockouts_after_replay ( root_bank . slot ( ) , & slot_history ) ;
if let Some ( wait_slot_for_supermajority ) = config . wait_for_supermajority {
if root_bank . slot ( ) = = wait_slot_for_supermajority {
// intentionally fail to restore tower; we're supposedly in a new hard fork; past
// out-of-chain vote state doesn't make sense at all
// what if --wait-for-supermajority again if the validator restarted?
let message = format! ( " Hardfork is detected; discarding tower restoration result: {:?} " , tower ) ;
datapoint_error! (
" tower_error " ,
(
" error " ,
message ,
String
) ,
) ;
error! ( " {} " , message ) ;
// unconditionally relax tower requirement so that we can always restore tower
// from root bank.
should_require_tower = false ;
return Err ( crate ::consensus ::TowerError ::HardFork ( wait_slot_for_supermajority ) ) ;
}
}
2021-01-21 18:34:51 -08:00
if let Some ( warp_slot ) = config . warp_slot {
// unconditionally relax tower requirement so that we can always restore tower
// from root bank after the warp
should_require_tower = false ;
return Err ( crate ::consensus ::TowerError ::HardFork ( warp_slot ) ) ;
}
2020-11-12 06:29:04 -08:00
tower
2020-09-19 14:03:54 +09:00
} )
. unwrap_or_else ( | err | {
let voting_has_been_active =
active_vote_account_exists_in_bank ( & bank_forks . working_bank ( ) , & vote_account ) ;
2020-10-15 18:30:33 +09:00
if ! err . is_file_missing ( ) {
2020-09-19 14:03:54 +09:00
datapoint_error! (
" tower_error " ,
(
" error " ,
format! ( " Unable to restore tower: {} " , err ) ,
String
) ,
) ;
}
2020-11-12 06:29:04 -08:00
if should_require_tower & & voting_has_been_active {
2020-09-19 14:03:54 +09:00
error! ( " Requested mandatory tower restore failed: {} " , err ) ;
error! (
" And there is an existing vote_account containing actual votes. \
2020-10-21 10:26:20 +09:00
Aborting due to possible conflicting duplicate votes " ,
2020-09-19 14:03:54 +09:00
) ;
2020-12-08 01:43:03 +09:00
abort ( ) ;
2020-09-19 14:03:54 +09:00
}
2020-10-15 18:30:33 +09:00
if err . is_file_missing ( ) & & ! voting_has_been_active {
2020-09-19 14:03:54 +09:00
// Currently, don't protect against spoofed snapshots with no tower at all
info! (
" Ignoring expected failed tower restore because this is the initial \
validator start with the vote account .. . "
) ;
} else {
error! (
" Rebuilding a new tower from the latest vote account due to failed tower restore: {} " ,
err
) ;
}
Tower ::new_from_bankforks (
& bank_forks ,
& ledger_path ,
& validator_identity ,
& vote_account ,
)
} )
}
2020-02-20 19:53:26 -07:00
#[ allow(clippy::type_complexity) ]
2020-07-01 15:19:40 +09:00
fn new_banks_from_ledger (
2020-09-19 14:03:54 +09:00
validator_identity : & Pubkey ,
vote_account : & Pubkey ,
2020-02-25 00:27:19 -07:00
config : & ValidatorConfig ,
2020-07-01 15:19:40 +09:00
ledger_path : & Path ,
2019-11-04 22:14:55 -07:00
poh_verify : bool ,
2020-07-14 21:14:48 -06:00
exit : & Arc < AtomicBool > ,
2020-12-16 17:56:38 -08:00
enforce_ulimit_nofile : bool ,
2019-04-19 02:39:44 -07:00
) -> (
2020-02-20 19:53:26 -07:00
GenesisConfig ,
2019-04-19 02:39:44 -07:00
BankForks ,
2020-07-14 21:14:48 -06:00
Arc < Blockstore > ,
2019-04-19 02:39:44 -07:00
Receiver < bool > ,
2019-05-09 14:10:04 -07:00
CompletedSlotsReceiver ,
2019-04-19 02:39:44 -07:00
LeaderScheduleCache ,
2020-02-20 19:53:26 -07:00
Option < ( Slot , Hash ) > ,
2020-07-14 21:14:48 -06:00
TransactionHistoryServices ,
2020-09-19 14:03:54 +09:00
Tower ,
2019-04-19 02:39:44 -07:00
) {
2020-07-01 15:19:40 +09:00
info! ( " loading ledger from {:?}... " , ledger_path ) ;
let genesis_config = open_genesis_config ( ledger_path , config . max_genesis_archive_unpacked_size ) ;
2020-02-24 19:27:04 -08:00
// This needs to be limited otherwise the state in the VoteAccount data
// grows too large
let leader_schedule_slot_offset = genesis_config . epoch_schedule . leader_schedule_slot_offset ;
let slots_per_epoch = genesis_config . epoch_schedule . slots_per_epoch ;
let leader_epoch_offset = ( leader_schedule_slot_offset + slots_per_epoch - 1 ) / slots_per_epoch ;
assert! ( leader_epoch_offset < = MAX_LEADER_SCHEDULE_EPOCH_OFFSET ) ;
2019-11-08 23:56:57 -05:00
let genesis_hash = genesis_config . hash ( ) ;
info! ( " genesis hash: {} " , genesis_hash ) ;
2020-02-25 00:27:19 -07:00
if let Some ( expected_genesis_hash ) = config . expected_genesis_hash {
2019-11-08 23:56:57 -05:00
if genesis_hash ! = expected_genesis_hash {
error! ( " genesis hash mismatch: expected {} " , expected_genesis_hash ) ;
2020-07-01 15:19:40 +09:00
error! ( " Delete the ledger directory to continue: {:?} " , ledger_path ) ;
2020-12-08 01:43:03 +09:00
abort ( ) ;
2019-08-21 18:16:40 -07:00
}
}
2019-02-19 18:31:56 -08:00
2020-09-01 22:06:06 -07:00
let BlockstoreSignals {
mut blockstore ,
ledger_signal_receiver ,
completed_slots_receiver ,
..
2020-12-16 17:56:38 -08:00
} = Blockstore ::open_with_signal (
ledger_path ,
config . wal_recovery_mode . clone ( ) ,
enforce_ulimit_nofile ,
)
. expect ( " Failed to open ledger database " ) ;
2020-03-23 08:42:32 -07:00
blockstore . set_no_compaction ( config . no_rocksdb_compaction ) ;
2019-02-26 21:16:18 -08:00
2020-09-19 14:03:54 +09:00
let restored_tower = Tower ::restore ( ledger_path , & validator_identity ) ;
if let Ok ( tower ) = & restored_tower {
reconcile_blockstore_roots_with_tower ( & tower , & blockstore ) . unwrap_or_else ( | err | {
error! ( " Failed to reconcile blockstore with tower: {:?} " , err ) ;
2020-12-08 01:43:03 +09:00
abort ( )
2020-09-19 14:03:54 +09:00
} ) ;
}
2020-01-13 14:13:52 -07:00
let process_options = blockstore_processor ::ProcessOptions {
2020-12-07 09:49:55 +01:00
bpf_jit : config . bpf_jit ,
2019-11-04 22:14:55 -07:00
poh_verify ,
2020-01-22 19:31:50 -07:00
dev_halt_at_slot : config . dev_halt_at_slot ,
2020-01-24 18:27:04 -07:00
new_hard_forks : config . new_hard_forks . clone ( ) ,
2020-03-22 11:10:04 -07:00
frozen_accounts : config . frozen_accounts . clone ( ) ,
2020-09-23 18:46:42 -07:00
debug_keys : config . debug_keys . clone ( ) ,
2020-12-31 18:06:03 -08:00
account_indexes : config . account_indexes . clone ( ) ,
2021-01-11 17:00:23 -08:00
accounts_db_caching_enabled : config . accounts_db_caching_enabled ,
2020-01-13 14:13:52 -07:00
.. blockstore_processor ::ProcessOptions ::default ( )
2019-11-04 19:10:06 -07:00
} ;
2020-07-14 21:14:48 -06:00
let blockstore = Arc ::new ( blockstore ) ;
let transaction_history_services =
2020-09-10 08:56:26 -07:00
if config . rpc_addrs . is_some ( ) & & config . rpc_config . enable_rpc_transaction_history {
2021-02-01 14:00:51 -07:00
initialize_rpc_transaction_history_services (
blockstore . clone ( ) ,
exit ,
config . rpc_config . enable_cpi_and_log_storage ,
)
2020-07-14 21:14:48 -06:00
} else {
TransactionHistoryServices ::default ( )
} ;
2020-05-06 08:24:59 -07:00
let ( mut bank_forks , mut leader_schedule_cache , snapshot_hash ) = bank_forks_utils ::load (
& genesis_config ,
& blockstore ,
config . account_paths . clone ( ) ,
2020-12-21 21:33:37 -08:00
config . account_shrink_paths . clone ( ) ,
2020-05-06 08:24:59 -07:00
config . snapshot_config . as_ref ( ) ,
process_options ,
2020-07-14 21:14:48 -06:00
transaction_history_services
. transaction_status_sender
. clone ( ) ,
2020-05-06 08:24:59 -07:00
)
. unwrap_or_else ( | err | {
error! ( " Failed to load ledger: {:?} " , err ) ;
2020-12-08 01:43:03 +09:00
abort ( )
2020-05-06 08:24:59 -07:00
} ) ;
2019-02-06 19:47:55 -08:00
2021-01-21 18:34:51 -08:00
if let Some ( warp_slot ) = config . warp_slot {
let snapshot_config = config . snapshot_config . as_ref ( ) . unwrap_or_else ( | | {
error! ( " warp slot requires a snapshot config " ) ;
abort ( ) ;
} ) ;
let working_bank = bank_forks . working_bank ( ) ;
if warp_slot < = working_bank . slot ( ) {
error! (
" warp slot ({}) cannot be less than the working bank slot ({}) " ,
warp_slot ,
working_bank . slot ( )
) ;
abort ( ) ;
}
info! ( " warping to slot {} " , warp_slot ) ;
bank_forks . insert ( Bank ::warp_from_parent (
& bank_forks . root_bank ( ) ,
& Pubkey ::default ( ) ,
warp_slot ,
) ) ;
bank_forks . set_root (
warp_slot ,
2021-02-18 23:42:09 -08:00
& solana_runtime ::accounts_background_service ::AbsRequestSender ::default ( ) ,
2021-01-21 18:34:51 -08:00
Some ( warp_slot ) ,
) ;
leader_schedule_cache . set_root ( & bank_forks . root_bank ( ) ) ;
let archive_file = solana_runtime ::snapshot_utils ::bank_to_snapshot_archive (
ledger_path ,
& bank_forks . root_bank ( ) ,
None ,
& snapshot_config . snapshot_package_output_path ,
snapshot_config . archive_format ,
2021-02-05 18:48:16 -06:00
Some ( & bank_forks . root_bank ( ) . get_thread_pool ( ) ) ,
2021-01-21 18:34:51 -08:00
)
. unwrap_or_else ( | err | {
error! ( " Unable to create snapshot: {} " , err ) ;
abort ( ) ;
} ) ;
info! ( " created snapshot: {} " , archive_file . display ( ) ) ;
}
2020-09-19 14:03:54 +09:00
let tower = post_process_restored_tower (
restored_tower ,
& validator_identity ,
& vote_account ,
& config ,
& ledger_path ,
& bank_forks ,
) ;
info! ( " Tower state: {:?} " , tower ) ;
2020-01-22 19:31:50 -07:00
leader_schedule_cache . set_fixed_leader_schedule ( config . fixed_leader_schedule . clone ( ) ) ;
2019-12-03 16:31:59 -08:00
2020-01-22 19:31:50 -07:00
bank_forks . set_snapshot_config ( config . snapshot_config . clone ( ) ) ;
2020-04-16 15:12:20 -07:00
bank_forks . set_accounts_hash_interval_slots ( config . accounts_hash_interval_slots ) ;
2019-08-25 21:33:41 -07:00
2019-02-06 19:47:55 -08:00
(
2020-02-20 19:53:26 -07:00
genesis_config ,
2019-02-20 17:05:57 -08:00
bank_forks ,
2020-01-13 14:13:52 -07:00
blockstore ,
2019-02-16 20:58:07 -07:00
ledger_signal_receiver ,
2019-05-09 14:10:04 -07:00
completed_slots_receiver ,
2019-04-19 02:39:44 -07:00
leader_schedule_cache ,
2020-02-20 19:53:26 -07:00
snapshot_hash ,
2020-07-14 21:14:48 -06:00
transaction_history_services ,
2020-09-19 14:03:54 +09:00
tower ,
2019-02-16 20:58:07 -07:00
)
}
2020-11-12 14:01:13 -08:00
fn blockstore_contains_bad_shred_version (
blockstore : & Blockstore ,
start_slot : Slot ,
shred_version : u16 ,
) -> bool {
let now = Instant ::now ( ) ;
2020-06-23 14:29:07 -07:00
// Search for shreds with incompatible version in blockstore
2020-06-22 20:27:25 -07:00
if let Ok ( slot_meta_iterator ) = blockstore . slot_meta_iterator ( start_slot ) {
2020-11-12 14:01:13 -08:00
info! ( " Searching for incorrect shreds.. " ) ;
2020-06-23 14:29:07 -07:00
for ( slot , _meta ) in slot_meta_iterator {
if let Ok ( shreds ) = blockstore . get_data_shreds_for_slot ( slot , 0 ) {
for shred in & shreds {
if shred . version ( ) ! = shred_version {
2020-11-12 14:01:13 -08:00
return true ;
2020-06-23 14:29:07 -07:00
}
}
}
2020-11-12 14:01:13 -08:00
if now . elapsed ( ) . as_secs ( ) > 60 {
info! ( " Didn't find incorrect shreds after 60 seconds, aborting " ) ;
return false ;
}
2020-06-23 14:29:07 -07:00
}
}
2020-11-12 14:01:13 -08:00
false
}
fn backup_and_clear_blockstore ( ledger_path : & Path , start_slot : Slot , shred_version : u16 ) {
let blockstore = Blockstore ::open ( ledger_path ) . unwrap ( ) ;
let do_copy_and_clear =
blockstore_contains_bad_shred_version ( & blockstore , start_slot , shred_version ) ;
2020-06-23 14:29:07 -07:00
// If found, then copy shreds to another db and clear from start_slot
if do_copy_and_clear {
let folder_name = format! ( " backup_rocksdb_ {} " , thread_rng ( ) . gen_range ( 0 , 99999 ) ) ;
let backup_blockstore = Blockstore ::open ( & ledger_path . join ( folder_name ) ) ;
2020-06-22 20:27:25 -07:00
let mut last_print = Instant ::now ( ) ;
let mut copied = 0 ;
2020-06-23 14:29:07 -07:00
let mut last_slot = None ;
let slot_meta_iterator = blockstore . slot_meta_iterator ( start_slot ) . unwrap ( ) ;
2020-06-22 20:27:25 -07:00
for ( slot , _meta ) in slot_meta_iterator {
if let Ok ( shreds ) = blockstore . get_data_shreds_for_slot ( slot , 0 ) {
if let Ok ( ref backup_blockstore ) = backup_blockstore {
copied + = shreds . len ( ) ;
let _ = backup_blockstore . insert_shreds ( shreds , None , true ) ;
}
}
if last_print . elapsed ( ) . as_millis ( ) > 3000 {
info! (
" Copying shreds from slot {} copied {} so far. " ,
start_slot , copied
) ;
last_print = Instant ::now ( ) ;
}
2020-06-23 14:29:07 -07:00
last_slot = Some ( slot ) ;
2020-06-22 20:27:25 -07:00
}
2020-06-23 14:29:07 -07:00
let end_slot = last_slot . unwrap ( ) ;
2020-06-22 20:27:25 -07:00
info! ( " Purging slots {} to {} " , start_slot , end_slot ) ;
2020-06-23 14:29:07 -07:00
blockstore . purge_from_next_slots ( start_slot , end_slot ) ;
2020-10-22 02:45:21 +09:00
blockstore . purge_slots ( start_slot , end_slot , PurgeType ::Exact ) ;
2020-06-22 20:27:25 -07:00
info! ( " Purging done, compacting db.. " ) ;
if let Err ( e ) = blockstore . compact_storage ( start_slot , end_slot ) {
warn! (
" Error from compacting storage from {} to {}: {:?} " ,
start_slot , end_slot , e
) ;
}
info! ( " done " ) ;
}
2020-06-23 14:29:07 -07:00
drop ( blockstore ) ;
2020-06-22 20:27:25 -07:00
}
2020-07-14 21:14:48 -06:00
fn initialize_rpc_transaction_history_services (
blockstore : Arc < Blockstore > ,
exit : & Arc < AtomicBool > ,
2021-02-01 14:00:51 -07:00
enable_cpi_and_log_storage : bool ,
2020-07-14 21:14:48 -06:00
) -> TransactionHistoryServices {
let ( transaction_status_sender , transaction_status_receiver ) = unbounded ( ) ;
2021-02-01 14:00:51 -07:00
let transaction_status_sender = Some ( TransactionStatusSender {
sender : transaction_status_sender ,
enable_cpi_and_log_storage ,
} ) ;
2020-07-14 21:14:48 -06:00
let transaction_status_service = Some ( TransactionStatusService ::new (
transaction_status_receiver ,
blockstore . clone ( ) ,
exit ,
) ) ;
let ( rewards_recorder_sender , rewards_receiver ) = unbounded ( ) ;
let rewards_recorder_sender = Some ( rewards_recorder_sender ) ;
let rewards_recorder_service = Some ( RewardsRecorderService ::new (
rewards_receiver ,
2020-09-09 09:33:14 -06:00
blockstore . clone ( ) ,
exit ,
) ) ;
let ( cache_block_time_sender , cache_block_time_receiver ) = unbounded ( ) ;
let cache_block_time_sender = Some ( cache_block_time_sender ) ;
let cache_block_time_service = Some ( CacheBlockTimeService ::new (
cache_block_time_receiver ,
2020-07-14 21:14:48 -06:00
blockstore ,
exit ,
) ) ;
TransactionHistoryServices {
transaction_status_sender ,
transaction_status_service ,
rewards_recorder_sender ,
rewards_recorder_service ,
2020-09-09 09:33:14 -06:00
cache_block_time_sender ,
cache_block_time_service ,
2020-07-14 21:14:48 -06:00
}
}
2020-06-30 12:43:48 -07:00
// Return true on error, indicating the validator should exit.
2020-05-28 12:22:19 -07:00
fn wait_for_supermajority (
config : & ValidatorConfig ,
bank : & Bank ,
cluster_info : & ClusterInfo ,
rpc_override_health_check : Arc < AtomicBool > ,
2020-06-30 12:43:48 -07:00
) -> bool {
if let Some ( wait_for_supermajority ) = config . wait_for_supermajority {
match wait_for_supermajority . cmp ( & bank . slot ( ) ) {
std ::cmp ::Ordering ::Less = > return false ,
std ::cmp ::Ordering ::Greater = > {
error! ( " Ledger does not have enough data to wait for supermajority, please enable snapshot fetch. Has {} needs {} " , bank . slot ( ) , wait_for_supermajority ) ;
return true ;
}
_ = > { }
}
} else {
return false ;
}
if let Some ( expected_bank_hash ) = config . expected_bank_hash {
if bank . hash ( ) ! = expected_bank_hash {
error! (
" Bank hash({}) does not match expected value: {} " ,
bank . hash ( ) ,
expected_bank_hash
) ;
return true ;
}
2020-01-30 10:26:27 -07:00
}
2020-04-17 11:05:59 -07:00
for i in 1 .. {
2020-11-11 11:32:06 -07:00
if i % 10 = = 1 {
info! (
" Waiting for 80% of activated stake at slot {} to be in gossip... " ,
bank . slot ( )
) ;
}
2020-04-17 11:05:59 -07:00
let gossip_stake_percent = get_stake_percent_in_gossip ( & bank , & cluster_info , i % 10 = = 0 ) ;
2020-01-30 10:26:27 -07:00
2020-03-09 20:31:09 -07:00
if gossip_stake_percent > = 80 {
2020-01-30 10:26:27 -07:00
break ;
}
2020-05-28 12:22:19 -07:00
// The normal RPC health checks don't apply as the node is waiting, so feign health to
// prevent load balancers from removing the node from their list of candidates during a
// manual restart.
rpc_override_health_check . store ( true , Ordering ::Relaxed ) ;
2020-01-30 10:26:27 -07:00
sleep ( Duration ::new ( 1 , 0 ) ) ;
}
2020-05-28 12:22:19 -07:00
rpc_override_health_check . store ( false , Ordering ::Relaxed ) ;
2020-06-30 12:43:48 -07:00
false
2020-01-30 10:26:27 -07:00
}
2020-01-07 14:33:39 -07:00
fn report_target_features ( ) {
warn! (
" CUDA is {}abled " ,
if solana_perf ::perf_libs ::api ( ) . is_some ( ) {
" en "
} else {
" dis "
}
) ;
2020-03-01 15:17:23 -07:00
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
2020-01-07 14:33:39 -07:00
{
2020-11-09 08:04:34 -08:00
unsafe { check_avx ( ) } ;
}
}
// Validator binaries built on a machine with AVX support will generate invalid opcodes
// when run on machines without AVX causing a non-obvious process abort. Instead detect
// the mismatch and error cleanly.
#[ target_feature(enable = " avx " ) ]
unsafe fn check_avx ( ) {
if is_x86_feature_detected! ( " avx " ) {
info! ( " AVX detected " ) ;
} else {
error! (
" Your machine does not have AVX support, please rebuild from source on your machine "
) ;
2020-12-08 01:43:03 +09:00
abort ( ) ;
2020-01-07 14:33:39 -07:00
}
}
2020-01-07 14:18:34 -07:00
// Get the activated stake percentage (based on the provided bank) that is visible in gossip
2020-04-21 12:54:45 -07:00
fn get_stake_percent_in_gossip ( bank : & Bank , cluster_info : & ClusterInfo , log : bool ) -> u64 {
2020-04-17 11:05:59 -07:00
let mut online_stake = 0 ;
let mut wrong_shred_stake = 0 ;
let mut wrong_shred_nodes = vec! [ ] ;
let mut offline_stake = 0 ;
let mut offline_nodes = vec! [ ] ;
2020-01-07 14:18:34 -07:00
let mut total_activated_stake = 0 ;
2020-04-21 12:54:45 -07:00
let all_tvu_peers = cluster_info . all_tvu_peers ( ) ;
let my_shred_version = cluster_info . my_shred_version ( ) ;
let my_id = cluster_info . id ( ) ;
2020-01-07 14:18:34 -07:00
2020-12-21 19:18:19 +00:00
for ( _ , ( activated_stake , vote_account ) ) in bank . vote_accounts ( ) {
2020-01-07 14:18:34 -07:00
total_activated_stake + = activated_stake ;
2020-04-17 11:05:59 -07:00
2020-12-21 19:18:19 +00:00
if activated_stake = = 0 {
2020-04-17 11:05:59 -07:00
continue ;
}
2020-11-30 17:18:33 +00:00
let vote_state_node_pubkey = vote_account
. vote_state ( )
. as_ref ( )
. map ( | vote_state | vote_state . node_pubkey )
. unwrap_or_default ( ) ;
2020-04-17 11:05:59 -07:00
if let Some ( peer ) = all_tvu_peers
2020-01-07 14:18:34 -07:00
. iter ( )
2020-11-30 17:18:33 +00:00
. find ( | peer | peer . id = = vote_state_node_pubkey )
2020-01-07 14:18:34 -07:00
{
2020-04-18 10:16:19 -07:00
if peer . shred_version = = my_shred_version {
2020-04-17 11:05:59 -07:00
trace! (
" observed {} in gossip, (activated_stake={}) " ,
2020-11-30 17:18:33 +00:00
vote_state_node_pubkey ,
2020-04-17 11:05:59 -07:00
activated_stake
) ;
online_stake + = activated_stake ;
} else {
wrong_shred_stake + = activated_stake ;
2020-12-21 19:18:19 +00:00
wrong_shred_nodes . push ( ( activated_stake , vote_state_node_pubkey ) ) ;
2020-04-17 11:05:59 -07:00
}
2020-11-30 17:18:33 +00:00
} else if vote_state_node_pubkey = = my_id {
2020-04-18 10:16:19 -07:00
online_stake + = activated_stake ; // This node is online
2020-04-17 11:05:59 -07:00
} else {
offline_stake + = activated_stake ;
2020-12-21 19:18:19 +00:00
offline_nodes . push ( ( activated_stake , vote_state_node_pubkey ) ) ;
2020-04-17 11:05:59 -07:00
}
}
if log {
info! (
" {}% of active stake visible in gossip " ,
online_stake * 100 / total_activated_stake
) ;
if ! wrong_shred_nodes . is_empty ( ) {
info! (
" {}% of active stake has the wrong shred version in gossip " ,
wrong_shred_stake * 100 / total_activated_stake ,
2020-01-07 14:18:34 -07:00
) ;
2020-04-17 11:05:59 -07:00
for ( stake , identity ) in wrong_shred_nodes {
info! (
" {}% - {} " ,
stake * 100 / total_activated_stake ,
identity
) ;
}
}
if ! offline_nodes . is_empty ( ) {
info! (
" {}% of active stake is not visible in gossip " ,
offline_stake * 100 / total_activated_stake
) ;
for ( stake , identity ) in offline_nodes {
info! (
" {}% - {} " ,
stake * 100 / total_activated_stake ,
identity
) ;
}
2020-01-07 14:18:34 -07:00
}
}
2020-04-17 11:05:59 -07:00
online_stake * 100 / total_activated_stake
2020-01-07 14:18:34 -07:00
}
2020-07-07 09:41:45 -07:00
// Cleanup anything that looks like an accounts append-vec
fn cleanup_accounts_path ( account_path : & std ::path ::Path ) {
2021-02-22 21:24:09 +09:00
if let Err ( e ) = std ::fs ::remove_dir_all ( account_path ) {
2020-07-15 09:37:40 -07:00
warn! (
2021-02-22 21:24:09 +09:00
" encountered error removing accounts path: {:?}: {} " ,
account_path , e
2020-07-15 09:37:40 -07:00
) ;
2020-07-07 09:41:45 -07:00
}
}
2020-12-08 23:18:27 -08:00
pub fn is_snapshot_config_invalid (
snapshot_interval_slots : u64 ,
accounts_hash_interval_slots : u64 ,
) -> bool {
snapshot_interval_slots ! = 0
& & ( snapshot_interval_slots < accounts_hash_interval_slots
| | snapshot_interval_slots % accounts_hash_interval_slots ! = 0 )
}
2018-07-02 15:24:40 -07:00
#[ cfg(test) ]
mod tests {
2019-01-31 20:41:03 -08:00
use super ::* ;
2020-09-18 22:21:44 -07:00
use solana_ledger ::{ create_new_tmp_ledger , genesis_utils ::create_genesis_config_with_leader } ;
2020-12-29 09:35:57 -08:00
use solana_sdk ::genesis_config ::create_genesis_config ;
use solana_sdk ::poh_config ::PohConfig ;
2018-09-14 01:53:18 -07:00
use std ::fs ::remove_dir_all ;
2018-08-03 11:06:06 -07:00
2018-07-02 15:24:40 -07:00
#[ test ]
fn validator_exit ( ) {
2019-05-23 14:50:23 -07:00
solana_logger ::setup ( ) ;
2019-01-29 18:12:32 -08:00
let leader_keypair = Keypair ::new ( ) ;
2019-03-09 19:28:43 -08:00
let leader_node = Node ::new_localhost_with_pubkey ( & leader_keypair . pubkey ( ) ) ;
2018-10-25 16:58:40 -07:00
2019-01-29 18:12:32 -08:00
let validator_keypair = Keypair ::new ( ) ;
2019-03-09 19:28:43 -08:00
let validator_node = Node ::new_localhost_with_pubkey ( & validator_keypair . pubkey ( ) ) ;
2019-11-08 23:56:57 -05:00
let genesis_config =
create_genesis_config_with_leader ( 10_000 , & leader_keypair . pubkey ( ) , 1000 )
. genesis_config ;
let ( validator_ledger_path , _blockhash ) = create_new_tmp_ledger! ( & genesis_config ) ;
2019-01-29 18:12:32 -08:00
2019-05-15 15:19:29 -07:00
let voting_keypair = Arc ::new ( Keypair ::new ( ) ) ;
2020-01-30 11:58:39 -07:00
let config = ValidatorConfig {
2020-12-01 20:25:09 -07:00
rpc_addrs : Some ( ( validator_node . info . rpc , validator_node . info . rpc_pubsub ) ) ,
2020-01-30 11:58:39 -07:00
.. ValidatorConfig ::default ( )
} ;
2019-05-23 22:05:16 -07:00
let validator = Validator ::new (
2019-01-29 18:12:32 -08:00
validator_node ,
2019-01-30 20:51:50 -07:00
& Arc ::new ( validator_keypair ) ,
2019-01-24 12:04:04 -08:00
& validator_ledger_path ,
2019-03-09 19:28:43 -08:00
& voting_keypair . pubkey ( ) ,
2020-03-31 08:23:42 -07:00
vec! [ voting_keypair . clone ( ) ] ,
2020-12-18 10:54:48 -08:00
vec! [ leader_node . info ] ,
2019-11-20 16:43:10 -07:00
& config ,
2021-02-03 16:26:17 +00:00
true , // should_check_duplicate_instance
2018-09-14 01:53:18 -07:00
) ;
2020-12-10 17:28:52 -08:00
validator . close ( ) ;
2018-09-14 01:53:18 -07:00
remove_dir_all ( validator_ledger_path ) . unwrap ( ) ;
2018-07-02 11:20:35 -07:00
}
2018-09-25 15:41:29 -07:00
2018-07-17 08:18:42 -07:00
#[ test ]
2020-06-22 20:27:25 -07:00
fn test_backup_and_clear_blockstore ( ) {
use std ::time ::Instant ;
solana_logger ::setup ( ) ;
use solana_ledger ::get_tmp_ledger_path ;
use solana_ledger ::{ blockstore , entry } ;
let blockstore_path = get_tmp_ledger_path! ( ) ;
{
2020-06-23 14:29:07 -07:00
let blockstore = Blockstore ::open ( & blockstore_path ) . unwrap ( ) ;
let entries = entry ::create_ticks ( 1 , 0 , Hash ::default ( ) ) ;
2020-06-22 20:27:25 -07:00
info! ( " creating shreds " ) ;
let mut last_print = Instant ::now ( ) ;
for i in 1 .. 10 {
2020-06-23 14:29:07 -07:00
let shreds = blockstore ::entries_to_test_shreds ( entries . clone ( ) , i , i - 1 , true , 1 ) ;
2020-06-22 20:27:25 -07:00
blockstore . insert_shreds ( shreds , None , true ) . unwrap ( ) ;
if last_print . elapsed ( ) . as_millis ( ) > 5000 {
info! ( " inserted {} " , i ) ;
last_print = Instant ::now ( ) ;
}
}
2020-06-23 14:29:07 -07:00
drop ( blockstore ) ;
2020-06-22 20:27:25 -07:00
2020-06-23 14:29:07 -07:00
backup_and_clear_blockstore ( & blockstore_path , 5 , 2 ) ;
2020-06-22 20:27:25 -07:00
2020-06-23 14:29:07 -07:00
let blockstore = Blockstore ::open ( & blockstore_path ) . unwrap ( ) ;
assert! ( blockstore . meta ( 4 ) . unwrap ( ) . unwrap ( ) . next_slots . is_empty ( ) ) ;
for i in 5 .. 10 {
2020-06-22 20:27:25 -07:00
assert! ( blockstore
. get_data_shreds_for_slot ( i , 0 )
. unwrap ( )
. is_empty ( ) ) ;
}
}
}
#[ test ]
2018-07-17 08:18:42 -07:00
fn validator_parallel_exit ( ) {
2019-01-29 18:12:32 -08:00
let leader_keypair = Keypair ::new ( ) ;
2019-03-09 19:28:43 -08:00
let leader_node = Node ::new_localhost_with_pubkey ( & leader_keypair . pubkey ( ) ) ;
2019-01-29 18:12:32 -08:00
2018-09-14 01:53:18 -07:00
let mut ledger_paths = vec! [ ] ;
2019-08-20 23:59:31 -07:00
let mut validators : Vec < Validator > = ( 0 .. 2 )
2019-02-26 19:36:46 -08:00
. map ( | _ | {
2019-01-29 18:12:32 -08:00
let validator_keypair = Keypair ::new ( ) ;
2019-03-09 19:28:43 -08:00
let validator_node = Node ::new_localhost_with_pubkey ( & validator_keypair . pubkey ( ) ) ;
2019-11-08 23:56:57 -05:00
let genesis_config =
create_genesis_config_with_leader ( 10_000 , & leader_keypair . pubkey ( ) , 1000 )
. genesis_config ;
let ( validator_ledger_path , _blockhash ) = create_new_tmp_ledger! ( & genesis_config ) ;
2018-09-14 01:53:18 -07:00
ledger_paths . push ( validator_ledger_path . clone ( ) ) ;
2020-08-19 22:04:38 -07:00
let vote_account_keypair = Keypair ::new ( ) ;
2020-01-30 11:58:39 -07:00
let config = ValidatorConfig {
2020-12-01 20:25:09 -07:00
rpc_addrs : Some ( ( validator_node . info . rpc , validator_node . info . rpc_pubsub ) ) ,
2020-01-30 11:58:39 -07:00
.. ValidatorConfig ::default ( )
} ;
2019-05-23 22:05:16 -07:00
Validator ::new (
2019-01-29 18:12:32 -08:00
validator_node ,
2019-01-30 20:51:50 -07:00
& Arc ::new ( validator_keypair ) ,
2019-01-24 12:04:04 -08:00
& validator_ledger_path ,
2020-03-31 08:23:42 -07:00
& vote_account_keypair . pubkey ( ) ,
2020-08-19 22:04:38 -07:00
vec! [ Arc ::new ( vote_account_keypair ) ] ,
2020-12-18 10:54:48 -08:00
vec! [ leader_node . info . clone ( ) ] ,
2019-11-20 16:43:10 -07:00
& config ,
2021-02-03 16:26:17 +00:00
true , // should_check_duplicate_instance
2018-09-14 01:53:18 -07:00
)
2018-12-07 20:01:28 -07:00
} )
. collect ( ) ;
2018-09-14 01:53:18 -07:00
2020-03-25 18:09:19 -07:00
// Each validator can exit in parallel to speed many sequential calls to join`
2019-08-20 23:59:31 -07:00
validators . iter_mut ( ) . for_each ( | v | v . exit ( ) ) ;
2019-01-29 18:12:32 -08:00
// While join is called sequentially, the above exit call notified all the
// validators to exit from all their threads
validators . into_iter ( ) . for_each ( | validator | {
2020-12-10 17:28:52 -08:00
validator . join ( ) ;
2018-08-03 11:06:06 -07:00
} ) ;
2018-09-14 01:53:18 -07:00
for path in ledger_paths {
remove_dir_all ( path ) . unwrap ( ) ;
}
2018-07-17 08:18:42 -07:00
}
2020-06-30 12:43:48 -07:00
#[ test ]
fn test_wait_for_supermajority ( ) {
solana_logger ::setup ( ) ;
use solana_sdk ::hash ::hash ;
let node_keypair = Arc ::new ( Keypair ::new ( ) ) ;
let cluster_info = ClusterInfo ::new (
ContactInfo ::new_localhost ( & node_keypair . pubkey ( ) , timestamp ( ) ) ,
node_keypair ,
) ;
let ( genesis_config , _mint_keypair ) = create_genesis_config ( 1 ) ;
let bank = Arc ::new ( Bank ::new ( & genesis_config ) ) ;
let mut config = ValidatorConfig ::default ( ) ;
let rpc_override_health_check = Arc ::new ( AtomicBool ::new ( false ) ) ;
assert! ( ! wait_for_supermajority (
& config ,
& bank ,
& cluster_info ,
rpc_override_health_check . clone ( )
) ) ;
// bank=0, wait=1, should fail
config . wait_for_supermajority = Some ( 1 ) ;
assert! ( wait_for_supermajority (
& config ,
& bank ,
& cluster_info ,
rpc_override_health_check . clone ( )
) ) ;
// bank=1, wait=0, should pass, bank is past the wait slot
let bank = Bank ::new_from_parent ( & bank , & Pubkey ::default ( ) , 1 ) ;
config . wait_for_supermajority = Some ( 0 ) ;
assert! ( ! wait_for_supermajority (
& config ,
& bank ,
& cluster_info ,
rpc_override_health_check . clone ( )
) ) ;
// bank=1, wait=1, equal, but bad hash provided
config . wait_for_supermajority = Some ( 1 ) ;
config . expected_bank_hash = Some ( hash ( & [ 1 ] ) ) ;
assert! ( wait_for_supermajority (
& config ,
& bank ,
& cluster_info ,
rpc_override_health_check
) ) ;
}
2020-12-08 23:18:27 -08:00
#[ test ]
fn test_interval_check ( ) {
assert! ( ! is_snapshot_config_invalid ( 0 , 100 ) ) ;
assert! ( is_snapshot_config_invalid ( 1 , 100 ) ) ;
assert! ( is_snapshot_config_invalid ( 230 , 100 ) ) ;
assert! ( ! is_snapshot_config_invalid ( 500 , 100 ) ) ;
assert! ( ! is_snapshot_config_invalid ( 5 , 5 ) ) ;
}
2020-12-29 09:35:57 -08:00
#[ test ]
#[ should_panic ]
fn test_poh_speed ( ) {
solana_logger ::setup ( ) ;
let poh_config = PohConfig {
target_tick_duration : Duration ::from_millis ( solana_sdk ::clock ::MS_PER_TICK ) ,
// make PoH rate really fast to cause the panic condition
2021-01-07 09:49:42 -06:00
hashes_per_tick : Some ( 100 * solana_sdk ::clock ::DEFAULT_HASHES_PER_TICK ) ,
2020-12-29 09:35:57 -08:00
.. PohConfig ::default ( )
} ;
let genesis_config = GenesisConfig {
poh_config ,
.. GenesisConfig ::default ( )
} ;
check_poh_speed ( & genesis_config , Some ( 10_000 ) ) ;
}
#[ test ]
fn test_poh_speed_no_hashes_per_tick ( ) {
let poh_config = PohConfig {
target_tick_duration : Duration ::from_millis ( solana_sdk ::clock ::MS_PER_TICK ) ,
hashes_per_tick : None ,
.. PohConfig ::default ( )
} ;
let genesis_config = GenesisConfig {
poh_config ,
.. GenesisConfig ::default ( )
} ;
check_poh_speed ( & genesis_config , Some ( 10_000 ) ) ;
}
2018-07-02 11:20:35 -07:00
}