solana_runtime/bank/
epoch_accounts_hash_utils.rs1use {
4 crate::bank::Bank,
5 solana_sdk::{
6 clock::{Epoch, Slot},
7 vote::state::MAX_LOCKOUT_HISTORY,
8 },
9};
10
11#[must_use]
13pub fn is_enabled_this_epoch(bank: &Bank) -> bool {
14 const MINIMUM_CALCULATION_INTERVAL: u64 =
21 (MAX_LOCKOUT_HISTORY as u64).saturating_add(CALCULATION_INTERVAL_BUFFER);
22 const CALCULATION_INTERVAL_BUFFER: u64 = 150;
30
31 let calculation_interval = calculation_interval(bank);
32 calculation_interval >= MINIMUM_CALCULATION_INTERVAL
33}
34
35#[must_use]
39#[inline]
40pub fn calculation_offset_start(bank: &Bank) -> Slot {
41 calculation_info(bank).calculation_offset_start
42}
43
44#[must_use]
49#[inline]
50pub fn calculation_offset_stop(bank: &Bank) -> Slot {
51 calculation_info(bank).calculation_offset_stop
52}
53
54#[must_use]
56#[inline]
57pub fn calculation_start(bank: &Bank) -> Slot {
58 calculation_info(bank).calculation_start
59}
60
61#[must_use]
63#[inline]
64pub fn calculation_stop(bank: &Bank) -> Slot {
65 calculation_info(bank).calculation_stop
66}
67
68#[must_use]
70#[inline]
71pub fn calculation_interval(bank: &Bank) -> u64 {
72 calculation_info(bank).calculation_interval
73}
74
75#[must_use]
77pub fn is_in_calculation_window(bank: &Bank) -> bool {
78 let info = calculation_info(bank);
79 let range = info.calculation_start..info.calculation_stop;
80 range.contains(&bank.slot())
81}
82
83pub fn calculation_info(bank: &Bank) -> CalculationInfo {
85 let epoch = bank.epoch();
86 let epoch_schedule = bank.epoch_schedule();
87
88 let slots_per_epoch = epoch_schedule.get_slots_in_epoch(epoch);
89 let calculation_offset_start = slots_per_epoch / 4;
90 let calculation_offset_stop = slots_per_epoch / 4 * 3;
91
92 let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
93 let last_slot_in_epoch = epoch_schedule.get_last_slot_in_epoch(epoch);
94 let calculation_start = first_slot_in_epoch.saturating_add(calculation_offset_start);
95 let calculation_stop = first_slot_in_epoch.saturating_add(calculation_offset_stop);
96 let calculation_interval = calculation_offset_stop.saturating_sub(calculation_offset_start);
97
98 CalculationInfo {
99 epoch,
100 slots_per_epoch,
101 first_slot_in_epoch,
102 last_slot_in_epoch,
103 calculation_offset_start,
104 calculation_offset_stop,
105 calculation_start,
106 calculation_stop,
107 calculation_interval,
108 }
109}
110
111#[derive(Debug, Default, Copy, Clone)]
117pub struct CalculationInfo {
118 pub epoch: Epoch,
123 pub slots_per_epoch: u64,
125 pub first_slot_in_epoch: Slot,
127 pub last_slot_in_epoch: Slot,
129
130 pub calculation_offset_start: Slot,
135 pub calculation_offset_stop: Slot,
137 pub calculation_start: Slot,
139 pub calculation_stop: Slot,
141 pub calculation_interval: u64,
143}
144
145#[cfg(test)]
146mod tests {
147 use {
148 super::*,
149 solana_sdk::{epoch_schedule::EpochSchedule, genesis_config::GenesisConfig},
150 test_case::test_case,
151 };
152
153 #[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 {
159 let genesis_config = GenesisConfig {
160 epoch_schedule: EpochSchedule::custom(slots_per_epoch, slots_per_epoch, false),
161 ..GenesisConfig::default()
162 };
163 let bank = Bank::new_for_tests(&genesis_config);
164 is_enabled_this_epoch(&bank)
165 }
166
167 #[test]
168 fn test_calculation_offset_bounds() {
169 let bank = Bank::default_for_tests();
170 let offset_start = calculation_offset_start(&bank);
171 let offset_stop = calculation_offset_stop(&bank);
172 assert!(offset_start < offset_stop);
173 }
174
175 #[test]
176 fn test_calculation_bounds() {
177 let bank = Bank::default_for_tests();
178 let start = calculation_start(&bank);
179 let stop = calculation_stop(&bank);
180 assert!(start < stop);
181 }
182
183 #[test]
184 fn test_calculation_info() {
185 for slots_per_epoch in [32, 361, 362, 8_192, 65_536, 432_000, 123_456_789] {
186 for warmup in [false, true] {
187 let genesis_config = GenesisConfig {
188 epoch_schedule: EpochSchedule::custom(slots_per_epoch, slots_per_epoch, warmup),
189 ..GenesisConfig::default()
190 };
191 let info = calculation_info(&Bank::new_for_tests(&genesis_config));
192 assert!(info.calculation_offset_start < info.calculation_offset_stop);
193 assert!(info.calculation_offset_start < info.slots_per_epoch);
194 assert!(info.calculation_offset_stop < info.slots_per_epoch);
195 assert!(info.calculation_start < info.calculation_stop);
196 assert!(info.calculation_start > info.first_slot_in_epoch);
197 assert!(info.calculation_stop < info.last_slot_in_epoch);
198 assert!(info.calculation_interval > 0);
199 }
200 }
201 }
202}