Refactor `push` and `pop` in `InvokeContext::process_instruction()`. (#26285)

* Refactor push and pop in InvokeContext::process_instruction().

* Moves set_return_data, compute_units_consumed and timings from process_instruction() into process_executable_chain().

* Clear unused import: native_loader.

* Moves verify_callee_time inside and_then lambda.

* Chains statements back to back,
so that there is no room for additional "?" operators throwing errors.

* Typo in comment
Co-authored-by: Trent Nelson <trent.a.b.nelson@gmail.com>
This commit is contained in:
Alexander Meißner 2022-06-29 12:07:50 +02:00 committed by GitHub
parent f44fcd1880
commit 3e44df598a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 41 additions and 50 deletions

View File

@ -843,14 +843,6 @@ impl<'a> InvokeContext<'a> {
timings: &mut ExecuteTimings,
) -> Result<(), InstructionError> {
*compute_units_consumed = 0;
let program_id = program_indices
.last()
.map(|index| {
self.transaction_context
.get_key_of_account_at_index(*index)
.map(|pubkey| *pubkey)
})
.unwrap_or_else(|| Ok(native_loader::id()))?;
let nesting_level = self
.transaction_context
@ -884,37 +876,17 @@ impl<'a> InvokeContext<'a> {
}
}
let result = self
.push(instruction_accounts, program_indices, instruction_data)
self.push(instruction_accounts, program_indices, instruction_data)?;
self.process_executable_chain(compute_units_consumed, timings)
.and_then(|_| {
let mut process_executable_chain_time =
Measure::start("process_executable_chain_time");
self.transaction_context
.set_return_data(program_id, Vec::new())?;
let pre_remaining_units = self.compute_meter.borrow().get_remaining();
let execution_result = self.process_executable_chain();
let post_remaining_units = self.compute_meter.borrow().get_remaining();
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
process_executable_chain_time.stop();
// Verify the called program has not misbehaved
let mut verify_callee_time = Measure::start("verify_callee_time");
let result = execution_result.and_then(|_| {
if is_top_level_instruction {
self.verify(instruction_accounts, program_indices)
} else {
self.verify_and_update(instruction_accounts, false)
}
});
let result = if is_top_level_instruction {
self.verify(instruction_accounts, program_indices)
} else {
self.verify_and_update(instruction_accounts, false)
};
verify_callee_time.stop();
saturating_add_assign!(
timings
.execute_accessories
.process_instructions
.process_executable_chain_us,
process_executable_chain_time.as_us()
);
saturating_add_assign!(
timings
.execute_accessories
@ -922,25 +894,28 @@ impl<'a> InvokeContext<'a> {
.verify_callee_us,
verify_callee_time.as_us()
);
result
});
// Pop the invoke_stack to restore previous state
let _ = self.pop();
result
})
// MUST pop if and only if `push` succeeded, independent of `result`.
// Thus, the `.and()` instead of an `.and_then()`.
.and(self.pop())
}
/// Calls the instruction's program entrypoint method
fn process_executable_chain(&mut self) -> Result<(), InstructionError> {
fn process_executable_chain(
&mut self,
compute_units_consumed: &mut u64,
timings: &mut ExecuteTimings,
) -> Result<(), InstructionError> {
let instruction_context = self.transaction_context.get_current_instruction_context()?;
let mut process_executable_chain_time = Measure::start("process_executable_chain_time");
let (first_instruction_account, builtin_id) = {
let borrowed_root_account = instruction_context
.try_borrow_program_account(self.transaction_context, 0)
.map_err(|_| InstructionError::UnsupportedProgramId)?;
let owner_id = borrowed_root_account.get_owner();
if solana_sdk::native_loader::check_id(owner_id) {
if native_loader::check_id(owner_id) {
(1, *borrowed_root_account.get_key())
} else {
(0, *owner_id)
@ -951,20 +926,36 @@ impl<'a> InvokeContext<'a> {
if entry.program_id == builtin_id {
let program_id =
*instruction_context.get_last_program_key(self.transaction_context)?;
if builtin_id == program_id {
self.transaction_context
.set_return_data(program_id, Vec::new())?;
let pre_remaining_units = self.compute_meter.borrow().get_remaining();
let result = if builtin_id == program_id {
let logger = self.get_log_collector();
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
return (entry.process_instruction)(first_instruction_account, self)
(entry.process_instruction)(first_instruction_account, self)
.map(|()| {
stable_log::program_success(&logger, &program_id);
})
.map_err(|err| {
stable_log::program_failure(&logger, &program_id, &err);
err
});
})
} else {
return (entry.process_instruction)(first_instruction_account, self);
}
(entry.process_instruction)(first_instruction_account, self)
};
let post_remaining_units = self.compute_meter.borrow().get_remaining();
*compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
process_executable_chain_time.stop();
saturating_add_assign!(
timings
.execute_accessories
.process_instructions
.process_executable_chain_us,
process_executable_chain_time.as_us()
);
return result;
}
}
@ -1145,7 +1136,7 @@ pub fn with_mock_invoke_context<R, F: FnMut(&mut InvokeContext) -> R>(
let transaction_accounts = vec![
(
loader_id,
AccountSharedData::new(0, 0, &solana_sdk::native_loader::id()),
AccountSharedData::new(0, 0, &native_loader::id()),
),
(
Pubkey::new_unique(),
@ -1189,7 +1180,7 @@ pub fn mock_process_instruction(
program_indices.insert(0, transaction_accounts.len());
let mut preparation =
prepare_mock_invoke_context(transaction_accounts, instruction_accounts, &program_indices);
let processor_account = AccountSharedData::new(0, 0, &solana_sdk::native_loader::id());
let processor_account = AccountSharedData::new(0, 0, &native_loader::id());
preparation
.transaction_accounts
.push((*loader_id, processor_account));