#[cfg(any(target_os = "solana", target_arch = "bpf"))]
use crate::syscalls::sol_get_sysvar;
use crate::{error::ProgramError, Address};
#[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
use core::hint::black_box;
pub mod clock;
pub mod fees;
pub mod instructions;
pub mod rent;
pub mod slot_hashes;
const OFFSET_LENGTH_EXCEEDS_SYSVAR: u64 = 1;
const SYSVAR_NOT_FOUND: u64 = 2;
pub trait Sysvar: Sized {
fn get() -> Result<Self, ProgramError> {
Err(ProgramError::UnsupportedSysvar)
}
}
#[macro_export]
macro_rules! impl_sysvar_get {
($syscall_name:ident) => {
fn get() -> Result<Self, $crate::error::ProgramError> {
let mut var = core::mem::MaybeUninit::<Self>::uninit();
let var_addr = var.as_mut_ptr() as *mut _ as *mut u8;
#[cfg(any(target_os = "solana", target_arch = "bpf"))]
let result = unsafe { $crate::syscalls::$syscall_name(var_addr) };
#[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
let result = core::hint::black_box(var_addr as *const _ as u64);
match result {
$crate::SUCCESS => {
Ok(unsafe { var.assume_init() })
}
_ => Err($crate::error::ProgramError::UnsupportedSysvar),
}
}
};
($syscall_id:expr, $padding:literal) => {
#[inline(always)]
fn get() -> Result<Self, $crate::error::ProgramError> {
let mut var = core::mem::MaybeUninit::<Self>::uninit();
let var_addr = var.as_mut_ptr() as *mut _ as *mut u8;
#[cfg(target_os = "solana")]
let result = unsafe {
let length = core::mem::size_of::<Self>() - $padding;
var_addr.add(length).write_bytes(0, $padding);
$crate::syscalls::sol_get_sysvar(
&$syscall_id as *const _ as *const u8,
var_addr,
0,
length as u64,
)
};
#[cfg(not(target_os = "solana"))]
let result = {
unsafe { var_addr.write_bytes(0, size_of::<Self>()) };
core::hint::black_box(var_addr as *const _ as u64)
};
match result {
$crate::SUCCESS => {
Ok(unsafe { var.assume_init() })
}
$crate::sysvars::OFFSET_LENGTH_EXCEEDS_SYSVAR => {
Err($crate::error::ProgramError::InvalidArgument)
}
$crate::sysvars::SYSVAR_NOT_FOUND => {
Err($crate::error::ProgramError::UnsupportedSysvar)
}
_ => Err($crate::error::ProgramError::UnsupportedSysvar),
}
}
};
}
#[inline]
pub unsafe fn get_sysvar_unchecked(
dst: *mut u8,
sysvar_id: &Address,
offset: usize,
len: usize,
) -> Result<(), ProgramError> {
#[cfg(any(target_os = "solana", target_arch = "bpf"))]
{
let result = unsafe {
sol_get_sysvar(
sysvar_id as *const _ as *const u8,
dst,
offset as u64,
len as u64,
)
};
match result {
crate::SUCCESS => Ok(()),
OFFSET_LENGTH_EXCEEDS_SYSVAR => Err(ProgramError::InvalidArgument),
SYSVAR_NOT_FOUND => Err(ProgramError::UnsupportedSysvar),
_ => Err(ProgramError::UnsupportedSysvar),
}
}
#[cfg(not(any(target_os = "solana", target_arch = "bpf")))]
{
black_box((dst, sysvar_id, offset, len));
Ok(())
}
}
#[inline(always)]
pub fn get_sysvar(dst: &mut [u8], sysvar_id: &Address, offset: usize) -> Result<(), ProgramError> {
unsafe { get_sysvar_unchecked(dst.as_mut_ptr(), sysvar_id, offset, dst.len()) }
}