Refactor: process_instruction() (#20448)
* Adds first_instruction_account parameter to process_instruction(). * Removes InvokeContext::remove_first_keyed_account() from all BPF loaders. * Removes InvokeContext::remove_first_keyed_account() from all builtin programs. * Removes InvokeContext::remove_first_keyed_account() from all mock ups. * Deprecates InvokeContext::remove_first_keyed_account(). * Documents index base of keyed_account_at_index(). * Adds dynamic offset to call sites of "keyed_account_at_index()".
This commit is contained in:
committed by
GitHub
parent
a6a4cfda89
commit
4e65487d2f
@ -11,7 +11,8 @@ use solana_sdk::{
|
||||
compute_budget::ComputeBudget,
|
||||
feature_set::{
|
||||
demote_program_write_locks, do_support_realloc, neon_evm_compute_budget,
|
||||
prevent_calling_precompiles_as_programs, tx_wide_compute_cap, FeatureSet,
|
||||
prevent_calling_precompiles_as_programs, remove_native_loader, tx_wide_compute_cap,
|
||||
FeatureSet,
|
||||
},
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::Hash,
|
||||
@ -329,12 +330,14 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||
.ok_or(InstructionError::CallDepth)
|
||||
}
|
||||
fn remove_first_keyed_account(&mut self) -> Result<(), InstructionError> {
|
||||
let stack_frame = &mut self
|
||||
.invoke_stack
|
||||
.last_mut()
|
||||
.ok_or(InstructionError::CallDepth)?;
|
||||
stack_frame.keyed_accounts_range.start =
|
||||
stack_frame.keyed_accounts_range.start.saturating_add(1);
|
||||
if !self.is_feature_active(&remove_native_loader::id()) {
|
||||
let stack_frame = &mut self
|
||||
.invoke_stack
|
||||
.last_mut()
|
||||
.ok_or(InstructionError::CallDepth)?;
|
||||
stack_frame.keyed_accounts_range.start =
|
||||
stack_frame.keyed_accounts_range.start.saturating_add(1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn get_keyed_accounts(&self) -> Result<&[KeyedAccount], InstructionError> {
|
||||
@ -596,14 +599,18 @@ mod tests {
|
||||
|
||||
fn mock_process_instruction(
|
||||
program_id: &Pubkey,
|
||||
first_instruction_account: usize,
|
||||
data: &[u8],
|
||||
invoke_context: &mut dyn InvokeContext,
|
||||
) -> Result<(), InstructionError> {
|
||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||
assert_eq!(*program_id, keyed_accounts[0].owner()?);
|
||||
assert_eq!(
|
||||
*program_id,
|
||||
keyed_accounts[first_instruction_account].owner()?
|
||||
);
|
||||
assert_ne!(
|
||||
keyed_accounts[1].owner()?,
|
||||
*keyed_accounts[0].unsigned_key()
|
||||
keyed_accounts[first_instruction_account + 1].owner()?,
|
||||
*keyed_accounts[first_instruction_account].unsigned_key()
|
||||
);
|
||||
|
||||
if let Ok(instruction) = bincode::deserialize(data) {
|
||||
@ -611,13 +618,19 @@ mod tests {
|
||||
MockInstruction::NoopSuccess => (),
|
||||
MockInstruction::NoopFail => return Err(InstructionError::GenericError),
|
||||
MockInstruction::ModifyOwned => {
|
||||
keyed_accounts[0].try_account_ref_mut()?.data_as_mut_slice()[0] = 1
|
||||
keyed_accounts[first_instruction_account]
|
||||
.try_account_ref_mut()?
|
||||
.data_as_mut_slice()[0] = 1
|
||||
}
|
||||
MockInstruction::ModifyNotOwned => {
|
||||
keyed_accounts[1].try_account_ref_mut()?.data_as_mut_slice()[0] = 1
|
||||
keyed_accounts[first_instruction_account + 1]
|
||||
.try_account_ref_mut()?
|
||||
.data_as_mut_slice()[0] = 1
|
||||
}
|
||||
MockInstruction::ModifyReadonly => {
|
||||
keyed_accounts[2].try_account_ref_mut()?.data_as_mut_slice()[0] = 1
|
||||
keyed_accounts[first_instruction_account + 2]
|
||||
.try_account_ref_mut()?
|
||||
.data_as_mut_slice()[0] = 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -809,6 +822,7 @@ mod tests {
|
||||
|
||||
fn mock_system_process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
first_instruction_account: usize,
|
||||
data: &[u8],
|
||||
invoke_context: &mut dyn InvokeContext,
|
||||
) -> Result<(), InstructionError> {
|
||||
@ -817,11 +831,11 @@ mod tests {
|
||||
match instruction {
|
||||
MockSystemInstruction::Correct => Ok(()),
|
||||
MockSystemInstruction::AttemptCredit { lamports } => {
|
||||
keyed_accounts[0]
|
||||
keyed_accounts[first_instruction_account]
|
||||
.account
|
||||
.borrow_mut()
|
||||
.checked_sub_lamports(lamports)?;
|
||||
keyed_accounts[1]
|
||||
keyed_accounts[first_instruction_account + 1]
|
||||
.account
|
||||
.borrow_mut()
|
||||
.checked_add_lamports(lamports)?;
|
||||
@ -829,7 +843,10 @@ mod tests {
|
||||
}
|
||||
// Change data in a read-only account
|
||||
MockSystemInstruction::AttemptDataChange { data } => {
|
||||
keyed_accounts[1].account.borrow_mut().set_data(vec![data]);
|
||||
keyed_accounts[first_instruction_account + 1]
|
||||
.account
|
||||
.borrow_mut()
|
||||
.set_data(vec![data]);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -979,6 +996,7 @@ mod tests {
|
||||
|
||||
fn mock_system_process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
first_instruction_account: usize,
|
||||
data: &[u8],
|
||||
invoke_context: &mut dyn InvokeContext,
|
||||
) -> Result<(), InstructionError> {
|
||||
@ -986,8 +1004,10 @@ mod tests {
|
||||
if let Ok(instruction) = bincode::deserialize(data) {
|
||||
match instruction {
|
||||
MockSystemInstruction::BorrowFail => {
|
||||
let from_account = keyed_accounts[0].try_account_ref_mut()?;
|
||||
let dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
||||
let from_account =
|
||||
keyed_accounts[first_instruction_account].try_account_ref_mut()?;
|
||||
let dup_account =
|
||||
keyed_accounts[first_instruction_account + 2].try_account_ref_mut()?;
|
||||
if from_account.lamports() != dup_account.lamports() {
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
@ -995,11 +1015,13 @@ mod tests {
|
||||
}
|
||||
MockSystemInstruction::MultiBorrowMut => {
|
||||
let from_lamports = {
|
||||
let from_account = keyed_accounts[0].try_account_ref_mut()?;
|
||||
let from_account =
|
||||
keyed_accounts[first_instruction_account].try_account_ref_mut()?;
|
||||
from_account.lamports()
|
||||
};
|
||||
let dup_lamports = {
|
||||
let dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
||||
let dup_account = keyed_accounts[first_instruction_account + 2]
|
||||
.try_account_ref_mut()?;
|
||||
dup_account.lamports()
|
||||
};
|
||||
if from_lamports != dup_lamports {
|
||||
@ -1009,16 +1031,18 @@ mod tests {
|
||||
}
|
||||
MockSystemInstruction::DoWork { lamports, data } => {
|
||||
{
|
||||
let mut to_account = keyed_accounts[1].try_account_ref_mut()?;
|
||||
let mut dup_account = keyed_accounts[2].try_account_ref_mut()?;
|
||||
let mut to_account = keyed_accounts[first_instruction_account + 1]
|
||||
.try_account_ref_mut()?;
|
||||
let mut dup_account = keyed_accounts[first_instruction_account + 2]
|
||||
.try_account_ref_mut()?;
|
||||
dup_account.checked_sub_lamports(lamports)?;
|
||||
to_account.checked_add_lamports(lamports)?;
|
||||
dup_account.set_data(vec![data]);
|
||||
}
|
||||
keyed_accounts[0]
|
||||
keyed_accounts[first_instruction_account]
|
||||
.try_account_ref_mut()?
|
||||
.checked_sub_lamports(lamports)?;
|
||||
keyed_accounts[1]
|
||||
keyed_accounts[first_instruction_account + 1]
|
||||
.try_account_ref_mut()?
|
||||
.checked_add_lamports(lamports)?;
|
||||
Ok(())
|
||||
@ -1500,6 +1524,7 @@ mod tests {
|
||||
let mock_program_id = Pubkey::new_unique();
|
||||
fn mock_process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
_first_instruction_account: usize,
|
||||
_data: &[u8],
|
||||
_invoke_context: &mut dyn InvokeContext,
|
||||
) -> Result<(), InstructionError> {
|
||||
|
Reference in New Issue
Block a user