diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index 5b4aaac6f..5474087fd 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -642,7 +642,7 @@ impl<'a> InvokeContext<'a> { Ok((message, caller_write_privileges, program_indices)) } - /// Process a cross-program instruction + /// Processes a cross-program instruction and returns how many compute units were used pub fn process_instruction( &mut self, message: &Message, @@ -650,7 +650,7 @@ impl<'a> InvokeContext<'a> { program_indices: &[usize], account_indices: &[usize], caller_write_privileges: &[bool], - ) -> Result<(), InstructionError> { + ) -> Result { let is_lowest_invocation_level = self.invoke_stack.is_empty(); if !is_lowest_invocation_level { // Verify the calling program hasn't misbehaved @@ -661,11 +661,13 @@ impl<'a> InvokeContext<'a> { .push(message, instruction, program_indices, account_indices) .and_then(|_| { self.return_data = (*instruction.program_id(&message.account_keys), Vec::new()); + let pre_remaining_units = self.compute_meter.borrow().get_remaining(); self.process_executable_chain(&instruction.data)?; + let post_remaining_units = self.compute_meter.borrow().get_remaining(); // Verify the called program has not misbehaved if is_lowest_invocation_level { - self.verify(message, instruction, program_indices) + self.verify(message, instruction, program_indices)?; } else { let demote_program_write_locks = self .feature_set @@ -673,8 +675,10 @@ impl<'a> InvokeContext<'a> { let write_privileges: Vec = (0..message.account_keys.len()) .map(|i| message.is_writable(i, demote_program_write_locks)) .collect(); - self.verify_and_update(instruction, account_indices, &write_privileges) + self.verify_and_update(instruction, account_indices, &write_privileges)?; } + + Ok(pre_remaining_units.saturating_sub(post_remaining_units)) }); // Pop the invoke_stack to restore previous state @@ -1304,12 +1308,12 @@ mod tests { invoke_context.pop(); let cases = vec![ - (MockInstruction::NoopSuccess, Ok(())), + (MockInstruction::NoopSuccess, Ok(0)), ( MockInstruction::NoopFail, Err(InstructionError::GenericError), ), - (MockInstruction::ModifyOwned, Ok(())), + (MockInstruction::ModifyOwned, Ok(0)), ( MockInstruction::ModifyNotOwned, Err(InstructionError::ExternalAccountDataModified), diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 1c857ecb6..b249b09c8 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -111,17 +111,15 @@ impl MessageProcessor { invoke_context.instruction_recorder = Some(&instruction_recorders[instruction_index]); } - let pre_remaining_units = invoke_context.get_compute_meter().borrow().get_remaining(); let mut time = Measure::start("execute_instruction"); - invoke_context + let compute_meter_consumption = invoke_context .process_instruction(message, instruction, program_indices, &[], &[]) .map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?; time.stop(); - let post_remaining_units = invoke_context.get_compute_meter().borrow().get_remaining(); timings.accumulate_program( instruction.program_id(&message.account_keys), time.as_us(), - pre_remaining_units - post_remaining_units, + compute_meter_consumption, ); timings.accumulate(&invoke_context.timings); }