- Implicitly fixes invoke_context.return_data not being reset between instructions in process_message. (#21671) (#21684)

- Lets InvokeContext::process_cross_program_instruction() handle the first invocation depth too.
- Marks InvokeContext::verify(), InvokeContext::verify_and_update() and InvokeContext::process_executable_chain() private.
- Renames InvokeContext::process_cross_program_instruction() to InvokeContext::process_instruction().
- Removes InvokeContext::new_mock_with_sysvars().

(cherry picked from commit 1df88837c8)

Co-authored-by: Alexander Meißner <AlexanderMeissner@gmx.net>
This commit is contained in:
mergify[bot]
2021-12-08 10:48:49 +00:00
committed by GitHub
parent cabd851904
commit ef970bb14a
7 changed files with 91 additions and 97 deletions

View File

@ -192,20 +192,12 @@ impl<'a> InvokeContext<'a> {
pub fn new_mock( pub fn new_mock(
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)], accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
builtin_programs: &'a [BuiltinProgram], builtin_programs: &'a [BuiltinProgram],
) -> Self {
Self::new_mock_with_sysvars(accounts, builtin_programs, &[])
}
pub fn new_mock_with_sysvars(
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
builtin_programs: &'a [BuiltinProgram],
sysvars: &'a [(Pubkey, Vec<u8>)],
) -> Self { ) -> Self {
Self::new( Self::new(
Rent::default(), Rent::default(),
accounts, accounts,
builtin_programs, builtin_programs,
sysvars, &[],
Some(LogCollector::new_ref()), Some(LogCollector::new_ref()),
ComputeBudget::default(), ComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())), Rc::new(RefCell::new(Executors::default())),
@ -221,7 +213,7 @@ impl<'a> InvokeContext<'a> {
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
program_indices: &[usize], program_indices: &[usize],
account_indices: Option<&[usize]>, account_indices: &[usize],
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if self.invoke_stack.len() > self.compute_budget.max_invoke_depth { if self.invoke_stack.len() > self.compute_budget.max_invoke_depth {
return Err(InstructionError::CallDepth); return Err(InstructionError::CallDepth);
@ -302,10 +294,10 @@ impl<'a> InvokeContext<'a> {
}) })
.chain(instruction.accounts.iter().map(|index_in_instruction| { .chain(instruction.accounts.iter().map(|index_in_instruction| {
let index_in_instruction = *index_in_instruction as usize; let index_in_instruction = *index_in_instruction as usize;
let account_index = if let Some(account_indices) = account_indices { let account_index = if account_indices.is_empty() {
account_indices[index_in_instruction]
} else {
index_in_instruction index_in_instruction
} else {
account_indices[index_in_instruction]
}; };
( (
message.is_signer(index_in_instruction), message.is_signer(index_in_instruction),
@ -334,7 +326,7 @@ impl<'a> InvokeContext<'a> {
} }
/// Verify the results of an instruction /// Verify the results of an instruction
pub fn verify( fn verify(
&mut self, &mut self,
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
@ -403,7 +395,7 @@ impl<'a> InvokeContext<'a> {
} }
/// Verify and update PreAccount state based on program execution /// Verify and update PreAccount state based on program execution
pub fn verify_and_update( fn verify_and_update(
&mut self, &mut self,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
account_indices: &[usize], account_indices: &[usize],
@ -505,8 +497,9 @@ impl<'a> InvokeContext<'a> {
if let Some(instruction_recorder) = &self.instruction_recorder { if let Some(instruction_recorder) = &self.instruction_recorder {
instruction_recorder.record_instruction(instruction); instruction_recorder.record_instruction(instruction);
} }
self.process_cross_program_instruction( self.process_instruction(
&message, &message,
&message.instructions[0],
&program_indices, &program_indices,
&account_indices, &account_indices,
&caller_write_privileges, &caller_write_privileges,
@ -530,7 +523,7 @@ impl<'a> InvokeContext<'a> {
Ok(()) Ok(())
} }
/// Helper to prepare for process_cross_program_instruction() /// Helper to prepare for process_instruction()
pub fn create_message( pub fn create_message(
&mut self, &mut self,
instruction: &Instruction, instruction: &Instruction,
@ -644,26 +637,30 @@ impl<'a> InvokeContext<'a> {
} }
/// Process a cross-program instruction /// Process a cross-program instruction
pub fn process_cross_program_instruction( pub fn process_instruction(
&mut self, &mut self,
message: &Message, message: &Message,
instruction: &CompiledInstruction,
program_indices: &[usize], program_indices: &[usize],
account_indices: &[usize], account_indices: &[usize],
caller_write_privileges: &[bool], caller_write_privileges: &[bool],
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
// This function is always called with a valid instruction, if that changes return an error let is_lowest_invocation_level = self.invoke_stack.is_empty();
let instruction = message if !is_lowest_invocation_level {
.instructions
.get(0)
.ok_or(InstructionError::GenericError)?;
// Verify the calling program hasn't misbehaved // Verify the calling program hasn't misbehaved
self.verify_and_update(instruction, account_indices, caller_write_privileges)?; self.verify_and_update(instruction, account_indices, caller_write_privileges)?;
}
let result = self
.push(message, instruction, program_indices, account_indices)
.and_then(|_| {
self.return_data = (*instruction.program_id(&message.account_keys), Vec::new());
self.process_executable_chain(&instruction.data)?;
self.return_data = (*self.get_caller()?, Vec::new());
self.push(message, instruction, program_indices, Some(account_indices))?;
let result = self.process_instruction(&instruction.data).and_then(|_| {
// Verify the called program has not misbehaved // Verify the called program has not misbehaved
if is_lowest_invocation_level {
self.verify(message, instruction, program_indices)
} else {
let demote_program_write_locks = self let demote_program_write_locks = self
.feature_set .feature_set
.is_active(&demote_program_write_locks::id()); .is_active(&demote_program_write_locks::id());
@ -671,15 +668,19 @@ impl<'a> InvokeContext<'a> {
.map(|i| message.is_writable(i, demote_program_write_locks)) .map(|i| message.is_writable(i, demote_program_write_locks))
.collect(); .collect();
self.verify_and_update(instruction, account_indices, &write_privileges) self.verify_and_update(instruction, account_indices, &write_privileges)
}
}); });
// Restore previous state // Pop the invoke_stack to restore previous state
self.pop(); self.pop();
result result
} }
/// Calls the instruction's program entrypoint method /// Calls the instruction's program entrypoint method
pub fn process_instruction(&mut self, instruction_data: &[u8]) -> Result<(), InstructionError> { fn process_executable_chain(
&mut self,
instruction_data: &[u8],
) -> Result<(), InstructionError> {
let keyed_accounts = self.get_keyed_accounts()?; let keyed_accounts = self.get_keyed_accounts()?;
let root_account = keyed_account_at_index(keyed_accounts, 0) let root_account = keyed_account_at_index(keyed_accounts, 0)
.map_err(|_| InstructionError::UnsupportedProgramId)?; .map_err(|_| InstructionError::UnsupportedProgramId)?;
@ -917,7 +918,7 @@ pub fn with_mock_invoke_context<R, F: FnMut(&mut InvokeContext) -> R>(
&preparation.message, &preparation.message,
&preparation.message.instructions[0], &preparation.message.instructions[0],
&program_indices, &program_indices,
Some(&preparation.account_indices), &preparation.account_indices,
) )
.unwrap(); .unwrap();
callback(&mut invoke_context) callback(&mut invoke_context)
@ -936,13 +937,13 @@ pub fn mock_process_instruction_with_sysvars(
let processor_account = AccountSharedData::new_ref(0, 0, &solana_sdk::native_loader::id()); let processor_account = AccountSharedData::new_ref(0, 0, &solana_sdk::native_loader::id());
program_indices.insert(0, preparation.accounts.len()); program_indices.insert(0, preparation.accounts.len());
preparation.accounts.push((*loader_id, processor_account)); preparation.accounts.push((*loader_id, processor_account));
let mut invoke_context = let mut invoke_context = InvokeContext::new_mock(&preparation.accounts, &[]);
InvokeContext::new_mock_with_sysvars(&preparation.accounts, &[], sysvars); invoke_context.sysvars = sysvars;
invoke_context.push( invoke_context.push(
&preparation.message, &preparation.message,
&preparation.message.instructions[0], &preparation.message.instructions[0],
&program_indices, &program_indices,
Some(&preparation.account_indices), &preparation.account_indices,
)?; )?;
process_instruction(1, instruction_data, &mut invoke_context) process_instruction(1, instruction_data, &mut invoke_context)
} }
@ -1105,7 +1106,7 @@ mod tests {
&message, &message,
&message.instructions[0], &message.instructions[0],
&[MAX_DEPTH + depth_reached], &[MAX_DEPTH + depth_reached],
None, &[],
) )
{ {
break; break;
@ -1184,7 +1185,7 @@ mod tests {
); );
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]); let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
assert!(invoke_context assert!(invoke_context
.verify(&message, &message.instructions[0], &[0]) .verify(&message, &message.instructions[0], &[0])
@ -1249,7 +1250,7 @@ mod tests {
}]; }];
let mut invoke_context = InvokeContext::new_mock(&accounts, builtin_programs); let mut invoke_context = InvokeContext::new_mock(&accounts, builtin_programs);
invoke_context invoke_context
.push(&message, &caller_instruction, &program_indices[..1], None) .push(&message, &caller_instruction, &program_indices[..1], &[])
.unwrap(); .unwrap();
// not owned account modified by the caller (before the invoke) // not owned account modified by the caller (before the invoke)
@ -1264,8 +1265,9 @@ mod tests {
.collect::<Vec<bool>>(); .collect::<Vec<bool>>();
accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 1; accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 1;
assert_eq!( assert_eq!(
invoke_context.process_cross_program_instruction( invoke_context.process_instruction(
&message, &message,
&message.instructions[0],
&program_indices[1..], &program_indices[1..],
&account_indices, &account_indices,
&caller_write_privileges, &caller_write_privileges,
@ -1277,8 +1279,9 @@ mod tests {
// readonly account modified by the invoker // readonly account modified by the invoker
accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 1; accounts[2].1.borrow_mut().data_as_mut_slice()[0] = 1;
assert_eq!( assert_eq!(
invoke_context.process_cross_program_instruction( invoke_context.process_instruction(
&message, &message,
&message.instructions[0],
&program_indices[1..], &program_indices[1..],
&account_indices, &account_indices,
&caller_write_privileges, &caller_write_privileges,
@ -1306,7 +1309,7 @@ mod tests {
Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone()); Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone());
let message = Message::new(&[callee_instruction], None); let message = Message::new(&[callee_instruction], None);
invoke_context invoke_context
.push(&message, &caller_instruction, &program_indices[..1], None) .push(&message, &caller_instruction, &program_indices[..1], &[])
.unwrap(); .unwrap();
let caller_write_privileges = message let caller_write_privileges = message
.account_keys .account_keys
@ -1315,8 +1318,9 @@ mod tests {
.map(|(i, _)| message.is_writable(i, demote_program_write_locks)) .map(|(i, _)| message.is_writable(i, demote_program_write_locks))
.collect::<Vec<bool>>(); .collect::<Vec<bool>>();
assert_eq!( assert_eq!(
invoke_context.process_cross_program_instruction( invoke_context.process_instruction(
&message, &message,
&message.instructions[0],
&program_indices[1..], &program_indices[1..],
&account_indices, &account_indices,
&caller_write_privileges, &caller_write_privileges,
@ -1377,7 +1381,7 @@ mod tests {
}]; }];
let mut invoke_context = InvokeContext::new_mock(&accounts, builtin_programs); let mut invoke_context = InvokeContext::new_mock(&accounts, builtin_programs);
invoke_context invoke_context
.push(&message, &caller_instruction, &program_indices, None) .push(&message, &caller_instruction, &program_indices, &[])
.unwrap(); .unwrap();
// not owned account modified by the invoker // not owned account modified by the invoker
@ -1420,7 +1424,7 @@ mod tests {
Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone()); Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone());
let message = Message::new(&[callee_instruction.clone()], None); let message = Message::new(&[callee_instruction.clone()], None);
invoke_context invoke_context
.push(&message, &caller_instruction, &program_indices, None) .push(&message, &caller_instruction, &program_indices, &[])
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
invoke_context.native_invoke(callee_instruction, &[]), invoke_context.native_invoke(callee_instruction, &[]),
@ -1467,7 +1471,7 @@ mod tests {
invoke_context.feature_set = Arc::new(feature_set); invoke_context.feature_set = Arc::new(feature_set);
invoke_context invoke_context
.push(&noop_message, &noop_message.instructions[0], &[0], None) .push(&noop_message, &noop_message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
*invoke_context.get_compute_budget(), *invoke_context.get_compute_budget(),
@ -1476,7 +1480,7 @@ mod tests {
invoke_context.pop(); invoke_context.pop();
invoke_context invoke_context
.push(&neon_message, &neon_message.instructions[0], &[1], None) .push(&neon_message, &neon_message.instructions[0], &[1], &[])
.unwrap(); .unwrap();
let expected_compute_budget = ComputeBudget { let expected_compute_budget = ComputeBudget {
max_units: 500_000, max_units: 500_000,
@ -1490,7 +1494,7 @@ mod tests {
invoke_context.pop(); invoke_context.pop();
invoke_context invoke_context
.push(&noop_message, &noop_message.instructions[0], &[0], None) .push(&noop_message, &noop_message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
*invoke_context.get_compute_budget(), *invoke_context.get_compute_budget(),

View File

@ -319,8 +319,9 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
} }
invoke_context invoke_context
.process_cross_program_instruction( .process_instruction(
&message, &message,
&message.instructions[0],
&program_indices, &program_indices,
&account_indices, &account_indices,
&caller_privileges, &caller_privileges,

View File

@ -455,7 +455,7 @@ mod tests {
&preparation.message, &preparation.message,
&preparation.message.instructions[0], &preparation.message.instructions[0],
&program_indices, &program_indices,
Some(&preparation.account_indices), &preparation.account_indices,
) )
.unwrap(); .unwrap();

View File

@ -2368,8 +2368,9 @@ fn call<'a, 'b: 'a>(
// Process instruction // Process instruction
invoke_context invoke_context
.process_cross_program_instruction( .process_instruction(
&message, &message,
&message.instructions[0],
&program_indices, &program_indices,
&account_indices, &account_indices,
&caller_write_privileges, &caller_write_privileges,
@ -2967,7 +2968,7 @@ mod tests {
); );
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]); let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let mut syscall_panic = SyscallPanic { let mut syscall_panic = SyscallPanic {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)), invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@ -3044,7 +3045,7 @@ mod tests {
); );
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]); let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let mut syscall_sol_log = SyscallLog { let mut syscall_sol_log = SyscallLog {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)), invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@ -3148,7 +3149,7 @@ mod tests {
); );
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]); let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let cost = invoke_context.get_compute_budget().log_64_units; let cost = invoke_context.get_compute_budget().log_64_units;
let mut syscall_sol_log_u64 = SyscallLogU64 { let mut syscall_sol_log_u64 = SyscallLogU64 {
@ -3190,7 +3191,7 @@ mod tests {
); );
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]); let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let cost = invoke_context.get_compute_budget().log_pubkey_units; let cost = invoke_context.get_compute_budget().log_pubkey_units;
let mut syscall_sol_pubkey = SyscallLogPubkey { let mut syscall_sol_pubkey = SyscallLogPubkey {
@ -3464,7 +3465,7 @@ mod tests {
* 4, * 4,
); );
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let mut syscall = SyscallSha256 { let mut syscall = SyscallSha256 {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)), invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@ -3563,7 +3564,7 @@ mod tests {
let sysvars = [(sysvar::clock::id(), data)]; let sysvars = [(sysvar::clock::id(), data)];
invoke_context.sysvars = &sysvars; invoke_context.sysvars = &sysvars;
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let mut syscall = SyscallGetClockSysvar { let mut syscall = SyscallGetClockSysvar {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)), invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@ -3608,7 +3609,7 @@ mod tests {
let sysvars = [(sysvar::epoch_schedule::id(), data)]; let sysvars = [(sysvar::epoch_schedule::id(), data)];
invoke_context.sysvars = &sysvars; invoke_context.sysvars = &sysvars;
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let mut syscall = SyscallGetEpochScheduleSysvar { let mut syscall = SyscallGetEpochScheduleSysvar {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)), invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@ -3660,7 +3661,7 @@ mod tests {
let sysvars = [(sysvar::fees::id(), data)]; let sysvars = [(sysvar::fees::id(), data)];
invoke_context.sysvars = &sysvars; invoke_context.sysvars = &sysvars;
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let mut syscall = SyscallGetFeesSysvar { let mut syscall = SyscallGetFeesSysvar {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)), invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@ -3703,7 +3704,7 @@ mod tests {
let sysvars = [(sysvar::rent::id(), data)]; let sysvars = [(sysvar::rent::id(), data)];
invoke_context.sysvars = &sysvars; invoke_context.sysvars = &sysvars;
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let mut syscall = SyscallGetRentSysvar { let mut syscall = SyscallGetRentSysvar {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)), invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@ -3841,7 +3842,7 @@ mod tests {
); );
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]); let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let address = bpf_loader_upgradeable::id(); let address = bpf_loader_upgradeable::id();
@ -3957,7 +3958,7 @@ mod tests {
); );
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]); let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
invoke_context invoke_context
.push(&message, &message.instructions[0], &[0], None) .push(&message, &message.instructions[0], &[0], &[])
.unwrap(); .unwrap();
let cost = invoke_context let cost = invoke_context
.get_compute_budget() .get_compute_budget()

View File

@ -437,7 +437,7 @@ mod tests {
&preparation.message, &preparation.message,
&preparation.message.instructions[0], &preparation.message.instructions[0],
&program_indices, &program_indices,
Some(&preparation.account_indices), &preparation.account_indices,
)?; )?;
super::process_instruction(1, &instruction.data, &mut invoke_context) super::process_instruction(1, &instruction.data, &mut invoke_context)
} }
@ -1084,7 +1084,7 @@ mod tests {
&preparation.message, &preparation.message,
&preparation.message.instructions[0], &preparation.message.instructions[0],
&program_indices, &program_indices,
Some(&preparation.account_indices), &preparation.account_indices,
) )
.unwrap(); .unwrap();
assert_eq!( assert_eq!(

View File

@ -213,7 +213,7 @@ native machine code before execting it in the virtual machine.",
&preparation.message, &preparation.message,
&preparation.message.instructions[0], &preparation.message.instructions[0],
&program_indices, &program_indices,
Some(&preparation.account_indices), &preparation.account_indices,
) )
.unwrap(); .unwrap();
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap(); let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();

View File

@ -104,31 +104,19 @@ impl MessageProcessor {
invoke_context.instruction_recorder = invoke_context.instruction_recorder =
Some(&instruction_recorders[instruction_index]); Some(&instruction_recorders[instruction_index]);
} }
let result = invoke_context let pre_remaining_units = invoke_context.get_compute_meter().borrow().get_remaining();
.push(message, instruction, program_indices, None)
.and_then(|_| {
let pre_remaining_units =
invoke_context.get_compute_meter().borrow().get_remaining();
let mut time = Measure::start("execute_instruction"); let mut time = Measure::start("execute_instruction");
invoke_context
invoke_context.process_instruction(&instruction.data)?; .process_instruction(message, instruction, program_indices, &[], &[])
invoke_context.verify(message, instruction, program_indices)?; .map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
time.stop(); time.stop();
let post_remaining_units = let post_remaining_units = invoke_context.get_compute_meter().borrow().get_remaining();
invoke_context.get_compute_meter().borrow().get_remaining();
timings.accumulate_program( timings.accumulate_program(
instruction.program_id(&message.account_keys), instruction.program_id(&message.account_keys),
time.as_us(), time.as_us(),
pre_remaining_units - post_remaining_units, pre_remaining_units - post_remaining_units,
); );
timings.accumulate(&invoke_context.timings); timings.accumulate(&invoke_context.timings);
Ok(())
})
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err));
invoke_context.pop();
result?;
} }
Ok(()) Ok(())
} }