solana_epoch_schedule/
sysvar.rs1pub use solana_sdk_ids::sysvar::epoch_schedule::{check_id, id, ID};
2use {
3 crate::EpochSchedule,
4 solana_get_sysvar::{get_sysvar_unchecked, GetSysvar},
5 solana_program_error::ProgramError,
6 solana_sysvar_id::impl_sysvar_id,
7};
8
9impl_sysvar_id!(EpochSchedule);
10
11#[repr(C)]
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub struct PodEpochSchedule {
18 slots_per_epoch: [u8; 8],
19 leader_schedule_slot_offset: [u8; 8],
20 warmup: u8,
21 first_normal_epoch: [u8; 8],
22 first_normal_slot: [u8; 8],
23}
24
25const POD_EPOCH_SCHEDULE_SIZE: usize = 33;
26const _: () = assert!(core::mem::size_of::<PodEpochSchedule>() == POD_EPOCH_SCHEDULE_SIZE);
27
28impl PodEpochSchedule {
29 pub fn fetch() -> Result<Self, ProgramError> {
32 let mut pod = core::mem::MaybeUninit::<Self>::uninit();
33 unsafe {
36 get_sysvar_unchecked(
37 pod.as_mut_ptr() as *mut u8,
38 (&id()) as *const _ as *const u8,
39 0,
40 POD_EPOCH_SCHEDULE_SIZE as u64,
41 )?;
42 Ok(pod.assume_init())
43 }
44 }
45
46 pub fn slots_per_epoch(&self) -> u64 {
47 u64::from_le_bytes(self.slots_per_epoch)
48 }
49
50 pub fn leader_schedule_slot_offset(&self) -> u64 {
51 u64::from_le_bytes(self.leader_schedule_slot_offset)
52 }
53
54 pub fn warmup(&self) -> bool {
55 self.warmup > 0
58 }
59
60 pub fn first_normal_epoch(&self) -> u64 {
61 u64::from_le_bytes(self.first_normal_epoch)
62 }
63
64 pub fn first_normal_slot(&self) -> u64 {
65 u64::from_le_bytes(self.first_normal_slot)
66 }
67}
68
69impl From<PodEpochSchedule> for EpochSchedule {
70 fn from(pod: PodEpochSchedule) -> Self {
71 Self {
72 slots_per_epoch: pod.slots_per_epoch(),
73 leader_schedule_slot_offset: pod.leader_schedule_slot_offset(),
74 warmup: pod.warmup(),
75 first_normal_epoch: pod.first_normal_epoch(),
76 first_normal_slot: pod.first_normal_slot(),
77 }
78 }
79}
80
81impl GetSysvar for EpochSchedule {
82 fn get() -> Result<Self, ProgramError> {
83 Ok(PodEpochSchedule::fetch()?.into())
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_pod_epoch_schedule_conversion() {
93 let pod = PodEpochSchedule {
94 slots_per_epoch: 432000u64.to_le_bytes(),
95 leader_schedule_slot_offset: 432000u64.to_le_bytes(),
96 warmup: 1,
97 first_normal_epoch: 14u64.to_le_bytes(),
98 first_normal_slot: 524256u64.to_le_bytes(),
99 };
100
101 let epoch_schedule = EpochSchedule::from(pod);
102
103 assert_eq!(epoch_schedule.slots_per_epoch, 432000);
104 assert_eq!(epoch_schedule.leader_schedule_slot_offset, 432000);
105 assert!(epoch_schedule.warmup);
106 assert_eq!(epoch_schedule.first_normal_epoch, 14);
107 assert_eq!(epoch_schedule.first_normal_slot, 524256);
108 }
109}