use solana_address::Address;
use solana_program_runtime::invoke_context::InvokeContext;
use solana_transaction::InstructionError;
use solana_transaction_context::IndexOfAccount;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SvmInstructionAccount {
pub key: Address,
pub is_signer: bool,
pub is_writable: bool,
pub lamports: u64,
pub data: Vec<u8>,
pub owner: Address,
pub index_in_transaction: IndexOfAccount,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SvmInstructionCtx {
pub program_id: Address,
pub accounts: Vec<SvmInstructionAccount>,
pub data: Vec<u8>,
}
impl SvmInstructionCtx {
#[doc(hidden)]
pub fn from_invoke_context(
invoke_context: &InvokeContext<'_, '_>,
) -> Result<Self, InstructionError> {
let instruction_context =
invoke_context.transaction_context.get_current_instruction_context()?;
let program_id = *instruction_context.get_program_key()?;
let data = instruction_context.get_instruction_data().to_vec();
let count = instruction_context.get_number_of_instruction_accounts();
let mut accounts = Vec::with_capacity(usize::from(count));
for index in 0..count {
let borrowed = instruction_context.try_borrow_instruction_account(index)?;
accounts.push(SvmInstructionAccount {
key: *instruction_context.get_key_of_instruction_account(index)?,
is_signer: borrowed.is_signer(),
is_writable: borrowed.is_writable(),
lamports: borrowed.get_lamports(),
data: borrowed.get_data().to_vec(),
owner: *borrowed.get_owner(),
index_in_transaction: instruction_context
.get_index_of_instruction_account_in_transaction(index)?,
});
}
Ok(Self { program_id, accounts, data })
}
#[doc(hidden)]
pub fn write_back(
&self,
invoke_context: &mut InvokeContext<'_, '_>,
) -> Result<(), InstructionError> {
let instruction_context =
invoke_context.transaction_context.get_current_instruction_context()?;
let count = instruction_context.get_number_of_instruction_accounts();
for index in 0..count {
let account =
self.accounts.get(usize::from(index)).ok_or(InstructionError::MissingAccount)?;
let mut borrowed = instruction_context.try_borrow_instruction_account(index)?;
if borrowed.get_lamports() != account.lamports {
borrowed.set_lamports(account.lamports)?;
}
if borrowed.get_data() != account.data.as_slice() {
borrowed.set_data_from_slice(&account.data)?;
}
if *borrowed.get_owner() != account.owner {
borrowed.set_owner(account.owner.as_ref())?;
}
}
Ok(())
}
}