2021-12-27 09:49:32 -08:00
|
|
|
//! Successors of instruction_context_context::StackFrame, KeyedAccount and AccountInfo
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
account::{AccountSharedData, ReadableAccount, WritableAccount},
|
2022-01-19 13:40:09 -08:00
|
|
|
instruction::{CompiledInstruction, InstructionError},
|
2021-12-30 06:46:36 -08:00
|
|
|
lamports::LamportsError,
|
2021-12-27 09:49:32 -08:00
|
|
|
pubkey::Pubkey,
|
|
|
|
};
|
2022-01-03 14:30:56 -08:00
|
|
|
use std::{
|
|
|
|
cell::{RefCell, RefMut},
|
2022-01-05 00:39:37 -08:00
|
|
|
collections::HashSet,
|
2022-01-03 14:30:56 -08:00
|
|
|
pin::Pin,
|
|
|
|
};
|
2021-12-27 09:49:32 -08:00
|
|
|
|
|
|
|
pub type TransactionAccount = (Pubkey, AccountSharedData);
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct InstructionAccount {
|
2021-12-30 06:46:36 -08:00
|
|
|
pub index_in_transaction: usize,
|
|
|
|
pub index_in_caller: usize,
|
2021-12-27 09:49:32 -08:00
|
|
|
pub is_signer: bool,
|
|
|
|
pub is_writable: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Loaded transaction shared between runtime and programs.
|
|
|
|
///
|
|
|
|
/// This context is valid for the entire duration of a transaction being processed.
|
2021-12-30 06:46:36 -08:00
|
|
|
#[derive(Debug)]
|
2021-12-27 09:49:32 -08:00
|
|
|
pub struct TransactionContext {
|
2022-01-03 14:30:56 -08:00
|
|
|
account_keys: Pin<Box<[Pubkey]>>,
|
|
|
|
accounts: Pin<Box<[RefCell<AccountSharedData>]>>,
|
2021-12-27 09:49:32 -08:00
|
|
|
instruction_context_capacity: usize,
|
|
|
|
instruction_context_stack: Vec<InstructionContext>,
|
2022-01-19 13:40:09 -08:00
|
|
|
number_of_instructions_at_transaction_level: usize,
|
|
|
|
instruction_trace: Vec<Vec<CompiledInstruction>>,
|
2021-12-27 09:49:32 -08:00
|
|
|
return_data: (Pubkey, Vec<u8>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TransactionContext {
|
|
|
|
/// Constructs a new TransactionContext
|
|
|
|
pub fn new(
|
|
|
|
transaction_accounts: Vec<TransactionAccount>,
|
|
|
|
instruction_context_capacity: usize,
|
2022-01-19 13:40:09 -08:00
|
|
|
number_of_instructions_at_transaction_level: usize,
|
2021-12-27 09:49:32 -08:00
|
|
|
) -> Self {
|
2022-01-03 14:30:56 -08:00
|
|
|
let (account_keys, accounts): (Vec<Pubkey>, Vec<RefCell<AccountSharedData>>) =
|
|
|
|
transaction_accounts
|
|
|
|
.into_iter()
|
|
|
|
.map(|(key, account)| (key, RefCell::new(account)))
|
|
|
|
.unzip();
|
2021-12-27 09:49:32 -08:00
|
|
|
Self {
|
2022-01-03 14:30:56 -08:00
|
|
|
account_keys: Pin::new(account_keys.into_boxed_slice()),
|
|
|
|
accounts: Pin::new(accounts.into_boxed_slice()),
|
2021-12-27 09:49:32 -08:00
|
|
|
instruction_context_capacity,
|
|
|
|
instruction_context_stack: Vec::with_capacity(instruction_context_capacity),
|
2022-01-19 13:40:09 -08:00
|
|
|
number_of_instructions_at_transaction_level,
|
|
|
|
instruction_trace: Vec::with_capacity(number_of_instructions_at_transaction_level),
|
2021-12-27 09:49:32 -08:00
|
|
|
return_data: (Pubkey::default(), Vec::new()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-19 13:40:09 -08:00
|
|
|
/// Used by the bank in the runtime to write back the processed accounts and recorded instructions
|
|
|
|
pub fn deconstruct(self) -> (Vec<TransactionAccount>, Vec<Vec<CompiledInstruction>>) {
|
|
|
|
(
|
|
|
|
Vec::from(Pin::into_inner(self.account_keys))
|
|
|
|
.into_iter()
|
|
|
|
.zip(
|
|
|
|
Vec::from(Pin::into_inner(self.accounts))
|
|
|
|
.into_iter()
|
|
|
|
.map(|account| account.into_inner()),
|
|
|
|
)
|
|
|
|
.collect(),
|
|
|
|
self.instruction_trace,
|
|
|
|
)
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Used in mock_process_instruction
|
|
|
|
pub fn deconstruct_without_keys(self) -> Result<Vec<AccountSharedData>, InstructionError> {
|
|
|
|
if !self.instruction_context_stack.is_empty() {
|
|
|
|
return Err(InstructionError::CallDepth);
|
|
|
|
}
|
2022-01-03 14:30:56 -08:00
|
|
|
Ok(Vec::from(Pin::into_inner(self.accounts))
|
2021-12-27 09:49:32 -08:00
|
|
|
.into_iter()
|
|
|
|
.map(|account| account.into_inner())
|
|
|
|
.collect())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the total number of accounts loaded in this Transaction
|
|
|
|
pub fn get_number_of_accounts(&self) -> usize {
|
|
|
|
self.accounts.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Searches for an account by its key
|
|
|
|
pub fn get_key_of_account_at_index(&self, index_in_transaction: usize) -> &Pubkey {
|
|
|
|
&self.account_keys[index_in_transaction]
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Searches for an account by its key
|
|
|
|
pub fn get_account_at_index(&self, index_in_transaction: usize) -> &RefCell<AccountSharedData> {
|
|
|
|
&self.accounts[index_in_transaction]
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Searches for an account by its key
|
|
|
|
pub fn find_index_of_account(&self, pubkey: &Pubkey) -> Option<usize> {
|
|
|
|
self.account_keys.iter().position(|key| key == pubkey)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Searches for a program account by its key
|
|
|
|
pub fn find_index_of_program_account(&self, pubkey: &Pubkey) -> Option<usize> {
|
|
|
|
self.account_keys.iter().rposition(|key| key == pubkey)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets an InstructionContext by its height in the stack
|
|
|
|
pub fn get_instruction_context_at(
|
|
|
|
&self,
|
2021-12-30 06:46:36 -08:00
|
|
|
level: usize,
|
2021-12-27 09:49:32 -08:00
|
|
|
) -> Result<&InstructionContext, InstructionError> {
|
2021-12-30 06:46:36 -08:00
|
|
|
if level >= self.instruction_context_stack.len() {
|
2021-12-27 09:49:32 -08:00
|
|
|
return Err(InstructionError::CallDepth);
|
|
|
|
}
|
2021-12-30 06:46:36 -08:00
|
|
|
Ok(&self.instruction_context_stack[level])
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets the max height of the InstructionContext stack
|
|
|
|
pub fn get_instruction_context_capacity(&self) -> usize {
|
|
|
|
self.instruction_context_capacity
|
|
|
|
}
|
|
|
|
|
2021-12-30 06:46:36 -08:00
|
|
|
/// Gets the level of the next InstructionContext
|
|
|
|
pub fn get_instruction_context_stack_height(&self) -> usize {
|
|
|
|
self.instruction_context_stack.len()
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the current InstructionContext
|
|
|
|
pub fn get_current_instruction_context(&self) -> Result<&InstructionContext, InstructionError> {
|
2021-12-30 06:46:36 -08:00
|
|
|
let level = self
|
|
|
|
.instruction_context_stack
|
|
|
|
.len()
|
|
|
|
.checked_sub(1)
|
|
|
|
.ok_or(InstructionError::CallDepth)?;
|
|
|
|
self.get_instruction_context_at(level)
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Pushes a new InstructionContext
|
|
|
|
pub fn push(
|
|
|
|
&mut self,
|
2021-12-30 06:46:36 -08:00
|
|
|
program_accounts: &[usize],
|
2021-12-27 09:49:32 -08:00
|
|
|
instruction_accounts: &[InstructionAccount],
|
2021-12-30 06:46:36 -08:00
|
|
|
instruction_data: &[u8],
|
2021-12-27 09:49:32 -08:00
|
|
|
) -> Result<(), InstructionError> {
|
|
|
|
if self.instruction_context_stack.len() >= self.instruction_context_capacity {
|
|
|
|
return Err(InstructionError::CallDepth);
|
|
|
|
}
|
2022-01-19 13:40:09 -08:00
|
|
|
if self.instruction_context_stack.is_empty() {
|
|
|
|
debug_assert!(
|
|
|
|
self.instruction_trace.len() < self.number_of_instructions_at_transaction_level
|
|
|
|
);
|
|
|
|
self.instruction_trace.push(Vec::new());
|
|
|
|
}
|
2021-12-30 06:46:36 -08:00
|
|
|
self.instruction_context_stack.push(InstructionContext {
|
|
|
|
program_accounts: program_accounts.to_vec(),
|
|
|
|
instruction_accounts: instruction_accounts.to_vec(),
|
|
|
|
instruction_data: instruction_data.to_vec(),
|
|
|
|
});
|
2021-12-27 09:49:32 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Pops the current InstructionContext
|
|
|
|
pub fn pop(&mut self) -> Result<(), InstructionError> {
|
|
|
|
if self.instruction_context_stack.is_empty() {
|
|
|
|
return Err(InstructionError::CallDepth);
|
|
|
|
}
|
|
|
|
self.instruction_context_stack.pop();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-12-30 06:46:36 -08:00
|
|
|
/// Returns the key of the current InstructionContexts program account
|
|
|
|
pub fn get_program_key(&self) -> Result<&Pubkey, InstructionError> {
|
|
|
|
let instruction_context = self.get_current_instruction_context()?;
|
|
|
|
let program_account = instruction_context.try_borrow_program_account(self)?;
|
|
|
|
Ok(&self.account_keys[program_account.index_in_transaction])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the owner of the current InstructionContexts program account
|
|
|
|
pub fn get_loader_key(&self) -> Result<Pubkey, InstructionError> {
|
|
|
|
let instruction_context = self.get_current_instruction_context()?;
|
|
|
|
let program_account = instruction_context.try_borrow_program_account(self)?;
|
|
|
|
Ok(*program_account.get_owner())
|
|
|
|
}
|
|
|
|
|
2021-12-27 09:49:32 -08:00
|
|
|
/// Gets the return data of the current InstructionContext or any above
|
|
|
|
pub fn get_return_data(&self) -> (&Pubkey, &[u8]) {
|
|
|
|
(&self.return_data.0, &self.return_data.1)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the return data of the current InstructionContext
|
2022-01-10 09:26:51 -08:00
|
|
|
pub fn set_return_data(
|
|
|
|
&mut self,
|
|
|
|
program_id: Pubkey,
|
|
|
|
data: Vec<u8>,
|
|
|
|
) -> Result<(), InstructionError> {
|
|
|
|
self.return_data = (program_id, data);
|
2021-12-27 09:49:32 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
2022-01-19 13:40:09 -08:00
|
|
|
|
|
|
|
/// Used by the runtime when a new CPI instruction begins
|
|
|
|
pub fn record_compiled_instruction(&mut self, instruction: CompiledInstruction) {
|
|
|
|
if let Some(records) = self.instruction_trace.last_mut() {
|
|
|
|
records.push(instruction);
|
|
|
|
}
|
|
|
|
}
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Loaded instruction shared between runtime and programs.
|
|
|
|
///
|
|
|
|
/// This context is valid for the entire duration of a (possibly cross program) instruction being processed.
|
2021-12-30 06:46:36 -08:00
|
|
|
#[derive(Debug)]
|
2021-12-27 09:49:32 -08:00
|
|
|
pub struct InstructionContext {
|
2021-12-30 06:46:36 -08:00
|
|
|
program_accounts: Vec<usize>,
|
|
|
|
instruction_accounts: Vec<InstructionAccount>,
|
2021-12-27 09:49:32 -08:00
|
|
|
instruction_data: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InstructionContext {
|
|
|
|
/// Number of program accounts
|
|
|
|
pub fn get_number_of_program_accounts(&self) -> usize {
|
2021-12-30 06:46:36 -08:00
|
|
|
self.program_accounts.len()
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Number of accounts in this Instruction (without program accounts)
|
|
|
|
pub fn get_number_of_instruction_accounts(&self) -> usize {
|
2021-12-30 06:46:36 -08:00
|
|
|
self.instruction_accounts.len()
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
2021-12-30 06:46:36 -08:00
|
|
|
/// Number of accounts in this Instruction
|
|
|
|
pub fn get_number_of_accounts(&self) -> usize {
|
|
|
|
self.program_accounts
|
|
|
|
.len()
|
|
|
|
.saturating_add(self.instruction_accounts.len())
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Data parameter for the programs `process_instruction` handler
|
|
|
|
pub fn get_instruction_data(&self) -> &[u8] {
|
|
|
|
&self.instruction_data
|
|
|
|
}
|
|
|
|
|
2021-12-30 06:46:36 -08:00
|
|
|
/// Searches for a program account by its key
|
|
|
|
pub fn find_index_of_program_account(
|
|
|
|
&self,
|
|
|
|
transaction_context: &TransactionContext,
|
|
|
|
pubkey: &Pubkey,
|
|
|
|
) -> Option<usize> {
|
|
|
|
self.program_accounts
|
|
|
|
.iter()
|
|
|
|
.position(|index_in_transaction| {
|
|
|
|
&transaction_context.account_keys[*index_in_transaction] == pubkey
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Searches for an account by its key
|
|
|
|
pub fn find_index_of_account(
|
|
|
|
&self,
|
|
|
|
transaction_context: &TransactionContext,
|
|
|
|
pubkey: &Pubkey,
|
|
|
|
) -> Option<usize> {
|
|
|
|
self.instruction_accounts
|
|
|
|
.iter()
|
|
|
|
.position(|instruction_account| {
|
|
|
|
&transaction_context.account_keys[instruction_account.index_in_transaction]
|
|
|
|
== pubkey
|
|
|
|
})
|
|
|
|
.map(|index| index.saturating_add(self.program_accounts.len()))
|
|
|
|
}
|
|
|
|
|
2022-01-03 14:30:56 -08:00
|
|
|
/// Translates the given instruction wide index into a transaction wide index
|
|
|
|
pub fn get_index_in_transaction(
|
|
|
|
&self,
|
|
|
|
index_in_instruction: usize,
|
|
|
|
) -> Result<usize, InstructionError> {
|
|
|
|
if index_in_instruction < self.program_accounts.len() {
|
|
|
|
Ok(self.program_accounts[index_in_instruction])
|
|
|
|
} else if index_in_instruction < self.get_number_of_accounts() {
|
|
|
|
Ok(self.instruction_accounts
|
|
|
|
[index_in_instruction.saturating_sub(self.program_accounts.len())]
|
|
|
|
.index_in_transaction)
|
|
|
|
} else {
|
|
|
|
Err(InstructionError::NotEnoughAccountKeys)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-27 09:49:32 -08:00
|
|
|
/// Tries to borrow an account from this Instruction
|
|
|
|
pub fn try_borrow_account<'a, 'b: 'a>(
|
|
|
|
&'a self,
|
|
|
|
transaction_context: &'b TransactionContext,
|
|
|
|
index_in_instruction: usize,
|
|
|
|
) -> Result<BorrowedAccount<'a>, InstructionError> {
|
2022-01-03 14:30:56 -08:00
|
|
|
let index_in_transaction = self.get_index_in_transaction(index_in_instruction)?;
|
2021-12-27 09:49:32 -08:00
|
|
|
if index_in_transaction >= transaction_context.accounts.len() {
|
|
|
|
return Err(InstructionError::MissingAccount);
|
|
|
|
}
|
|
|
|
let account = transaction_context.accounts[index_in_transaction]
|
|
|
|
.try_borrow_mut()
|
|
|
|
.map_err(|_| InstructionError::AccountBorrowFailed)?;
|
|
|
|
Ok(BorrowedAccount {
|
|
|
|
transaction_context,
|
|
|
|
instruction_context: self,
|
|
|
|
index_in_transaction,
|
|
|
|
index_in_instruction,
|
|
|
|
account,
|
|
|
|
})
|
|
|
|
}
|
2021-12-30 06:46:36 -08:00
|
|
|
|
2022-01-05 00:39:37 -08:00
|
|
|
/// Gets the last program account of this Instruction
|
2021-12-30 06:46:36 -08:00
|
|
|
pub fn try_borrow_program_account<'a, 'b: 'a>(
|
|
|
|
&'a self,
|
|
|
|
transaction_context: &'b TransactionContext,
|
|
|
|
) -> Result<BorrowedAccount<'a>, InstructionError> {
|
|
|
|
self.try_borrow_account(
|
|
|
|
transaction_context,
|
|
|
|
self.program_accounts.len().saturating_sub(1),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-01-05 00:39:37 -08:00
|
|
|
/// Gets an instruction account of this Instruction
|
2021-12-30 06:46:36 -08:00
|
|
|
pub fn try_borrow_instruction_account<'a, 'b: 'a>(
|
|
|
|
&'a self,
|
|
|
|
transaction_context: &'b TransactionContext,
|
|
|
|
index_in_instruction: usize,
|
|
|
|
) -> Result<BorrowedAccount<'a>, InstructionError> {
|
|
|
|
self.try_borrow_account(
|
|
|
|
transaction_context,
|
|
|
|
self.program_accounts
|
|
|
|
.len()
|
|
|
|
.saturating_add(index_in_instruction),
|
|
|
|
)
|
|
|
|
}
|
2022-01-05 00:39:37 -08:00
|
|
|
|
|
|
|
/// Calculates the set of all keys of signer accounts in this Instruction
|
|
|
|
pub fn get_signers(&self, transaction_context: &TransactionContext) -> HashSet<Pubkey> {
|
|
|
|
let mut result = HashSet::new();
|
|
|
|
for instruction_account in self.instruction_accounts.iter() {
|
|
|
|
if instruction_account.is_signer {
|
|
|
|
result.insert(
|
|
|
|
transaction_context.account_keys[instruction_account.index_in_transaction],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Shared account borrowed from the TransactionContext and an InstructionContext.
|
2021-12-30 06:46:36 -08:00
|
|
|
#[derive(Debug)]
|
2021-12-27 09:49:32 -08:00
|
|
|
pub struct BorrowedAccount<'a> {
|
|
|
|
transaction_context: &'a TransactionContext,
|
|
|
|
instruction_context: &'a InstructionContext,
|
|
|
|
index_in_transaction: usize,
|
|
|
|
index_in_instruction: usize,
|
|
|
|
account: RefMut<'a, AccountSharedData>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> BorrowedAccount<'a> {
|
2021-12-30 06:46:36 -08:00
|
|
|
/// Returns the index of this account (transaction wide)
|
|
|
|
pub fn get_index_in_transaction(&self) -> usize {
|
|
|
|
self.index_in_transaction
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the index of this account (instruction wide)
|
|
|
|
pub fn get_index_in_instruction(&self) -> usize {
|
|
|
|
self.index_in_instruction
|
|
|
|
}
|
|
|
|
|
2021-12-27 09:49:32 -08:00
|
|
|
/// Returns the public key of this account (transaction wide)
|
|
|
|
pub fn get_key(&self) -> &Pubkey {
|
|
|
|
&self.transaction_context.account_keys[self.index_in_transaction]
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the owner of this account (transaction wide)
|
|
|
|
pub fn get_owner(&self) -> &Pubkey {
|
|
|
|
self.account.owner()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Assignes the owner of this account (transaction wide)
|
2022-01-03 14:30:56 -08:00
|
|
|
pub fn set_owner(&mut self, pubkey: &[u8]) -> Result<(), InstructionError> {
|
|
|
|
self.account.copy_into_owner_from_slice(pubkey);
|
2022-01-05 00:39:37 -08:00
|
|
|
self.verify_writability()
|
|
|
|
// TODO: return Err(InstructionError::ModifiedProgramId);
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the number of lamports of this account (transaction wide)
|
|
|
|
pub fn get_lamports(&self) -> u64 {
|
|
|
|
self.account.lamports()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Overwrites the number of lamports of this account (transaction wide)
|
|
|
|
pub fn set_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
|
|
|
|
self.account.set_lamports(lamports);
|
2022-01-05 00:39:37 -08:00
|
|
|
if self.index_in_instruction < self.instruction_context.program_accounts.len() {
|
|
|
|
return Err(InstructionError::ExecutableLamportChange);
|
|
|
|
}
|
|
|
|
if !self.is_writable() {
|
|
|
|
return Err(InstructionError::ReadonlyLamportChange);
|
2022-01-03 14:30:56 -08:00
|
|
|
}
|
2022-01-05 00:39:37 -08:00
|
|
|
// TODO: return Err(InstructionError::ExternalAccountLamportSpend);
|
|
|
|
Ok(())
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
2021-12-30 06:46:36 -08:00
|
|
|
/// Adds lamports to this account (transaction wide)
|
|
|
|
pub fn checked_add_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
|
|
|
|
self.set_lamports(
|
|
|
|
self.get_lamports()
|
|
|
|
.checked_add(lamports)
|
|
|
|
.ok_or(LamportsError::ArithmeticOverflow)?,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Subtracts lamports from this account (transaction wide)
|
|
|
|
pub fn checked_sub_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
|
|
|
|
self.set_lamports(
|
|
|
|
self.get_lamports()
|
|
|
|
.checked_sub(lamports)
|
|
|
|
.ok_or(LamportsError::ArithmeticUnderflow)?,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-01-05 00:39:37 -08:00
|
|
|
/// Verifies that this account is writable (instruction wide)
|
|
|
|
fn verify_writability(&self) -> Result<(), InstructionError> {
|
|
|
|
if self.index_in_instruction < self.instruction_context.program_accounts.len() {
|
|
|
|
return Err(InstructionError::ExecutableDataModified);
|
|
|
|
}
|
|
|
|
if !self.is_writable() {
|
|
|
|
return Err(InstructionError::ReadonlyDataModified);
|
|
|
|
}
|
|
|
|
// TODO: return Err(InstructionError::ExternalAccountDataModified);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-12-27 09:49:32 -08:00
|
|
|
/// Returns a read-only slice of the account data (transaction wide)
|
|
|
|
pub fn get_data(&self) -> &[u8] {
|
|
|
|
self.account.data()
|
|
|
|
}
|
|
|
|
|
2022-01-03 14:30:56 -08:00
|
|
|
/// Overwrites the account data and size (transaction wide)
|
|
|
|
pub fn set_data(&mut self, data: &[u8]) -> Result<(), InstructionError> {
|
|
|
|
if data.len() == self.account.data().len() {
|
|
|
|
self.account.data_as_mut_slice().copy_from_slice(data);
|
|
|
|
} else {
|
|
|
|
self.account.set_data_from_slice(data);
|
2022-01-05 00:39:37 -08:00
|
|
|
// TODO: return Err(InstructionError::AccountDataSizeChanged);
|
2021-12-30 06:46:36 -08:00
|
|
|
}
|
2022-01-05 00:39:37 -08:00
|
|
|
self.verify_writability()
|
2021-12-30 06:46:36 -08:00
|
|
|
}
|
|
|
|
|
2022-01-03 14:30:56 -08:00
|
|
|
/*pub fn realloc(&self, new_len: usize, zero_init: bool) {
|
2022-01-05 00:39:37 -08:00
|
|
|
// TODO: return Err(InstructionError::InvalidRealloc);
|
|
|
|
// TODO: return Err(InstructionError::AccountDataSizeChanged);
|
2022-01-03 14:30:56 -08:00
|
|
|
}*/
|
|
|
|
|
2021-12-30 06:46:36 -08:00
|
|
|
/// Deserializes the account data into a state
|
|
|
|
pub fn get_state<T: serde::de::DeserializeOwned>(&self) -> Result<T, InstructionError> {
|
|
|
|
self.account
|
|
|
|
.deserialize_data()
|
|
|
|
.map_err(|_| InstructionError::InvalidAccountData)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Serializes a state into the account data
|
|
|
|
pub fn set_state<T: serde::Serialize>(&mut self, state: &T) -> Result<(), InstructionError> {
|
|
|
|
let data = self.account.data_as_mut_slice();
|
|
|
|
let serialized_size =
|
|
|
|
bincode::serialized_size(state).map_err(|_| InstructionError::GenericError)?;
|
|
|
|
if serialized_size > data.len() as u64 {
|
|
|
|
return Err(InstructionError::AccountDataTooSmall);
|
|
|
|
}
|
2022-01-03 14:30:56 -08:00
|
|
|
bincode::serialize_into(&mut *data, state).map_err(|_| InstructionError::GenericError)?;
|
2022-01-05 00:39:37 -08:00
|
|
|
self.verify_writability()
|
2021-12-30 06:46:36 -08:00
|
|
|
}
|
|
|
|
|
2021-12-27 09:49:32 -08:00
|
|
|
/// Returns whether this account is executable (transaction wide)
|
|
|
|
pub fn is_executable(&self) -> bool {
|
|
|
|
self.account.executable()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Configures whether this account is executable (transaction wide)
|
|
|
|
pub fn set_executable(&mut self, is_executable: bool) -> Result<(), InstructionError> {
|
|
|
|
self.account.set_executable(is_executable);
|
2022-01-05 00:39:37 -08:00
|
|
|
self.verify_writability()
|
|
|
|
// TODO: return Err(InstructionError::ExecutableAccountNotRentExempt);
|
|
|
|
// TODO: return Err(InstructionError::ExecutableModified);
|
2022-01-03 14:30:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the rent epoch of this account (transaction wide)
|
|
|
|
pub fn get_rent_epoch(&self) -> u64 {
|
|
|
|
self.account.rent_epoch()
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns whether this account is a signer (instruction wide)
|
|
|
|
pub fn is_signer(&self) -> bool {
|
2021-12-30 06:46:36 -08:00
|
|
|
if self.index_in_instruction < self.instruction_context.program_accounts.len() {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
self.instruction_context.instruction_accounts[self
|
|
|
|
.index_in_instruction
|
|
|
|
.saturating_sub(self.instruction_context.program_accounts.len())]
|
|
|
|
.is_signer
|
|
|
|
}
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns whether this account is writable (instruction wide)
|
|
|
|
pub fn is_writable(&self) -> bool {
|
2021-12-30 06:46:36 -08:00
|
|
|
if self.index_in_instruction < self.instruction_context.program_accounts.len() {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
self.instruction_context.instruction_accounts[self
|
|
|
|
.index_in_instruction
|
|
|
|
.saturating_sub(self.instruction_context.program_accounts.len())]
|
|
|
|
.is_writable
|
|
|
|
}
|
2021-12-27 09:49:32 -08:00
|
|
|
}
|
|
|
|
}
|