use solana_program::account_info::AccountInfo;
use solana_program::pubkey::Pubkey;
use crate::OnDemandError;
#[derive(Clone, Default)]
#[cfg_attr(feature = "anchor", derive(serde::Serialize, serde::Deserialize))]
pub struct Instructions;
impl Instructions {
#[inline(always)]
pub fn extract_ix_data<'a>(ix_sysvar: &AccountInfo<'a>, idx: usize) -> std::result::Result<(&'a Pubkey, &'a [u8]), OnDemandError> {
unsafe {
let data = ix_sysvar.data.borrow();
let base = data.as_ptr();
let data_len = data.len();
if data_len < 2 {
return Err(OnDemandError::InvalidInstructionError);
}
let num_instructions = (base as *const u16).read_unaligned() as usize;
if idx >= num_instructions {
return Err(OnDemandError::InvalidInstructionError);
}
let offset_table_size = num_instructions * 2;
if data_len < 2 + offset_table_size {
return Err(OnDemandError::InvalidInstructionError);
}
let start_offset = (base.add(2 + (idx << 1)) as *const u16).read_unaligned() as usize;
if start_offset >= data_len {
return Err(OnDemandError::InvalidInstructionError);
}
let mut p = base.add(start_offset);
let remaining = data_len - start_offset;
if remaining < 2 {
return Err(OnDemandError::InvalidInstructionError);
}
let num_accounts = (p as *const u16).read_unaligned() as usize;
p = p.add(2);
let accounts_size = num_accounts * 33;
if remaining < accounts_size + 36 { return Err(OnDemandError::InvalidInstructionError);
}
p = p.add(accounts_size);
let program_id = &*(p as *const Pubkey);
p = p.add(32);
let instruction_data_len = (p as *const u16).read_unaligned() as usize;
p = p.add(2);
let consumed = start_offset + accounts_size + 36;
if data_len < consumed + instruction_data_len {
return Err(OnDemandError::InvalidInstructionError);
}
Ok((program_id, core::slice::from_raw_parts(p, instruction_data_len)))
}
}
}
#[cfg(feature = "anchor")]
impl anchor_lang::Owner for Instructions {
fn owner() -> Pubkey {
anchor_lang::solana_program::sysvar::instructions::id()
}
}
#[cfg(feature = "anchor")]
impl anchor_lang::AccountDeserialize for Instructions {
fn try_deserialize_unchecked(_buf: &mut &[u8]) -> anchor_lang::Result<Self> {
Err(anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into())
}
}
#[cfg(feature = "anchor")]
impl anchor_lang::AccountSerialize for Instructions {
fn try_serialize<W: std::io::Write>(&self, _writer: &mut W) -> anchor_lang::Result<()> {
Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into())
}
}
#[cfg(feature = "anchor")]
impl anchor_lang::solana_program::sysvar::SysvarId for Instructions {
fn id() -> anchor_lang::solana_program::pubkey::Pubkey {
anchor_lang::solana_program::sysvar::instructions::id()
}
fn check_id(pubkey: &anchor_lang::solana_program::pubkey::Pubkey) -> bool {
pubkey == &Self::id()
}
}
#[cfg(feature = "anchor")]
impl anchor_lang::solana_program::sysvar::Sysvar for Instructions {
fn size_of() -> usize {
0
}
fn from_account_info(
account_info: &anchor_lang::solana_program::account_info::AccountInfo,
) -> core::result::Result<Self, anchor_lang::solana_program::program_error::ProgramError> {
use anchor_lang::solana_program::sysvar::SysvarId;
if Self::check_id(account_info.key) {
Ok(Self)
} else {
Err(anchor_lang::solana_program::program_error::ProgramError::InvalidAccountData)
}
}
}