use {
crate::bank::Bank,
solana_sdk::{
clock::{Epoch, Slot},
vote::state::MAX_LOCKOUT_HISTORY,
},
};
#[must_use]
pub fn is_enabled_this_epoch(bank: &Bank) -> bool {
const MINIMUM_CALCULATION_INTERVAL: u64 =
(MAX_LOCKOUT_HISTORY as u64).saturating_add(CALCULATION_INTERVAL_BUFFER);
const CALCULATION_INTERVAL_BUFFER: u64 = 150;
let calculation_interval = calculation_interval(bank);
calculation_interval >= MINIMUM_CALCULATION_INTERVAL
}
#[must_use]
#[inline]
pub fn calculation_offset_start(bank: &Bank) -> Slot {
calculation_info(bank).calculation_offset_start
}
#[must_use]
#[inline]
pub fn calculation_offset_stop(bank: &Bank) -> Slot {
calculation_info(bank).calculation_offset_stop
}
#[must_use]
#[inline]
pub fn calculation_start(bank: &Bank) -> Slot {
calculation_info(bank).calculation_start
}
#[must_use]
#[inline]
pub fn calculation_stop(bank: &Bank) -> Slot {
calculation_info(bank).calculation_stop
}
#[must_use]
#[inline]
pub fn calculation_interval(bank: &Bank) -> u64 {
calculation_info(bank).calculation_interval
}
#[must_use]
pub fn is_in_calculation_window(bank: &Bank) -> bool {
let info = calculation_info(bank);
let range = info.calculation_start..info.calculation_stop;
range.contains(&bank.slot())
}
pub fn calculation_info(bank: &Bank) -> CalculationInfo {
let epoch = bank.epoch();
let epoch_schedule = bank.epoch_schedule();
let slots_per_epoch = epoch_schedule.get_slots_in_epoch(epoch);
let calculation_offset_start = slots_per_epoch / 4;
let calculation_offset_stop = slots_per_epoch / 4 * 3;
let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
let last_slot_in_epoch = epoch_schedule.get_last_slot_in_epoch(epoch);
let calculation_start = first_slot_in_epoch.saturating_add(calculation_offset_start);
let calculation_stop = first_slot_in_epoch.saturating_add(calculation_offset_stop);
let calculation_interval = calculation_offset_stop.saturating_sub(calculation_offset_start);
CalculationInfo {
epoch,
slots_per_epoch,
first_slot_in_epoch,
last_slot_in_epoch,
calculation_offset_start,
calculation_offset_stop,
calculation_start,
calculation_stop,
calculation_interval,
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct CalculationInfo {
pub epoch: Epoch,
pub slots_per_epoch: u64,
pub first_slot_in_epoch: Slot,
pub last_slot_in_epoch: Slot,
pub calculation_offset_start: Slot,
pub calculation_offset_stop: Slot,
pub calculation_start: Slot,
pub calculation_stop: Slot,
pub calculation_interval: u64,
}
#[cfg(test)]
mod tests {
use {
super::*,
solana_sdk::{epoch_schedule::EpochSchedule, genesis_config::GenesisConfig},
test_case::test_case,
};
#[test_case( 32 => false)] #[test_case( 361 => false)] #[test_case( 362 => false)] #[test_case( 8_192 => true)] #[test_case(432_000 => true)] fn test_is_enabled_this_epoch(slots_per_epoch: u64) -> bool {
let genesis_config = GenesisConfig {
epoch_schedule: EpochSchedule::custom(slots_per_epoch, slots_per_epoch, false),
..GenesisConfig::default()
};
let bank = Bank::new_for_tests(&genesis_config);
is_enabled_this_epoch(&bank)
}
#[test]
fn test_calculation_offset_bounds() {
let bank = Bank::default_for_tests();
let offset_start = calculation_offset_start(&bank);
let offset_stop = calculation_offset_stop(&bank);
assert!(offset_start < offset_stop);
}
#[test]
fn test_calculation_bounds() {
let bank = Bank::default_for_tests();
let start = calculation_start(&bank);
let stop = calculation_stop(&bank);
assert!(start < stop);
}
#[test]
fn test_calculation_info() {
for slots_per_epoch in [32, 361, 362, 8_192, 65_536, 432_000, 123_456_789] {
for warmup in [false, true] {
let genesis_config = GenesisConfig {
epoch_schedule: EpochSchedule::custom(slots_per_epoch, slots_per_epoch, warmup),
..GenesisConfig::default()
};
let info = calculation_info(&Bank::new_for_tests(&genesis_config));
assert!(info.calculation_offset_start < info.calculation_offset_stop);
assert!(info.calculation_offset_start < info.slots_per_epoch);
assert!(info.calculation_offset_stop < info.slots_per_epoch);
assert!(info.calculation_start < info.calculation_stop);
assert!(info.calculation_start > info.first_slot_in_epoch);
assert!(info.calculation_stop < info.last_slot_in_epoch);
assert!(info.calculation_interval > 0);
}
}
}
}