Make leader_schedule a utitlity module named leader_schedule_utils (#2988)

This commit is contained in:
carllin 2019-02-27 14:41:46 -08:00 committed by GitHub
parent 3a20a20807
commit 6d1b43f1b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 141 additions and 153 deletions

View File

@ -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);

View File

@ -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

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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