2018-09-26 05:52:13 -07:00
|
|
|
//! The `poh_recorder` module provides an object for synchronizing with Proof of History.
|
2018-11-05 09:47:41 -08:00
|
|
|
//! It synchronizes PoH, bank's register_tick and the ledger
|
2018-09-26 05:52:13 -07:00
|
|
|
//!
|
2019-02-24 08:59:49 -08:00
|
|
|
//! PohRecorder will send ticks or entries to a WorkingBank, if the current range of ticks is
|
|
|
|
//! within the specified WorkingBank range.
|
|
|
|
//!
|
|
|
|
//! For Ticks:
|
2019-10-16 12:53:11 -07:00
|
|
|
//! * new tick_height must be > WorkingBank::min_tick_height && new tick_height must be <= WorkingBank::max_tick_height
|
2019-02-24 08:59:49 -08:00
|
|
|
//!
|
|
|
|
//! For Entries:
|
2019-05-18 14:01:36 -07:00
|
|
|
//! * recorded entry must be >= WorkingBank::min_tick_height && entry must be < WorkingBank::max_tick_height
|
2019-02-24 08:59:49 -08:00
|
|
|
//!
|
2020-01-13 13:13:52 -08:00
|
|
|
use solana_ledger::blockstore::Blockstore;
|
2019-10-18 09:28:51 -07:00
|
|
|
use solana_ledger::entry::Entry;
|
|
|
|
use solana_ledger::leader_schedule_cache::LeaderScheduleCache;
|
|
|
|
use solana_ledger::poh::Poh;
|
2019-02-18 22:26:22 -08:00
|
|
|
use solana_runtime::bank::Bank;
|
2019-09-06 14:30:56 -07:00
|
|
|
pub use solana_sdk::clock::Slot;
|
|
|
|
use solana_sdk::clock::NUM_CONSECUTIVE_LEADER_SLOTS;
|
2018-11-16 08:04:46 -08:00
|
|
|
use solana_sdk::hash::Hash;
|
2019-05-18 14:01:36 -07:00
|
|
|
use solana_sdk::poh_config::PohConfig;
|
2019-03-20 13:49:46 -07:00
|
|
|
use solana_sdk::pubkey::Pubkey;
|
2019-05-22 15:54:24 -07:00
|
|
|
use solana_sdk::timing;
|
2018-11-29 16:18:47 -08:00
|
|
|
use solana_sdk::transaction::Transaction;
|
2019-07-26 11:33:51 -07:00
|
|
|
use std::cmp;
|
2019-09-18 12:16:22 -07:00
|
|
|
use std::sync::mpsc::{channel, Receiver, SendError, Sender, SyncSender};
|
2019-05-18 14:01:36 -07:00
|
|
|
use std::sync::{Arc, Mutex};
|
2019-05-22 15:54:24 -07:00
|
|
|
use std::time::Instant;
|
2020-01-02 19:50:43 -08:00
|
|
|
use thiserror::Error;
|
2018-09-26 05:52:13 -07:00
|
|
|
|
2020-02-26 13:35:50 -08:00
|
|
|
pub const GRACE_TICKS_FACTOR: u64 = 2;
|
|
|
|
pub const MAX_GRACE_SLOTS: u64 = 2;
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2020-01-02 19:50:43 -08:00
|
|
|
#[derive(Error, Debug, Clone)]
|
2018-10-18 22:57:48 -07:00
|
|
|
pub enum PohRecorderError {
|
2020-01-02 19:50:43 -08:00
|
|
|
#[error("invalid calling object")]
|
2018-10-25 14:56:21 -07:00
|
|
|
InvalidCallingObject,
|
2020-01-02 19:50:43 -08:00
|
|
|
|
|
|
|
#[error("max height reached")]
|
2018-10-18 22:57:48 -07:00
|
|
|
MaxHeightReached,
|
2020-01-02 19:50:43 -08:00
|
|
|
|
|
|
|
#[error("min height not reached")]
|
2019-02-19 16:17:36 -08:00
|
|
|
MinHeightNotReached,
|
2020-01-02 19:50:43 -08:00
|
|
|
|
|
|
|
#[error("send WorkingBankEntry error")]
|
|
|
|
SendError(#[from] SendError<WorkingBankEntry>),
|
2019-02-19 16:17:36 -08:00
|
|
|
}
|
|
|
|
|
2020-01-02 19:50:43 -08:00
|
|
|
type Result<T> = std::result::Result<T, PohRecorderError>;
|
|
|
|
|
2019-09-18 12:16:22 -07:00
|
|
|
pub type WorkingBankEntry = (Arc<Bank>, (Entry, u64));
|
2019-03-03 16:44:06 -08:00
|
|
|
|
2019-02-19 16:17:36 -08:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct WorkingBank {
|
|
|
|
pub bank: Arc<Bank>,
|
|
|
|
pub min_tick_height: u64,
|
|
|
|
pub max_tick_height: u64,
|
2018-10-18 22:57:48 -07:00
|
|
|
}
|
|
|
|
|
2018-09-26 05:52:13 -07:00
|
|
|
pub struct PohRecorder {
|
2019-05-18 14:01:36 -07:00
|
|
|
pub poh: Arc<Mutex<Poh>>,
|
|
|
|
tick_height: u64,
|
2019-04-09 17:53:04 -07:00
|
|
|
clear_bank_signal: Option<SyncSender<bool>>,
|
2019-10-16 12:53:11 -07:00
|
|
|
start_slot: Slot, // parent slot
|
|
|
|
start_tick_height: u64, // first tick_height this recorder will observe
|
|
|
|
tick_cache: Vec<(Entry, u64)>, // cache of entry and its tick_height
|
2019-02-24 08:59:49 -08:00
|
|
|
working_bank: Option<WorkingBank>,
|
2019-09-18 12:16:22 -07:00
|
|
|
sender: Sender<WorkingBankEntry>,
|
2019-10-16 12:53:11 -07:00
|
|
|
leader_first_tick_height: Option<u64>,
|
|
|
|
leader_last_tick_height: u64, // zero if none
|
2019-07-17 14:10:15 -07:00
|
|
|
grace_ticks: u64,
|
2019-03-20 13:49:46 -07:00
|
|
|
id: Pubkey,
|
2020-01-13 13:13:52 -08:00
|
|
|
blockstore: Arc<Blockstore>,
|
2019-04-19 02:39:44 -07:00
|
|
|
leader_schedule_cache: Arc<LeaderScheduleCache>,
|
2019-05-18 14:01:36 -07:00
|
|
|
poh_config: Arc<PohConfig>,
|
2019-05-06 11:23:06 -07:00
|
|
|
ticks_per_slot: u64,
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PohRecorder {
|
2019-04-09 17:53:04 -07:00
|
|
|
fn clear_bank(&mut self) {
|
2019-03-20 14:50:02 -07:00
|
|
|
if let Some(working_bank) = self.working_bank.take() {
|
|
|
|
let bank = working_bank.bank;
|
2019-04-19 02:39:44 -07:00
|
|
|
let next_leader_slot = self.leader_schedule_cache.next_leader_slot(
|
2019-03-29 20:00:36 -07:00
|
|
|
&self.id,
|
|
|
|
bank.slot(),
|
|
|
|
&bank,
|
2020-01-13 13:13:52 -08:00
|
|
|
Some(&self.blockstore),
|
2020-02-26 13:35:50 -08:00
|
|
|
GRACE_TICKS_FACTOR * MAX_GRACE_SLOTS,
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-07-09 15:36:30 -07:00
|
|
|
assert_eq!(self.ticks_per_slot, bank.ticks_per_slot());
|
2019-10-16 12:53:11 -07:00
|
|
|
let (leader_first_tick_height, leader_last_tick_height, grace_ticks) =
|
|
|
|
Self::compute_leader_slot_tick_heights(next_leader_slot, self.ticks_per_slot);
|
2019-07-26 11:33:51 -07:00
|
|
|
self.grace_ticks = grace_ticks;
|
2019-10-16 12:53:11 -07:00
|
|
|
self.leader_first_tick_height = leader_first_tick_height;
|
|
|
|
self.leader_last_tick_height = leader_last_tick_height;
|
2019-03-20 13:49:46 -07:00
|
|
|
}
|
2019-03-11 13:58:23 -07:00
|
|
|
if let Some(ref signal) = self.clear_bank_signal {
|
|
|
|
let _ = signal.try_send(true);
|
|
|
|
}
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
|
|
|
|
2019-04-23 11:56:30 -07:00
|
|
|
pub fn would_be_leader(&self, within_next_n_ticks: u64) -> bool {
|
2019-07-17 14:10:15 -07:00
|
|
|
self.has_bank()
|
2019-10-16 12:53:11 -07:00
|
|
|
|| self
|
|
|
|
.leader_first_tick_height
|
|
|
|
.map_or(false, |leader_first_tick_height| {
|
|
|
|
let ideal_leader_tick_height =
|
|
|
|
leader_first_tick_height.saturating_sub(self.grace_ticks);
|
|
|
|
self.tick_height + within_next_n_ticks >= ideal_leader_tick_height
|
|
|
|
&& self.tick_height <= self.leader_last_tick_height
|
|
|
|
})
|
2019-05-01 11:37:29 -07:00
|
|
|
}
|
|
|
|
|
2019-10-19 20:28:33 -07:00
|
|
|
pub fn leader_after_n_slots(&self, slots: u64) -> Option<Pubkey> {
|
2019-10-16 12:53:11 -07:00
|
|
|
let current_slot = self.tick_height.saturating_sub(1) / self.ticks_per_slot;
|
2019-06-24 15:56:50 -07:00
|
|
|
self.leader_schedule_cache
|
2019-10-16 12:53:11 -07:00
|
|
|
.slot_leader_at(current_slot + slots, None)
|
2019-06-24 15:56:50 -07:00
|
|
|
}
|
2019-07-18 14:54:27 -07:00
|
|
|
|
2019-07-17 14:10:15 -07:00
|
|
|
pub fn next_slot_leader(&self) -> Option<Pubkey> {
|
2019-10-19 20:28:33 -07:00
|
|
|
self.leader_after_n_slots(1)
|
2019-03-12 17:42:53 -07:00
|
|
|
}
|
|
|
|
|
2019-03-03 16:44:06 -08:00
|
|
|
pub fn bank(&self) -> Option<Arc<Bank>> {
|
|
|
|
self.working_bank.clone().map(|w| w.bank)
|
|
|
|
}
|
2019-03-12 17:42:53 -07:00
|
|
|
|
2019-07-09 15:36:30 -07:00
|
|
|
pub fn has_bank(&self) -> bool {
|
|
|
|
self.working_bank.is_some()
|
|
|
|
}
|
|
|
|
|
2019-03-04 07:08:22 -08:00
|
|
|
pub fn tick_height(&self) -> u64 {
|
2019-05-18 14:01:36 -07:00
|
|
|
self.tick_height
|
2019-03-04 07:08:22 -08:00
|
|
|
}
|
2019-03-12 17:42:53 -07:00
|
|
|
|
2019-07-09 15:36:30 -07:00
|
|
|
pub fn ticks_per_slot(&self) -> u64 {
|
|
|
|
self.ticks_per_slot
|
|
|
|
}
|
2019-03-18 13:24:07 -07:00
|
|
|
|
2020-01-13 15:55:41 -08:00
|
|
|
fn received_any_previous_leader_data(&self, slot: Slot) -> bool {
|
|
|
|
(slot.saturating_sub(NUM_CONSECUTIVE_LEADER_SLOTS)..slot).any(|i| {
|
|
|
|
// Check if we have received any data in previous leader's slots
|
|
|
|
if let Ok(slot_meta) = self.blockstore.meta(i as Slot) {
|
|
|
|
if let Some(slot_meta) = slot_meta {
|
|
|
|
slot_meta.received > 0
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-02-29 00:05:35 -08:00
|
|
|
fn prev_slot_was_mine(&self, current_slot: Slot) -> bool {
|
|
|
|
if let Some(leader_id) = self
|
|
|
|
.leader_schedule_cache
|
|
|
|
.slot_leader_at(current_slot.saturating_sub(1), None)
|
|
|
|
{
|
|
|
|
leader_id == self.id
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-13 15:55:41 -08:00
|
|
|
fn reached_leader_tick(&self, leader_first_tick_height: u64) -> bool {
|
|
|
|
let target_tick_height = leader_first_tick_height.saturating_sub(1);
|
|
|
|
let ideal_target_tick_height = target_tick_height.saturating_sub(self.grace_ticks);
|
|
|
|
let current_slot = self.tick_height / self.ticks_per_slot;
|
|
|
|
// we've approached target_tick_height OR poh was reset to run immediately
|
|
|
|
// Or, previous leader didn't transmit in any of its leader slots, so ignore grace ticks
|
|
|
|
self.tick_height >= target_tick_height
|
|
|
|
|| self.start_tick_height + self.grace_ticks == leader_first_tick_height
|
|
|
|
|| (self.tick_height >= ideal_target_tick_height
|
2020-02-29 00:05:35 -08:00
|
|
|
&& (self.prev_slot_was_mine(current_slot)
|
|
|
|
|| !self.received_any_previous_leader_data(current_slot)))
|
2020-01-13 15:55:41 -08:00
|
|
|
}
|
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
/// returns if leader slot has been reached, how many grace ticks were afforded,
|
2019-07-09 15:36:30 -07:00
|
|
|
/// imputed leader_slot and self.start_slot
|
2019-10-16 12:53:11 -07:00
|
|
|
/// reached_leader_slot() == true means "ready for a bank"
|
|
|
|
pub fn reached_leader_slot(&self) -> (bool, u64, Slot, Slot) {
|
2019-07-09 15:36:30 -07:00
|
|
|
trace!(
|
2019-10-16 12:53:11 -07:00
|
|
|
"tick_height {}, start_tick_height {}, leader_first_tick_height {:?}, grace_ticks {}, has_bank {}",
|
2019-07-09 15:36:30 -07:00
|
|
|
self.tick_height,
|
2019-10-16 12:53:11 -07:00
|
|
|
self.start_tick_height,
|
|
|
|
self.leader_first_tick_height,
|
2019-07-17 14:10:15 -07:00
|
|
|
self.grace_ticks,
|
|
|
|
self.has_bank()
|
2019-07-09 15:36:30 -07:00
|
|
|
);
|
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
let next_tick_height = self.tick_height + 1;
|
|
|
|
let next_leader_slot = (next_tick_height - 1) / self.ticks_per_slot;
|
|
|
|
if let Some(leader_first_tick_height) = self.leader_first_tick_height {
|
|
|
|
let target_tick_height = leader_first_tick_height.saturating_sub(1);
|
2020-01-13 15:55:41 -08:00
|
|
|
if self.reached_leader_tick(leader_first_tick_height) {
|
2019-10-16 12:53:11 -07:00
|
|
|
assert!(next_tick_height >= self.start_tick_height);
|
|
|
|
let ideal_target_tick_height = target_tick_height.saturating_sub(self.grace_ticks);
|
2019-07-17 14:10:15 -07:00
|
|
|
|
2019-07-09 15:36:30 -07:00
|
|
|
return (
|
|
|
|
true,
|
2019-10-16 12:53:11 -07:00
|
|
|
self.tick_height.saturating_sub(ideal_target_tick_height),
|
|
|
|
next_leader_slot,
|
2019-07-09 15:36:30 -07:00
|
|
|
self.start_slot,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2019-10-16 12:53:11 -07:00
|
|
|
(false, 0, next_leader_slot, self.start_slot)
|
2019-03-15 13:22:16 -07:00
|
|
|
}
|
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
// returns (leader_first_tick_height, leader_last_tick_height, grace_ticks) given the next
|
|
|
|
// slot this recorder will lead
|
|
|
|
fn compute_leader_slot_tick_heights(
|
2019-07-26 11:33:51 -07:00
|
|
|
next_leader_slot: Option<(Slot, Slot)>,
|
2019-03-20 15:14:21 -07:00
|
|
|
ticks_per_slot: u64,
|
2019-07-26 11:33:51 -07:00
|
|
|
) -> (Option<u64>, u64, u64) {
|
2019-03-20 15:14:21 -07:00
|
|
|
next_leader_slot
|
2019-10-16 12:53:11 -07:00
|
|
|
.map(|(first_slot, last_slot)| {
|
|
|
|
let leader_first_tick_height = first_slot * ticks_per_slot + 1;
|
|
|
|
let last_tick_height = (last_slot + 1) * ticks_per_slot;
|
|
|
|
let num_slots = last_slot - first_slot + 1;
|
2019-07-26 11:33:51 -07:00
|
|
|
let grace_ticks = cmp::min(
|
2019-11-19 17:55:42 -08:00
|
|
|
ticks_per_slot * MAX_GRACE_SLOTS,
|
2019-10-16 12:53:11 -07:00
|
|
|
ticks_per_slot * num_slots / GRACE_TICKS_FACTOR,
|
2019-07-26 11:33:51 -07:00
|
|
|
);
|
2019-10-16 12:53:11 -07:00
|
|
|
(
|
|
|
|
Some(leader_first_tick_height + grace_ticks),
|
|
|
|
last_tick_height,
|
|
|
|
grace_ticks,
|
|
|
|
)
|
2019-03-20 15:14:21 -07:00
|
|
|
})
|
2019-07-26 11:33:51 -07:00
|
|
|
.unwrap_or((
|
|
|
|
None,
|
|
|
|
0,
|
|
|
|
cmp::min(
|
2019-11-19 17:55:42 -08:00
|
|
|
ticks_per_slot * MAX_GRACE_SLOTS,
|
2019-07-26 11:33:51 -07:00
|
|
|
ticks_per_slot * NUM_CONSECUTIVE_LEADER_SLOTS / GRACE_TICKS_FACTOR,
|
|
|
|
),
|
|
|
|
))
|
2019-03-20 15:14:21 -07:00
|
|
|
}
|
|
|
|
|
2019-02-24 08:59:49 -08:00
|
|
|
// synchronize PoH with a bank
|
2019-07-26 11:33:51 -07:00
|
|
|
pub fn reset(
|
|
|
|
&mut self,
|
|
|
|
blockhash: Hash,
|
|
|
|
start_slot: Slot,
|
|
|
|
next_leader_slot: Option<(Slot, Slot)>,
|
|
|
|
) {
|
2019-03-05 17:56:51 -08:00
|
|
|
self.clear_bank();
|
2019-02-19 16:17:36 -08:00
|
|
|
let mut cache = vec![];
|
2019-05-18 14:01:36 -07:00
|
|
|
{
|
|
|
|
let mut poh = self.poh.lock().unwrap();
|
|
|
|
info!(
|
2019-07-17 14:10:15 -07:00
|
|
|
"reset poh from: {},{},{} to: {},{}",
|
|
|
|
poh.hash, self.tick_height, self.start_slot, blockhash, start_slot
|
2019-05-18 14:01:36 -07:00
|
|
|
);
|
|
|
|
poh.reset(blockhash, self.poh_config.hashes_per_tick);
|
|
|
|
}
|
|
|
|
|
2019-02-24 08:59:49 -08:00
|
|
|
std::mem::swap(&mut cache, &mut self.tick_cache);
|
2019-07-17 14:10:15 -07:00
|
|
|
|
2019-03-12 17:42:53 -07:00
|
|
|
self.start_slot = start_slot;
|
2019-10-16 12:53:11 -07:00
|
|
|
self.tick_height = (start_slot + 1) * self.ticks_per_slot;
|
|
|
|
self.start_tick_height = self.tick_height + 1;
|
2019-07-17 14:10:15 -07:00
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
let (leader_first_tick_height, leader_last_tick_height, grace_ticks) =
|
|
|
|
Self::compute_leader_slot_tick_heights(next_leader_slot, self.ticks_per_slot);
|
2019-07-26 11:33:51 -07:00
|
|
|
self.grace_ticks = grace_ticks;
|
2019-10-16 12:53:11 -07:00
|
|
|
self.leader_first_tick_height = leader_first_tick_height;
|
|
|
|
self.leader_last_tick_height = leader_last_tick_height;
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_working_bank(&mut self, working_bank: WorkingBank) {
|
2019-02-26 21:57:45 -08:00
|
|
|
trace!("new working bank");
|
2019-07-09 15:36:30 -07:00
|
|
|
assert_eq!(working_bank.bank.ticks_per_slot(), self.ticks_per_slot());
|
2019-02-24 08:59:49 -08:00
|
|
|
self.working_bank = Some(working_bank);
|
2019-07-25 11:08:44 -07:00
|
|
|
let _ = self.flush_cache(false);
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
2019-03-03 16:44:06 -08:00
|
|
|
pub fn set_bank(&mut self, bank: &Arc<Bank>) {
|
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank: bank.clone(),
|
|
|
|
min_tick_height: bank.tick_height(),
|
2019-07-09 15:36:30 -07:00
|
|
|
max_tick_height: bank.max_tick_height(),
|
2019-03-03 16:44:06 -08:00
|
|
|
};
|
|
|
|
self.set_working_bank(working_bank);
|
|
|
|
}
|
2019-02-24 08:59:49 -08:00
|
|
|
|
|
|
|
// Flush cache will delay flushing the cache for a bank until it past the WorkingBank::min_tick_height
|
|
|
|
// On a record flush will flush the cache at the WorkingBank::min_tick_height, since a record
|
|
|
|
// occurs after the min_tick_height was generated
|
|
|
|
fn flush_cache(&mut self, tick: bool) -> Result<()> {
|
|
|
|
// check_tick_height is called before flush cache, so it cannot overrun the bank
|
|
|
|
// so a bank that is so late that it's slot fully generated before it starts recording
|
|
|
|
// will fail instead of broadcasting any ticks
|
|
|
|
let working_bank = self
|
|
|
|
.working_bank
|
|
|
|
.as_ref()
|
2020-01-02 19:50:43 -08:00
|
|
|
.ok_or(PohRecorderError::MaxHeightReached)?;
|
2019-05-18 14:01:36 -07:00
|
|
|
if self.tick_height < working_bank.min_tick_height {
|
2020-01-02 19:50:43 -08:00
|
|
|
return Err(PohRecorderError::MinHeightNotReached);
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
2019-05-18 14:01:36 -07:00
|
|
|
if tick && self.tick_height == working_bank.min_tick_height {
|
2020-01-02 19:50:43 -08:00
|
|
|
return Err(PohRecorderError::MinHeightNotReached);
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
|
|
|
|
2019-05-18 14:01:36 -07:00
|
|
|
let entry_count = self
|
2019-02-24 08:59:49 -08:00
|
|
|
.tick_cache
|
|
|
|
.iter()
|
|
|
|
.take_while(|x| x.1 <= working_bank.max_tick_height)
|
|
|
|
.count();
|
2019-09-18 12:16:22 -07:00
|
|
|
let mut send_result: std::result::Result<(), SendError<WorkingBankEntry>> = Ok(());
|
|
|
|
|
|
|
|
if entry_count > 0 {
|
2019-07-17 14:10:15 -07:00
|
|
|
trace!(
|
2019-03-04 16:40:28 -08:00
|
|
|
"flush_cache: bank_slot: {} tick_height: {} max: {} sending: {}",
|
2019-02-26 21:57:45 -08:00
|
|
|
working_bank.bank.slot(),
|
2019-02-24 08:59:49 -08:00
|
|
|
working_bank.bank.tick_height(),
|
|
|
|
working_bank.max_tick_height,
|
2019-05-18 14:01:36 -07:00
|
|
|
entry_count,
|
2019-02-24 08:59:49 -08:00
|
|
|
);
|
2019-09-18 12:16:22 -07:00
|
|
|
|
|
|
|
for tick in &self.tick_cache[..entry_count] {
|
|
|
|
working_bank.bank.register_tick(&tick.0.hash);
|
|
|
|
send_result = self.sender.send((working_bank.bank.clone(), tick.clone()));
|
|
|
|
if send_result.is_err() {
|
|
|
|
break;
|
|
|
|
}
|
2019-02-19 16:17:36 -08:00
|
|
|
}
|
2019-09-18 12:16:22 -07:00
|
|
|
}
|
2019-05-18 14:01:36 -07:00
|
|
|
if self.tick_height >= working_bank.max_tick_height {
|
2019-03-03 16:44:06 -08:00
|
|
|
info!(
|
2019-07-09 15:36:30 -07:00
|
|
|
"poh_record: max_tick_height {} reached, clearing working_bank {}",
|
|
|
|
working_bank.max_tick_height,
|
2019-03-03 16:44:06 -08:00
|
|
|
working_bank.bank.slot()
|
|
|
|
);
|
2019-10-16 12:53:11 -07:00
|
|
|
let working_slot =
|
|
|
|
(working_bank.max_tick_height / self.ticks_per_slot).saturating_sub(1);
|
|
|
|
self.start_slot = working_slot;
|
|
|
|
self.start_tick_height = working_slot * self.ticks_per_slot + 1;
|
2019-03-11 13:58:23 -07:00
|
|
|
self.clear_bank();
|
2019-02-19 16:17:36 -08:00
|
|
|
}
|
2019-05-18 14:01:36 -07:00
|
|
|
if send_result.is_err() {
|
|
|
|
info!("WorkingBank::sender disconnected {:?}", send_result);
|
|
|
|
// revert the cache, but clear the working bank
|
2019-03-11 13:58:23 -07:00
|
|
|
self.clear_bank();
|
2019-02-24 08:59:49 -08:00
|
|
|
} else {
|
2019-05-18 14:01:36 -07:00
|
|
|
// commit the flush
|
|
|
|
let _ = self.tick_cache.drain(..entry_count);
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
|
|
|
|
2018-12-12 18:52:11 -08:00
|
|
|
Ok(())
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|
|
|
|
|
2019-02-24 08:59:49 -08:00
|
|
|
pub fn tick(&mut self) {
|
2019-05-22 15:54:24 -07:00
|
|
|
let now = Instant::now();
|
2019-05-18 14:01:36 -07:00
|
|
|
let poh_entry = self.poh.lock().unwrap().tick();
|
2020-04-24 15:04:23 -07:00
|
|
|
inc_new_counter_warn!(
|
2019-05-22 15:54:24 -07:00
|
|
|
"poh_recorder-tick_lock_contention",
|
2019-10-30 18:55:29 -07:00
|
|
|
timing::duration_as_us(&now.elapsed()) as usize
|
2019-05-22 15:54:24 -07:00
|
|
|
);
|
|
|
|
let now = Instant::now();
|
2019-05-18 14:01:36 -07:00
|
|
|
if let Some(poh_entry) = poh_entry {
|
|
|
|
self.tick_height += 1;
|
2019-10-16 12:53:11 -07:00
|
|
|
trace!("tick_height {}", self.tick_height);
|
2019-05-03 16:41:19 -07:00
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
if self.leader_first_tick_height.is_none() {
|
2020-04-24 15:04:23 -07:00
|
|
|
inc_new_counter_warn!(
|
2019-05-22 15:54:24 -07:00
|
|
|
"poh_recorder-tick_overhead",
|
2019-10-30 18:55:29 -07:00
|
|
|
timing::duration_as_us(&now.elapsed()) as usize
|
2019-05-22 15:54:24 -07:00
|
|
|
);
|
2019-05-18 14:01:36 -07:00
|
|
|
return;
|
|
|
|
}
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-05-18 14:01:36 -07:00
|
|
|
let entry = Entry {
|
|
|
|
num_hashes: poh_entry.num_hashes,
|
|
|
|
hash: poh_entry.hash,
|
|
|
|
transactions: vec![],
|
|
|
|
};
|
|
|
|
|
|
|
|
self.tick_cache.push((entry, self.tick_height));
|
|
|
|
let _ = self.flush_cache(true);
|
|
|
|
}
|
2020-04-24 15:04:23 -07:00
|
|
|
inc_new_counter_warn!(
|
2019-05-22 15:54:24 -07:00
|
|
|
"poh_recorder-tick_overhead",
|
2019-10-30 18:55:29 -07:00
|
|
|
timing::duration_as_us(&now.elapsed()) as usize
|
2019-05-22 15:54:24 -07:00
|
|
|
);
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|
|
|
|
|
2019-05-18 14:01:36 -07:00
|
|
|
pub fn record(
|
|
|
|
&mut self,
|
2019-07-09 15:36:30 -07:00
|
|
|
bank_slot: Slot,
|
2019-05-18 14:01:36 -07:00
|
|
|
mixin: Hash,
|
|
|
|
transactions: Vec<Transaction>,
|
|
|
|
) -> Result<()> {
|
|
|
|
// Entries without transactions are used to track real-time passing in the ledger and
|
|
|
|
// cannot be generated by `record()`
|
|
|
|
assert!(!transactions.is_empty(), "No transactions provided");
|
|
|
|
loop {
|
|
|
|
self.flush_cache(false)?;
|
|
|
|
|
|
|
|
let working_bank = self
|
|
|
|
.working_bank
|
|
|
|
.as_ref()
|
2020-01-02 19:50:43 -08:00
|
|
|
.ok_or(PohRecorderError::MaxHeightReached)?;
|
2019-05-18 14:01:36 -07:00
|
|
|
if bank_slot != working_bank.bank.slot() {
|
2020-01-02 19:50:43 -08:00
|
|
|
return Err(PohRecorderError::MaxHeightReached);
|
2019-05-18 14:01:36 -07:00
|
|
|
}
|
|
|
|
|
2019-10-30 18:55:29 -07:00
|
|
|
{
|
|
|
|
let now = Instant::now();
|
|
|
|
let mut poh_lock = self.poh.lock().unwrap();
|
2020-04-24 15:04:23 -07:00
|
|
|
inc_new_counter_warn!(
|
2019-05-22 15:54:24 -07:00
|
|
|
"poh_recorder-record_lock_contention",
|
2019-10-30 18:55:29 -07:00
|
|
|
timing::duration_as_us(&now.elapsed()) as usize
|
|
|
|
);
|
|
|
|
let now = Instant::now();
|
|
|
|
let res = poh_lock.record(mixin);
|
2020-04-24 15:04:23 -07:00
|
|
|
inc_new_counter_warn!(
|
2019-10-30 18:55:29 -07:00
|
|
|
"poh_recorder-record_ms",
|
|
|
|
timing::duration_as_us(&now.elapsed()) as usize
|
2019-05-22 15:54:24 -07:00
|
|
|
);
|
2019-10-30 18:55:29 -07:00
|
|
|
if let Some(poh_entry) = res {
|
|
|
|
let entry = Entry {
|
|
|
|
num_hashes: poh_entry.num_hashes,
|
|
|
|
hash: poh_entry.hash,
|
|
|
|
transactions,
|
|
|
|
};
|
|
|
|
self.sender
|
|
|
|
.send((working_bank.bank.clone(), (entry, self.tick_height)))?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
2019-05-18 14:01:36 -07:00
|
|
|
}
|
|
|
|
// record() might fail if the next PoH hash needs to be a tick. But that's ok, tick()
|
|
|
|
// and re-record()
|
|
|
|
self.tick();
|
|
|
|
}
|
2018-10-18 22:57:48 -07:00
|
|
|
}
|
|
|
|
|
2019-05-18 14:01:36 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-04-09 17:53:04 -07:00
|
|
|
pub fn new_with_clear_signal(
|
2019-03-12 17:42:53 -07:00
|
|
|
tick_height: u64,
|
|
|
|
last_entry_hash: Hash,
|
2019-07-09 15:36:30 -07:00
|
|
|
start_slot: Slot,
|
2019-07-26 11:33:51 -07:00
|
|
|
next_leader_slot: Option<(Slot, Slot)>,
|
2019-03-15 13:22:16 -07:00
|
|
|
ticks_per_slot: u64,
|
2019-03-20 14:23:58 -07:00
|
|
|
id: &Pubkey,
|
2020-01-13 13:13:52 -08:00
|
|
|
blockstore: &Arc<Blockstore>,
|
2019-04-09 17:53:04 -07:00
|
|
|
clear_bank_signal: Option<SyncSender<bool>>,
|
2019-04-19 02:39:44 -07:00
|
|
|
leader_schedule_cache: &Arc<LeaderScheduleCache>,
|
2019-05-18 14:01:36 -07:00
|
|
|
poh_config: &Arc<PohConfig>,
|
2019-09-18 12:16:22 -07:00
|
|
|
) -> (Self, Receiver<WorkingBankEntry>) {
|
2019-05-18 14:01:36 -07:00
|
|
|
let poh = Arc::new(Mutex::new(Poh::new(
|
|
|
|
last_entry_hash,
|
|
|
|
poh_config.hashes_per_tick,
|
|
|
|
)));
|
2019-03-03 16:44:06 -08:00
|
|
|
let (sender, receiver) = channel();
|
2019-10-16 12:53:11 -07:00
|
|
|
let (leader_first_tick_height, leader_last_tick_height, grace_ticks) =
|
|
|
|
Self::compute_leader_slot_tick_heights(next_leader_slot, ticks_per_slot);
|
2019-03-03 16:44:06 -08:00
|
|
|
(
|
2019-04-09 17:53:04 -07:00
|
|
|
Self {
|
2019-03-03 16:44:06 -08:00
|
|
|
poh,
|
2019-05-18 14:01:36 -07:00
|
|
|
tick_height,
|
2019-03-03 16:44:06 -08:00
|
|
|
tick_cache: vec![],
|
|
|
|
working_bank: None,
|
|
|
|
sender,
|
2019-04-09 17:53:04 -07:00
|
|
|
clear_bank_signal,
|
2019-03-12 17:42:53 -07:00
|
|
|
start_slot,
|
2019-10-16 12:53:11 -07:00
|
|
|
start_tick_height: tick_height + 1,
|
|
|
|
leader_first_tick_height,
|
|
|
|
leader_last_tick_height,
|
2019-07-17 14:10:15 -07:00
|
|
|
grace_ticks,
|
2019-03-20 14:23:58 -07:00
|
|
|
id: *id,
|
2020-01-13 13:13:52 -08:00
|
|
|
blockstore: blockstore.clone(),
|
2019-04-19 02:39:44 -07:00
|
|
|
leader_schedule_cache: leader_schedule_cache.clone(),
|
2019-05-06 11:23:06 -07:00
|
|
|
ticks_per_slot,
|
2019-05-18 14:01:36 -07:00
|
|
|
poh_config: poh_config.clone(),
|
2019-03-03 16:44:06 -08:00
|
|
|
},
|
|
|
|
receiver,
|
|
|
|
)
|
2018-10-18 22:57:48 -07:00
|
|
|
}
|
|
|
|
|
2019-04-09 17:53:04 -07:00
|
|
|
/// A recorder to synchronize PoH with the following data structures
|
|
|
|
/// * bank - the LastId's queue is updated on `tick` and `record` events
|
|
|
|
/// * sender - the Entry channel that outputs to the ledger
|
|
|
|
pub fn new(
|
|
|
|
tick_height: u64,
|
|
|
|
last_entry_hash: Hash,
|
2019-07-09 15:36:30 -07:00
|
|
|
start_slot: Slot,
|
2019-07-26 11:33:51 -07:00
|
|
|
next_leader_slot: Option<(Slot, Slot)>,
|
2019-04-09 17:53:04 -07:00
|
|
|
ticks_per_slot: u64,
|
|
|
|
id: &Pubkey,
|
2020-01-13 13:13:52 -08:00
|
|
|
blockstore: &Arc<Blockstore>,
|
2019-04-19 02:39:44 -07:00
|
|
|
leader_schedule_cache: &Arc<LeaderScheduleCache>,
|
2019-05-18 14:01:36 -07:00
|
|
|
poh_config: &Arc<PohConfig>,
|
2019-09-18 12:16:22 -07:00
|
|
|
) -> (Self, Receiver<WorkingBankEntry>) {
|
2019-04-09 17:53:04 -07:00
|
|
|
Self::new_with_clear_signal(
|
|
|
|
tick_height,
|
|
|
|
last_entry_hash,
|
|
|
|
start_slot,
|
2019-07-09 15:36:30 -07:00
|
|
|
next_leader_slot,
|
2019-04-09 17:53:04 -07:00
|
|
|
ticks_per_slot,
|
|
|
|
id,
|
2020-01-13 13:13:52 -08:00
|
|
|
blockstore,
|
2019-04-09 17:53:04 -07:00
|
|
|
None,
|
2019-04-19 02:39:44 -07:00
|
|
|
leader_schedule_cache,
|
2019-05-18 14:01:36 -07:00
|
|
|
poh_config,
|
2019-02-24 08:59:49 -08:00
|
|
|
)
|
2018-10-18 22:57:48 -07:00
|
|
|
}
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2020-01-13 15:55:41 -08:00
|
|
|
use bincode::serialize;
|
2020-03-21 10:54:40 -07:00
|
|
|
use solana_ledger::genesis_utils::{create_genesis_config, GenesisConfigInfo};
|
2020-01-13 15:55:41 -08:00
|
|
|
use solana_ledger::{blockstore::Blockstore, blockstore_meta::SlotMeta, get_tmp_ledger_path};
|
2019-11-06 10:52:30 -08:00
|
|
|
use solana_perf::test_tx::test_tx;
|
2019-09-06 14:30:56 -07:00
|
|
|
use solana_sdk::clock::DEFAULT_TICKS_PER_SLOT;
|
2018-11-16 08:04:46 -08:00
|
|
|
use solana_sdk::hash::hash;
|
2019-03-11 13:58:23 -07:00
|
|
|
use std::sync::mpsc::sync_channel;
|
2018-09-26 05:52:13 -07:00
|
|
|
|
|
|
|
#[test]
|
2019-02-24 08:59:49 -08:00
|
|
|
fn test_poh_recorder_no_zero_tick() {
|
2019-03-01 08:44:55 -08:00
|
|
|
let prev_hash = Hash::default();
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
DEFAULT_TICKS_PER_SLOT,
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::default()),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
poh_recorder.tick();
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 1);
|
|
|
|
assert_eq!(poh_recorder.tick_cache[0].1, 1);
|
2019-05-18 14:01:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, 1);
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_poh_recorder_tick_height_is_last_tick() {
|
2019-03-01 08:44:55 -08:00
|
|
|
let prev_hash = Hash::default();
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
DEFAULT_TICKS_PER_SLOT,
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::default()),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 2);
|
|
|
|
assert_eq!(poh_recorder.tick_cache[1].1, 2);
|
2019-05-18 14:01:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, 2);
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_poh_recorder_reset_clears_cache() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-03-29 20:00:36 -07:00
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
Hash::default(),
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
DEFAULT_TICKS_PER_SLOT,
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::default()),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
poh_recorder.tick();
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 1);
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(Hash::default(), 0, Some((4, 4)));
|
2019-03-29 20:00:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 0);
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_poh_recorder_clear() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-02-24 08:59:49 -08:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank,
|
|
|
|
min_tick_height: 2,
|
|
|
|
max_tick_height: 3,
|
|
|
|
};
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
|
|
|
assert!(poh_recorder.working_bank.is_some());
|
|
|
|
poh_recorder.clear_bank();
|
|
|
|
assert!(poh_recorder.working_bank.is_none());
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_poh_recorder_tick_sent_after_min() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-02-19 16:17:36 -08:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank: bank.clone(),
|
|
|
|
min_tick_height: 2,
|
|
|
|
max_tick_height: 3,
|
|
|
|
};
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
|
|
|
//tick height equal to min_tick_height
|
|
|
|
//no tick has been sent
|
|
|
|
assert_eq!(poh_recorder.tick_cache.last().unwrap().1, 2);
|
|
|
|
assert!(entry_receiver.try_recv().is_err());
|
|
|
|
|
|
|
|
// all ticks are sent after height > min
|
|
|
|
poh_recorder.tick();
|
2019-05-18 14:01:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, 3);
|
2019-03-29 20:00:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 0);
|
2019-09-18 12:16:22 -07:00
|
|
|
let mut num_entries = 0;
|
|
|
|
while let Ok((wbank, (_entry, _tick_height))) = entry_receiver.try_recv() {
|
|
|
|
assert_eq!(wbank.slot(), bank.slot());
|
|
|
|
num_entries += 1;
|
|
|
|
}
|
|
|
|
assert_eq!(num_entries, 3);
|
2019-03-29 20:00:36 -07:00
|
|
|
assert!(poh_recorder.working_bank.is_none());
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
2018-12-10 20:03:04 -08:00
|
|
|
|
2019-02-24 08:59:49 -08:00
|
|
|
#[test]
|
|
|
|
fn test_poh_recorder_tick_sent_upto_and_including_max() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2018-09-26 05:52:13 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
|
|
|
assert_eq!(poh_recorder.tick_cache.last().unwrap().1, 4);
|
2019-05-18 14:01:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, 4);
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank,
|
|
|
|
min_tick_height: 2,
|
|
|
|
max_tick_height: 3,
|
|
|
|
};
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
|
|
|
poh_recorder.tick();
|
2018-12-12 18:52:11 -08:00
|
|
|
|
2019-05-18 14:01:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, 5);
|
2019-03-29 20:00:36 -07:00
|
|
|
assert!(poh_recorder.working_bank.is_none());
|
2019-09-18 12:16:22 -07:00
|
|
|
let mut num_entries = 0;
|
|
|
|
while let Ok(_) = entry_receiver.try_recv() {
|
|
|
|
num_entries += 1;
|
|
|
|
}
|
|
|
|
assert_eq!(num_entries, 3);
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-02-19 16:17:36 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-02-24 08:59:49 -08:00
|
|
|
fn test_poh_recorder_record_to_early() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-02-19 16:17:36 -08:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank: bank.clone(),
|
|
|
|
min_tick_height: 2,
|
|
|
|
max_tick_height: 3,
|
|
|
|
};
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
|
|
|
poh_recorder.tick();
|
|
|
|
let tx = test_tx();
|
|
|
|
let h1 = hash(b"hello world!");
|
|
|
|
assert!(poh_recorder
|
|
|
|
.record(bank.slot(), h1, vec![tx.clone()])
|
|
|
|
.is_err());
|
|
|
|
assert!(entry_receiver.try_recv().is_err());
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
2019-02-19 16:17:36 -08:00
|
|
|
|
2019-03-22 14:17:39 -07:00
|
|
|
#[test]
|
|
|
|
fn test_poh_recorder_record_bad_slot() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-03-22 14:17:39 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank: bank.clone(),
|
|
|
|
min_tick_height: 1,
|
|
|
|
max_tick_height: 2,
|
|
|
|
};
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
|
|
|
poh_recorder.tick();
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 1);
|
2019-05-18 14:01:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, 1);
|
2019-03-29 20:00:36 -07:00
|
|
|
let tx = test_tx();
|
|
|
|
let h1 = hash(b"hello world!");
|
|
|
|
assert_matches!(
|
|
|
|
poh_recorder.record(bank.slot() + 1, h1, vec![tx.clone()]),
|
2020-01-02 19:50:43 -08:00
|
|
|
Err(PohRecorderError::MaxHeightReached)
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-03-22 14:17:39 -07:00
|
|
|
}
|
|
|
|
|
2019-02-24 08:59:49 -08:00
|
|
|
#[test]
|
|
|
|
fn test_poh_recorder_record_at_min_passes() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-02-19 16:17:36 -08:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank: bank.clone(),
|
|
|
|
min_tick_height: 1,
|
|
|
|
max_tick_height: 2,
|
|
|
|
};
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
|
|
|
poh_recorder.tick();
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 1);
|
2019-05-18 14:01:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, 1);
|
2019-03-29 20:00:36 -07:00
|
|
|
let tx = test_tx();
|
|
|
|
let h1 = hash(b"hello world!");
|
|
|
|
assert!(poh_recorder
|
|
|
|
.record(bank.slot(), h1, vec![tx.clone()])
|
|
|
|
.is_ok());
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 0);
|
|
|
|
|
|
|
|
//tick in the cache + entry
|
2019-09-18 12:16:22 -07:00
|
|
|
let (_bank, (e, _tick_height)) = entry_receiver.recv().expect("recv 1");
|
|
|
|
assert!(e.is_tick());
|
|
|
|
let (_bank, (e, _tick_height)) = entry_receiver.recv().expect("recv 2");
|
|
|
|
assert!(!e.is_tick());
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-02-19 16:17:36 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-02-24 08:59:49 -08:00
|
|
|
fn test_poh_recorder_record_at_max_fails() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-02-19 16:17:36 -08:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank: bank.clone(),
|
|
|
|
min_tick_height: 1,
|
|
|
|
max_tick_height: 2,
|
|
|
|
};
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
2019-05-18 14:01:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, 2);
|
2019-03-29 20:00:36 -07:00
|
|
|
let tx = test_tx();
|
|
|
|
let h1 = hash(b"hello world!");
|
|
|
|
assert!(poh_recorder
|
|
|
|
.record(bank.slot(), h1, vec![tx.clone()])
|
|
|
|
.is_err());
|
|
|
|
|
2019-09-18 12:16:22 -07:00
|
|
|
let (_bank, (entry, _tick_height)) = entry_receiver.recv().unwrap();
|
|
|
|
assert!(entry.is_tick());
|
|
|
|
let (_bank, (entry, _tick_height)) = entry_receiver.recv().unwrap();
|
|
|
|
assert!(entry.is_tick());
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-02-24 08:59:49 -08:00
|
|
|
}
|
2019-02-19 16:17:36 -08:00
|
|
|
|
2019-02-24 08:59:49 -08:00
|
|
|
#[test]
|
|
|
|
fn test_poh_cache_on_disconnect() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-02-19 16:17:36 -08:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank,
|
|
|
|
min_tick_height: 2,
|
|
|
|
max_tick_height: 3,
|
|
|
|
};
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
2019-05-18 14:01:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, 2);
|
2019-03-29 20:00:36 -07:00
|
|
|
drop(entry_receiver);
|
|
|
|
poh_recorder.tick();
|
|
|
|
assert!(poh_recorder.working_bank.is_none());
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 3);
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|
2019-03-04 07:08:22 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_reset_current() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-03-29 20:00:36 -07:00
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
Hash::default(),
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
DEFAULT_TICKS_PER_SLOT,
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::default()),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 2);
|
2019-05-18 14:01:36 -07:00
|
|
|
let hash = poh_recorder.poh.lock().unwrap().hash;
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(hash, 0, Some((4, 4)));
|
2019-03-29 20:00:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 0);
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-03-04 07:08:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_reset_with_cached() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-03-29 20:00:36 -07:00
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
Hash::default(),
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
DEFAULT_TICKS_PER_SLOT,
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::default()),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 2);
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(poh_recorder.tick_cache[0].0.hash, 0, Some((4, 4)));
|
2019-03-29 20:00:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 0);
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-03-04 07:08:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_reset_to_new_value() {
|
2019-07-17 14:10:15 -07:00
|
|
|
solana_logger::setup();
|
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-03-29 20:00:36 -07:00
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
Hash::default(),
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
DEFAULT_TICKS_PER_SLOT,
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::default()),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
|
|
|
poh_recorder.tick();
|
2019-10-16 12:53:11 -07:00
|
|
|
poh_recorder.tick();
|
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 4);
|
|
|
|
assert_eq!(poh_recorder.tick_height, 4);
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(hash(b"hello"), 0, Some((4, 4))); // parent slot 0 implies tick_height of 3
|
2019-03-29 20:00:36 -07:00
|
|
|
assert_eq!(poh_recorder.tick_cache.len(), 0);
|
|
|
|
poh_recorder.tick();
|
2019-10-23 12:11:04 -07:00
|
|
|
assert_eq!(poh_recorder.tick_height, DEFAULT_TICKS_PER_SLOT + 1);
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-03-04 07:08:22 -08:00
|
|
|
}
|
2019-03-05 17:56:51 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_reset_clear_bank() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
Hash::default(),
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank,
|
|
|
|
min_tick_height: 2,
|
|
|
|
max_tick_height: 3,
|
|
|
|
};
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(hash(b"hello"), 0, Some((4, 4)));
|
2019-03-29 20:00:36 -07:00
|
|
|
assert!(poh_recorder.working_bank.is_none());
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-03-05 17:56:51 -08:00
|
|
|
}
|
2019-03-11 13:58:23 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn test_clear_signal() {
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-04-09 17:53:04 -07:00
|
|
|
let (sender, receiver) = sync_channel(1);
|
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new_with_clear_signal(
|
2019-03-29 20:00:36 -07:00
|
|
|
0,
|
|
|
|
Hash::default(),
|
|
|
|
0,
|
|
|
|
None,
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-09 17:53:04 -07:00
|
|
|
Some(sender),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::default()),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
|
|
|
poh_recorder.set_bank(&bank);
|
|
|
|
poh_recorder.clear_bank();
|
|
|
|
assert!(receiver.try_recv().is_ok());
|
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-03-11 13:58:23 -07:00
|
|
|
}
|
2019-03-13 14:06:12 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_poh_recorder_reset_start_slot() {
|
2019-10-16 12:53:11 -07:00
|
|
|
solana_logger::setup();
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-03-29 20:00:36 -07:00
|
|
|
let ticks_per_slot = 5;
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
mut genesis_config, ..
|
|
|
|
} = create_genesis_config(2);
|
|
|
|
genesis_config.ticks_per_slot = ticks_per_slot;
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((4, 4)),
|
2019-03-29 20:00:36 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-03-13 14:06:12 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let end_slot = 3;
|
2019-10-16 12:53:11 -07:00
|
|
|
let max_tick_height = (end_slot + 1) * ticks_per_slot;
|
2019-03-29 20:00:36 -07:00
|
|
|
let working_bank = WorkingBank {
|
|
|
|
bank: bank.clone(),
|
|
|
|
min_tick_height: 1,
|
|
|
|
max_tick_height,
|
|
|
|
};
|
|
|
|
|
|
|
|
poh_recorder.set_working_bank(working_bank);
|
|
|
|
for _ in 0..max_tick_height {
|
|
|
|
poh_recorder.tick();
|
|
|
|
}
|
2019-03-13 14:06:12 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let tx = test_tx();
|
|
|
|
let h1 = hash(b"hello world!");
|
|
|
|
assert!(poh_recorder
|
|
|
|
.record(bank.slot(), h1, vec![tx.clone()])
|
|
|
|
.is_err());
|
|
|
|
assert!(poh_recorder.working_bank.is_none());
|
|
|
|
// Make sure the starting slot is updated
|
2019-07-17 14:10:15 -07:00
|
|
|
assert_eq!(poh_recorder.start_slot, end_slot);
|
2019-03-13 14:06:12 -07:00
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-03-13 14:06:12 -07:00
|
|
|
}
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2020-01-13 15:55:41 -08:00
|
|
|
#[test]
|
|
|
|
fn test_reached_leader_tick() {
|
|
|
|
solana_logger::setup();
|
|
|
|
|
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
|
|
|
let prev_hash = bank.last_blockhash();
|
2020-02-29 00:05:35 -08:00
|
|
|
let leader_schedule_cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
|
2020-01-13 15:55:41 -08:00
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
|
|
|
None,
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
|
|
|
&Arc::new(blockstore),
|
2020-02-29 00:05:35 -08:00
|
|
|
&leader_schedule_cache,
|
2020-01-13 15:55:41 -08:00
|
|
|
&Arc::new(PohConfig::default()),
|
|
|
|
);
|
|
|
|
|
2020-02-29 00:05:35 -08:00
|
|
|
let bootstrap_validator_id = leader_schedule_cache.slot_leader_at(0, None).unwrap();
|
|
|
|
|
2020-01-13 15:55:41 -08:00
|
|
|
assert_eq!(poh_recorder.reached_leader_tick(0), true);
|
|
|
|
|
|
|
|
let grace_ticks = bank.ticks_per_slot() * MAX_GRACE_SLOTS;
|
|
|
|
let new_tick_height = NUM_CONSECUTIVE_LEADER_SLOTS * bank.ticks_per_slot();
|
|
|
|
for _ in 0..new_tick_height {
|
|
|
|
poh_recorder.tick();
|
|
|
|
}
|
|
|
|
|
|
|
|
poh_recorder.grace_ticks = grace_ticks;
|
|
|
|
// True, as previous leader did not transmit in its slots
|
|
|
|
assert_eq!(
|
|
|
|
poh_recorder.reached_leader_tick(new_tick_height + grace_ticks),
|
|
|
|
true
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut parent_meta = SlotMeta::default();
|
|
|
|
parent_meta.received = 1;
|
|
|
|
poh_recorder
|
|
|
|
.blockstore
|
|
|
|
.put_meta_bytes(0, &serialize(&parent_meta).unwrap())
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// False, as previous leader transmitted in one of its recent slots
|
|
|
|
// and grace ticks have not expired
|
|
|
|
assert_eq!(
|
|
|
|
poh_recorder.reached_leader_tick(new_tick_height + grace_ticks),
|
|
|
|
false
|
|
|
|
);
|
2020-02-29 00:05:35 -08:00
|
|
|
|
|
|
|
// From the bootstrap validator's perspective, it should have reached
|
|
|
|
// the tick
|
|
|
|
poh_recorder.id = bootstrap_validator_id;
|
|
|
|
assert!(poh_recorder.reached_leader_tick(new_tick_height + grace_ticks));
|
2020-01-13 15:55:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-15 13:22:16 -07:00
|
|
|
#[test]
|
2019-10-16 12:53:11 -07:00
|
|
|
fn test_reached_leader_slot() {
|
2019-07-17 14:10:15 -07:00
|
|
|
solana_logger::setup();
|
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-03-29 20:00:36 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
|
|
|
None,
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-19 02:39:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-03-29 20:00:36 -07:00
|
|
|
);
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
// Test that with no next leader slot, we don't reach the leader slot
|
|
|
|
assert_eq!(poh_recorder.reached_leader_slot().0, false);
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
// Test that with no next leader slot in reset(), we don't reach the leader slot
|
2019-07-17 14:10:15 -07:00
|
|
|
poh_recorder.reset(bank.last_blockhash(), 0, None);
|
2019-10-16 12:53:11 -07:00
|
|
|
assert_eq!(poh_recorder.reached_leader_slot().0, false);
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
// Provide a leader slot one slot down
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(bank.last_blockhash(), 0, Some((2, 2)));
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let init_ticks = poh_recorder.tick_height();
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
// Send one slot worth of ticks
|
|
|
|
for _ in 0..bank.ticks_per_slot() {
|
|
|
|
poh_recorder.tick();
|
|
|
|
}
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
// Tick should be recorded
|
|
|
|
assert_eq!(
|
|
|
|
poh_recorder.tick_height(),
|
|
|
|
init_ticks + bank.ticks_per_slot()
|
|
|
|
);
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2020-01-13 15:55:41 -08:00
|
|
|
let mut parent_meta = SlotMeta::default();
|
|
|
|
parent_meta.received = 1;
|
|
|
|
poh_recorder
|
|
|
|
.blockstore
|
|
|
|
.put_meta_bytes(0, &serialize(&parent_meta).unwrap())
|
|
|
|
.unwrap();
|
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
// Test that we don't reach the leader slot because of grace ticks
|
|
|
|
assert_eq!(poh_recorder.reached_leader_slot().0, false);
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-07-17 14:10:15 -07:00
|
|
|
// reset poh now. we should immediately be leader
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(bank.last_blockhash(), 1, Some((2, 2)));
|
2019-10-16 12:53:11 -07:00
|
|
|
let (reached_leader_slot, grace_ticks, leader_slot, ..) =
|
|
|
|
poh_recorder.reached_leader_slot();
|
|
|
|
assert_eq!(reached_leader_slot, true);
|
|
|
|
assert_eq!(grace_ticks, 0);
|
|
|
|
assert_eq!(leader_slot, 2);
|
|
|
|
|
|
|
|
// Now test that with grace ticks we can reach leader slot
|
|
|
|
// Set the leader slot one slot down
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(bank.last_blockhash(), 1, Some((3, 3)));
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-07-17 14:10:15 -07:00
|
|
|
// Send one slot worth of ticks ("skips" slot 2)
|
2019-03-29 20:00:36 -07:00
|
|
|
for _ in 0..bank.ticks_per_slot() {
|
|
|
|
poh_recorder.tick();
|
|
|
|
}
|
|
|
|
|
|
|
|
// We are not the leader yet, as expected
|
2019-10-16 12:53:11 -07:00
|
|
|
assert_eq!(poh_recorder.reached_leader_slot().0, false);
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
// Send the grace ticks
|
|
|
|
for _ in 0..bank.ticks_per_slot() / GRACE_TICKS_FACTOR {
|
2019-03-29 20:00:36 -07:00
|
|
|
poh_recorder.tick();
|
|
|
|
}
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
// We should be the leader now
|
2019-10-16 12:53:11 -07:00
|
|
|
let (reached_leader_slot, grace_ticks, leader_slot, ..) =
|
|
|
|
poh_recorder.reached_leader_slot();
|
|
|
|
assert_eq!(reached_leader_slot, true);
|
|
|
|
assert_eq!(grace_ticks, bank.ticks_per_slot() / GRACE_TICKS_FACTOR);
|
|
|
|
assert_eq!(leader_slot, 3);
|
2019-03-15 13:22:16 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
// Let's test that correct grace ticks are reported
|
2019-10-16 12:53:11 -07:00
|
|
|
// Set the leader slot one slot down
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(bank.last_blockhash(), 2, Some((4, 4)));
|
2019-03-18 13:24:07 -07:00
|
|
|
|
2019-07-17 14:10:15 -07:00
|
|
|
// send ticks for a slot
|
|
|
|
for _ in 0..bank.ticks_per_slot() {
|
2019-03-29 20:00:36 -07:00
|
|
|
poh_recorder.tick();
|
|
|
|
}
|
2019-03-18 13:24:07 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
// We are not the leader yet, as expected
|
2019-10-16 12:53:11 -07:00
|
|
|
assert_eq!(poh_recorder.reached_leader_slot().0, false);
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(bank.last_blockhash(), 3, Some((4, 4)));
|
2019-07-17 14:10:15 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
// without sending more ticks, we should be leader now
|
2019-10-16 12:53:11 -07:00
|
|
|
let (reached_leader_slot, grace_ticks, leader_slot, ..) =
|
|
|
|
poh_recorder.reached_leader_slot();
|
|
|
|
assert_eq!(reached_leader_slot, true);
|
|
|
|
assert_eq!(grace_ticks, 0);
|
|
|
|
assert_eq!(leader_slot, 4);
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
// Let's test that if a node overshoots the ticks for its target
|
2019-10-16 12:53:11 -07:00
|
|
|
// leader slot, reached_leader_slot() will return true, because it's overdue
|
|
|
|
// Set the leader slot one slot down
|
2019-07-26 11:33:51 -07:00
|
|
|
poh_recorder.reset(bank.last_blockhash(), 4, Some((5, 5)));
|
2019-03-19 14:49:36 -07:00
|
|
|
|
2019-10-16 12:53:11 -07:00
|
|
|
// Overshoot ticks for the slot
|
|
|
|
let overshoot_factor = 4;
|
|
|
|
for _ in 0..overshoot_factor * bank.ticks_per_slot() {
|
2019-03-29 20:00:36 -07:00
|
|
|
poh_recorder.tick();
|
|
|
|
}
|
2019-03-19 14:49:36 -07:00
|
|
|
|
2019-07-09 15:36:30 -07:00
|
|
|
// We are overdue to lead
|
2019-10-16 12:53:11 -07:00
|
|
|
let (reached_leader_slot, grace_ticks, leader_slot, ..) =
|
|
|
|
poh_recorder.reached_leader_slot();
|
|
|
|
assert_eq!(reached_leader_slot, true);
|
|
|
|
assert_eq!(grace_ticks, overshoot_factor * bank.ticks_per_slot());
|
|
|
|
assert_eq!(leader_slot, 9);
|
2019-03-29 20:00:36 -07:00
|
|
|
}
|
2020-01-13 13:13:52 -08:00
|
|
|
Blockstore::destroy(&ledger_path).unwrap();
|
2019-03-15 13:22:16 -07:00
|
|
|
}
|
2019-04-22 19:49:32 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_would_be_leader_soon() {
|
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
2019-04-22 19:49:32 -07:00
|
|
|
let prev_hash = bank.last_blockhash();
|
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
prev_hash,
|
|
|
|
0,
|
|
|
|
None,
|
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-04-22 19:49:32 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
2019-05-18 14:01:36 -07:00
|
|
|
&Arc::new(PohConfig::default()),
|
2019-04-22 19:49:32 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
// Test that with no leader slot, we don't reach the leader tick
|
|
|
|
assert_eq!(
|
2019-04-23 11:56:30 -07:00
|
|
|
poh_recorder.would_be_leader(2 * bank.ticks_per_slot()),
|
2019-04-22 19:49:32 -07:00
|
|
|
false
|
|
|
|
);
|
|
|
|
|
2019-07-17 14:10:15 -07:00
|
|
|
poh_recorder.reset(bank.last_blockhash(), 0, None);
|
2019-04-22 19:49:32 -07:00
|
|
|
|
|
|
|
assert_eq!(
|
2019-04-23 11:56:30 -07:00
|
|
|
poh_recorder.would_be_leader(2 * bank.ticks_per_slot()),
|
2019-04-22 19:49:32 -07:00
|
|
|
false
|
|
|
|
);
|
|
|
|
|
|
|
|
// We reset with leader slot after 3 slots
|
2019-07-26 11:33:51 -07:00
|
|
|
let bank_slot = bank.slot() + 3;
|
|
|
|
poh_recorder.reset(bank.last_blockhash(), 0, Some((bank_slot, bank_slot)));
|
2019-04-22 19:49:32 -07:00
|
|
|
|
|
|
|
// Test that the node won't be leader in next 2 slots
|
|
|
|
assert_eq!(
|
2019-04-23 11:56:30 -07:00
|
|
|
poh_recorder.would_be_leader(2 * bank.ticks_per_slot()),
|
2019-04-22 19:49:32 -07:00
|
|
|
false
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test that the node will be leader in next 3 slots
|
2019-04-23 11:56:30 -07:00
|
|
|
assert_eq!(
|
|
|
|
poh_recorder.would_be_leader(3 * bank.ticks_per_slot()),
|
|
|
|
true
|
|
|
|
);
|
2019-04-22 19:49:32 -07:00
|
|
|
|
|
|
|
assert_eq!(
|
2019-04-23 11:56:30 -07:00
|
|
|
poh_recorder.would_be_leader(2 * bank.ticks_per_slot()),
|
2019-04-22 19:49:32 -07:00
|
|
|
false
|
|
|
|
);
|
|
|
|
|
2019-07-25 11:08:44 -07:00
|
|
|
// Move the bank up a slot (so that max_tick_height > slot 0's tick_height)
|
|
|
|
let bank = Arc::new(Bank::new_from_parent(&bank, &Pubkey::default(), 1));
|
2019-04-22 19:49:32 -07:00
|
|
|
// If we set the working bank, the node should be leader within next 2 slots
|
|
|
|
poh_recorder.set_bank(&bank);
|
2019-04-23 11:56:30 -07:00
|
|
|
assert_eq!(
|
|
|
|
poh_recorder.would_be_leader(2 * bank.ticks_per_slot()),
|
|
|
|
true
|
|
|
|
);
|
2019-04-22 19:49:32 -07:00
|
|
|
}
|
|
|
|
}
|
2019-07-25 11:08:44 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_flush_virtual_ticks() {
|
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
|
|
|
// test that virtual ticks are flushed into a newly set bank asap
|
2020-01-13 13:13:52 -08:00
|
|
|
let blockstore = Blockstore::open(&ledger_path)
|
|
|
|
.expect("Expected to be able to open database ledger");
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(2);
|
|
|
|
let bank = Arc::new(Bank::new(&genesis_config));
|
|
|
|
let genesis_hash = bank.last_blockhash();
|
2019-07-25 11:08:44 -07:00
|
|
|
|
|
|
|
let (mut poh_recorder, _entry_receiver) = PohRecorder::new(
|
|
|
|
0,
|
|
|
|
bank.last_blockhash(),
|
|
|
|
0,
|
2019-07-26 11:33:51 -07:00
|
|
|
Some((2, 2)),
|
2019-07-25 11:08:44 -07:00
|
|
|
bank.ticks_per_slot(),
|
|
|
|
&Pubkey::default(),
|
2020-01-13 13:13:52 -08:00
|
|
|
&Arc::new(blockstore),
|
2019-07-25 11:08:44 -07:00
|
|
|
&Arc::new(LeaderScheduleCache::new_from_bank(&bank)),
|
|
|
|
&Arc::new(PohConfig::default()),
|
|
|
|
);
|
|
|
|
//create a new bank
|
|
|
|
let bank = Arc::new(Bank::new_from_parent(&bank, &Pubkey::default(), 2));
|
|
|
|
//put 2 slots worth of virtual ticks into poh
|
|
|
|
for _ in 0..(bank.ticks_per_slot() * 2) {
|
|
|
|
poh_recorder.tick();
|
|
|
|
}
|
|
|
|
poh_recorder.set_bank(&bank.clone());
|
2020-01-16 23:26:50 -08:00
|
|
|
assert_eq!(Some(false), bank.check_hash_age(&genesis_hash, 1));
|
2019-07-25 11:08:44 -07:00
|
|
|
}
|
|
|
|
}
|
2019-07-26 11:33:51 -07:00
|
|
|
|
|
|
|
#[test]
|
2019-10-16 12:53:11 -07:00
|
|
|
fn test_compute_leader_slot_tick_heights() {
|
2019-07-26 11:33:51 -07:00
|
|
|
assert_eq!(
|
2019-10-16 12:53:11 -07:00
|
|
|
PohRecorder::compute_leader_slot_tick_heights(None, 0),
|
2019-07-26 11:33:51 -07:00
|
|
|
(None, 0, 0)
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
2019-10-16 12:53:11 -07:00
|
|
|
PohRecorder::compute_leader_slot_tick_heights(Some((4, 4)), 8),
|
|
|
|
(Some(37), 40, 4)
|
2019-07-26 11:33:51 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
2019-10-16 12:53:11 -07:00
|
|
|
PohRecorder::compute_leader_slot_tick_heights(Some((4, 7)), 8),
|
2019-11-19 17:55:42 -08:00
|
|
|
(Some(49), 64, 2 * 8)
|
2019-07-26 11:33:51 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
2019-10-16 12:53:11 -07:00
|
|
|
PohRecorder::compute_leader_slot_tick_heights(Some((6, 7)), 8),
|
|
|
|
(Some(57), 64, 8)
|
2019-07-26 11:33:51 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
2019-10-16 12:53:11 -07:00
|
|
|
PohRecorder::compute_leader_slot_tick_heights(Some((6, 7)), 4),
|
|
|
|
(Some(29), 32, 4)
|
2019-07-26 11:33:51 -07:00
|
|
|
);
|
|
|
|
}
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|