Make leader_schedule a utitlity module named leader_schedule_utils (#2988)
This commit is contained in:
parent
3a20a20807
commit
6d1b43f1b1
|
@ -1,7 +1,7 @@
|
|||
use crate::bank_forks::BankForks;
|
||||
use crate::blocktree::Blocktree;
|
||||
use crate::entry::{Entry, EntrySlice};
|
||||
use crate::leader_scheduler::LeaderScheduler;
|
||||
use crate::leader_schedule_utils;
|
||||
use rayon::prelude::*;
|
||||
use solana_metrics::counter::Counter;
|
||||
use solana_runtime::bank::{Bank, BankError, Result};
|
||||
|
@ -180,7 +180,8 @@ pub fn process_blocktree(
|
|||
entry_height += entries.len() as u64;
|
||||
}
|
||||
|
||||
let slot_complete = LeaderScheduler::num_ticks_left_in_slot(&bank, bank.tick_height()) == 0;
|
||||
let slot_complete =
|
||||
leader_schedule_utils::num_ticks_left_in_slot(&bank, bank.tick_height()) == 0;
|
||||
|
||||
if !slot_complete || meta.next_slots.is_empty() {
|
||||
// Reached the end of this fork. Record the final entry height and last entry id
|
||||
|
@ -202,7 +203,7 @@ pub fn process_blocktree(
|
|||
|
||||
// This is a fork point, create a new child bank for each fork
|
||||
pending_slots.extend(meta.next_slots.iter().map(|next_slot| {
|
||||
let leader = LeaderScheduler::default().slot_leader_at(*next_slot, &bank);
|
||||
let leader = leader_schedule_utils::slot_leader_at(*next_slot, &bank);
|
||||
let child_bank = Bank::new_from_parent_and_id(&bank, leader, *next_slot);
|
||||
trace!("Add child bank for slot={}", next_slot);
|
||||
bank_forks.insert(*next_slot, child_bank);
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::entry::create_ticks;
|
|||
use crate::entry::next_entry_mut;
|
||||
use crate::entry::Entry;
|
||||
use crate::gossip_service::GossipService;
|
||||
use crate::leader_scheduler::LeaderScheduler;
|
||||
use crate::leader_schedule_utils;
|
||||
use crate::poh_recorder::PohRecorder;
|
||||
use crate::poh_service::{PohService, PohServiceConfig};
|
||||
use crate::rpc_pubsub_service::PubSubService;
|
||||
|
@ -279,7 +279,7 @@ impl Fullnode {
|
|||
rotation_info.leader_id,
|
||||
rotation_info.last_entry_id,
|
||||
);
|
||||
let was_leader = LeaderScheduler::default().slot_leader(&rotation_info.bank) == self.id;
|
||||
let was_leader = leader_schedule_utils::slot_leader(&rotation_info.bank) == self.id;
|
||||
|
||||
if let Some(ref mut rpc_service) = self.rpc_service {
|
||||
// TODO: This is not the correct bank. Instead TVU should pass along the
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
//! The `bank` module tracks client accounts and the progress of on-chain
|
||||
//! programs. It offers a high-level API that signs transactions
|
||||
//! on behalf of the caller, and a low-level API for when they have
|
||||
//! already been signed and verified.
|
||||
|
||||
use crate::leader_schedule::LeaderSchedule;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
|
||||
/// Return the leader schedule for the given epoch.
|
||||
fn leader_schedule(epoch_height: u64, bank: &Bank) -> LeaderSchedule {
|
||||
let stakes = bank.staked_nodes_at_epoch(epoch_height);
|
||||
let mut seed = [0u8; 32];
|
||||
seed[0..8].copy_from_slice(&epoch_height.to_le_bytes());
|
||||
let stakes: Vec<_> = stakes.into_iter().collect();
|
||||
LeaderSchedule::new(&stakes, seed, bank.slots_per_epoch())
|
||||
}
|
||||
|
||||
/// Return the leader for the slot at the slot_index and epoch_height returned
|
||||
/// by the given function.
|
||||
fn slot_leader_by<F>(bank: &Bank, get_slot_index: F) -> Pubkey
|
||||
where
|
||||
F: Fn(u64, u64, u64) -> (u64, u64),
|
||||
{
|
||||
let (slot_index, epoch_height) = get_slot_index(
|
||||
bank.slot_index(),
|
||||
bank.epoch_height(),
|
||||
bank.slots_per_epoch(),
|
||||
);
|
||||
let leader_schedule = leader_schedule(epoch_height, bank);
|
||||
leader_schedule[slot_index as usize]
|
||||
}
|
||||
|
||||
/// Return the leader for the current slot.
|
||||
pub fn slot_leader(bank: &Bank) -> Pubkey {
|
||||
slot_leader_by(bank, |slot_index, epoch_height, _| {
|
||||
(slot_index, epoch_height)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the leader for the given slot.
|
||||
pub fn slot_leader_at(slot: u64, bank: &Bank) -> Pubkey {
|
||||
let epoch = slot / bank.slots_per_epoch();
|
||||
slot_leader_by(bank, |_, _, _| (slot, epoch))
|
||||
}
|
||||
|
||||
/// Return the epoch height and slot index of the slot before the current slot.
|
||||
fn prev_slot_leader_index(slot_index: u64, epoch_height: u64, slots_per_epoch: u64) -> (u64, u64) {
|
||||
if epoch_height == 0 && slot_index == 0 {
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
if slot_index == 0 {
|
||||
(slots_per_epoch - 1, epoch_height - 1)
|
||||
} else {
|
||||
(slot_index - 1, epoch_height)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the slot_index and epoch height of the slot following the current slot.
|
||||
fn next_slot_leader_index(slot_index: u64, epoch_height: u64, slots_per_epoch: u64) -> (u64, u64) {
|
||||
if slot_index + 1 == slots_per_epoch {
|
||||
(0, epoch_height + 1)
|
||||
} else {
|
||||
(slot_index + 1, epoch_height)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the leader for the slot before the current slot.
|
||||
pub fn prev_slot_leader(bank: &Bank) -> Pubkey {
|
||||
slot_leader_by(bank, prev_slot_leader_index)
|
||||
}
|
||||
|
||||
/// Return the leader for the slot following the current slot.
|
||||
pub fn next_slot_leader(bank: &Bank) -> Pubkey {
|
||||
slot_leader_by(bank, next_slot_leader_index)
|
||||
}
|
||||
|
||||
// Returns the number of ticks remaining from the specified tick_height to the end of the
|
||||
// slot implied by the tick_height
|
||||
pub fn num_ticks_left_in_slot(bank: &Bank, tick_height: u64) -> u64 {
|
||||
bank.ticks_per_slot() - tick_height % bank.ticks_per_slot() - 1
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use solana_sdk::genesis_block::GenesisBlock;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
|
||||
#[test]
|
||||
fn test_leader_schedule_via_bank() {
|
||||
let pubkey = Keypair::new().pubkey();
|
||||
let (genesis_block, _mint_keypair) = GenesisBlock::new_with_leader(2, pubkey, 2);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
|
||||
let ids_and_stakes: Vec<_> = bank.staked_nodes().into_iter().collect();
|
||||
let seed = [0u8; 32];
|
||||
let leader_schedule =
|
||||
LeaderSchedule::new(&ids_and_stakes, seed, genesis_block.slots_per_epoch);
|
||||
|
||||
assert_eq!(leader_schedule[0], pubkey);
|
||||
assert_eq!(leader_schedule[1], pubkey);
|
||||
assert_eq!(leader_schedule[2], pubkey);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leader_scheduler1_basic() {
|
||||
let pubkey = Keypair::new().pubkey();
|
||||
let genesis_block = GenesisBlock::new_with_leader(2, pubkey, 2).0;
|
||||
let bank = Bank::new(&genesis_block);
|
||||
assert_eq!(slot_leader(&bank), pubkey);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leader_scheduler1_prev_slot_leader_index() {
|
||||
assert_eq!(prev_slot_leader_index(0, 0, 2), (0, 0));
|
||||
assert_eq!(prev_slot_leader_index(1, 0, 2), (0, 0));
|
||||
assert_eq!(prev_slot_leader_index(0, 1, 2), (1, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leader_scheduler1_next_slot_leader_index() {
|
||||
assert_eq!(next_slot_leader_index(0, 0, 2), (1, 0));
|
||||
assert_eq!(next_slot_leader_index(1, 0, 2), (0, 1));
|
||||
}
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
//! The `bank` module tracks client accounts and the progress of on-chain
|
||||
//! programs. It offers a high-level API that signs transactions
|
||||
//! on behalf of the caller, and a low-level API for when they have
|
||||
//! already been signed and verified.
|
||||
|
||||
use crate::leader_schedule::LeaderSchedule;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LeaderScheduler {}
|
||||
|
||||
impl LeaderScheduler {
|
||||
/// Return the leader schedule for the given epoch.
|
||||
fn leader_schedule(&self, epoch_height: u64, bank: &Bank) -> LeaderSchedule {
|
||||
let stakes = bank.staked_nodes_at_epoch(epoch_height);
|
||||
let mut seed = [0u8; 32];
|
||||
seed[0..8].copy_from_slice(&epoch_height.to_le_bytes());
|
||||
let stakes: Vec<_> = stakes.into_iter().collect();
|
||||
LeaderSchedule::new(&stakes, seed, bank.slots_per_epoch())
|
||||
}
|
||||
|
||||
/// Return the leader for the slot at the slot_index and epoch_height returned
|
||||
/// by the given function.
|
||||
fn slot_leader_by<F>(&self, bank: &Bank, get_slot_index: F) -> Pubkey
|
||||
where
|
||||
F: Fn(u64, u64, u64) -> (u64, u64),
|
||||
{
|
||||
let (slot_index, epoch_height) = get_slot_index(
|
||||
bank.slot_index(),
|
||||
bank.epoch_height(),
|
||||
bank.slots_per_epoch(),
|
||||
);
|
||||
let leader_schedule = self.leader_schedule(epoch_height, bank);
|
||||
leader_schedule[slot_index as usize]
|
||||
}
|
||||
|
||||
/// Return the leader for the current slot.
|
||||
pub fn slot_leader(&self, bank: &Bank) -> Pubkey {
|
||||
self.slot_leader_by(bank, |slot_index, epoch_height, _| {
|
||||
(slot_index, epoch_height)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the leader for the given slot.
|
||||
pub fn slot_leader_at(&self, slot: u64, bank: &Bank) -> Pubkey {
|
||||
let epoch = slot / bank.slots_per_epoch();
|
||||
self.slot_leader_by(bank, |_, _, _| (slot, epoch))
|
||||
}
|
||||
|
||||
/// Return the epoch height and slot index of the slot before the current slot.
|
||||
fn prev_slot_leader_index(
|
||||
slot_index: u64,
|
||||
epoch_height: u64,
|
||||
slots_per_epoch: u64,
|
||||
) -> (u64, u64) {
|
||||
if epoch_height == 0 && slot_index == 0 {
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
if slot_index == 0 {
|
||||
(slots_per_epoch - 1, epoch_height - 1)
|
||||
} else {
|
||||
(slot_index - 1, epoch_height)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the slot_index and epoch height of the slot following the current slot.
|
||||
fn next_slot_leader_index(
|
||||
slot_index: u64,
|
||||
epoch_height: u64,
|
||||
slots_per_epoch: u64,
|
||||
) -> (u64, u64) {
|
||||
if slot_index + 1 == slots_per_epoch {
|
||||
(0, epoch_height + 1)
|
||||
} else {
|
||||
(slot_index + 1, epoch_height)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the leader for the slot before the current slot.
|
||||
pub fn prev_slot_leader(&self, bank: &Bank) -> Pubkey {
|
||||
self.slot_leader_by(bank, Self::prev_slot_leader_index)
|
||||
}
|
||||
|
||||
/// Return the leader for the slot following the current slot.
|
||||
pub fn next_slot_leader(&self, bank: &Bank) -> Pubkey {
|
||||
self.slot_leader_by(bank, Self::next_slot_leader_index)
|
||||
}
|
||||
|
||||
// Returns the number of ticks remaining from the specified tick_height to the end of the
|
||||
// slot implied by the tick_height
|
||||
pub fn num_ticks_left_in_slot(bank: &Bank, tick_height: u64) -> u64 {
|
||||
bank.ticks_per_slot() - tick_height % bank.ticks_per_slot() - 1
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use solana_sdk::genesis_block::GenesisBlock;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
|
||||
#[test]
|
||||
fn test_leader_schedule_via_bank() {
|
||||
let pubkey = Keypair::new().pubkey();
|
||||
let (genesis_block, _mint_keypair) = GenesisBlock::new_with_leader(2, pubkey, 2);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
|
||||
let ids_and_stakes: Vec<_> = bank.staked_nodes().into_iter().collect();
|
||||
let seed = [0u8; 32];
|
||||
let leader_schedule =
|
||||
LeaderSchedule::new(&ids_and_stakes, seed, genesis_block.slots_per_epoch);
|
||||
|
||||
assert_eq!(leader_schedule[0], pubkey);
|
||||
assert_eq!(leader_schedule[1], pubkey);
|
||||
assert_eq!(leader_schedule[2], pubkey);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leader_scheduler1_basic() {
|
||||
let pubkey = Keypair::new().pubkey();
|
||||
let genesis_block = GenesisBlock::new_with_leader(2, pubkey, 2).0;
|
||||
let bank = Bank::new(&genesis_block);
|
||||
let leader_scheduler = LeaderScheduler::default();
|
||||
assert_eq!(leader_scheduler.slot_leader(&bank), pubkey);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leader_scheduler1_prev_slot_leader_index() {
|
||||
assert_eq!(LeaderScheduler::prev_slot_leader_index(0, 0, 2), (0, 0));
|
||||
assert_eq!(LeaderScheduler::prev_slot_leader_index(1, 0, 2), (0, 0));
|
||||
assert_eq!(LeaderScheduler::prev_slot_leader_index(0, 1, 2), (1, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leader_scheduler1_next_slot_leader_index() {
|
||||
assert_eq!(LeaderScheduler::next_slot_leader_index(0, 0, 2), (1, 0));
|
||||
assert_eq!(LeaderScheduler::next_slot_leader_index(1, 0, 2), (0, 1));
|
||||
}
|
||||
}
|
|
@ -41,7 +41,7 @@ pub mod gen_keys;
|
|||
pub mod gossip_service;
|
||||
pub mod leader_confirmation_service;
|
||||
pub mod leader_schedule;
|
||||
pub mod leader_scheduler;
|
||||
pub mod leader_schedule_utils;
|
||||
pub mod local_vote_signer_service;
|
||||
pub mod packet;
|
||||
pub mod poh;
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::blocktree::Blocktree;
|
|||
use crate::blocktree_processor::{self, BankForksInfo};
|
||||
use crate::cluster_info::ClusterInfo;
|
||||
use crate::entry::{Entry, EntryMeta, EntryReceiver, EntrySender, EntrySlice};
|
||||
use crate::leader_scheduler::LeaderScheduler;
|
||||
use crate::leader_schedule_utils;
|
||||
use crate::packet::BlobError;
|
||||
use crate::result::{Error, Result};
|
||||
use crate::rpc_subscriptions::RpcSubscriptions;
|
||||
|
@ -89,8 +89,9 @@ impl ReplayStage {
|
|||
|
||||
let num_ticks = bank.tick_height();
|
||||
let slot_height = bank.slot_height();
|
||||
let leader_id = LeaderScheduler::default().slot_leader(bank);
|
||||
let mut num_ticks_to_next_vote = LeaderScheduler::num_ticks_left_in_slot(bank, num_ticks);
|
||||
let leader_id = leader_schedule_utils::slot_leader(bank);
|
||||
let mut num_ticks_to_next_vote =
|
||||
leader_schedule_utils::num_ticks_left_in_slot(bank, num_ticks);
|
||||
|
||||
let mut entry_tick_height = num_ticks;
|
||||
let mut entries_with_meta = Vec::new();
|
||||
|
@ -216,7 +217,7 @@ impl ReplayStage {
|
|||
let slot = (tick_height + 1) / bank.ticks_per_slot();
|
||||
let first_tick_in_slot = slot * bank.ticks_per_slot();
|
||||
|
||||
let leader_id = LeaderScheduler::default().slot_leader_at(slot, &bank);
|
||||
let leader_id = leader_schedule_utils::slot_leader_at(slot, &bank);
|
||||
trace!("node {:?} scheduled as leader for slot {}", leader_id, slot,);
|
||||
|
||||
let old_bank = bank.clone();
|
||||
|
@ -242,7 +243,7 @@ impl ReplayStage {
|
|||
.unwrap();
|
||||
|
||||
let max_tick_height_for_slot = first_tick_in_slot
|
||||
+ LeaderScheduler::num_ticks_left_in_slot(&bank, first_tick_in_slot);
|
||||
+ leader_schedule_utils::num_ticks_left_in_slot(&bank, first_tick_in_slot);
|
||||
|
||||
(Some(slot), leader_id, max_tick_height_for_slot)
|
||||
};
|
||||
|
@ -346,7 +347,7 @@ impl ReplayStage {
|
|||
let (leader_id, next_slot) = {
|
||||
let slot = (current_tick_height + 1) / bank.ticks_per_slot();
|
||||
|
||||
(LeaderScheduler::default().slot_leader_at(slot, &bank), slot)
|
||||
(leader_schedule_utils::slot_leader_at(slot, &bank), slot)
|
||||
};
|
||||
|
||||
// If we were the leader for the last slot update the last id b/c we
|
||||
|
|
Loading…
Reference in New Issue