use crate::address::Address;
use crate::error::ProgramError;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct Clock {
pub slot: u64,
pub epoch_start_timestamp: i64,
pub epoch: u64,
pub leader_schedule_epoch: u64,
pub unix_timestamp: i64,
}
#[inline]
pub fn get_clock() -> Result<Clock, ProgramError> {
#[allow(unused_mut)]
let mut clock = Clock::default();
#[cfg(target_os = "solana")]
{
let rc =
unsafe { crate::syscalls::sol_get_clock_sysvar(&mut clock as *mut Clock as *mut u8) };
if rc != 0 {
return Err(ProgramError::UnsupportedSysvar);
}
}
Ok(clock)
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct Rent {
pub lamports_per_byte_year: u64,
pub exemption_threshold: f64,
pub burn_percent: u8,
}
#[inline]
pub fn get_rent() -> Result<Rent, ProgramError> {
#[allow(unused_mut)]
let mut rent = Rent::default();
#[cfg(target_os = "solana")]
{
let rc = unsafe { crate::syscalls::sol_get_rent_sysvar(&mut rent as *mut Rent as *mut u8) };
if rc != 0 {
return Err(ProgramError::UnsupportedSysvar);
}
}
Ok(rent)
}
impl Rent {
#[inline]
pub fn minimum_balance(&self, data_len: usize) -> u64 {
let total_size = (data_len as u64).saturating_add(128);
let lamports =
(total_size as f64) * self.lamports_per_byte_year as f64 * self.exemption_threshold;
lamports as u64
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct EpochSchedule {
pub slots_per_epoch: u64,
pub leader_schedule_slot_offset: u64,
pub warmup: bool,
pub first_normal_epoch: u64,
pub first_normal_slot: u64,
}
#[inline]
pub fn get_epoch_schedule() -> Result<EpochSchedule, ProgramError> {
#[allow(unused_mut)]
let mut schedule = EpochSchedule::default();
#[cfg(target_os = "solana")]
{
let rc = unsafe {
crate::syscalls::sol_get_epoch_schedule_sysvar(
&mut schedule as *mut EpochSchedule as *mut u8,
)
};
if rc != 0 {
return Err(ProgramError::UnsupportedSysvar);
}
}
Ok(schedule)
}
impl EpochSchedule {
#[inline]
pub fn get_epoch(&self, slot: u64) -> u64 {
if slot < self.first_normal_slot {
if slot == 0 {
return 0;
}
let mut epoch_len: u64 = 32; let mut epoch: u64 = 0;
let mut slot_remaining = slot;
while slot_remaining >= epoch_len {
slot_remaining -= epoch_len;
epoch += 1;
epoch_len = epoch_len.saturating_mul(2);
}
epoch
} else {
let normal_slot_index = slot - self.first_normal_slot;
self.first_normal_epoch + normal_slot_index / self.slots_per_epoch
}
}
#[inline]
pub fn get_first_slot_in_epoch(&self, epoch: u64) -> u64 {
if epoch <= self.first_normal_epoch {
if epoch == 0 {
return 0;
}
let shift = epoch.min(63);
32_u64.saturating_mul((1_u64 << shift).saturating_sub(1))
} else {
let normal_epoch_index = epoch - self.first_normal_epoch;
self.first_normal_slot + normal_epoch_index * self.slots_per_epoch
}
}
}
pub const CLOCK_ID: Address = crate::address!("SysvarC1ock11111111111111111111111111111111");
pub const RENT_ID: Address = crate::address!("SysvarRent111111111111111111111111111111111");
pub const EPOCH_SCHEDULE_ID: Address =
crate::address!("SysvarEpochSchedu1e111111111111111111111111");