solana_runtime/bank/
epoch_accounts_hash_utils.rs1use {
4 crate::bank::Bank,
5 solana_sdk::{
6 clock::{Epoch, Slot},
7 feature_set,
8 vote::state::MAX_LOCKOUT_HISTORY,
9 },
10};
11
12#[must_use]
14pub fn is_enabled_this_epoch(bank: &Bank) -> bool {
15 if bank
17 .feature_set
18 .is_active(&feature_set::accounts_lt_hash::id())
19 {
20 return false;
21 }
22
23 const MINIMUM_CALCULATION_INTERVAL: u64 =
30 (MAX_LOCKOUT_HISTORY as u64).saturating_add(CALCULATION_INTERVAL_BUFFER);
31 const CALCULATION_INTERVAL_BUFFER: u64 = 150;
39
40 let calculation_interval = calculation_interval(bank);
41 calculation_interval >= MINIMUM_CALCULATION_INTERVAL
42}
43
44#[must_use]
48#[inline]
49pub fn calculation_offset_start(bank: &Bank) -> Slot {
50 calculation_info(bank).calculation_offset_start
51}
52
53#[must_use]
58#[inline]
59pub fn calculation_offset_stop(bank: &Bank) -> Slot {
60 calculation_info(bank).calculation_offset_stop
61}
62
63#[must_use]
65#[inline]
66pub fn calculation_start(bank: &Bank) -> Slot {
67 calculation_info(bank).calculation_start
68}
69
70#[must_use]
72#[inline]
73pub fn calculation_stop(bank: &Bank) -> Slot {
74 calculation_info(bank).calculation_stop
75}
76
77#[must_use]
79#[inline]
80pub fn calculation_interval(bank: &Bank) -> u64 {
81 calculation_info(bank).calculation_interval
82}
83
84#[must_use]
86pub fn is_in_calculation_window(bank: &Bank) -> bool {
87 let info = calculation_info(bank);
88 let range = info.calculation_start..info.calculation_stop;
89 range.contains(&bank.slot())
90}
91
92pub fn calculation_info(bank: &Bank) -> CalculationInfo {
94 let epoch = bank.epoch();
95 let epoch_schedule = bank.epoch_schedule();
96
97 let slots_per_epoch = epoch_schedule.get_slots_in_epoch(epoch);
98 let calculation_offset_start = slots_per_epoch / 4;
99 let calculation_offset_stop = slots_per_epoch / 4 * 3;
100
101 let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch);
102 let last_slot_in_epoch = epoch_schedule.get_last_slot_in_epoch(epoch);
103 let calculation_start = first_slot_in_epoch.saturating_add(calculation_offset_start);
104 let calculation_stop = first_slot_in_epoch.saturating_add(calculation_offset_stop);
105 let calculation_interval = calculation_offset_stop.saturating_sub(calculation_offset_start);
106
107 CalculationInfo {
108 epoch,
109 slots_per_epoch,
110 first_slot_in_epoch,
111 last_slot_in_epoch,
112 calculation_offset_start,
113 calculation_offset_stop,
114 calculation_start,
115 calculation_stop,
116 calculation_interval,
117 }
118}
119
120#[derive(Debug, Default, Copy, Clone)]
126pub struct CalculationInfo {
127 pub epoch: Epoch,
132 pub slots_per_epoch: u64,
134 pub first_slot_in_epoch: Slot,
136 pub last_slot_in_epoch: Slot,
138
139 pub calculation_offset_start: Slot,
144 pub calculation_offset_stop: Slot,
146 pub calculation_start: Slot,
148 pub calculation_stop: Slot,
150 pub calculation_interval: u64,
152}
153
154#[cfg(test)]
155mod tests {
156 use {
157 super::*,
158 solana_sdk::{epoch_schedule::EpochSchedule, genesis_config::GenesisConfig},
159 test_case::test_case,
160 };
161
162 #[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 {
168 let genesis_config = GenesisConfig {
169 epoch_schedule: EpochSchedule::custom(slots_per_epoch, slots_per_epoch, false),
170 ..GenesisConfig::default()
171 };
172 let bank = Bank::new_for_tests(&genesis_config);
173 is_enabled_this_epoch(&bank)
174 }
175
176 #[test]
177 fn test_calculation_offset_bounds() {
178 let bank = Bank::default_for_tests();
179 let offset_start = calculation_offset_start(&bank);
180 let offset_stop = calculation_offset_stop(&bank);
181 assert!(offset_start < offset_stop);
182 }
183
184 #[test]
185 fn test_calculation_bounds() {
186 let bank = Bank::default_for_tests();
187 let start = calculation_start(&bank);
188 let stop = calculation_stop(&bank);
189 assert!(start < stop);
190 }
191
192 #[test]
193 fn test_calculation_info() {
194 for slots_per_epoch in [32, 361, 362, 8_192, 65_536, 432_000, 123_456_789] {
195 for warmup in [false, true] {
196 let genesis_config = GenesisConfig {
197 epoch_schedule: EpochSchedule::custom(slots_per_epoch, slots_per_epoch, warmup),
198 ..GenesisConfig::default()
199 };
200 let info = calculation_info(&Bank::new_for_tests(&genesis_config));
201 assert!(info.calculation_offset_start < info.calculation_offset_stop);
202 assert!(info.calculation_offset_start < info.slots_per_epoch);
203 assert!(info.calculation_offset_stop < info.slots_per_epoch);
204 assert!(info.calculation_start < info.calculation_stop);
205 assert!(info.calculation_start > info.first_slot_in_epoch);
206 assert!(info.calculation_stop < info.last_slot_in_epoch);
207 assert!(info.calculation_interval > 0);
208 }
209 }
210 }
211}