use crate::address::Address;
use crate::error::ProgramError;
#[inline(always)]
pub fn get_stack_height() -> u64 {
#[cfg(target_os = "solana")]
{
unsafe { crate::syscalls::sol_get_stack_height() }
}
#[cfg(not(target_os = "solana"))]
{
1 }
}
#[inline(always)]
pub fn is_top_level() -> bool {
get_stack_height() <= 1
}
#[inline(always)]
pub fn is_cpi() -> bool {
get_stack_height() > 1
}
#[inline(always)]
pub fn require_top_level() -> Result<(), ProgramError> {
if is_top_level() {
Ok(())
} else {
Err(ProgramError::InvalidArgument)
}
}
#[inline(always)]
pub fn require_cpi() -> Result<(), ProgramError> {
if is_cpi() {
Ok(())
} else {
Err(ProgramError::InvalidArgument)
}
}
#[derive(Clone, Debug)]
pub struct ProcessedInstruction {
pub program_id: Address,
pub data: [u8; 1232],
pub data_len: usize,
pub accounts_len: usize,
}
#[inline]
pub fn get_processed_instruction(index: u64) -> Option<ProcessedInstruction> {
#[cfg(target_os = "solana")]
{
let mut meta = ProcessedInstructionMeta {
data_len: 0,
accounts_len: 0,
};
let mut program_id = Address::default();
let mut data = [0u8; 1232];
let mut accounts_buf = [0u8; 2176];
meta.data_len = data.len() as u64;
meta.accounts_len = (accounts_buf.len() / 34) as u64;
let rc = unsafe {
crate::syscalls::sol_get_processed_sibling_instruction(
index,
&mut meta as *mut ProcessedInstructionMeta as *mut u8,
program_id.0.as_mut_ptr(),
data.as_mut_ptr(),
accounts_buf.as_mut_ptr(),
)
};
if rc != 0 {
return None;
}
Some(ProcessedInstruction {
program_id,
data,
data_len: meta.data_len as usize,
accounts_len: meta.accounts_len as usize,
})
}
#[cfg(not(target_os = "solana"))]
{
let _ = index;
None
}
}
pub const ED25519_PROGRAM_ID: Address =
crate::address!("Ed25519SigVerify111111111111111111111111111");
pub const SECP256K1_PROGRAM_ID: Address =
crate::address!("KeccakSecp256k11111111111111111111111111111");
#[inline]
pub fn require_ed25519_instruction(
sibling_index: u64,
) -> Result<ProcessedInstruction, ProgramError> {
let ix = get_processed_instruction(sibling_index).ok_or(ProgramError::InvalidArgument)?;
if !crate::address::address_eq(&ix.program_id, &ED25519_PROGRAM_ID) {
return Err(ProgramError::IncorrectProgramId);
}
Ok(ix)
}
#[inline]
pub fn require_secp256k1_instruction(
sibling_index: u64,
) -> Result<ProcessedInstruction, ProgramError> {
let ix = get_processed_instruction(sibling_index).ok_or(ProgramError::InvalidArgument)?;
if !crate::address::address_eq(&ix.program_id, &SECP256K1_PROGRAM_ID) {
return Err(ProgramError::IncorrectProgramId);
}
Ok(ix)
}
#[repr(C)]
#[allow(dead_code)]
struct ProcessedInstructionMeta {
data_len: u64,
accounts_len: u64,
}