use hopper_runtime::{error::ProgramError, AccountView, ProgramResult};
const NOT_BORROWED: u32 = 0xFF;
pub const HEADER_NODUP: u32 = NOT_BORROWED;
pub const HEADER_SIGNER: u32 = NOT_BORROWED | (1 << 8);
pub const HEADER_WRITABLE: u32 = NOT_BORROWED | (1 << 16);
pub const HEADER_SIGNER_WRITABLE: u32 = NOT_BORROWED | (1 << 8) | (1 << 16);
pub const HEADER_EXECUTABLE: u32 = NOT_BORROWED | (1 << 24);
pub const HEADER_AUTHORITY: u32 = HEADER_SIGNER_WRITABLE;
#[cfg(all(target_os = "solana", feature = "hopper-native-backend"))]
#[inline(always)]
unsafe fn read_account_header(account: &AccountView) -> u32 {
let ptr = account as *const AccountView as *const u8;
let raw_ptr = unsafe { *(ptr as *const *const u8) };
unsafe { core::ptr::read_unaligned(raw_ptr as *const u32) }
}
#[inline(always)]
pub fn check_account_fast(account: &AccountView, expected_header: u32) -> ProgramResult {
#[cfg(all(target_os = "solana", feature = "hopper-native-backend"))]
{
let actual = unsafe { read_account_header(account) };
if (actual & expected_header) == expected_header {
return Ok(());
}
decompose_header_error(actual, expected_header)
}
#[cfg(not(all(target_os = "solana", feature = "hopper-native-backend")))]
{
check_account_flags_fallback(account, expected_header)
}
}
#[cold]
#[inline(never)]
#[allow(dead_code)]
fn decompose_header_error(actual: u32, expected: u32) -> ProgramResult {
if actual & 0xFF != 0xFF {
return Err(ProgramError::AccountBorrowFailed);
}
if (expected & (1 << 8)) != 0 && (actual & (1 << 8)) == 0 {
return Err(ProgramError::MissingRequiredSignature);
}
if (expected & (1 << 16)) != 0 && (actual & (1 << 16)) == 0 {
return Err(ProgramError::InvalidAccountData);
}
if (expected & (1 << 24)) != 0 && (actual & (1 << 24)) == 0 {
return Err(ProgramError::InvalidAccountData);
}
Err(ProgramError::InvalidAccountData)
}
#[cfg(not(all(target_os = "solana", feature = "hopper-native-backend")))]
fn check_account_flags_fallback(account: &AccountView, expected: u32) -> ProgramResult {
if (expected & (1 << 8)) != 0 && !account.is_signer() {
return Err(ProgramError::MissingRequiredSignature);
}
if (expected & (1 << 16)) != 0 && !account.is_writable() {
return Err(ProgramError::InvalidAccountData);
}
if (expected & (1 << 24)) != 0 && !account.executable() {
return Err(ProgramError::InvalidAccountData);
}
Ok(())
}
#[inline(always)]
pub fn check_signer_fast(account: &AccountView) -> ProgramResult {
check_account_fast(account, HEADER_SIGNER)
}
#[inline(always)]
pub fn check_writable_fast(account: &AccountView) -> ProgramResult {
check_account_fast(account, HEADER_WRITABLE)
}
#[inline(always)]
pub fn check_authority_fast(account: &AccountView) -> ProgramResult {
check_account_fast(account, HEADER_AUTHORITY)
}
#[inline(always)]
pub fn check_executable_fast(account: &AccountView) -> ProgramResult {
check_account_fast(account, HEADER_EXECUTABLE)
}