add epoch_schedule sysvar (#6256)

* add epoch_schedule sysvar

* book sheesh!
This commit is contained in:
Rob Walker
2019-10-08 22:34:26 -07:00
committed by GitHub
parent f2ee01ace3
commit 7cf90766a3
46 changed files with 572 additions and 427 deletions

View File

@ -462,20 +462,21 @@ fn process_pending_slots(
#[cfg(test)]
pub mod tests {
use super::*;
use crate::blocktree::create_new_tmp_ledger;
use crate::entry::{create_ticks, next_entry, next_entry_mut, Entry};
use crate::genesis_utils::{
create_genesis_block, create_genesis_block_with_leader, GenesisBlockInfo,
use crate::{
blocktree::create_new_tmp_ledger,
entry::{create_ticks, next_entry, next_entry_mut, Entry},
genesis_utils::{create_genesis_block, create_genesis_block_with_leader, GenesisBlockInfo},
};
use rand::{thread_rng, Rng};
use solana_runtime::epoch_schedule::EpochSchedule;
use solana_sdk::hash::Hash;
use solana_sdk::instruction::InstructionError;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction;
use solana_sdk::transaction::Transaction;
use solana_sdk::transaction::TransactionError;
use solana_sdk::{
epoch_schedule::EpochSchedule,
hash::Hash,
instruction::InstructionError,
pubkey::Pubkey,
signature::{Keypair, KeypairUtil},
system_transaction,
transaction::{Transaction, TransactionError},
};
use std::sync::RwLock;
pub fn fill_blocktree_slot_with_ticks(

View File

@ -62,7 +62,7 @@ impl BroadcastRun for FailEntryVerificationBroadcastRun {
.expect("Failed to insert shreds in blocktree");
// 3) Start broadcast step
let bank_epoch = bank.get_stakers_epoch(bank.slot());
let bank_epoch = bank.get_leader_schedule_epoch(bank.slot());
let stakes = staking_utils::staked_nodes_at_epoch(&bank, bank_epoch);
let all_shred_bufs: Vec<Vec<u8>> = data_shreds

View File

@ -192,7 +192,7 @@ impl BroadcastRun for StandardBroadcastRun {
// 3) Start broadcast step
let broadcast_start = Instant::now();
let bank_epoch = bank.get_stakers_epoch(bank.slot());
let bank_epoch = bank.get_leader_schedule_epoch(bank.slot());
let stakes = staking_utils::staked_nodes_at_epoch(&bank, bank_epoch);
let all_shred_bufs: Vec<Vec<u8>> = data_shreds

View File

@ -8,17 +8,18 @@ use rand::seq::SliceRandom;
use rand::SeedableRng;
use rand_chacha::ChaChaRng;
use solana_metrics::datapoint;
use solana_runtime::epoch_schedule::EpochSchedule;
use solana_sdk::pubkey::Pubkey;
use std::cmp;
use std::collections::HashMap;
use std::mem;
use std::net::SocketAddr;
use std::net::UdpSocket;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
use std::thread::{self, sleep, Builder, JoinHandle};
use std::time::Duration;
use solana_sdk::{epoch_schedule::EpochSchedule, pubkey::Pubkey};
use std::{
cmp,
collections::HashMap,
mem,
net::SocketAddr,
net::UdpSocket,
sync::atomic::{AtomicBool, Ordering},
sync::{Arc, RwLock},
thread::{self, sleep, Builder, JoinHandle},
time::Duration,
};
pub const REPAIRMEN_SLEEP_MILLIS: usize = 100;
pub const REPAIR_REDUNDANCY: usize = 1;
@ -278,7 +279,7 @@ impl ClusterInfoRepairListener {
let mut total_coding_blobs_sent = 0;
let mut num_slots_repaired = 0;
let max_confirmed_repairee_epoch =
epoch_schedule.get_stakers_epoch(repairee_epoch_slots.root);
epoch_schedule.get_leader_schedule_epoch(repairee_epoch_slots.root);
let max_confirmed_repairee_slot =
epoch_schedule.get_last_slot_in_epoch(max_confirmed_repairee_epoch);
@ -655,7 +656,7 @@ mod tests {
let eligible_repairmen_refs: Vec<_> = eligible_repairmen.iter().collect();
// Have all the repairman send the repairs
let epoch_schedule = EpochSchedule::new(32, 16, false);
let epoch_schedule = EpochSchedule::custom(32, 16, false);
let num_missing_slots = num_slots / 2;
for repairman_pubkey in &eligible_repairmen {
ClusterInfoRepairListener::serve_repairs_to_repairee(
@ -699,7 +700,7 @@ mod tests {
let blocktree = Blocktree::open(&blocktree_path).unwrap();
let stakers_slot_offset = 16;
let slots_per_epoch = stakers_slot_offset * 2;
let epoch_schedule = EpochSchedule::new(slots_per_epoch, stakers_slot_offset, false);
let epoch_schedule = EpochSchedule::custom(slots_per_epoch, stakers_slot_offset, false);
// Create blobs for first two epochs and write them to blocktree
let total_slots = slots_per_epoch * 2;

View File

@ -1,12 +1,10 @@
use crate::blocktree::Blocktree;
use crate::leader_schedule::LeaderSchedule;
use crate::leader_schedule_utils;
use crate::{blocktree::Blocktree, leader_schedule::LeaderSchedule, leader_schedule_utils};
use solana_runtime::bank::Bank;
use solana_runtime::epoch_schedule::EpochSchedule;
use solana_sdk::pubkey::Pubkey;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque};
use std::sync::{Arc, RwLock};
use solana_sdk::{epoch_schedule::EpochSchedule, pubkey::Pubkey};
use std::{
collections::{hash_map::Entry, HashMap, VecDeque},
sync::{Arc, RwLock},
};
type CachedSchedules = (HashMap<u64, Arc<LeaderSchedule>>, VecDeque<u64>);
const MAX_SCHEDULES: usize = 10;
@ -40,11 +38,11 @@ impl LeaderScheduleCache {
max_schedules: CacheCapacity::default(),
};
// This sets the root and calculates the schedule at stakers_epoch(root)
// This sets the root and calculates the schedule at leader_schedule_epoch(root)
cache.set_root(root_bank);
// Calculate the schedule for all epochs between 0 and stakers_epoch(root)
let stakers_epoch = epoch_schedule.get_stakers_epoch(root_bank.slot());
// Calculate the schedule for all epochs between 0 and leader_schedule_epoch(root)
let stakers_epoch = epoch_schedule.get_leader_schedule_epoch(root_bank.slot());
for epoch in 0..stakers_epoch {
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
cache.slot_leader_at(first_slot_in_epoch, Some(root_bank));
@ -63,7 +61,9 @@ impl LeaderScheduleCache {
}
pub fn set_root(&self, root_bank: &Bank) {
let new_max_epoch = self.epoch_schedule.get_stakers_epoch(root_bank.slot());
let new_max_epoch = self
.epoch_schedule
.get_leader_schedule_epoch(root_bank.slot());
let old_max_epoch = {
let mut max_epoch = self.max_epoch.write().unwrap();
let old_max_epoch = *max_epoch;
@ -229,19 +229,20 @@ impl LeaderScheduleCache {
#[cfg(test)]
mod tests {
use super::*;
use crate::blocktree::tests::make_slot_entries;
use crate::genesis_utils::create_genesis_block;
use crate::genesis_utils::{
create_genesis_block_with_leader, GenesisBlockInfo, BOOTSTRAP_LEADER_LAMPORTS,
use crate::{
blocktree::{get_tmp_ledger_path, tests::make_slot_entries},
genesis_utils::{
create_genesis_block, create_genesis_block_with_leader, GenesisBlockInfo,
BOOTSTRAP_LEADER_LAMPORTS,
},
staking_utils::tests::setup_vote_and_stake_accounts,
};
use crate::staking_utils::tests::setup_vote_and_stake_accounts;
use solana_runtime::bank::Bank;
use solana_runtime::epoch_schedule::{EpochSchedule, MINIMUM_SLOTS_PER_EPOCH};
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::thread::Builder;
use crate::blocktree::get_tmp_ledger_path;
use solana_sdk::epoch_schedule::{
EpochSchedule, DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET, DEFAULT_SLOTS_PER_EPOCH,
MINIMUM_SLOTS_PER_EPOCH,
};
use std::{sync::mpsc::channel, sync::Arc, thread::Builder};
#[test]
fn test_new_cache() {
@ -255,7 +256,7 @@ mod tests {
// [0, stakers_epoch(bank.slot())] should
// be calculated by constructor
let epoch_schedule = bank.epoch_schedule();
let stakers_epoch = bank.get_stakers_epoch(bank.slot());
let stakers_epoch = bank.get_leader_schedule_epoch(bank.slot());
for epoch in 0..=stakers_epoch {
let first_slot_in_stakers_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
let last_slot_in_stakers_epoch = epoch_schedule.get_last_slot_in_epoch(epoch);
@ -307,7 +308,7 @@ mod tests {
fn run_thread_race() {
let slots_per_epoch = MINIMUM_SLOTS_PER_EPOCH as u64;
let epoch_schedule = EpochSchedule::new(slots_per_epoch, slots_per_epoch / 2, true);
let epoch_schedule = EpochSchedule::custom(slots_per_epoch, slots_per_epoch / 2, true);
let GenesisBlockInfo { genesis_block, .. } = create_genesis_block(2);
let bank = Arc::new(Bank::new(&genesis_block));
let cache = Arc::new(LeaderScheduleCache::new(epoch_schedule, &bank));
@ -353,7 +354,11 @@ mod tests {
BOOTSTRAP_LEADER_LAMPORTS,
)
.genesis_block;
genesis_block.epoch_warmup = false;
genesis_block.epoch_schedule = EpochSchedule::custom(
DEFAULT_SLOTS_PER_EPOCH,
DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET,
false,
);
let bank = Bank::new(&genesis_block);
let cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
@ -373,7 +378,7 @@ mod tests {
assert_eq!(
cache.next_leader_slot(
&pubkey,
2 * genesis_block.slots_per_epoch - 1, // no schedule generated for epoch 2
2 * genesis_block.epoch_schedule.slots_per_epoch - 1, // no schedule generated for epoch 2
&bank,
None
),
@ -400,7 +405,7 @@ mod tests {
BOOTSTRAP_LEADER_LAMPORTS,
)
.genesis_block;
genesis_block.epoch_warmup = false;
genesis_block.epoch_schedule.warmup = false;
let bank = Bank::new(&genesis_block);
let cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
@ -452,7 +457,7 @@ mod tests {
assert_eq!(
cache.next_leader_slot(
&pubkey,
2 * genesis_block.slots_per_epoch - 1, // no schedule generated for epoch 2
2 * genesis_block.epoch_schedule.slots_per_epoch - 1, // no schedule generated for epoch 2
&bank,
Some(&blocktree)
),
@ -479,7 +484,7 @@ mod tests {
mint_keypair,
..
} = create_genesis_block(10_000);
genesis_block.epoch_warmup = false;
genesis_block.epoch_schedule.warmup = false;
let bank = Bank::new(&genesis_block);
let cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
@ -498,14 +503,14 @@ mod tests {
// Have to wait until the epoch at after the epoch stakes generated at genesis
// for the new votes to take effect.
let mut target_slot = 1;
let epoch = bank.get_stakers_epoch(0);
while bank.get_stakers_epoch(target_slot) == epoch {
let epoch = bank.get_leader_schedule_epoch(0);
while bank.get_leader_schedule_epoch(target_slot) == epoch {
target_slot += 1;
}
let bank = Bank::new_from_parent(&Arc::new(bank), &Pubkey::default(), target_slot);
let mut expected_slot = 0;
let epoch = bank.get_stakers_epoch(target_slot);
let epoch = bank.get_leader_schedule_epoch(target_slot);
for i in 0..epoch {
expected_slot += bank.get_slots_in_epoch(i);
}
@ -514,7 +519,7 @@ mod tests {
let mut index = 0;
while schedule[index] != node_pubkey {
index += 1;
assert_ne!(index, genesis_block.slots_per_epoch);
assert_ne!(index, genesis_block.epoch_schedule.slots_per_epoch);
}
expected_slot += index;

View File

@ -69,7 +69,7 @@ mod tests {
let leader_schedule = LeaderSchedule::new(
&pubkeys_and_stakes,
seed,
genesis_block.slots_per_epoch,
genesis_block.epoch_schedule.slots_per_epoch,
NUM_CONSECUTIVE_LEADER_SLOTS,
);

View File

@ -1,22 +1,24 @@
//! The `repair_service` module implements the tools necessary to generate a thread which
//! regularly finds missing blobs in the ledger and sends repair requests for those blobs
use crate::bank_forks::BankForks;
use crate::blocktree::{Blocktree, CompletedSlotsReceiver, SlotMeta};
use crate::cluster_info::ClusterInfo;
use crate::cluster_info_repair_listener::ClusterInfoRepairListener;
use crate::result::Result;
use crate::service::Service;
use solana_metrics::datapoint_debug;
use solana_runtime::epoch_schedule::EpochSchedule;
use solana_sdk::pubkey::Pubkey;
use std::collections::BTreeSet;
use std::net::UdpSocket;
use std::ops::Bound::{Excluded, Unbounded};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::thread::{self, Builder, JoinHandle};
use std::time::Duration;
use crate::{
bank_forks::BankForks,
blocktree::{Blocktree, CompletedSlotsReceiver, SlotMeta},
cluster_info::ClusterInfo,
cluster_info_repair_listener::ClusterInfoRepairListener,
result::Result,
service::Service,
};
use solana_sdk::{epoch_schedule::EpochSchedule, pubkey::Pubkey};
use std::{
collections::BTreeSet,
net::UdpSocket,
ops::Bound::{Excluded, Unbounded},
sync::atomic::{AtomicBool, Ordering},
sync::{Arc, RwLock},
thread::sleep,
thread::{self, Builder, JoinHandle},
time::Duration,
};
pub const MAX_REPAIR_LENGTH: usize = 16;
pub const REPAIR_MS: u64 = 100;
@ -299,7 +301,7 @@ impl RepairService {
root: u64,
epoch_schedule: &EpochSchedule,
) {
let last_confirmed_epoch = epoch_schedule.get_stakers_epoch(root);
let last_confirmed_epoch = epoch_schedule.get_leader_schedule_epoch(root);
let last_epoch_slot = epoch_schedule.get_last_slot_in_epoch(last_confirmed_epoch);
let meta_iter = blocktree
@ -652,7 +654,7 @@ mod test {
.unwrap();
// Test that only slots > root from fork1 were included
let epoch_schedule = EpochSchedule::new(32, 32, false);
let epoch_schedule = EpochSchedule::custom(32, 32, false);
RepairService::get_completed_slots_past_root(
&blocktree,
@ -665,7 +667,7 @@ mod test {
assert_eq!(full_slots, expected);
// Test that slots past the last confirmed epoch boundary don't get included
let last_epoch = epoch_schedule.get_stakers_epoch(root);
let last_epoch = epoch_schedule.get_leader_schedule_epoch(root);
let last_slot = epoch_schedule.get_last_slot_in_epoch(last_epoch);
let fork3 = vec![last_slot, last_slot + 1];
let fork3_shreds: Vec<_> = make_chaining_slot_entries(&fork3, num_entries_per_slot)

View File

@ -1005,7 +1005,7 @@ mod test {
create_genesis_block_with_leader(50, &leader_pubkey, leader_lamports);
let mut genesis_block = genesis_block_info.genesis_block;
let leader_voting_pubkey = genesis_block_info.voting_keypair.pubkey();
genesis_block.epoch_warmup = false;
genesis_block.epoch_schedule.warmup = false;
genesis_block.ticks_per_slot = 4;
let bank0 = Bank::new(&genesis_block);
for _ in 1..genesis_block.ticks_per_slot {

View File

@ -1,28 +1,32 @@
//! The `retransmit_stage` retransmits blobs between validators
use crate::bank_forks::BankForks;
use crate::blocktree::{Blocktree, CompletedSlotsReceiver};
use crate::cluster_info::{compute_retransmit_peers, ClusterInfo, DATA_PLANE_FANOUT};
use crate::leader_schedule_cache::LeaderScheduleCache;
use crate::repair_service::RepairStrategy;
use crate::result::{Error, Result};
use crate::service::Service;
use crate::staking_utils;
use crate::streamer::PacketReceiver;
use crate::window_service::{should_retransmit_and_persist, WindowService};
use crate::{
bank_forks::BankForks,
blocktree::{Blocktree, CompletedSlotsReceiver},
cluster_info::{compute_retransmit_peers, ClusterInfo, DATA_PLANE_FANOUT},
leader_schedule_cache::LeaderScheduleCache,
repair_service::RepairStrategy,
result::{Error, Result},
service::Service,
staking_utils,
streamer::PacketReceiver,
window_service::{should_retransmit_and_persist, WindowService},
};
use rand::SeedableRng;
use rand_chacha::ChaChaRng;
use solana_measure::measure::Measure;
use solana_metrics::{datapoint_debug, inc_new_counter_error};
use solana_runtime::epoch_schedule::EpochSchedule;
use std::cmp;
use std::net::UdpSocket;
use std::sync::atomic::AtomicBool;
use std::sync::mpsc::channel;
use std::sync::mpsc::RecvTimeoutError;
use std::sync::{Arc, RwLock};
use std::thread::{self, Builder, JoinHandle};
use std::time::Duration;
use solana_metrics::inc_new_counter_error;
use solana_sdk::epoch_schedule::EpochSchedule;
use std::{
cmp,
net::UdpSocket,
sync::atomic::AtomicBool,
sync::mpsc::channel,
sync::mpsc::RecvTimeoutError,
sync::{Arc, RwLock},
thread::{self, Builder, JoinHandle},
time::Duration,
};
pub fn retransmit(
bank_forks: &Arc<RwLock<BankForks>>,
@ -42,7 +46,7 @@ pub fn retransmit(
}
let r_bank = bank_forks.read().unwrap().working_bank();
let bank_epoch = r_bank.get_stakers_epoch(r_bank.slot());
let bank_epoch = r_bank.get_leader_schedule_epoch(r_bank.slot());
let mut peers_len = 0;
let stakes = staking_utils::staked_nodes_at_epoch(&r_bank, bank_epoch);
let (peers, stakes_and_index) = cluster_info

View File

@ -211,27 +211,27 @@ pub(crate) mod tests {
..Stake::default()
};
let first_stakers_epoch = bank.get_stakers_epoch(bank.slot());
// find the first slot in the next staker's epoch
let first_leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
// find the first slot in the next leader schedule epoch
let mut slot = bank.slot();
loop {
slot += 1;
if bank.get_stakers_epoch(slot) != first_stakers_epoch {
if bank.get_leader_schedule_epoch(slot) != first_leader_schedule_epoch {
break;
}
}
let bank = new_from_parent(&Arc::new(bank), slot);
let next_stakers_epoch = bank.get_stakers_epoch(slot);
let next_leader_schedule_epoch = bank.get_leader_schedule_epoch(slot);
let result: Vec<_> = epoch_stakes_and_lockouts(&bank, first_stakers_epoch);
let result: Vec<_> = epoch_stakes_and_lockouts(&bank, first_leader_schedule_epoch);
assert_eq!(
result,
vec![(leader_stake.stake(first_stakers_epoch, None), None)]
vec![(leader_stake.stake(first_leader_schedule_epoch, None), None)]
);
// epoch stakes and lockouts are saved off for the future epoch, should
// match current bank state
let mut result: Vec<_> = epoch_stakes_and_lockouts(&bank, next_stakers_epoch);
let mut result: Vec<_> = epoch_stakes_and_lockouts(&bank, next_leader_schedule_epoch);
result.sort();
let stake_history =
StakeHistory::from_account(&bank.get_account(&stake_history::id()).unwrap()).unwrap();

View File

@ -296,8 +296,8 @@ mod test {
shred::SIZE_OF_SHRED_TYPE,
};
use rand::{seq::SliceRandom, thread_rng};
use solana_runtime::epoch_schedule::MINIMUM_SLOTS_PER_EPOCH;
use solana_sdk::{
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
hash::Hash,
signature::{Keypair, KeypairUtil},
};