From 3217a1d70cdaed1b8b2e2f833b1d81f61a22b36c Mon Sep 17 00:00:00 2001 From: Rob Walker Date: Tue, 11 Jun 2019 11:44:58 -0700 Subject: [PATCH] use highest staked node as bootstrap leader, remove bootstrap_leader from genesis_block (#4635) * use highest staked node as bootstrap leader, remove bootstrap_leader from genesis_block * clippy * fixup * fixup --- core/src/locktower.rs | 2 +- core/src/replay_stage.rs | 4 ++-- genesis/src/main.rs | 3 +-- runtime/src/bank.rs | 12 +++++++++--- runtime/src/genesis_utils.rs | 1 - runtime/src/stakes.rs | 32 ++++++++++++++++++++++++++++++++ sdk/src/genesis_block.rs | 5 ----- 7 files changed, 45 insertions(+), 14 deletions(-) diff --git a/core/src/locktower.rs b/core/src/locktower.rs index 24ea4131b..8bbf9c021 100644 --- a/core/src/locktower.rs +++ b/core/src/locktower.rs @@ -391,7 +391,7 @@ impl Locktower { let mut lockouts = VoteState::default(); if let Some(iter) = bank.epoch_vote_accounts(current_epoch) { for (delegate_pubkey, (_, account)) in iter { - if *delegate_pubkey == bank.collector_id() { + if delegate_pubkey == bank.collector_id() { let state = VoteState::deserialize(&account.data).expect("votes"); if lockouts.votes.len() < state.votes.len() { lockouts = state; diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index 6bf65f712..6eda01e11 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -388,7 +388,7 @@ impl ReplayStage { for bank_slot in &active_banks { let bank = bank_forks.read().unwrap().get(*bank_slot).unwrap().clone(); *ticks_per_slot = bank.ticks_per_slot(); - if bank.collector_id() != *my_pubkey { + if bank.collector_id() != my_pubkey { Self::replay_blocktree_into_bank(&bank, &blocktree, progress)?; } let max_tick_height = (*bank_slot + 1) * bank.ticks_per_slot() - 1; @@ -567,7 +567,7 @@ impl ReplayStage { ) { bank.freeze(); info!("bank frozen {}", bank.slot()); - if let Err(e) = slot_full_sender.send((bank.slot(), bank.collector_id())) { + if let Err(e) = slot_full_sender.send((bank.slot(), *bank.collector_id())) { trace!("{} slot_full alert failed: {:?}", my_pubkey, e); } } diff --git a/genesis/src/main.rs b/genesis/src/main.rs index 0d4a911ac..0d8d67ccc 100644 --- a/genesis/src/main.rs +++ b/genesis/src/main.rs @@ -247,7 +247,6 @@ fn main() -> Result<(), Box> { ); let mut genesis_block = GenesisBlock::new( - &bootstrap_leader_keypair.pubkey(), &[ // the mint ( @@ -366,7 +365,7 @@ mod tests { #[test] fn test_append_primordial_accounts_to_genesis() { - let mut genesis_block = GenesisBlock::new(&Pubkey::new_rand(), &[], &[]); + let mut genesis_block = GenesisBlock::new(&[], &[]); // Test invalid file returns error assert!(append_primordial_accounts("unknownfile", &mut genesis_block).is_err()); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index e663fbb67..039727123 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -345,8 +345,8 @@ impl Bank { bank } - pub fn collector_id(&self) -> Pubkey { - self.collector_id + pub fn collector_id(&self) -> &Pubkey { + &self.collector_id } pub fn slot(&self) -> u64 { @@ -473,13 +473,19 @@ impl Bank { fn process_genesis_block(&mut self, genesis_block: &GenesisBlock) { // Bootstrap leader collects fees until `new_from_parent` is called. - self.collector_id = genesis_block.bootstrap_leader_pubkey; self.fee_calculator = genesis_block.fee_calculator.clone(); self.update_fees(); for (pubkey, account) in genesis_block.accounts.iter() { self.store(pubkey, account); } + // highest staked node is the first collector + self.collector_id = self + .stakes + .read() + .unwrap() + .highest_staked_node() + .unwrap_or_default(); self.blockhash_queue .write() diff --git a/runtime/src/genesis_utils.rs b/runtime/src/genesis_utils.rs index 24ecf63b4..bd454359e 100644 --- a/runtime/src/genesis_utils.rs +++ b/runtime/src/genesis_utils.rs @@ -39,7 +39,6 @@ pub fn create_genesis_block_with_leader( ); let genesis_block = GenesisBlock::new( - &bootstrap_leader_pubkey, &[ // the mint ( diff --git a/runtime/src/stakes.rs b/runtime/src/stakes.rs index 849609647..0017e891f 100644 --- a/runtime/src/stakes.rs +++ b/runtime/src/stakes.rs @@ -3,6 +3,7 @@ use solana_sdk::account::Account; use solana_sdk::pubkey::Pubkey; use solana_stake_api::stake_state::StakeState; +use solana_vote_api::vote_state::VoteState; use std::collections::HashMap; #[derive(Default, Clone, PartialEq, Debug, Deserialize, Serialize)] @@ -84,6 +85,14 @@ impl Stakes { pub fn vote_accounts(&self) -> &HashMap { &self.vote_accounts } + + pub fn highest_staked_node(&self) -> Option { + self.vote_accounts + .iter() + .max_by(|(_ak, av), (_bk, bv)| av.0.cmp(&bv.0)) + .and_then(|(_k, (_stake, account))| VoteState::from(account)) + .map(|vote_state| vote_state.node_pubkey) + } } #[cfg(test)] @@ -153,6 +162,29 @@ mod tests { } } + #[test] + fn test_stakes_highest() { + let mut stakes = Stakes::default(); + + assert_eq!(stakes.highest_staked_node(), None); + + let ((vote_pubkey, vote_account), (stake_pubkey, stake_account)) = + create_staked_node_accounts(10); + + stakes.store(&vote_pubkey, &vote_account); + stakes.store(&stake_pubkey, &stake_account); + + let ((vote11_pubkey, vote11_account), (stake11_pubkey, stake11_account)) = + create_staked_node_accounts(11); + + stakes.store(&vote11_pubkey, &vote11_account); + stakes.store(&stake11_pubkey, &stake11_account); + + let vote11_node_pubkey = VoteState::from(&vote11_account).unwrap().node_pubkey; + + assert_eq!(stakes.highest_staked_node(), Some(vote11_node_pubkey)) + } + #[test] fn test_stakes_vote_account_disappear_reappear() { let mut stakes = Stakes::default(); diff --git a/sdk/src/genesis_block.rs b/sdk/src/genesis_block.rs index 4ca4f5472..7a031d2a4 100644 --- a/sdk/src/genesis_block.rs +++ b/sdk/src/genesis_block.rs @@ -15,7 +15,6 @@ use std::path::Path; #[derive(Serialize, Deserialize, Debug)] pub struct GenesisBlock { pub accounts: Vec<(Pubkey, Account)>, - pub bootstrap_leader_pubkey: Pubkey, pub epoch_warmup: bool, pub fee_calculator: FeeCalculator, pub native_instruction_processors: Vec<(String, Pubkey)>, @@ -30,7 +29,6 @@ pub fn create_genesis_block(lamports: u64) -> (GenesisBlock, Keypair) { let mint_keypair = Keypair::new(); ( GenesisBlock::new( - &Pubkey::default(), &[( mint_keypair.pubkey(), Account::new(lamports, 0, &system_program::id()), @@ -43,13 +41,11 @@ pub fn create_genesis_block(lamports: u64) -> (GenesisBlock, Keypair) { impl GenesisBlock { pub fn new( - bootstrap_leader_pubkey: &Pubkey, accounts: &[(Pubkey, Account)], native_instruction_processors: &[(String, Pubkey)], ) -> Self { Self { accounts: accounts.to_vec(), - bootstrap_leader_pubkey: *bootstrap_leader_pubkey, // TODO: leader_schedule to derive from actual stakes, instead ;) epoch_warmup: true, fee_calculator: FeeCalculator::default(), native_instruction_processors: native_instruction_processors.to_vec(), @@ -105,7 +101,6 @@ mod tests { fn test_genesis_block() { let mint_keypair = Keypair::new(); let block = GenesisBlock::new( - &Pubkey::default(), &[ ( mint_keypair.pubkey(),