diff --git a/leader-schedule/src/lib.rs b/leader-schedule/src/lib.rs index e528434c36a7f1..3f30d925fdbb3a 100644 --- a/leader-schedule/src/lib.rs +++ b/leader-schedule/src/lib.rs @@ -8,7 +8,7 @@ use { rand_chacha::{ChaChaRng, rand_core::SeedableRng}, solana_clock::Epoch, solana_pubkey::Pubkey, - std::{num::NonZeroUsize, sync::Arc}, + std::{iter, num::NonZeroUsize, sync::Arc}, }; mod vote_keyed; @@ -58,14 +58,8 @@ fn stake_weighted_slot_leaders( let mut seed = [0u8; 32]; seed[0..8].copy_from_slice(&epoch.to_le_bytes()); let rng = &mut ChaChaRng::from_seed(seed); - let mut current_slot_leader = SlotLeader::default(); - (0..len) - .map(|i| { - if i % repeat == 0 { - current_slot_leader = slot_leaders[weighted_index.sample(rng)]; - } - current_slot_leader - }) + iter::repeat_with(|| slot_leaders[weighted_index.sample(rng)]) + .take(len / repeat) .collect() } @@ -103,7 +97,7 @@ mod tests { let schedule: Vec<_> = repeat_with(|| unique_leaders[rng.random_range(0..3)]) .take(19) .collect(); - let schedule = LeaderSchedule::new_from_schedule(schedule); + let schedule = LeaderSchedule::new_from_schedule(schedule, NZ_1); let leaders = (0..NUM_SLOTS) .map(|i| (schedule[i as u64].id, i)) .into_group_map(); @@ -160,9 +154,9 @@ mod tests { } #[test_case(1, &[10, 20, 30], 12, NZ_1, &[1, 1, 2, 1, 1, 0, 0, 1, 2, 1, 0, 1])] - #[test_case(1, &[10, 20, 30], 12, NZ_2, &[1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 0, 0])] + #[test_case(1, &[10, 20, 30], 12, NZ_2, &[1, 1, 2, 1, 1, 0])] #[test_case(1, &[30, 10, 20], 12, NZ_1, &[2, 2, 0, 2, 2, 1, 1, 2, 0, 2, 1, 2])] - #[test_case(1, &[30, 10, 20], 12, NZ_2, &[2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 1, 1])] + #[test_case(1, &[30, 10, 20], 12, NZ_2, &[2, 2, 0, 2, 2, 1])] #[test_case(1, &[10, 20, 25, 30], 12, NZ_1, &[2, 2, 3, 1, 2, 0, 1, 1, 3, 2, 1, 2])] #[test_case(1, &[10, 20, 25, 30, 35, 40, 100], 15, NZ_1, &[4, 5, 6, 3, 4, 1, 2, 3, 6, 4, 2, 4, 5, 6, 6])] @@ -173,13 +167,13 @@ mod tests { #[test_case(1, &[10, 20, 25, 30, 35, 40, 100, 1000, 10_000], 25, NZ_1, &[8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8])] #[test_case(457468, &[10, 20, 30], 12, NZ_1, &[2, 2, 0, 1, 0, 2, 1, 2, 1, 2, 2, 2])] - #[test_case(457468, &[10, 20, 30], 12, NZ_2, &[2, 2, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2])] + #[test_case(457468, &[10, 20, 30], 12, NZ_2, &[2, 2, 0, 1, 0, 2])] #[test_case(457469, &[10, 20, 30], 12, NZ_1, &[1, 2, 2, 2, 2, 2, 2, 1, 0, 2, 2, 0])] #[test_case(457470, &[10, 20, 30], 12, NZ_1, &[2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 2])] #[test_case(3466545, &[10, 20, 30], 12, NZ_1, &[2, 2, 0, 0, 2, 1, 1, 1, 0, 0, 2, 2])] #[test_case(3466545, &[10, 20, 30], 13, NZ_1, &[2, 2, 0, 0, 2, 1, 1, 1, 0, 0, 2, 2, 1])] #[test_case(3466545, &[10, 20, 30], 14, NZ_1, &[2, 2, 0, 0, 2, 1, 1, 1, 0, 0, 2, 2, 1, 2])] - #[test_case(3466545, &[10, 20, 30], 14, NZ_2, &[2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 1, 1, 1, 1])] + #[test_case(3466545, &[10, 20, 30], 14, NZ_2, &[2, 2, 0, 0, 2, 1, 1])] fn test_stake_leader_schedule_exact_order( epoch: u64, stakes: &[u64], diff --git a/leader-schedule/src/vote_keyed.rs b/leader-schedule/src/vote_keyed.rs index 14d9450fcaed66..eae938156687b3 100644 --- a/leader-schedule/src/vote_keyed.rs +++ b/leader-schedule/src/vote_keyed.rs @@ -7,11 +7,22 @@ use { std::{collections::HashMap, iter, num::NonZeroUsize, ops::Index}, }; -#[derive(Debug, Default, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct LeaderSchedule { slot_leaders: Vec, // Inverted index from leader id to indices where they are the leader. leader_slots_map: HashMap>, + repeat: NonZeroUsize, +} + +impl Default for LeaderSchedule { + fn default() -> Self { + Self { + slot_leaders: Vec::default(), + leader_slots_map: HashMap::default(), + repeat: NonZeroUsize::new(1).unwrap(), + } + } } impl LeaderSchedule { @@ -36,14 +47,15 @@ impl LeaderSchedule { }) .collect(); let slot_leaders = stake_weighted_slot_leaders(slot_leader_stakes, epoch, len, repeat); - Self::new_from_schedule(slot_leaders) + Self::new_from_schedule(slot_leaders, repeat) } - pub fn new_from_schedule(slot_leaders: Vec) -> Self { + pub fn new_from_schedule(slot_leaders: Vec, repeat: NonZeroUsize) -> Self { let leader_slots_map = Self::invert_slot_leaders(&slot_leaders); Self { slot_leaders, leader_slots_map, + repeat, } } @@ -55,8 +67,14 @@ impl LeaderSchedule { .into_group_map() } - pub fn get_slot_leaders(&self) -> &[SlotLeader] { - &self.slot_leaders + pub fn get_slot_leaders(&self) -> impl Iterator { + self.slot_leaders + .iter() + .flat_map(|leader| iter::repeat_n(leader, self.repeat())) + } + + fn repeat(&self) -> usize { + self.repeat.get() } pub fn get_leader_upcoming_slots( @@ -70,18 +88,33 @@ impl LeaderSchedule { match index { Some(index) if !index.is_empty() => { let size = index.len(); - let start_offset = index - .binary_search(&(offset % num_slots)) - .unwrap_or_else(std::convert::identity) - + offset / num_slots * size; + let offset_in_epoch = offset % num_slots; + let repeat = self.repeat(); + let offset_chunk = offset_in_epoch / repeat; + // We don't store repetitions in the schedule, so we need to find the + // first element representing the latest chunk of `repeat` slots. + // Also, find out how many slots from the starting chunk we still have + // to yield. + let (start_index, offset_in_chunk) = match index.binary_search(&offset_chunk) { + Ok(index) => (index, offset_in_epoch % repeat), + Err(index) => (index, 0), + }; + let start_offset = start_index + offset / num_slots * size; // The modular arithmetic here and above replicate Index implementation // for LeaderSchedule, where the schedule keeps repeating endlessly. // The '%' returns where in a cycle we are and the '/' returns how many // times the schedule is repeated. - Box::new( - (start_offset..=usize::MAX) - .map(move |k| index[k % size] + k / size * num_slots), - ) + Box::new(iter::chain( + // First yield the remaining slots from the starting chunk. + (offset_in_chunk..repeat).map(move |k| { + index[start_offset % size] * repeat + start_offset / size * num_slots + k + }), + // Then start visiting next chunks (with the same `repeat`). + ((start_offset + 1)..).flat_map(move |k| { + (0..repeat) + .map(move |j| index[k % size] * repeat + k / size * num_slots + j) + }), + )) } _ => { // Empty iterator for pubkeys not in schedule @@ -91,23 +124,23 @@ impl LeaderSchedule { } pub fn num_slots(&self) -> usize { - self.slot_leaders.len() + self.slot_leaders.len().saturating_mul(self.repeat()) } pub fn get_slot_leader_at_index(&self, index: usize) -> SlotLeader { - self.slot_leaders[index % self.num_slots()] + self.slot_leaders[index % self.num_slots() / self.repeat()] } #[cfg(test)] pub fn get_vote_key_at_slot_index(&self, index: usize) -> &Pubkey { - &self.slot_leaders[index % self.num_slots()].vote_address + &self.slot_leaders[index % self.num_slots() / self.repeat()].vote_address } } impl Index for LeaderSchedule { type Output = SlotLeader; fn index(&self, index: u64) -> &SlotLeader { - &self.slot_leaders[index as usize % self.num_slots()] + &self.slot_leaders[index as usize % self.num_slots() / self.repeat()] } } @@ -115,10 +148,15 @@ impl Index for LeaderSchedule { mod tests { use {super::*, solana_vote::vote_account::VoteAccount}; + const NZ_1: NonZeroUsize = NonZeroUsize::new(1).unwrap(); + const NZ_2: NonZeroUsize = NonZeroUsize::new(2).unwrap(); + const NZ_4: NonZeroUsize = NonZeroUsize::new(4).unwrap(); + const NZ_8: NonZeroUsize = NonZeroUsize::new(8).unwrap(); + #[test] fn test_index() { let slot_leaders = vec![SlotLeader::new_unique(), SlotLeader::new_unique()]; - let leader_schedule = LeaderSchedule::new_from_schedule(slot_leaders.clone()); + let leader_schedule = LeaderSchedule::new_from_schedule(slot_leaders.clone(), NZ_1); assert_eq!(leader_schedule[0], slot_leaders[0]); assert_eq!(leader_schedule[1], slot_leaders[1]); assert_eq!(leader_schedule[2], slot_leaders[0]); @@ -127,7 +165,7 @@ mod tests { #[test] fn test_get_vote_key_at_slot_index() { let slot_leaders = vec![SlotLeader::new_unique(), SlotLeader::new_unique()]; - let leader_schedule = LeaderSchedule::new_from_schedule(slot_leaders.clone()); + let leader_schedule = LeaderSchedule::new_from_schedule(slot_leaders.clone(), NZ_1); assert_eq!( leader_schedule.get_vote_key_at_slot_index(0), &slot_leaders[0].vote_address @@ -156,7 +194,7 @@ mod tests { let epoch: Epoch = rand::random(); let len = num_keys * 10; - let repeat = NonZeroUsize::new(1).unwrap(); + let repeat = NZ_1; let leader_schedule = LeaderSchedule::new(&vote_accounts_map, epoch, len, repeat); let leader_schedule2 = LeaderSchedule::new(&vote_accounts_map, epoch, len, repeat); assert_eq!(leader_schedule.num_slots(), len); @@ -177,12 +215,12 @@ mod tests { .collect(); let epoch = rand::random::(); - let repeat = NonZeroUsize::new(8).unwrap(); + let repeat = NZ_8; let len = num_keys * repeat.get(); let leader_schedule = LeaderSchedule::new(&vote_accounts_map, epoch, len, repeat); assert_eq!(leader_schedule.num_slots(), len); let mut leader_node = SlotLeader::default(); - for (i, node) in leader_schedule.get_slot_leaders().iter().enumerate() { + for (i, node) in leader_schedule.get_slot_leaders().enumerate() { if i % repeat.get() == 0 { leader_node = *node; } else { @@ -213,48 +251,203 @@ mod tests { let epoch = 0; let len = 8; // What the schedule looks like without any repeats - let leaders1 = LeaderSchedule::new( - &vote_accounts_map, - epoch, - len, - NonZeroUsize::new(1).unwrap(), - ) - .get_slot_leaders() - .to_vec(); + let leader_schedule1 = LeaderSchedule::new(&vote_accounts_map, epoch, len, NZ_1); + let leaders1: Vec<_> = leader_schedule1.get_slot_leaders().collect(); // What the schedule looks like with repeats - let leaders2 = LeaderSchedule::new( - &vote_accounts_map, - epoch, - len, - NonZeroUsize::new(2).unwrap(), - ) - .get_slot_leaders() - .to_vec(); + let leader_schedule2 = LeaderSchedule::new(&vote_accounts_map, epoch, len, NZ_2); + let leaders2: Vec<_> = leader_schedule2.get_slot_leaders().collect(); assert_eq!(leaders1.len(), leaders2.len()); let leaders1_expected = vec![ - leader_alice, - leader_alice, - leader_alice, - leader_bob, - leader_alice, - leader_alice, - leader_alice, - leader_alice, + &leader_alice, + &leader_alice, + &leader_alice, + &leader_bob, + &leader_alice, + &leader_alice, + &leader_alice, + &leader_alice, ]; let leaders2_expected = vec![ - leader_alice, - leader_alice, - leader_alice, - leader_alice, - leader_alice, - leader_alice, - leader_bob, - leader_bob, + &leader_alice, + &leader_alice, + &leader_alice, + &leader_alice, + &leader_alice, + &leader_alice, + &leader_bob, + &leader_bob, ]; assert_eq!(leaders1, leaders1_expected); assert_eq!(leaders2, leaders2_expected); } + + #[test] + fn test_get_vote_key_at_slot_index_with_repeat() { + let slot_leaders = vec![SlotLeader::new_unique(), SlotLeader::new_unique()]; + let leader_schedule = LeaderSchedule::new_from_schedule(slot_leaders.clone(), NZ_4); + + for i in 0..4 { + assert_eq!( + leader_schedule.get_vote_key_at_slot_index(i), + &slot_leaders[0].vote_address + ); + } + for i in 4..8 { + assert_eq!( + leader_schedule.get_vote_key_at_slot_index(i), + &slot_leaders[1].vote_address + ); + } + assert_eq!( + leader_schedule.get_vote_key_at_slot_index(8), + &slot_leaders[0].vote_address + ); + } + + #[test] + fn test_get_leader_upcoming_slots_with_repeat() { + let leader_a = SlotLeader::new_unique(); + let leader_b = SlotLeader::new_unique(); + let leader_schedule = + LeaderSchedule::new_from_schedule(vec![leader_a, leader_b, leader_a], NZ_4); + + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 0) + .take(16) + .eq([0, 1, 2, 3, 8, 9, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 1) + .take(15) + .eq([1, 2, 3, 8, 9, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 2) + .take(14) + .eq([2, 3, 8, 9, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 3) + .take(13) + .eq([3, 8, 9, 10, 11, 12, 13, 14, 15, 20, 21, 22, 23]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 4) + .take(10) + .eq([8, 9, 10, 11, 12, 13, 14, 15, 20, 21]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 5) + .take(10) + .eq([8, 9, 10, 11, 12, 13, 14, 15, 20, 21]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 6) + .take(10) + .eq([8, 9, 10, 11, 12, 13, 14, 15, 20, 21]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 7) + .take(10) + .eq([8, 9, 10, 11, 12, 13, 14, 15, 20, 21]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 8) + .take(10) + .eq([8, 9, 10, 11, 12, 13, 14, 15, 20, 21]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 10) + .take(10) + .eq([10, 11, 12, 13, 14, 15, 20, 21, 22, 23]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 11) + .take(10) + .eq([11, 12, 13, 14, 15, 20, 21, 22, 23, 24]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 12) + .take(10) + .eq([12, 13, 14, 15, 20, 21, 22, 23, 24, 25]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 15) + .take(10) + .eq([15, 20, 21, 22, 23, 24, 25, 26, 27, 32]) + ); + + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 11) + .take(10) + .all(|slot| slot >= 11 && leader_schedule[slot as u64].id == leader_a.id) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_a.id, 15) + .take(10) + .all(|slot| slot >= 15 && leader_schedule[slot as u64].id == leader_a.id) + ); + + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_b.id, 0) + .take(8) + .eq([4, 5, 6, 7, 16, 17, 18, 19]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_b.id, 4) + .take(8) + .eq([4, 5, 6, 7, 16, 17, 18, 19]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_b.id, 5) + .take(8) + .eq([5, 6, 7, 16, 17, 18, 19, 28]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_b.id, 7) + .take(8) + .eq([7, 16, 17, 18, 19, 28, 29, 30]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_b.id, 8) + .take(8) + .eq([16, 17, 18, 19, 28, 29, 30, 31]) + ); + assert!( + leader_schedule + .get_leader_upcoming_slots(&leader_b.id, 5) + .take(8) + .all(|slot| slot >= 5 && leader_schedule[slot as u64].id == leader_b.id) + ); + + assert!( + leader_schedule + .get_leader_upcoming_slots(&Pubkey::new_unique(), 0) + .next() + .is_none() + ); + } } diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index 734bebcede2ec2..b5d210c97b751e 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -5524,7 +5524,7 @@ pub mod tests { solana_transaction_status::{ InnerInstruction, InnerInstructions, Reward, Rewards, TransactionTokenBalance, }, - std::{cmp::Ordering, time::Duration}, + std::{cmp::Ordering, num::NonZeroUsize, time::Duration}, }; // used for tests only @@ -10179,10 +10179,13 @@ pub mod tests { let bank = Arc::new(Bank::new_for_tests(&genesis_config)); let mut leader_schedule_cache = LeaderScheduleCache::new_from_bank(&bank); let fixed_schedule = FixedSchedule { - leader_schedule: Arc::new(LeaderSchedule::new_from_schedule(vec![SlotLeader { - id: leader_keypair.pubkey(), - vote_address: Pubkey::new_unique(), - }])), + leader_schedule: Arc::new(LeaderSchedule::new_from_schedule( + vec![SlotLeader { + id: leader_keypair.pubkey(), + vote_address: Pubkey::new_unique(), + }], + NonZeroUsize::new(1).unwrap(), + )), }; leader_schedule_cache.set_fixed_leader_schedule(Some(fixed_schedule)); diff --git a/local-cluster/src/integration_tests.rs b/local-cluster/src/integration_tests.rs index 30b85b479d4f86..53e69a834fc2d4 100644 --- a/local-cluster/src/integration_tests.rs +++ b/local-cluster/src/integration_tests.rs @@ -300,7 +300,7 @@ pub fn create_custom_leader_schedule( } info!("leader_schedule: {}", leader_schedule.len()); - LeaderSchedule::new_from_schedule(leader_schedule) + LeaderSchedule::new_from_schedule(leader_schedule, NonZeroUsize::new(1).unwrap()) } pub fn create_custom_leader_schedule_with_random_keys( diff --git a/local-cluster/tests/local_cluster.rs b/local-cluster/tests/local_cluster.rs index 991cddf093d5a4..ab289e1eb3d2f1 100644 --- a/local-cluster/tests/local_cluster.rs +++ b/local-cluster/tests/local_cluster.rs @@ -93,7 +93,7 @@ use { fs, io::Read, iter, - num::NonZeroU64, + num::{NonZeroU64, NonZeroUsize}, path::Path, sync::{ Arc, Mutex, @@ -1959,12 +1959,12 @@ fn do_test_future_tower(cluster_mode: ClusterMode) { let validator_keypairs = match cluster_mode { ClusterMode::MasterOnly => vec![ - "28bN3xyvrP4E8LwEgtLjhnkb7cY4amQb6DrYAbAYjgRV4GAGgkVM2K7wnxnAS7WDneuavza7x21MiafLu1HkwQt4", - ], + "28bN3xyvrP4E8LwEgtLjhnkb7cY4amQb6DrYAbAYjgRV4GAGgkVM2K7wnxnAS7WDneuavza7x21MiafLu1HkwQt4", + ], ClusterMode::MasterSlave => vec![ - "4qhhXNTbKD1a5vxDDLZcHKj7ELNeiivtUBxn3wUK1F5VRsQVP89VUhfXqSfgiFB14GfuBgtrQ96n9NvWQADVkcCg", - "3kHBzVwie5vTEaY6nFCPeFT8qDpoXzn7dCEioGRNBTnUDpvwnG85w8Wq63gVWpVTP8k2a8cgcWRjSXyUkEygpXWS", - ], + "4qhhXNTbKD1a5vxDDLZcHKj7ELNeiivtUBxn3wUK1F5VRsQVP89VUhfXqSfgiFB14GfuBgtrQ96n9NvWQADVkcCg", + "3kHBzVwie5vTEaY6nFCPeFT8qDpoXzn7dCEioGRNBTnUDpvwnG85w8Wq63gVWpVTP8k2a8cgcWRjSXyUkEygpXWS", + ], }; let validator_keys = create_test_validator_keys(&validator_keypairs); @@ -2701,9 +2701,10 @@ fn test_oc_bad_signatures() { // to casting votes with invalid blockhash. This is not what is meant to be // test and only inflates test time. let fixed_schedule = FixedSchedule { - leader_schedule: Arc::new(LeaderSchedule::new_from_schedule(vec![SlotLeader::from( - &validator_keys.first().unwrap().0, - )])), + leader_schedule: Arc::new(LeaderSchedule::new_from_schedule( + vec![SlotLeader::from(&validator_keys.first().unwrap().0)], + NonZeroUsize::new(1).unwrap(), + )), }; let mut validator_config = ValidatorConfig { diff --git a/poh/src/poh_recorder.rs b/poh/src/poh_recorder.rs index 181fd8d684e625..dcff8bc8df675c 100644 --- a/poh/src/poh_recorder.rs +++ b/poh/src/poh_recorder.rs @@ -21,12 +21,13 @@ use { arc_swap::ArcSwap, crossbeam_channel::{Receiver, SendError, Sender, TrySendError, bounded, unbounded}, log::*, - solana_clock::{BankId, NUM_CONSECUTIVE_LEADER_SLOTS, Slot}, + solana_clock::{BankId, Slot}, solana_entry::{ entry::Entry, poh::{Poh, PohEntry}, }, solana_hash::Hash, + solana_leader_schedule::NUM_CONSECUTIVE_LEADER_SLOTS, solana_ledger::{blockstore::Blockstore, leader_schedule_cache::LeaderScheduleCache}, solana_measure::measure_us, solana_poh_config::PohConfig, @@ -795,15 +796,15 @@ impl PohRecorder { } fn start_slot_was_mine_or_previous_leader(&self, next_leader_slot: Slot) -> bool { - (next_leader_slot.saturating_sub(NUM_CONSECUTIVE_LEADER_SLOTS)..next_leader_slot).any( - |slot| { + (next_leader_slot.saturating_sub(NUM_CONSECUTIVE_LEADER_SLOTS.get() as u64) + ..next_leader_slot) + .any(|slot| { // Check if the last slot PoH reset to was any of the // previous leader's slots. // If so, PoH is currently building on the previous leader's blocks // If not, PoH is building on a different fork slot == self.start_slot() - }, - ) + }) } // Check if the last slot PoH reset onto was the previous leader's last slot. @@ -813,8 +814,9 @@ impl PohRecorder { next_leader_slot: Slot, ) -> bool { // Walk backwards from the slot before our next leader slot. - for slot in - (next_leader_slot.saturating_sub(NUM_CONSECUTIVE_LEADER_SLOTS)..next_leader_slot).rev() + for slot in (next_leader_slot.saturating_sub(NUM_CONSECUTIVE_LEADER_SLOTS.get() as u64) + ..next_leader_slot) + .rev() { // Identify which leader is responsible for building this slot. let leader_for_slot = self.leader_schedule_cache.slot_leader_at(slot, None); @@ -893,7 +895,7 @@ impl PohRecorder { 0, cmp::min( ticks_per_slot * MAX_GRACE_SLOTS, - ticks_per_slot * NUM_CONSECUTIVE_LEADER_SLOTS / GRACE_TICKS_FACTOR, + ticks_per_slot * NUM_CONSECUTIVE_LEADER_SLOTS.get() as u64 / GRACE_TICKS_FACTOR, ), )) } @@ -1867,16 +1869,12 @@ mod tests { let leader_b = SlotLeader::new_unique(); let leader_c = SlotLeader::new_unique(); let leader_d = SlotLeader::new_unique(); - let consecutive_leader_slots = NUM_CONSECUTIVE_LEADER_SLOTS as usize; - let mut slot_leaders = Vec::with_capacity(consecutive_leader_slots * 3); - slot_leaders.extend(std::iter::repeat_n(leader_a, consecutive_leader_slots)); - slot_leaders.extend(std::iter::repeat_n(leader_b, consecutive_leader_slots)); - slot_leaders.extend(std::iter::repeat_n(leader_c, consecutive_leader_slots)); - slot_leaders.extend(std::iter::repeat_n(leader_d, consecutive_leader_slots)); + let slot_leaders = vec![leader_a, leader_b, leader_c, leader_d]; let mut leader_schedule_cache = LeaderScheduleCache::new_from_bank(&bank); let fixed_schedule = solana_leader_schedule::FixedSchedule { leader_schedule: Arc::new(solana_leader_schedule::LeaderSchedule::new_from_schedule( slot_leaders, + NUM_CONSECUTIVE_LEADER_SLOTS, )), }; leader_schedule_cache.set_fixed_leader_schedule(Some(fixed_schedule)); @@ -1900,15 +1898,17 @@ mod tests { let grace_ticks = ticks_per_slot * MAX_GRACE_SLOTS; poh_recorder.grace_ticks = grace_ticks; + let num_consecutive_leader_slots = NUM_CONSECUTIVE_LEADER_SLOTS.get() as u64; + // Setup leader slot ranges. let leader_a_start_slot = 0; - let leader_a_end_slot = leader_a_start_slot + NUM_CONSECUTIVE_LEADER_SLOTS - 1; + let leader_a_end_slot = leader_a_start_slot + num_consecutive_leader_slots - 1; let leader_b_start_slot = leader_a_end_slot + 1; - let leader_b_end_slot = leader_b_start_slot + NUM_CONSECUTIVE_LEADER_SLOTS - 1; + let leader_b_end_slot = leader_b_start_slot + num_consecutive_leader_slots - 1; let leader_c_start_slot = leader_b_end_slot + 1; - let leader_c_end_slot = leader_c_start_slot + NUM_CONSECUTIVE_LEADER_SLOTS - 1; + let leader_c_end_slot = leader_c_start_slot + num_consecutive_leader_slots - 1; let leader_d_start_slot = leader_c_end_slot + 1; - let leader_d_end_slot = leader_d_start_slot + NUM_CONSECUTIVE_LEADER_SLOTS - 1; + let leader_d_end_slot = leader_d_start_slot + num_consecutive_leader_slots - 1; // Reset onto Leader A's first slot 0. poh_recorder.reset( @@ -1917,7 +1917,7 @@ mod tests { ); // Setup leader start ticks. - let ticks_in_leader_slot_set = ticks_per_slot * NUM_CONSECUTIVE_LEADER_SLOTS; + let ticks_in_leader_slot_set = ticks_per_slot * num_consecutive_leader_slots; let leader_a_start_tick = 1; let leader_b_start_tick = leader_a_start_tick + ticks_in_leader_slot_set; let leader_c_start_tick = leader_b_start_tick + ticks_in_leader_slot_set; @@ -1996,7 +1996,7 @@ mod tests { assert!(poh_recorder.reached_leader_tick(&leader_d.id, leader_d_start_tick)); // Add some active (partially received) blocks to the active fork. - let active_descendants = vec![NUM_CONSECUTIVE_LEADER_SLOTS]; + let active_descendants = vec![NUM_CONSECUTIVE_LEADER_SLOTS.get() as u64]; poh_recorder.update_start_bank_active_descendants(&active_descendants); // True, because Leader D observes pending blocks on the active fork, diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 0b2a034fd9586d..eb489b466dd079 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -987,7 +987,6 @@ impl JsonRpcRequestProcessor { slot_leaders.extend( leader_schedule .get_slot_leaders() - .iter() .map(|slot_leader| slot_leader.id) .skip(slot_index as usize) .take(limit.saturating_sub(slot_leaders.len())), @@ -2933,7 +2932,6 @@ pub mod rpc_minimal { solana_runtime::leader_schedule_utils::leader_schedule_by_identity( leader_schedule .get_slot_leaders() - .iter() .map(|slot_leader| &slot_leader.id) .enumerate(), );