Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup - mock_process_instruction() #31088

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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