diff --git a/ledger/src/leader_schedule.rs b/ledger/src/leader_schedule.rs index 57eaf8fb82f892..1f4938b8a5a1e1 100644 --- a/ledger/src/leader_schedule.rs +++ b/ledger/src/leader_schedule.rs @@ -4,6 +4,7 @@ use { rand_chacha::{rand_core::SeedableRng, ChaChaRng}, solana_pubkey::Pubkey, solana_sdk::clock::Epoch, + solana_vote::vote_account::VoteAccountsHashMap, std::{collections::HashMap, convert::identity, ops::Index, sync::Arc}, }; @@ -22,6 +23,27 @@ pub struct LeaderSchedule { } impl LeaderSchedule { + // Note: passing in zero vote accounts will cause a panic. + pub fn new_by_vote_delegation( + vote_accounts_map: &VoteAccountsHashMap, + epoch: Epoch, + len: u64, + repeat: u64, + ) -> Self { + let stakes: Vec<_> = vote_accounts_map + .iter() + .map(|(vote_pubkey, (stake, _account))| (*vote_pubkey, *stake)) + .collect(); + let slot_leaders = Self::stake_weighted_slot_leaders( + stakes, + |vote_key| *vote_accounts_map.get(vote_key).unwrap().1.node_pubkey(), + epoch, + len, + repeat, + ); + Self::new_from_schedule(slot_leaders) + } + // Note: passing in zero stakers will cause a panic. pub fn new_by_node_total_stake( stakes: &HashMap, @@ -33,13 +55,15 @@ impl LeaderSchedule { .iter() .map(|(pubkey, stake)| (*pubkey, *stake)) .collect(); - let slot_leaders = Self::stake_weighted_slot_leaders(stakes, epoch, len, repeat); + let slot_leaders = + Self::stake_weighted_slot_leaders(stakes, |leader| *leader, epoch, len, repeat); Self::new_from_schedule(slot_leaders) } // Note: passing in zero stakers will cause a panic. fn stake_weighted_slot_leaders( mut stakes: Vec<(Pubkey, u64)>, + get_leader_node: impl Fn(&Pubkey) -> Pubkey, epoch: Epoch, len: u64, repeat: u64, @@ -54,7 +78,7 @@ impl LeaderSchedule { (0..len) .map(|i| { if i % repeat == 0 { - current_node = ids[weighted_index.sample(rng)]; + current_node = get_leader_node(&ids[weighted_index.sample(rng)]); } current_node }) diff --git a/ledger/src/leader_schedule_utils.rs b/ledger/src/leader_schedule_utils.rs index 12068b718ca7bb..b8bdfeeb85c3c6 100644 --- a/ledger/src/leader_schedule_utils.rs +++ b/ledger/src/leader_schedule_utils.rs @@ -10,14 +10,33 @@ use { /// Return the leader schedule for the given epoch. pub fn leader_schedule(epoch: Epoch, bank: &Bank) -> Option { - bank.epoch_staked_nodes(epoch).map(|stakes| { - LeaderSchedule::new_by_node_total_stake( - &stakes, - epoch, - bank.get_slots_in_epoch(epoch), - NUM_CONSECUTIVE_LEADER_SLOTS, - ) - }) + let use_new_leader_schedule = match bank + .feature_set + .new_leader_schedule_epoch(bank.epoch_schedule()) + { + Some(new_leader_schedule_epoch) => epoch >= new_leader_schedule_epoch, + None => false, + }; + + if use_new_leader_schedule { + bank.epoch_vote_accounts(epoch).map(|vote_accounts_map| { + LeaderSchedule::new_by_vote_delegation( + vote_accounts_map, + epoch, + bank.get_slots_in_epoch(epoch), + NUM_CONSECUTIVE_LEADER_SLOTS, + ) + }) + } else { + bank.epoch_staked_nodes(epoch).map(|stakes| { + LeaderSchedule::new_by_node_total_stake( + &stakes, + epoch, + bank.get_slots_in_epoch(epoch), + NUM_CONSECUTIVE_LEADER_SLOTS, + ) + }) + } } /// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot diff --git a/sdk/feature-set/src/lib.rs b/sdk/feature-set/src/lib.rs index 27c9da24d2e09c..f8dfb541a902ab 100644 --- a/sdk/feature-set/src/lib.rs +++ b/sdk/feature-set/src/lib.rs @@ -920,6 +920,10 @@ pub mod reserve_minimal_cus_for_builtin_instructions { solana_pubkey::declare_id!("C9oAhLxDBm3ssWtJx1yBGzPY55r2rArHmN1pbQn6HogH"); } +pub mod enable_vote_address_leader_schedule { + solana_pubkey::declare_id!("5JsG4NWH8Jbrqdd8uL6BNwnyZK3dQSoieRXG5vmofj9y"); +} + pub mod raise_block_limits_to_50m { solana_pubkey::declare_id!("5oMCU3JPaFLr8Zr4ct7yFA7jdk6Mw1RmB8K4u9ZbS42z"); } @@ -1149,6 +1153,7 @@ lazy_static! { (deplete_cu_meter_on_vm_failure::id(), "Deplete compute meter for vm errors SIMD-0182 #3993"), (reserve_minimal_cus_for_builtin_instructions::id(), "Reserve minimal CUs for builtin instructions SIMD-170 #2562"), (raise_block_limits_to_50m::id(), "Raise block limit to 50M SIMD-0207"), + (enable_vote_address_leader_schedule::id(), "Enable vote address leader schedule SIMD-0180 #4573"), (fix_alt_bn128_multiplication_input_length::id(), "fix alt_bn128 multiplication input length SIMD-0222 #3686"), /*************** ADD NEW FEATURES HERE ***************/ ] @@ -1212,6 +1217,19 @@ impl FeatureSet { self.active.get(feature_id).copied() } + pub fn new_leader_schedule_epoch(&self, epoch_schedule: &EpochSchedule) -> Option { + // check the epoch of the slot when the new leader schedule feature was + // activated and then use the following epoch to start using the new + // leader schedule. + const NEW_LEADER_SCHEDULE_EPOCH_DELAY: u64 = 1; + self.activated_slot(&enable_vote_address_leader_schedule::id()) + .map(|slot| { + epoch_schedule + .get_epoch(slot) + .wrapping_add(NEW_LEADER_SCHEDULE_EPOCH_DELAY) + }) + } + /// List of enabled features that trigger full inflation pub fn full_inflation_features_enabled(&self) -> AHashSet { let mut hash_set = FULL_INFLATION_FEATURE_PAIRS