Add --wait-for-super-majority to facilitate asynchronous cluster restarts
This commit is contained in:
		@@ -48,7 +48,8 @@ use std::{
 | 
				
			|||||||
    sync::atomic::{AtomicBool, Ordering},
 | 
					    sync::atomic::{AtomicBool, Ordering},
 | 
				
			||||||
    sync::mpsc::Receiver,
 | 
					    sync::mpsc::Receiver,
 | 
				
			||||||
    sync::{Arc, Mutex, RwLock},
 | 
					    sync::{Arc, Mutex, RwLock},
 | 
				
			||||||
    thread::Result,
 | 
					    thread::{sleep, Result},
 | 
				
			||||||
 | 
					    time::Duration,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug)]
 | 
					#[derive(Clone, Debug)]
 | 
				
			||||||
@@ -67,6 +68,7 @@ pub struct ValidatorConfig {
 | 
				
			|||||||
    pub broadcast_stage_type: BroadcastStageType,
 | 
					    pub broadcast_stage_type: BroadcastStageType,
 | 
				
			||||||
    pub partition_cfg: Option<PartitionCfg>,
 | 
					    pub partition_cfg: Option<PartitionCfg>,
 | 
				
			||||||
    pub fixed_leader_schedule: Option<FixedSchedule>,
 | 
					    pub fixed_leader_schedule: Option<FixedSchedule>,
 | 
				
			||||||
 | 
					    pub wait_for_super_majority: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for ValidatorConfig {
 | 
					impl Default for ValidatorConfig {
 | 
				
			||||||
@@ -86,6 +88,7 @@ impl Default for ValidatorConfig {
 | 
				
			|||||||
            broadcast_stage_type: BroadcastStageType::Standard,
 | 
					            broadcast_stage_type: BroadcastStageType::Standard,
 | 
				
			||||||
            partition_cfg: None,
 | 
					            partition_cfg: None,
 | 
				
			||||||
            fixed_leader_schedule: None,
 | 
					            fixed_leader_schedule: None,
 | 
				
			||||||
 | 
					            wait_for_super_majority: false,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -293,14 +296,7 @@ impl Validator {
 | 
				
			|||||||
        if config.snapshot_config.is_some() {
 | 
					        if config.snapshot_config.is_some() {
 | 
				
			||||||
            poh_recorder.set_bank(&bank);
 | 
					            poh_recorder.set_bank(&bank);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        let poh_recorder = Arc::new(Mutex::new(poh_recorder));
 | 
					        let poh_recorder = Arc::new(Mutex::new(poh_recorder));
 | 
				
			||||||
        let poh_service = PohService::new(poh_recorder.clone(), &poh_config, &exit);
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            blocktree.new_shreds_signals.len(),
 | 
					 | 
				
			||||||
            1,
 | 
					 | 
				
			||||||
            "New shred signal for the TVU should be the same as the clear bank signal."
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let ip_echo_server = solana_net_utils::ip_echo_server(node.sockets.ip_echo.unwrap());
 | 
					        let ip_echo_server = solana_net_utils::ip_echo_server(node.sockets.ip_echo.unwrap());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -321,6 +317,22 @@ impl Validator {
 | 
				
			|||||||
                .set_entrypoint(entrypoint_info.clone());
 | 
					                .set_entrypoint(entrypoint_info.clone());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if config.wait_for_super_majority {
 | 
				
			||||||
 | 
					            info!(
 | 
				
			||||||
 | 
					                "Waiting more than 66% of activated stake at slot {} to be in gossip...",
 | 
				
			||||||
 | 
					                bank.slot()
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            loop {
 | 
				
			||||||
 | 
					                let gossip_stake_percent = get_stake_percent_in_gossip(&bank, &cluster_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                info!("{}% of activated stake in gossip", gossip_stake_percent,);
 | 
				
			||||||
 | 
					                if gossip_stake_percent > 66 {
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                sleep(Duration::new(1, 0));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let sockets = Sockets {
 | 
					        let sockets = Sockets {
 | 
				
			||||||
            repair: node
 | 
					            repair: node
 | 
				
			||||||
                .sockets
 | 
					                .sockets
 | 
				
			||||||
@@ -353,6 +365,13 @@ impl Validator {
 | 
				
			|||||||
            Some(voting_keypair.clone())
 | 
					            Some(voting_keypair.clone())
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let poh_service = PohService::new(poh_recorder.clone(), &poh_config, &exit);
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            blocktree.new_shreds_signals.len(),
 | 
				
			||||||
 | 
					            1,
 | 
				
			||||||
 | 
					            "New shred signal for the TVU should be the same as the clear bank signal."
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let tvu = Tvu::new(
 | 
					        let tvu = Tvu::new(
 | 
				
			||||||
            vote_account,
 | 
					            vote_account,
 | 
				
			||||||
            voting_keypair,
 | 
					            voting_keypair,
 | 
				
			||||||
@@ -584,6 +603,35 @@ pub fn new_validator_for_tests() -> (Validator, ContactInfo, Keypair, PathBuf) {
 | 
				
			|||||||
    (node, contact_info, mint_keypair, ledger_path)
 | 
					    (node, contact_info, mint_keypair, ledger_path)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Get the activated stake percentage (based on the provided bank) that is visible in gossip
 | 
				
			||||||
 | 
					fn get_stake_percent_in_gossip(
 | 
				
			||||||
 | 
					    bank: &Arc<solana_runtime::bank::Bank>,
 | 
				
			||||||
 | 
					    cluster_info: &Arc<RwLock<ClusterInfo>>,
 | 
				
			||||||
 | 
					) -> u64 {
 | 
				
			||||||
 | 
					    let mut gossip_stake = 0;
 | 
				
			||||||
 | 
					    let mut total_activated_stake = 0;
 | 
				
			||||||
 | 
					    let tvu_peers = cluster_info.read().unwrap().tvu_peers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (activated_stake, vote_account) in bank.vote_accounts().values() {
 | 
				
			||||||
 | 
					        let vote_state =
 | 
				
			||||||
 | 
					            solana_vote_program::vote_state::VoteState::from(&vote_account).unwrap_or_default();
 | 
				
			||||||
 | 
					        total_activated_stake += activated_stake;
 | 
				
			||||||
 | 
					        if tvu_peers
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .any(|peer| peer.id == vote_state.node_pubkey)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            trace!(
 | 
				
			||||||
 | 
					                "observed {} in gossip, (activated_stake={})",
 | 
				
			||||||
 | 
					                vote_state.node_pubkey,
 | 
				
			||||||
 | 
					                activated_stake
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            gossip_stake += activated_stake;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gossip_stake * 100 / total_activated_stake
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -537,6 +537,12 @@ pub fn main() {
 | 
				
			|||||||
                .takes_value(true)
 | 
					                .takes_value(true)
 | 
				
			||||||
                .help("Redirect logging to the specified file, '-' for standard error"),
 | 
					                .help("Redirect logging to the specified file, '-' for standard error"),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        .arg(
 | 
				
			||||||
 | 
					            Arg::with_name("wait_for_super_majority")
 | 
				
			||||||
 | 
					                .long("wait-for-super-majority")
 | 
				
			||||||
 | 
					                .takes_value(false)
 | 
				
			||||||
 | 
					                .help("After processing the ledger, wait until a super majority of stake is visible on gossip before starting PoH"),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
        .get_matches();
 | 
					        .get_matches();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let identity_keypair = Arc::new(
 | 
					    let identity_keypair = Arc::new(
 | 
				
			||||||
@@ -582,6 +588,7 @@ pub fn main() {
 | 
				
			|||||||
    validator_config.dev_halt_at_slot = value_t!(matches, "dev_halt_at_slot", Slot).ok();
 | 
					    validator_config.dev_halt_at_slot = value_t!(matches, "dev_halt_at_slot", Slot).ok();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    validator_config.rpc_config.enable_validator_exit = matches.is_present("enable_rpc_exit");
 | 
					    validator_config.rpc_config.enable_validator_exit = matches.is_present("enable_rpc_exit");
 | 
				
			||||||
 | 
					    validator_config.wait_for_super_majority = matches.is_present("wait_for_super_majority");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    validator_config.rpc_config.faucet_addr = matches.value_of("rpc_faucet_addr").map(|address| {
 | 
					    validator_config.rpc_config.faucet_addr = matches.value_of("rpc_faucet_addr").map(|address| {
 | 
				
			||||||
        solana_net_utils::parse_host_port(address).expect("failed to parse faucet address")
 | 
					        solana_net_utils::parse_host_port(address).expect("failed to parse faucet address")
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user