diff --git a/core/src/cluster_info_vote_listener.rs b/core/src/cluster_info_vote_listener.rs index 774770e007..0166fa1fce 100644 --- a/core/src/cluster_info_vote_listener.rs +++ b/core/src/cluster_info_vote_listener.rs @@ -1145,9 +1145,7 @@ mod tests { // Create the set of relevant voters for the next epoch let new_epoch = last_known_epoch + 1; let first_slot_in_new_epoch = bank.epoch_schedule().get_first_slot_in_epoch(new_epoch); - let new_keypairs: Vec<_> = (0..10) - .map(|_| ValidatorVoteKeypairs::new(Keypair::new(), Keypair::new(), Keypair::new())) - .collect(); + let new_keypairs: Vec<_> = (0..10).map(|_| ValidatorVoteKeypairs::new_rand()).collect(); let new_epoch_authorized_voters: HashMap<_, _> = new_keypairs .iter() .chain(validator_voting_keypairs[0..5].iter()) @@ -1186,15 +1184,14 @@ mod tests { let ref_count_per_vote = 2; // Create some voters at genesis - let validator_keypairs: Vec<_> = (0..2) - .map(|_| ValidatorVoteKeypairs::new(Keypair::new(), Keypair::new(), Keypair::new())) - .collect(); + let validator_keypairs: Vec<_> = + (0..2).map(|_| ValidatorVoteKeypairs::new_rand()).collect(); let GenesisConfigInfo { genesis_config, .. } = genesis_utils::create_genesis_config_with_vote_accounts( 10_000, &validator_keypairs, - 100, + vec![100; validator_keypairs.len()], ); let bank = Bank::new(&genesis_config); let exit = Arc::new(AtomicBool::new(false)); @@ -1331,14 +1328,13 @@ mod tests { Vec, Arc, ) { - let validator_voting_keypairs: Vec<_> = (0..10) - .map(|_| ValidatorVoteKeypairs::new(Keypair::new(), Keypair::new(), Keypair::new())) - .collect(); + let validator_voting_keypairs: Vec<_> = + (0..10).map(|_| ValidatorVoteKeypairs::new_rand()).collect(); let GenesisConfigInfo { genesis_config, .. } = genesis_utils::create_genesis_config_with_vote_accounts( 10_000, &validator_voting_keypairs, - 100, + vec![100; validator_voting_keypairs.len()], ); let bank = Bank::new(&genesis_config); let vote_tracker = VoteTracker::new(&bank); diff --git a/core/src/consensus.rs b/core/src/consensus.rs index 73b65d6d71..bd05c1ad91 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -687,12 +687,7 @@ pub mod test { create_genesis_config_with_vote_accounts, GenesisConfigInfo, ValidatorVoteKeypairs, }, }; - use solana_sdk::{ - clock::Slot, - hash::Hash, - pubkey::Pubkey, - signature::{Keypair, Signer}, - }; + use solana_sdk::{clock::Slot, hash::Hash, pubkey::Pubkey, signature::Signer}; use solana_vote_program::{ vote_state::{Vote, VoteStateVersions, MAX_LOCKOUT_HISTORY}, vote_transaction, @@ -947,14 +942,8 @@ pub mod test { HeaviestSubtreeForkChoice, ) { let keypairs: HashMap<_, _> = std::iter::repeat_with(|| { - let node_keypair = Keypair::new(); - let vote_keypair = Keypair::new(); - let stake_keypair = Keypair::new(); - let node_pubkey = node_keypair.pubkey(); - ( - node_pubkey, - ValidatorVoteKeypairs::new(node_keypair, vote_keypair, stake_keypair), - ) + let vote_keypairs = ValidatorVoteKeypairs::new_rand(); + (vote_keypairs.node_keypair.pubkey(), vote_keypairs) }) .take(num_keypairs) .collect(); @@ -990,7 +979,11 @@ pub mod test { genesis_config, mint_keypair, voting_keypair: _, - } = create_genesis_config_with_vote_accounts(1_000_000_000, &validator_keypairs, stake); + } = create_genesis_config_with_vote_accounts( + 1_000_000_000, + &validator_keypairs, + vec![stake; validator_keypairs.len()], + ); let bank0 = Bank::new(&genesis_config); diff --git a/core/src/progress_map.rs b/core/src/progress_map.rs index 47eba07e36..4a94cc0feb 100644 --- a/core/src/progress_map.rs +++ b/core/src/progress_map.rs @@ -168,7 +168,7 @@ impl ForkProgress { num_dropped_blocks_on_fork: u64, ) -> Self { let validator_fork_info = { - if bank.collector_id() == my_pubkey { + if bank.collector_id() == my_pubkey && bank.slot() > 0 { let stake = bank.epoch_vote_account_stake(voting_pubkey); Some(ValidatorStakeInfo::new( *voting_pubkey, diff --git a/core/src/repair_service.rs b/core/src/repair_service.rs index c4b83901f4..45368e5745 100644 --- a/core/src/repair_service.rs +++ b/core/src/repair_service.rs @@ -1182,7 +1182,7 @@ mod test { } = genesis_utils::create_genesis_config_with_vote_accounts( 1_000_000_000, &[&keypairs], - 10000, + vec![10000], ); let bank0 = Arc::new(Bank::new(&genesis_config)); let bank9 = Bank::new_from_parent(&bank0, &Pubkey::default(), duplicate_slot); @@ -1244,7 +1244,7 @@ mod test { genesis_utils::create_genesis_config_with_vote_accounts( 1_000_000_000, &[keypairs], - 100, + vec![100], ); let bank0 = Bank::new(&genesis_config); diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index 8d9220737f..eb33acc0a7 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -1955,9 +1955,8 @@ pub(crate) mod tests { Blockstore::open(&ledger_path) .expect("Expected to be able to open database ledger"), ); - let validator_authorized_voter_keypairs: Vec<_> = (0..20) - .map(|_| ValidatorVoteKeypairs::new(Keypair::new(), Keypair::new(), Keypair::new())) - .collect(); + let validator_authorized_voter_keypairs: Vec<_> = + (0..20).map(|_| ValidatorVoteKeypairs::new_rand()).collect(); let validator_voting_keys: HashMap<_, _> = validator_authorized_voter_keypairs .iter() @@ -1967,7 +1966,7 @@ pub(crate) mod tests { genesis_utils::create_genesis_config_with_vote_accounts( 10_000, &validator_authorized_voter_keypairs, - 100, + vec![100; validator_authorized_voter_keypairs.len()], ); let bank0 = Bank::new(&genesis_config); let mut progress = ProgressMap::default(); @@ -2658,15 +2657,9 @@ pub(crate) mod tests { #[test] fn test_compute_bank_stats_confirmed() { - let node_keypair = Keypair::new(); - let vote_keypair = Keypair::new(); - let stake_keypair = Keypair::new(); - let node_pubkey = node_keypair.pubkey(); - let mut keypairs = HashMap::new(); - keypairs.insert( - node_pubkey, - ValidatorVoteKeypairs::new(node_keypair, vote_keypair, stake_keypair), - ); + let vote_keypairs = ValidatorVoteKeypairs::new_rand(); + let node_pubkey = vote_keypairs.node_keypair.pubkey(); + let keypairs: HashMap<_, _> = vec![(node_pubkey, vote_keypairs)].into_iter().collect(); let (bank_forks, mut progress, mut heaviest_subtree_fork_choice) = initialize_state(&keypairs, 10_000); @@ -2985,14 +2978,8 @@ pub(crate) mod tests { #[test] fn test_update_slot_propagated_threshold_from_votes() { let keypairs: HashMap<_, _> = iter::repeat_with(|| { - let node_keypair = Keypair::new(); - let vote_keypair = Keypair::new(); - let stake_keypair = Keypair::new(); - let node_pubkey = node_keypair.pubkey(); - ( - node_pubkey, - ValidatorVoteKeypairs::new(node_keypair, vote_keypair, stake_keypair), - ) + let vote_keypairs = ValidatorVoteKeypairs::new_rand(); + (vote_keypairs.node_keypair.pubkey(), vote_keypairs) }) .take(10) .collect(); @@ -3165,17 +3152,10 @@ pub(crate) mod tests { #[test] fn test_update_propagation_status() { // Create genesis stakers - let node_keypair = Keypair::new(); - let vote_keypair = Keypair::new(); - let stake_keypair = Keypair::new(); - let vote_pubkey = Arc::new(vote_keypair.pubkey()); - let mut keypairs = HashMap::new(); - - keypairs.insert( - node_keypair.pubkey(), - ValidatorVoteKeypairs::new(node_keypair, vote_keypair, stake_keypair), - ); - + let vote_keypairs = ValidatorVoteKeypairs::new_rand(); + let node_pubkey = vote_keypairs.node_keypair.pubkey(); + let vote_pubkey = Arc::new(vote_keypairs.vote_keypair.pubkey()); + let keypairs: HashMap<_, _> = vec![(node_pubkey, vote_keypairs)].into_iter().collect(); let stake = 10_000; let (mut bank_forks, mut progress_map, _) = initialize_state(&keypairs, stake); @@ -3257,14 +3237,8 @@ pub(crate) mod tests { #[test] fn test_chain_update_propagation_status() { let keypairs: HashMap<_, _> = iter::repeat_with(|| { - let node_keypair = Keypair::new(); - let vote_keypair = Keypair::new(); - let stake_keypair = Keypair::new(); - let node_pubkey = node_keypair.pubkey(); - ( - node_pubkey, - ValidatorVoteKeypairs::new(node_keypair, vote_keypair, stake_keypair), - ) + let vote_keypairs = ValidatorVoteKeypairs::new_rand(); + (vote_keypairs.node_keypair.pubkey(), vote_keypairs) }) .take(10) .collect(); @@ -3340,14 +3314,8 @@ pub(crate) mod tests { fn test_chain_update_propagation_status2() { let num_validators = 6; let keypairs: HashMap<_, _> = iter::repeat_with(|| { - let node_keypair = Keypair::new(); - let vote_keypair = Keypair::new(); - let stake_keypair = Keypair::new(); - let node_pubkey = node_keypair.pubkey(); - ( - node_pubkey, - ValidatorVoteKeypairs::new(node_keypair, vote_keypair, stake_keypair), - ) + let vote_keypairs = ValidatorVoteKeypairs::new_rand(); + (vote_keypairs.node_keypair.pubkey(), vote_keypairs) }) .take(num_validators) .collect(); diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 588ba80596..806ddfd321 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -1786,7 +1786,7 @@ pub mod tests { blockhash: Hash, alice: Keypair, leader_pubkey: Pubkey, - leader_vote_keypair: Keypair, + leader_vote_keypair: Arc, block_commitment_cache: Arc>, confirmed_block_signatures: Vec, } @@ -1847,7 +1847,7 @@ pub mod tests { vote, ); let vote_msg = Message::new(&[vote_ix], Some(&leader_vote_keypair.pubkey())); - let vote_tx = Transaction::new(&[&leader_vote_keypair], vote_msg, Hash::default()); + let vote_tx = Transaction::new(&[&*leader_vote_keypair], vote_msg, Hash::default()); let shreds = entries_to_test_shreds( vec![next_entry_mut(&mut Hash::default(), 0, vec![vote_tx])], 1, @@ -3208,7 +3208,7 @@ pub mod tests { ); } - fn new_bank_forks() -> (Arc>, Keypair, Keypair) { + fn new_bank_forks() -> (Arc>, Keypair, Arc) { let GenesisConfigInfo { mut genesis_config, mint_keypair, diff --git a/core/src/rpc_pubsub.rs b/core/src/rpc_pubsub.rs index 119a915577..288aedda5d 100644 --- a/core/src/rpc_pubsub.rs +++ b/core/src/rpc_pubsub.rs @@ -928,11 +928,13 @@ mod tests { fn test_vote_subscribe() { let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())); - let validator_voting_keypairs: Vec<_> = (0..10) - .map(|_| ValidatorVoteKeypairs::new(Keypair::new(), Keypair::new(), Keypair::new())) - .collect(); - let GenesisConfigInfo { genesis_config, .. } = - create_genesis_config_with_vote_accounts(10_000, &validator_voting_keypairs, 100); + let validator_voting_keypairs: Vec<_> = + (0..10).map(|_| ValidatorVoteKeypairs::new_rand()).collect(); + let GenesisConfigInfo { genesis_config, .. } = create_genesis_config_with_vote_accounts( + 10_000, + &validator_voting_keypairs, + vec![100; validator_voting_keypairs.len()], + ); let exit = Arc::new(AtomicBool::new(false)); let bank = Bank::new(&genesis_config); let bank_forks = BankForks::new(bank); diff --git a/core/src/validator.rs b/core/src/validator.rs index 76f86a3c5f..9167b646c4 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -849,6 +849,8 @@ impl TestValidator { } = create_genesis_config_with_leader_ex( mint_lamports, &contact_info.id, + Arc::new(Keypair::new()), + Arc::new(Keypair::new()), 42, bootstrap_validator_lamports, ); @@ -865,7 +867,6 @@ impl TestValidator { let (ledger_path, blockhash) = create_new_tmp_ledger!(&genesis_config); - let leader_voting_keypair = Arc::new(voting_keypair); let config = ValidatorConfig { rpc_ports: Some((node.info.rpc.port(), node.info.rpc_pubsub.port())), ..ValidatorConfig::default() @@ -874,8 +875,8 @@ impl TestValidator { node, &node_keypair, &ledger_path, - &leader_voting_keypair.pubkey(), - vec![leader_voting_keypair.clone()], + &voting_keypair.pubkey(), + vec![voting_keypair.clone()], None, true, &config, @@ -887,7 +888,7 @@ impl TestValidator { alice: mint_keypair, ledger_path, genesis_hash: blockhash, - vote_pubkey: leader_voting_keypair.pubkey(), + vote_pubkey: voting_keypair.pubkey(), } } } diff --git a/core/tests/gossip.rs b/core/tests/gossip.rs index ce3fd8a00d..13de97b281 100644 --- a/core/tests/gossip.rs +++ b/core/tests/gossip.rs @@ -29,13 +29,12 @@ fn test_node(exit: &Arc) -> (Arc, GossipService, UdpSoc } fn test_node_with_bank( - node_keypair: Keypair, + node_keypair: Arc, exit: &Arc, bank_forks: Arc>, ) -> (Arc, GossipService, UdpSocket) { - let keypair = Arc::new(node_keypair); - let mut test_node = Node::new_localhost_with_pubkey(&keypair.pubkey()); - let cluster_info = Arc::new(ClusterInfo::new(test_node.info.clone(), keypair)); + let mut test_node = Node::new_localhost_with_pubkey(&node_keypair.pubkey()); + let cluster_info = Arc::new(ClusterInfo::new(test_node.info.clone(), node_keypair)); let gossip_service = GossipService::new( &cluster_info, Some(bank_forks), @@ -224,7 +223,11 @@ pub fn cluster_info_scale() { let vote_keypairs: Vec<_> = (0..num_nodes) .map(|_| ValidatorVoteKeypairs::new_rand()) .collect(); - let genesis_config_info = create_genesis_config_with_vote_accounts(10_000, &vote_keypairs, 100); + let genesis_config_info = create_genesis_config_with_vote_accounts( + 10_000, + &vote_keypairs, + vec![100; vote_keypairs.len()], + ); let bank0 = Bank::new(&genesis_config_info.genesis_config); let bank_forks = Arc::new(RwLock::new(BankForks::new(bank0))); diff --git a/local-cluster/src/cluster_tests.rs b/local-cluster/src/cluster_tests.rs index 7da84a5b6d..e737b004ab 100644 --- a/local-cluster/src/cluster_tests.rs +++ b/local-cluster/src/cluster_tests.rs @@ -16,11 +16,10 @@ use solana_ledger::{ use solana_sdk::{ client::SyncClient, clock::{ - self, Slot, DEFAULT_MS_PER_SLOT, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, - NUM_CONSECUTIVE_LEADER_SLOTS, + self, Slot, DEFAULT_TICKS_PER_SECOND, DEFAULT_TICKS_PER_SLOT, NUM_CONSECUTIVE_LEADER_SLOTS, }, commitment_config::CommitmentConfig, - epoch_schedule::{EpochSchedule, MINIMUM_SLOTS_PER_EPOCH}, + epoch_schedule::MINIMUM_SLOTS_PER_EPOCH, hash::Hash, poh_config::PohConfig, pubkey::Pubkey, @@ -172,11 +171,6 @@ pub fn verify_ledger_ticks(ledger_path: &Path, ticks_per_slot: usize) { } } -pub fn time_until_nth_epoch(epoch: u64, slots_per_epoch: u64, stakers_slot_offset: u64) -> u64 { - let epoch_schedule = EpochSchedule::custom(slots_per_epoch, stakers_slot_offset, true); - epoch_schedule.get_last_slot_in_epoch(epoch) * DEFAULT_MS_PER_SLOT -} - pub fn sleep_n_epochs( num_epochs: f64, config: &PohConfig, diff --git a/local-cluster/src/local_cluster.rs b/local-cluster/src/local_cluster.rs index 79c649a2c5..e299f08640 100644 --- a/local-cluster/src/local_cluster.rs +++ b/local-cluster/src/local_cluster.rs @@ -11,9 +11,9 @@ use solana_core::{ gossip_service::discover_cluster, validator::{Validator, ValidatorConfig}, }; -use solana_ledger::{ - create_new_tmp_ledger, - genesis_utils::{create_genesis_config_with_leader, GenesisConfigInfo}, +use solana_ledger::create_new_tmp_ledger; +use solana_runtime::genesis_utils::{ + create_genesis_config_with_vote_accounts, GenesisConfigInfo, ValidatorVoteKeypairs, }; use solana_sdk::{ client::SyncClient, @@ -49,8 +49,12 @@ pub struct ClusterConfig { pub validator_configs: Vec, /// Number of nodes that are unstaked and not voting (a.k.a listening) pub num_listeners: u64, - /// The specific pubkeys of each node if specified - pub validator_keys: Option>>, + /// List of tuples (pubkeys, in_genesis) of each node if specified. If + /// `in_genesis` == true, the validator's vote and stake accounts + // will be inserted into the genesis block instead of warming up through + // creating the vote accounts. The first validator (bootstrap leader) automatically + // is assumed to be `in_genesis` == true. + pub validator_keys: Option, bool)>>, /// The stakes of each node pub node_stakes: Vec, /// The total lamports available to the cluster @@ -58,6 +62,7 @@ pub struct ClusterConfig { pub ticks_per_slot: u64, pub slots_per_epoch: u64, pub stakers_slot_offset: u64, + pub skip_warmup_slots: bool, pub native_instruction_processors: Vec<(String, Pubkey)>, pub operating_mode: OperatingMode, pub poh_config: PohConfig, @@ -77,6 +82,7 @@ impl Default for ClusterConfig { native_instruction_processors: vec![], operating_mode: OperatingMode::Development, poh_config: PohConfig::default(), + skip_warmup_slots: false, } } } @@ -108,32 +114,57 @@ impl LocalCluster { pub fn new(config: &ClusterConfig) -> Self { assert_eq!(config.validator_configs.len(), config.node_stakes.len()); - let validator_keys = { + let mut validator_keys = { if let Some(ref keys) = config.validator_keys { assert_eq!(config.validator_configs.len(), keys.len()); keys.clone() } else { - iter::repeat_with(|| Arc::new(Keypair::new())) + iter::repeat_with(|| (Arc::new(Keypair::new()), false)) .take(config.validator_configs.len()) .collect() } }; - let leader_keypair = &validator_keys[0]; + // Bootstrap leader should always be in genesis block + validator_keys[0].1 = true; + let (keys_in_genesis, stakes_in_genesis): (Vec, Vec) = + validator_keys + .iter() + .zip(&config.node_stakes) + .filter_map(|((node_keypair, in_genesis), stake)| { + if *in_genesis { + Some(( + ValidatorVoteKeypairs { + node_keypair: node_keypair.clone(), + vote_keypair: Arc::new(Keypair::new()), + stake_keypair: Arc::new(Keypair::new()), + }, + stake, + )) + } else { + None + } + }) + .unzip(); + let leader_keypair = &keys_in_genesis[0].node_keypair; + let leader_vote_keypair = &keys_in_genesis[0].vote_keypair; let leader_pubkey = leader_keypair.pubkey(); let leader_node = Node::new_localhost_with_pubkey(&leader_pubkey); let GenesisConfigInfo { mut genesis_config, mint_keypair, - voting_keypair, - } = create_genesis_config_with_leader( + .. + } = create_genesis_config_with_vote_accounts( config.cluster_lamports, - &leader_pubkey, - config.node_stakes[0], + &keys_in_genesis, + stakes_in_genesis, ); genesis_config.ticks_per_slot = config.ticks_per_slot; - genesis_config.epoch_schedule = - EpochSchedule::custom(config.slots_per_epoch, config.stakers_slot_offset, true); + genesis_config.epoch_schedule = EpochSchedule::custom( + config.slots_per_epoch, + config.stakers_slot_offset, + !config.skip_warmup_slots, + ); genesis_config.operating_mode = config.operating_mode; genesis_config.poh_config = config.poh_config.clone(); @@ -167,7 +198,6 @@ impl LocalCluster { let (leader_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config); let leader_contact_info = leader_node.info.clone(); - let leader_voting_keypair = Arc::new(voting_keypair); let mut leader_config = config.validator_configs[0].clone(); leader_config.rpc_ports = Some(( leader_node.info.rpc.port(), @@ -176,10 +206,10 @@ impl LocalCluster { leader_config.account_paths = vec![leader_ledger_path.join("accounts")]; let leader_server = Validator::new( leader_node, - &leader_keypair, + leader_keypair, &leader_ledger_path, - &leader_voting_keypair.pubkey(), - vec![leader_voting_keypair.clone()], + &leader_vote_keypair.pubkey(), + vec![leader_vote_keypair.clone()], None, true, &leader_config, @@ -188,7 +218,7 @@ impl LocalCluster { let mut validators = HashMap::new(); let leader_info = ValidatorInfo { keypair: leader_keypair.clone(), - voting_keypair: leader_voting_keypair, + voting_keypair: leader_vote_keypair.clone(), ledger_path: leader_ledger_path, contact_info: leader_contact_info.clone(), }; @@ -208,12 +238,21 @@ impl LocalCluster { genesis_config, }; - for (stake, validator_config, key) in izip!( + let node_pubkey_to_vote_key: HashMap> = keys_in_genesis + .into_iter() + .map(|keypairs| (keypairs.node_keypair.pubkey(), keypairs.vote_keypair)) + .collect(); + for (stake, validator_config, (key, _)) in izip!( (&config.node_stakes[1..]).iter(), config.validator_configs[1..].iter(), validator_keys[1..].iter(), ) { - cluster.add_validator(validator_config, *stake, key.clone()); + cluster.add_validator( + validator_config, + *stake, + key.clone(), + node_pubkey_to_vote_key.get(&key.pubkey()).cloned(), + ); } let listener_config = ValidatorConfig { @@ -221,7 +260,7 @@ impl LocalCluster { ..config.validator_configs[0].clone() }; (0..config.num_listeners).for_each(|_| { - cluster.add_validator(&listener_config, 0, Arc::new(Keypair::new())); + cluster.add_validator(&listener_config, 0, Arc::new(Keypair::new()), None); }); discover_cluster( @@ -257,6 +296,7 @@ impl LocalCluster { validator_config: &ValidatorConfig, stake: u64, validator_keypair: Arc, + mut voting_keypair: Option>, ) -> Pubkey { let client = create_client( self.entry_point_info.client_facing_addr(), @@ -264,7 +304,10 @@ impl LocalCluster { ); // Must have enough tokens to fund vote account and set delegate - let voting_keypair = Keypair::new(); + let should_create_vote_pubkey = voting_keypair.is_none(); + if voting_keypair.is_none() { + voting_keypair = Some(Arc::new(Keypair::new())); + } let validator_pubkey = validator_keypair.pubkey(); let validator_node = Node::new_localhost_with_pubkey(&validator_keypair.pubkey()); let contact_info = validator_node.info.clone(); @@ -275,24 +318,25 @@ impl LocalCluster { info!("listener {} ", validator_pubkey,); } else { // Give the validator some lamports to setup vote accounts - let validator_balance = Self::transfer_with_client( - &client, - &self.funding_keypair, - &validator_pubkey, - stake * 2 + 2, - ); - info!( - "validator {} balance {}", - validator_pubkey, validator_balance - ); - - Self::setup_vote_and_stake_accounts( - &client, - &voting_keypair, - &validator_keypair, - stake, - ) - .unwrap(); + if should_create_vote_pubkey { + let validator_balance = Self::transfer_with_client( + &client, + &self.funding_keypair, + &validator_pubkey, + stake * 2 + 2, + ); + info!( + "validator {} balance {}", + validator_pubkey, validator_balance + ); + Self::setup_vote_and_stake_accounts( + &client, + voting_keypair.as_ref().unwrap(), + &validator_keypair, + stake, + ) + .unwrap(); + } } let mut config = validator_config.clone(); @@ -300,8 +344,8 @@ impl LocalCluster { validator_node.info.rpc.port(), validator_node.info.rpc_pubsub.port(), )); - let voting_keypair = Arc::new(voting_keypair); config.account_paths = vec![ledger_path.join("accounts")]; + let voting_keypair = voting_keypair.unwrap(); let validator_server = Validator::new( validator_node, &validator_keypair, @@ -417,6 +461,10 @@ impl LocalCluster { ) -> Result<()> { let vote_account_pubkey = vote_account.pubkey(); let node_pubkey = from_account.pubkey(); + info!( + "setup_vote_and_stake_accounts: {}, {}", + node_pubkey, vote_account_pubkey + ); let stake_account_keypair = Keypair::new(); let stake_account_pubkey = stake_account_keypair.pubkey(); diff --git a/local-cluster/tests/local_cluster.rs b/local-cluster/tests/local_cluster.rs index 088a40ca20..0921f4d550 100644 --- a/local-cluster/tests/local_cluster.rs +++ b/local-cluster/tests/local_cluster.rs @@ -229,7 +229,6 @@ fn run_cluster_partition( .collect(); assert_eq!(node_stakes.len(), num_nodes); let cluster_lamports = node_stakes.iter().sum::() * 2; - let partition_start_epoch = 2; let enable_partition = Arc::new(AtomicBool::new(true)); let mut validator_config = ValidatorConfig::default(); validator_config.enable_partition = Some(enable_partition.clone()); @@ -243,7 +242,7 @@ fn run_cluster_partition( assert_eq!(validator_keys.len(), num_nodes); let num_slots_per_rotation = leader_schedule.num_slots() as u64; let fixed_schedule = FixedSchedule { - start_epoch: partition_start_epoch, + start_epoch: 0, leader_schedule: Arc::new(leader_schedule), }; validator_config.fixed_leader_schedule = Some(fixed_schedule); @@ -261,11 +260,20 @@ fn run_cluster_partition( } }; + let slots_per_epoch = 2048; let config = ClusterConfig { cluster_lamports, node_stakes, validator_configs: vec![validator_config; num_nodes], - validator_keys: Some(validator_keys), + validator_keys: Some( + validator_keys + .into_iter() + .zip(iter::repeat_with(|| true)) + .collect(), + ), + slots_per_epoch, + stakers_slot_offset: slots_per_epoch, + skip_warmup_slots: true, ..ClusterConfig::default() }; @@ -275,33 +283,29 @@ fn run_cluster_partition( ); let mut cluster = LocalCluster::new(&config); + info!("PARTITION_TEST spend_and_verify_all_nodes(), ensure all nodes are caught up"); + cluster_tests::spend_and_verify_all_nodes( + &cluster.entry_point_info, + &cluster.funding_keypair, + num_nodes, + HashSet::new(), + ); + let cluster_nodes = discover_cluster(&cluster.entry_point_info.gossip, num_nodes).unwrap(); + // Check epochs have correct number of slots info!("PARTITION_TEST sleeping until partition starting condition",); - loop { - let mut reached_epoch = true; - for node in &cluster_nodes { - let node_client = RpcClient::new_socket(node.rpc); - if let Ok(epoch_info) = node_client.get_epoch_info() { - info!("slots_per_epoch: {:?}", epoch_info); - if epoch_info.slots_in_epoch <= (1 << VOTE_THRESHOLD_DEPTH) { - reached_epoch = false; - break; - } - } else { - reached_epoch = false; - } - } - - if reached_epoch { - info!("PARTITION_TEST start partition"); - enable_partition.store(false, Ordering::Relaxed); - on_partition_start(&mut cluster); - break; - } else { - sleep(Duration::from_millis(100)); - } + for node in &cluster_nodes { + let node_client = RpcClient::new_socket(node.rpc); + let epoch_info = node_client.get_epoch_info().unwrap(); + info!("slots_per_epoch: {:?}", epoch_info); + assert_eq!(epoch_info.slots_in_epoch, slots_per_epoch); } + + info!("PARTITION_TEST start partition"); + enable_partition.store(false, Ordering::Relaxed); + on_partition_start(&mut cluster); + sleep(Duration::from_millis(leader_schedule_time)); info!("PARTITION_TEST remove partition"); @@ -472,7 +476,6 @@ fn run_kill_partition_switch_threshold( } #[test] -#[ignore] #[serial] fn test_kill_partition_switch_threshold_no_progress() { let max_switch_threshold_failure_pct = 1.0 - 2.0 * SWITCH_FORK_THRESHOLD; @@ -501,9 +504,8 @@ fn test_kill_partition_switch_threshold_no_progress() { } #[test] -#[ignore] #[serial] -fn test_kill_partition_switch_threshold() { +fn test_kill_partition_switch_threshold_progress() { let max_switch_threshold_failure_pct = 1.0 - 2.0 * SWITCH_FORK_THRESHOLD; let total_stake = 10_000; @@ -760,7 +762,7 @@ fn test_frozen_account_from_genesis() { Arc::new(solana_sdk::signature::keypair_from_seed(&[0u8; 32]).unwrap()); let config = ClusterConfig { - validator_keys: Some(vec![validator_identity.clone()]), + validator_keys: Some(vec![(validator_identity.clone(), true)]), node_stakes: vec![100; 1], cluster_lamports: 1_000, validator_configs: vec![ @@ -788,7 +790,7 @@ fn test_frozen_account_from_snapshot() { snapshot_test_config.validator_config.frozen_accounts = vec![validator_identity.pubkey()]; let config = ClusterConfig { - validator_keys: Some(vec![validator_identity.clone()]), + validator_keys: Some(vec![(validator_identity.clone(), true)]), node_stakes: vec![100; 1], cluster_lamports: 1_000, validator_configs: vec![snapshot_test_config.validator_config.clone()], @@ -864,6 +866,7 @@ fn test_consistency_halt() { &validator_snapshot_test_config.validator_config, validator_stake as u64, Arc::new(Keypair::new()), + None, ); let num_nodes = 2; assert_eq!( @@ -958,6 +961,7 @@ fn test_snapshot_download() { &validator_snapshot_test_config.validator_config, stake, Arc::new(Keypair::new()), + None, ); } @@ -1095,6 +1099,7 @@ fn test_snapshots_blockstore_floor() { &validator_snapshot_test_config.validator_config, validator_stake, Arc::new(Keypair::new()), + None, ); let all_pubkeys = cluster.get_node_pubkeys(); let validator_id = all_pubkeys diff --git a/runtime/src/bank_utils.rs b/runtime/src/bank_utils.rs index 312862dbe4..15c766a523 100644 --- a/runtime/src/bank_utils.rs +++ b/runtime/src/bank_utils.rs @@ -2,15 +2,12 @@ use crate::{ bank::Bank, genesis_utils::{self, GenesisConfigInfo, ValidatorVoteKeypairs}, }; -use solana_sdk::{ - pubkey::Pubkey, - signature::{Keypair, Signer}, -}; +use solana_sdk::{pubkey::Pubkey, signature::Signer}; pub fn setup_bank_and_vote_pubkeys(num_vote_accounts: usize, stake: u64) -> (Bank, Vec) { // Create some voters at genesis let validator_voting_keypairs: Vec<_> = (0..num_vote_accounts) - .map(|_| ValidatorVoteKeypairs::new(Keypair::new(), Keypair::new(), Keypair::new())) + .map(|_| ValidatorVoteKeypairs::new_rand()) .collect(); let vote_pubkeys: Vec<_> = validator_voting_keypairs @@ -21,7 +18,7 @@ pub fn setup_bank_and_vote_pubkeys(num_vote_accounts: usize, stake: u64) -> (Ban genesis_utils::create_genesis_config_with_vote_accounts( 10_000, &validator_voting_keypairs, - stake, + vec![stake; validator_voting_keypairs.len()], ); let bank = Bank::new(&genesis_config); (bank, vote_pubkeys) diff --git a/runtime/src/genesis_utils.rs b/runtime/src/genesis_utils.rs index 000a9ead13..be2645eaf6 100644 --- a/runtime/src/genesis_utils.rs +++ b/runtime/src/genesis_utils.rs @@ -9,19 +9,23 @@ use solana_sdk::{ }; use solana_stake_program::stake_state; use solana_vote_program::vote_state; -use std::borrow::Borrow; +use std::{borrow::Borrow, sync::Arc}; // The default stake placed with the bootstrap validator pub const BOOTSTRAP_VALIDATOR_LAMPORTS: u64 = 42; pub struct ValidatorVoteKeypairs { - pub node_keypair: Keypair, - pub vote_keypair: Keypair, - pub stake_keypair: Keypair, + pub node_keypair: Arc, + pub vote_keypair: Arc, + pub stake_keypair: Arc, } impl ValidatorVoteKeypairs { - pub fn new(node_keypair: Keypair, vote_keypair: Keypair, stake_keypair: Keypair) -> Self { + pub fn new( + node_keypair: Arc, + vote_keypair: Arc, + stake_keypair: Arc, + ) -> Self { Self { node_keypair, vote_keypair, @@ -31,9 +35,9 @@ impl ValidatorVoteKeypairs { pub fn new_rand() -> Self { Self { - node_keypair: Keypair::new(), - vote_keypair: Keypair::new(), - stake_keypair: Keypair::new(), + node_keypair: Arc::new(Keypair::new()), + vote_keypair: Arc::new(Keypair::new()), + stake_keypair: Arc::new(Keypair::new()), } } } @@ -41,7 +45,7 @@ impl ValidatorVoteKeypairs { pub struct GenesisConfigInfo { pub genesis_config: GenesisConfig, pub mint_keypair: Keypair, - pub voting_keypair: Keypair, + pub voting_keypair: Arc, } pub fn create_genesis_config(mint_lamports: u64) -> GenesisConfigInfo { @@ -51,15 +55,26 @@ pub fn create_genesis_config(mint_lamports: u64) -> GenesisConfigInfo { pub fn create_genesis_config_with_vote_accounts( mint_lamports: u64, voting_keypairs: &[impl Borrow], - stake: u64, + stakes: Vec, ) -> GenesisConfigInfo { - let mut genesis_config_info = create_genesis_config(mint_lamports); - for validator_voting_keypairs in voting_keypairs { + assert_eq!(voting_keypairs.len(), stakes.len()); + + let mut genesis_config_info = create_genesis_config_with_leader_ex( + mint_lamports, + &voting_keypairs[0].borrow().node_keypair.pubkey(), + voting_keypairs[0].borrow().vote_keypair.clone(), + voting_keypairs[0].borrow().stake_keypair.clone(), + stakes[0], + BOOTSTRAP_VALIDATOR_LAMPORTS, + ); + + for (validator_voting_keypairs, stake) in voting_keypairs.iter().zip(stakes) { let node_pubkey = validator_voting_keypairs.borrow().node_keypair.pubkey(); let vote_pubkey = validator_voting_keypairs.borrow().vote_keypair.pubkey(); let stake_pubkey = validator_voting_keypairs.borrow().stake_keypair.pubkey(); // Create accounts + let node_account = Account::new(BOOTSTRAP_VALIDATOR_LAMPORTS, 0, &system_program::id()); let vote_account = vote_state::create_account(&vote_pubkey, &node_pubkey, 0, stake); let stake_account = stake_state::create_account( &stake_pubkey, @@ -71,7 +86,8 @@ pub fn create_genesis_config_with_vote_accounts( // Put newly created accounts into genesis genesis_config_info.genesis_config.accounts.extend(vec![ - (vote_pubkey, vote_account.clone()), + (node_pubkey, node_account), + (vote_pubkey, vote_account), (stake_pubkey, stake_account), ]); } @@ -87,6 +103,8 @@ pub fn create_genesis_config_with_leader( create_genesis_config_with_leader_ex( mint_lamports, bootstrap_validator_pubkey, + Arc::new(Keypair::new()), + Arc::new(Keypair::new()), bootstrap_validator_stake_lamports, BOOTSTRAP_VALIDATOR_LAMPORTS, ) @@ -95,13 +113,12 @@ pub fn create_genesis_config_with_leader( pub fn create_genesis_config_with_leader_ex( mint_lamports: u64, bootstrap_validator_pubkey: &Pubkey, + bootstrap_validator_voting_keypair: Arc, + bootstrap_validator_staking_keypair: Arc, bootstrap_validator_stake_lamports: u64, bootstrap_validator_lamports: u64, ) -> GenesisConfigInfo { let mint_keypair = Keypair::new(); - let bootstrap_validator_voting_keypair = Keypair::new(); - let bootstrap_validator_staking_keypair = Keypair::new(); - let bootstrap_validator_vote_account = vote_state::create_account( &bootstrap_validator_voting_keypair.pubkey(), &bootstrap_validator_pubkey,