1use crate::address::Address;
8use crate::error::ProgramError;
9
10#[repr(C)]
14#[derive(Clone, Copy, Debug, Default)]
15pub struct Clock {
16 pub slot: u64,
17 pub epoch_start_timestamp: i64,
18 pub epoch: u64,
19 pub leader_schedule_epoch: u64,
20 pub unix_timestamp: i64,
21}
22
23#[inline]
25pub fn get_clock() -> Result<Clock, ProgramError> {
26 #[allow(unused_mut)]
27 let mut clock = Clock::default();
28
29 #[cfg(target_os = "solana")]
30 {
31 let rc =
32 unsafe { crate::syscalls::sol_get_clock_sysvar(&mut clock as *mut Clock as *mut u8) };
34 if rc != 0 {
35 return Err(ProgramError::UnsupportedSysvar);
36 }
37 }
38
39 Ok(clock)
40}
41
42#[repr(C)]
46#[derive(Clone, Copy, Debug, Default)]
47pub struct Rent {
48 pub lamports_per_byte_year: u64,
49 pub exemption_threshold: f64,
50 pub burn_percent: u8,
51}
52
53pub const LAMPORTS_PER_BYTE_YEAR: u64 = 3_480;
55
56pub const EXEMPTION_THRESHOLD_YEARS: u64 = 2;
58
59pub const ACCOUNT_STORAGE_OVERHEAD: u64 = 128;
61
62#[inline]
64pub const fn rent_exempt_minimum(data_len: usize) -> u64 {
65 (data_len as u64 + ACCOUNT_STORAGE_OVERHEAD)
66 * LAMPORTS_PER_BYTE_YEAR
67 * EXEMPTION_THRESHOLD_YEARS
68}
69
70#[inline]
72pub fn get_rent() -> Result<Rent, ProgramError> {
73 #[allow(unused_mut)]
74 let mut rent = Rent::default();
75
76 #[cfg(target_os = "solana")]
77 {
78 let rc = unsafe { crate::syscalls::sol_get_rent_sysvar(&mut rent as *mut Rent as *mut u8) };
80 if rc != 0 {
81 return Err(ProgramError::UnsupportedSysvar);
82 }
83 }
84
85 Ok(rent)
86}
87
88impl Rent {
89 #[inline]
91 pub fn minimum_balance(&self, data_len: usize) -> u64 {
92 let total_size = (data_len as u64).saturating_add(ACCOUNT_STORAGE_OVERHEAD);
93 (total_size as f64 * self.lamports_per_byte_year as f64 * self.exemption_threshold) as u64
94 }
95}
96
97#[repr(C)]
104#[derive(Clone, Copy, Debug, Default)]
105pub struct EpochSchedule {
106 pub slots_per_epoch: u64,
107 pub leader_schedule_slot_offset: u64,
108 pub warmup: bool,
109 pub first_normal_epoch: u64,
110 pub first_normal_slot: u64,
111}
112
113#[inline]
115pub fn get_epoch_schedule() -> Result<EpochSchedule, ProgramError> {
116 #[allow(unused_mut)]
117 let mut schedule = EpochSchedule::default();
118
119 #[cfg(target_os = "solana")]
120 {
121 let rc = unsafe {
123 crate::syscalls::sol_get_epoch_schedule_sysvar(
124 &mut schedule as *mut EpochSchedule as *mut u8,
125 )
126 };
127 if rc != 0 {
128 return Err(ProgramError::UnsupportedSysvar);
129 }
130 }
131
132 Ok(schedule)
133}
134
135impl EpochSchedule {
136 #[inline]
138 pub fn get_epoch(&self, slot: u64) -> u64 {
139 if slot < self.first_normal_slot {
140 if slot == 0 {
143 return 0;
144 }
145 let mut epoch_len: u64 = 32; let mut epoch: u64 = 0;
148 let mut slot_remaining = slot;
149 while slot_remaining >= epoch_len {
150 slot_remaining -= epoch_len;
151 epoch += 1;
152 epoch_len = epoch_len.saturating_mul(2);
153 }
154 epoch
155 } else {
156 let normal_slot_index = slot - self.first_normal_slot;
157 self.first_normal_epoch + normal_slot_index / self.slots_per_epoch
158 }
159 }
160
161 #[inline]
163 pub fn get_first_slot_in_epoch(&self, epoch: u64) -> u64 {
164 if epoch <= self.first_normal_epoch {
165 if epoch == 0 {
167 return 0;
168 }
169 let shift = epoch.min(63);
172 32_u64.saturating_mul((1_u64 << shift).saturating_sub(1))
173 } else {
174 let normal_epoch_index = epoch - self.first_normal_epoch;
175 self.first_normal_slot + normal_epoch_index * self.slots_per_epoch
176 }
177 }
178}
179
180pub const CLOCK_ID: Address = crate::address!("SysvarC1ock11111111111111111111111111111111");
184
185pub const RENT_ID: Address = crate::address!("SysvarRent111111111111111111111111111111111");
187
188pub const EPOCH_SCHEDULE_ID: Address =
190 crate::address!("SysvarEpochSchedu1e111111111111111111111111");