Skip to content

Commit

Permalink
Cleanup - mock_process_instruction() (#31088)
Browse files Browse the repository at this point in the history
* Uses declare_process_instruction!() in all tests.

* Adds post_adjustments to mock_process_instruction().
Removes "solana_sbf_rust_external_spend" from assert_instruction_count() as it panics.
  • Loading branch information
Lichtso authored Apr 7, 2023
1 parent bcd43d7 commit 0cd57ad
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 423 deletions.
209 changes: 108 additions & 101 deletions program-runtime/src/invoke_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,18 @@ use {
/// Adapter so we can unify the interfaces of built-in programs and syscalls
#[macro_export]
macro_rules! declare_process_instruction {
($cu_to_consume:expr) => {
pub fn process_instruction(
invoke_context: &mut InvokeContext,
) -> Result<(), Box<dyn std::error::Error>> {
($process_instruction:ident, $cu_to_consume:expr, |$invoke_context:ident| $inner:tt) => {
pub fn $process_instruction(
invoke_context: &mut $crate::invoke_context::InvokeContext,
) -> std::result::Result<(), Box<dyn std::error::Error>> {
fn process_instruction_inner(
$invoke_context: &mut $crate::invoke_context::InvokeContext,
) -> std::result::Result<(), solana_sdk::instruction::InstructionError> {
$inner
}
if invoke_context
.feature_set
.is_active(&feature_set::native_programs_consume_cu::id())
.is_active(&solana_sdk::feature_set::native_programs_consume_cu::id())
{
invoke_context.consume_checked($cu_to_consume)?;
}
Expand Down Expand Up @@ -919,7 +924,7 @@ macro_rules! with_mock_invoke_context {
};
}

pub fn mock_process_instruction<F: FnMut(&mut InvokeContext)>(
pub fn mock_process_instruction<F: FnMut(&mut InvokeContext), G: FnMut(&mut InvokeContext)>(
loader_id: &Pubkey,
mut program_indices: Vec<IndexOfAccount>,
instruction_data: &[u8],
Expand All @@ -928,6 +933,7 @@ pub fn mock_process_instruction<F: FnMut(&mut InvokeContext)>(
expected_result: Result<(), InstructionError>,
process_instruction: ProcessInstructionWithContext,
mut pre_adjustments: F,
mut post_adjustments: G,
) -> Vec<AccountSharedData> {
let mut instruction_accounts: Vec<InstructionAccount> =
Vec::with_capacity(instruction_account_metas.len());
Expand Down Expand Up @@ -971,6 +977,7 @@ pub fn mock_process_instruction<F: FnMut(&mut InvokeContext)>(
&mut ExecuteTimings::default(),
);
assert_eq!(result, expected_result);
post_adjustments(&mut invoke_context);
let mut transaction_accounts = transaction_context.deconstruct_without_keys().unwrap();
transaction_accounts.pop();
transaction_accounts
Expand Down Expand Up @@ -1030,105 +1037,105 @@ mod tests {

const MOCK_BUILTIN_COMPUTE_UNIT_COST: u64 = 1;

#[allow(clippy::integer_arithmetic)]
fn mock_process_instruction(
invoke_context: &mut InvokeContext,
) -> Result<(), Box<dyn std::error::Error>> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
let program_id = instruction_context.get_last_program_key(transaction_context)?;
// mock builtin must consume units
invoke_context.consume_checked(MOCK_BUILTIN_COMPUTE_UNIT_COST)?;
let instruction_accounts = (0..4)
.map(|instruction_account_index| InstructionAccount {
index_in_transaction: instruction_account_index,
index_in_caller: instruction_account_index,
index_in_callee: instruction_account_index,
is_signer: false,
is_writable: false,
})
.collect::<Vec<_>>();
assert_eq!(
program_id,
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.get_owner()
);
assert_ne!(
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.get_owner(),
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.get_key()
);

if let Ok(instruction) = bincode::deserialize(instruction_data) {
match instruction {
MockInstruction::NoopSuccess => (),
MockInstruction::NoopFail => return Err(Box::new(InstructionError::GenericError)),
MockInstruction::ModifyOwned => instruction_context
declare_process_instruction!(
process_instruction,
MOCK_BUILTIN_COMPUTE_UNIT_COST,
|invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
let program_id = instruction_context.get_last_program_key(transaction_context)?;
let instruction_accounts = (0..4)
.map(|instruction_account_index| InstructionAccount {
index_in_transaction: instruction_account_index,
index_in_caller: instruction_account_index,
index_in_callee: instruction_account_index,
is_signer: false,
is_writable: false,
})
.collect::<Vec<_>>();
assert_eq!(
program_id,
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.set_data_from_slice(&[1])?,
MockInstruction::ModifyNotOwned => instruction_context
.get_owner()
);
assert_ne!(
instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.set_data_from_slice(&[1])?,
MockInstruction::ModifyReadonly => instruction_context
.try_borrow_instruction_account(transaction_context, 2)?
.set_data_from_slice(&[1])?,
MockInstruction::UnbalancedPush => {
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_add_lamports(1)?;
let program_id = *transaction_context.get_key_of_account_at_index(3)?;
let metas = vec![
AccountMeta::new_readonly(
*transaction_context.get_key_of_account_at_index(0)?,
false,
),
AccountMeta::new_readonly(
*transaction_context.get_key_of_account_at_index(1)?,
false,
),
];
let inner_instruction = Instruction::new_with_bincode(
program_id,
&MockInstruction::NoopSuccess,
metas,
);
invoke_context
.transaction_context
.get_next_instruction_context()
.unwrap()
.configure(&[3], &instruction_accounts, &[]);
let result = invoke_context.push();
assert_eq!(result, Err(InstructionError::UnbalancedInstruction));
result?;
invoke_context
.native_invoke(inner_instruction.into(), &[])
.and(invoke_context.pop())?;
}
MockInstruction::UnbalancedPop => instruction_context
.get_owner(),
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_add_lamports(1)?,
MockInstruction::ConsumeComputeUnits {
compute_units_to_consume,
desired_result,
} => {
invoke_context.consume_checked(compute_units_to_consume)?;
return desired_result
.map_err(|err| Box::new(err) as Box<dyn std::error::Error>);
.get_key()
);

if let Ok(instruction) = bincode::deserialize(instruction_data) {
match instruction {
MockInstruction::NoopSuccess => (),
MockInstruction::NoopFail => return Err(InstructionError::GenericError),
MockInstruction::ModifyOwned => instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.set_data_from_slice(&[1])?,
MockInstruction::ModifyNotOwned => instruction_context
.try_borrow_instruction_account(transaction_context, 1)?
.set_data_from_slice(&[1])?,
MockInstruction::ModifyReadonly => instruction_context
.try_borrow_instruction_account(transaction_context, 2)?
.set_data_from_slice(&[1])?,
MockInstruction::UnbalancedPush => {
instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_add_lamports(1)?;
let program_id = *transaction_context.get_key_of_account_at_index(3)?;
let metas = vec![
AccountMeta::new_readonly(
*transaction_context.get_key_of_account_at_index(0)?,
false,
),
AccountMeta::new_readonly(
*transaction_context.get_key_of_account_at_index(1)?,
false,
),
];
let inner_instruction = Instruction::new_with_bincode(
program_id,
&MockInstruction::NoopSuccess,
metas,
);
invoke_context
.transaction_context
.get_next_instruction_context()
.unwrap()
.configure(&[3], &instruction_accounts, &[]);
let result = invoke_context.push();
assert_eq!(result, Err(InstructionError::UnbalancedInstruction));
result?;
invoke_context
.native_invoke(inner_instruction.into(), &[])
.and(invoke_context.pop())?;
}
MockInstruction::UnbalancedPop => instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.checked_add_lamports(1)?,
MockInstruction::ConsumeComputeUnits {
compute_units_to_consume,
desired_result,
} => {
invoke_context
.consume_checked(compute_units_to_consume)
.map_err(|_| InstructionError::ComputationalBudgetExceeded)?;
return desired_result;
}
MockInstruction::Resize { new_len } => instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.set_data(vec![0; new_len as usize])?,
}
MockInstruction::Resize { new_len } => instruction_context
.try_borrow_instruction_account(transaction_context, 0)?
.set_data(vec![0; new_len as usize])?,
} else {
return Err(InstructionError::InvalidInstructionData);
}
} else {
return Err(Box::new(InstructionError::InvalidInstructionData));
Ok(())
}
Ok(())
}
);

#[test]
fn test_instruction_stack_height() {
Expand Down Expand Up @@ -1236,7 +1243,7 @@ mod tests {
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
let builtin_programs = &[BuiltinProgram {
program_id: callee_program_id,
process_instruction: mock_process_instruction,
process_instruction,
}];
invoke_context.builtin_programs = builtin_programs;

Expand Down Expand Up @@ -1381,7 +1388,7 @@ mod tests {
with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
let builtin_programs = &[BuiltinProgram {
program_id: program_key,
process_instruction: mock_process_instruction,
process_instruction,
}];
invoke_context.builtin_programs = builtin_programs;

Expand Down
7 changes: 2 additions & 5 deletions programs/address-lookup-table/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ use {
std::convert::TryFrom,
};

declare_process_instruction!(750);
pub fn process_instruction_inner(
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
declare_process_instruction!(process_instruction, 750, |invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
Expand All @@ -39,7 +36,7 @@ pub fn process_instruction_inner(
}
ProgramInstruction::CloseLookupTable => Processor::close_lookup_table(invoke_context),
}
}
});

fn checked_add(a: usize, b: usize) -> Result<usize, InstructionError> {
a.checked_add(b).ok_or(InstructionError::ArithmeticOverflow)
Expand Down
3 changes: 3 additions & 0 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1696,6 +1696,7 @@ mod tests {
expected_result,
super::process_instruction,
|_invoke_context| {},
|_invoke_context| {},
)
}

Expand Down Expand Up @@ -1982,6 +1983,7 @@ mod tests {
|invoke_context| {
invoke_context.mock_set_remaining(0);
},
|_invoke_context| {},
);

// Case: Account not a program
Expand Down Expand Up @@ -2524,6 +2526,7 @@ mod tests {
expected_result,
super::process_instruction,
|_invoke_context| {},
|_invoke_context| {},
)
}

Expand Down
16 changes: 3 additions & 13 deletions programs/compute-budget/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
use {solana_program_runtime::invoke_context::InvokeContext, solana_sdk::feature_set};

pub fn process_instruction(
invoke_context: &mut InvokeContext,
) -> Result<(), Box<dyn std::error::Error>> {
// Consume compute units if feature `native_programs_consume_cu` is activated,
if invoke_context
.feature_set
.is_active(&feature_set::native_programs_consume_cu::id())
{
invoke_context.consume_checked(150)?;
}
use solana_program_runtime::declare_process_instruction;

declare_process_instruction!(process_instruction, 150, |_invoke_context| {
// Do nothing, compute budget instructions handled by the runtime
Ok(())
}
});
10 changes: 4 additions & 6 deletions programs/config/src/config_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,15 @@
use {
crate::ConfigKeys,
bincode::deserialize,
solana_program_runtime::{declare_process_instruction, ic_msg, invoke_context::InvokeContext},
solana_program_runtime::{declare_process_instruction, ic_msg},
solana_sdk::{
feature_set, instruction::InstructionError, program_utils::limited_deserialize,
pubkey::Pubkey, transaction_context::IndexOfAccount,
},
std::collections::BTreeSet,
};

declare_process_instruction!(450);
pub fn process_instruction_inner(
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
declare_process_instruction!(process_instruction, 450, |invoke_context| {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let data = instruction_context.get_instruction_data();
Expand Down Expand Up @@ -134,7 +131,7 @@ pub fn process_instruction_inner(
}
config_account.get_data_mut()?[..data.len()].copy_from_slice(data);
Ok(())
}
});

#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -168,6 +165,7 @@ mod tests {
expected_result,
super::process_instruction,
|_invoke_context| {},
|_invoke_context| {},
)
}

Expand Down
1 change: 1 addition & 0 deletions programs/loader-v3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ mod tests {
expected_result,
super::process_instruction,
|_invoke_context| {},
|_invoke_context| {},
)
}

Expand Down
Loading

0 comments on commit 0cd57ad

Please sign in to comment.