Hoist new leader scheduler up to protocol level
Attempt to feel similar to LeaderScheduler to easy migration.
This commit is contained in:
parent
ba50e1ac81
commit
af206111e2
|
@ -2251,7 +2251,6 @@ dependencies = [
|
|||
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -15,7 +15,6 @@ fnv = "1.0.6"
|
|||
hashbrown = "0.1.8"
|
||||
log = "0.4.2"
|
||||
rand = "0.6.5"
|
||||
rand_chacha = "0.1.1"
|
||||
serde = "1.0.88"
|
||||
serde_derive = "1.0.88"
|
||||
serde_json = "1.0.38"
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
use crate::accounts::{Accounts, ErrorCounters, InstructionAccounts, InstructionLoaders};
|
||||
use crate::last_id_queue::LastIdQueue;
|
||||
use crate::leader_schedule::LeaderSchedule;
|
||||
use crate::runtime::{self, RuntimeError};
|
||||
use crate::status_cache::StatusCache;
|
||||
use bincode::serialize;
|
||||
|
@ -723,7 +722,9 @@ impl Bank {
|
|||
}
|
||||
|
||||
/// Return the checkpointed stakes that should be used to generate a leader schedule.
|
||||
fn staked_nodes_at_slot(&self, slot_height: u64) -> HashMap<Pubkey, u64> {
|
||||
fn staked_nodes_at_slot(&self, current_slot_height: u64) -> HashMap<Pubkey, u64> {
|
||||
let slot_height = current_slot_height.saturating_sub(self.stakers_slot_offset);
|
||||
|
||||
let parents = self.parents();
|
||||
let mut banks = vec![self];
|
||||
banks.extend(parents.iter().map(|x| x.as_ref()));
|
||||
|
@ -741,87 +742,6 @@ impl Bank {
|
|||
self.ticks_per_slot
|
||||
}
|
||||
|
||||
/// Return the number of slots per tick that should be used calls to epoch_height().
|
||||
pub fn slots_per_epoch(&self) -> u64 {
|
||||
self.slots_per_epoch
|
||||
}
|
||||
|
||||
/// Return the checkpointed stakes that should be used to generate a leader schedule.
|
||||
fn staked_nodes_at_epoch(&self, epoch_height: u64) -> HashMap<Pubkey, u64> {
|
||||
let epoch_slot_height = epoch_height * self.slots_per_epoch();
|
||||
let slot_height = epoch_slot_height.saturating_sub(self.stakers_slot_offset);
|
||||
self.staked_nodes_at_slot(slot_height)
|
||||
}
|
||||
|
||||
/// Return the leader schedule for the given epoch.
|
||||
fn leader_schedule(&self, epoch_height: u64) -> LeaderSchedule {
|
||||
let stakes = self.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, self.slots_per_epoch())
|
||||
}
|
||||
|
||||
/// Return the leader for the slot at the slot_index and epoch_height returned
|
||||
/// by the given function.
|
||||
pub fn slot_leader_by<F>(&self, get_slot_index: F) -> Pubkey
|
||||
where
|
||||
F: Fn(u64, u64, u64) -> (u64, u64),
|
||||
{
|
||||
let (slot_index, epoch_height) = get_slot_index(
|
||||
self.slot_index(),
|
||||
self.epoch_height(),
|
||||
self.slots_per_epoch(),
|
||||
);
|
||||
let leader_schedule = self.leader_schedule(epoch_height);
|
||||
leader_schedule[slot_index as usize]
|
||||
}
|
||||
|
||||
/// Return the leader for the current slot.
|
||||
pub fn slot_leader(&self) -> Pubkey {
|
||||
self.slot_leader_by(|slot_index, epoch_height, _| (slot_index, epoch_height))
|
||||
}
|
||||
|
||||
/// 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) -> Pubkey {
|
||||
self.slot_leader_by(Self::prev_slot_leader_index)
|
||||
}
|
||||
|
||||
/// Return the leader for the slot following the current slot.
|
||||
pub fn next_slot_leader(&self) -> Pubkey {
|
||||
self.slot_leader_by(Self::next_slot_leader_index)
|
||||
}
|
||||
|
||||
/// Return the number of ticks since genesis.
|
||||
pub fn tick_height(&self) -> u64 {
|
||||
self.last_id_queue.read().unwrap().tick_height()
|
||||
|
@ -837,6 +757,17 @@ impl Bank {
|
|||
self.tick_height() / self.ticks_per_slot()
|
||||
}
|
||||
|
||||
/// Return the number of slots per tick.
|
||||
pub fn slots_per_epoch(&self) -> u64 {
|
||||
self.slots_per_epoch
|
||||
}
|
||||
|
||||
/// Return the checkpointed stakes that should be used to generate a leader schedule.
|
||||
pub fn staked_nodes_at_epoch(&self, epoch_height: u64) -> HashMap<Pubkey, u64> {
|
||||
let epoch_slot_height = epoch_height * self.slots_per_epoch();
|
||||
self.staked_nodes_at_slot(epoch_slot_height)
|
||||
}
|
||||
|
||||
/// Return the number of slots since the last epoch boundary.
|
||||
pub fn slot_index(&self) -> u64 {
|
||||
self.slot_height() % self.slots_per_epoch()
|
||||
|
@ -1262,23 +1193,7 @@ mod tests {
|
|||
let mut expected = HashMap::new();
|
||||
expected.insert(pubkey, bootstrap_tokens - 1);
|
||||
let bank = Bank::new_from_parent(&Arc::new(bank));
|
||||
assert_eq!(bank.staked_nodes_at_epoch(bank.epoch_height()), expected,);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bank_leader_schedule_basic() {
|
||||
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 mut seed = [0u8; 32];
|
||||
seed[0..8].copy_from_slice(&bank.epoch_height().to_le_bytes());
|
||||
let leader_schedule = LeaderSchedule::new(&ids_and_stakes, seed, bank.slots_per_epoch());
|
||||
|
||||
assert_eq!(leader_schedule[0], pubkey);
|
||||
assert_eq!(leader_schedule[1], pubkey);
|
||||
assert_eq!(leader_schedule[2], pubkey);
|
||||
assert_eq!(bank.staked_nodes_at_slot(bank.slot_height()), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1535,24 +1450,4 @@ mod tests {
|
|||
bank.squash();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bank_slot_leader_basic() {
|
||||
let pubkey = Keypair::new().pubkey();
|
||||
let bank = Bank::new(&GenesisBlock::new_with_leader(2, pubkey, 2).0);
|
||||
assert_eq!(bank.slot_leader(), pubkey);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bank_prev_slot_leader_index() {
|
||||
assert_eq!(Bank::prev_slot_leader_index(0, 0, 2), (0, 0));
|
||||
assert_eq!(Bank::prev_slot_leader_index(1, 0, 2), (0, 0));
|
||||
assert_eq!(Bank::prev_slot_leader_index(0, 1, 2), (1, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bank_next_slot_leader_index() {
|
||||
assert_eq!(Bank::next_slot_leader_index(0, 0, 2), (1, 0));
|
||||
assert_eq!(Bank::next_slot_leader_index(1, 0, 2), (0, 1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ mod accounts;
|
|||
pub mod bank;
|
||||
pub mod bloom;
|
||||
mod last_id_queue;
|
||||
mod leader_schedule;
|
||||
mod runtime;
|
||||
mod status_cache;
|
||||
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
//! 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 LeaderScheduler1 {}
|
||||
|
||||
impl LeaderScheduler1 {
|
||||
/// 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.
|
||||
pub 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 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)
|
||||
}
|
||||
}
|
||||
|
||||
#[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 = LeaderScheduler1::default();
|
||||
assert_eq!(leader_scheduler.slot_leader(&bank), pubkey);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leader_scheduler1_prev_slot_leader_index() {
|
||||
assert_eq!(LeaderScheduler1::prev_slot_leader_index(0, 0, 2), (0, 0));
|
||||
assert_eq!(LeaderScheduler1::prev_slot_leader_index(1, 0, 2), (0, 0));
|
||||
assert_eq!(LeaderScheduler1::prev_slot_leader_index(0, 1, 2), (1, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leader_scheduler1_next_slot_leader_index() {
|
||||
assert_eq!(LeaderScheduler1::next_slot_leader_index(0, 0, 2), (1, 0));
|
||||
assert_eq!(LeaderScheduler1::next_slot_leader_index(1, 0, 2), (0, 1));
|
||||
}
|
||||
}
|
|
@ -39,7 +39,9 @@ pub mod fullnode;
|
|||
pub mod gen_keys;
|
||||
pub mod gossip_service;
|
||||
pub mod leader_confirmation_service;
|
||||
pub mod leader_schedule;
|
||||
pub mod leader_scheduler;
|
||||
pub mod leader_scheduler1;
|
||||
pub mod local_vote_signer_service;
|
||||
pub mod packet;
|
||||
pub mod poh;
|
||||
|
|
Loading…
Reference in New Issue