Refactor - mock_process_instruction() (#30893)

* Uses InvokeContext::process_instruction() in mock_process_instruction().

* Uses InvokeContext::process_instruction() in tests of loader-v3.

* Only throw InstructionError::BuiltinProgramsMustConsumeComputeUnits if result.is_ok().

* Adds CU cost to loader-v3.
This commit is contained in:
Alexander Meißner 2023-03-24 22:45:03 +01:00 committed by GitHub
parent bf7fa02214
commit fb7d303995
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 53 deletions

View File

@ -774,6 +774,7 @@ impl<'a> InvokeContext<'a> {
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
if is_builtin_program
&& result.is_ok()
&& *compute_units_consumed == 0
&& self
.feature_set
@ -1024,20 +1025,19 @@ pub fn mock_process_instruction(
if let Some(feature_set) = feature_set_override {
invoke_context.feature_set = feature_set;
}
invoke_context
.transaction_context
.get_next_instruction_context()
.unwrap()
.configure(
&program_indices,
&preparation.instruction_accounts,
instruction_data,
);
let result = invoke_context
.push()
.and_then(|_| process_instruction(&mut invoke_context));
let pop_result = invoke_context.pop();
assert_eq!(result.and(pop_result), expected_result);
let builtin_programs = &[BuiltinProgram {
program_id: *loader_id,
process_instruction,
}];
invoke_context.builtin_programs = builtin_programs;
let result = invoke_context.process_instruction(
instruction_data,
&preparation.instruction_accounts,
&program_indices,
&mut 0,
&mut ExecuteTimings::default(),
);
assert_eq!(result, expected_result);
let mut transaction_accounts = transaction_context.deconstruct_without_keys().unwrap();
transaction_accounts.pop();
transaction_accounts

View File

@ -21,7 +21,7 @@ use {
},
solana_sdk::{
entrypoint::{HEAP_LENGTH, SUCCESS},
feature_set::FeatureSet,
feature_set::{self, FeatureSet},
instruction::InstructionError,
loader_v3::{self, LoaderV3State, DEPLOYMENT_COOLDOWN_IN_SLOTS},
loader_v3_instruction::LoaderV3Instruction,
@ -534,6 +534,12 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
let instruction_data = instruction_context.get_instruction_data();
let program_id = instruction_context.get_last_program_key(transaction_context)?;
if loader_v3::check_id(program_id) {
if invoke_context
.feature_set
.is_active(&feature_set::native_programs_consume_cu::id())
{
invoke_context.consume_checked(2000)?;
}
match limited_deserialize(instruction_data)? {
LoaderV3Instruction::Write { offset, bytes } => {
process_instruction_write(invoke_context, offset, bytes)
@ -590,67 +596,49 @@ pub fn process_instruction(invoke_context: &mut InvokeContext) -> Result<(), Ins
mod tests {
use {
super::*,
solana_program_runtime::invoke_context::mock_process_instruction,
solana_sdk::{
account::{
create_account_shared_data_for_test, AccountSharedData, ReadableAccount,
WritableAccount,
},
account_utils::StateMut,
native_loader,
instruction::AccountMeta,
slot_history::Slot,
sysvar::{clock, rent},
transaction_context::{IndexOfAccount, InstructionAccount, TransactionContext},
transaction_context::IndexOfAccount,
},
std::{fs::File, io::Read, path::Path},
};
fn process_instruction(
mut program_indices: Vec<IndexOfAccount>,
program_indices: Vec<IndexOfAccount>,
instruction_data: &[u8],
mut transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
instruction_accounts: &[(IndexOfAccount, bool, bool)],
expected_result: Result<(), InstructionError>,
) -> Vec<AccountSharedData> {
program_indices.insert(0, transaction_accounts.len() as IndexOfAccount);
let processor_account = AccountSharedData::new(0, 0, &native_loader::id());
transaction_accounts.push((loader_v3::id(), processor_account));
let compute_budget = ComputeBudget::default();
let mut transaction_context = TransactionContext::new(
transaction_accounts,
Some(rent::Rent::default()),
compute_budget.max_invoke_stack_height,
compute_budget.max_instruction_trace_length,
);
transaction_context.enable_cap_accounts_data_allocations_per_transaction();
let instruction_accounts = instruction_accounts
.iter()
.enumerate()
.map(
|(instruction_account_index, (index_in_transaction, is_signer, is_writable))| {
InstructionAccount {
index_in_transaction: *index_in_transaction,
index_in_caller: *index_in_transaction,
index_in_callee: instruction_account_index as IndexOfAccount,
is_signer: *is_signer,
is_writable: *is_writable,
}
|(index_in_transaction, is_signer, is_writable)| AccountMeta {
pubkey: transaction_accounts[*index_in_transaction as usize].0,
is_signer: *is_signer,
is_writable: *is_writable,
},
)
.collect::<Vec<_>>();
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context
.transaction_context
.get_next_instruction_context()
.unwrap()
.configure(&program_indices, &instruction_accounts, instruction_data);
let result = invoke_context
.push()
.and_then(|_| super::process_instruction(&mut invoke_context));
let pop_result = invoke_context.pop();
assert_eq!(result.and(pop_result), expected_result);
let mut transaction_accounts = transaction_context.deconstruct_without_keys().unwrap();
transaction_accounts.pop();
transaction_accounts
mock_process_instruction(
&loader_v3::id(),
program_indices,
instruction_data,
transaction_accounts,
instruction_accounts,
None,
None,
expected_result,
super::process_instruction,
)
}
fn load_program_account_from_elf(