diff --git a/accounts-db/src/transaction_results.rs b/accounts-db/src/transaction_results.rs index bc0a330f507399..79efa66425aabd 100644 --- a/accounts-db/src/transaction_results.rs +++ b/accounts-db/src/transaction_results.rs @@ -11,9 +11,8 @@ use { }, solana_program_runtime::loaded_programs::LoadedProgramsForTxBatch, solana_sdk::{ - instruction::{CompiledInstruction, TRANSACTION_LEVEL_STACK_HEIGHT}, transaction::{self, TransactionError}, - transaction_context::{TransactionContext, TransactionReturnData}, + transaction_context::TransactionReturnData, }, }; @@ -110,109 +109,3 @@ impl DurableNonceFee { } } } - -/// Extract the InnerInstructionsList from a TransactionContext -pub fn inner_instructions_list_from_instruction_trace( - transaction_context: &TransactionContext, -) -> InnerInstructionsList { - debug_assert!(transaction_context - .get_instruction_context_at_index_in_trace(0) - .map(|instruction_context| instruction_context.get_stack_height() - == TRANSACTION_LEVEL_STACK_HEIGHT) - .unwrap_or(true)); - let mut outer_instructions = Vec::new(); - for index_in_trace in 0..transaction_context.get_instruction_trace_length() { - if let Ok(instruction_context) = - transaction_context.get_instruction_context_at_index_in_trace(index_in_trace) - { - let stack_height = instruction_context.get_stack_height(); - if stack_height == TRANSACTION_LEVEL_STACK_HEIGHT { - outer_instructions.push(Vec::new()); - } else if let Some(inner_instructions) = outer_instructions.last_mut() { - let stack_height = u8::try_from(stack_height).unwrap_or(u8::MAX); - let instruction = CompiledInstruction::new_from_raw_parts( - instruction_context - .get_index_of_program_account_in_transaction( - instruction_context - .get_number_of_program_accounts() - .saturating_sub(1), - ) - .unwrap_or_default() as u8, - instruction_context.get_instruction_data().to_vec(), - (0..instruction_context.get_number_of_instruction_accounts()) - .map(|instruction_account_index| { - instruction_context - .get_index_of_instruction_account_in_transaction( - instruction_account_index, - ) - .unwrap_or_default() as u8 - }) - .collect(), - ); - inner_instructions.push(InnerInstruction { - instruction, - stack_height, - }); - } else { - debug_assert!(false); - } - } else { - debug_assert!(false); - } - } - outer_instructions -} - -#[cfg(test)] -mod tests { - use { - super::*, - solana_sdk::{sysvar::rent::Rent, transaction_context::TransactionContext}, - }; - - #[test] - fn test_inner_instructions_list_from_instruction_trace() { - let instruction_trace = [1, 2, 1, 1, 2, 3, 2]; - let mut transaction_context = - TransactionContext::new(vec![], Rent::default(), 3, instruction_trace.len()); - for (index_in_trace, stack_height) in instruction_trace.into_iter().enumerate() { - while stack_height <= transaction_context.get_instruction_context_stack_height() { - transaction_context.pop().unwrap(); - } - if stack_height > transaction_context.get_instruction_context_stack_height() { - transaction_context - .get_next_instruction_context() - .unwrap() - .configure(&[], &[], &[index_in_trace as u8]); - transaction_context.push().unwrap(); - } - } - let inner_instructions = - inner_instructions_list_from_instruction_trace(&transaction_context); - - assert_eq!( - inner_instructions, - vec![ - vec![InnerInstruction { - instruction: CompiledInstruction::new_from_raw_parts(0, vec![1], vec![]), - stack_height: 2, - }], - vec![], - vec![ - InnerInstruction { - instruction: CompiledInstruction::new_from_raw_parts(0, vec![4], vec![]), - stack_height: 2, - }, - InnerInstruction { - instruction: CompiledInstruction::new_from_raw_parts(0, vec![5], vec![]), - stack_height: 3, - }, - InnerInstruction { - instruction: CompiledInstruction::new_from_raw_parts(0, vec![6], vec![]), - stack_height: 2, - }, - ] - ] - ); - } -} diff --git a/runtime/src/svm/transaction_processor.rs b/runtime/src/svm/transaction_processor.rs index 56a3d9a774f58c..e72caca4d3c85a 100644 --- a/runtime/src/svm/transaction_processor.rs +++ b/runtime/src/svm/transaction_processor.rs @@ -11,8 +11,8 @@ use { rent_collector::RentCollector, transaction_error_metrics::TransactionErrorMetrics, transaction_results::{ - inner_instructions_list_from_instruction_trace, DurableNonceFee, - TransactionCheckResult, TransactionExecutionDetails, TransactionExecutionResult, + DurableNonceFee, TransactionCheckResult, TransactionExecutionDetails, + TransactionExecutionResult, }, }, solana_measure::measure::Measure, @@ -37,7 +37,8 @@ use { feature_set::FeatureSet, fee::FeeStructure, hash::Hash, - instruction::InstructionError, + inner_instruction::{InnerInstruction, InnerInstructionsList}, + instruction::{CompiledInstruction, InstructionError, TRANSACTION_LEVEL_STACK_HEIGHT}, loader_v4::{self, LoaderV4State, LoaderV4Status}, message::SanitizedMessage, native_loader, @@ -569,7 +570,7 @@ impl TransactionBatchProcessor { }); let inner_instructions = if enable_cpi_recording { - Some(inner_instructions_list_from_instruction_trace( + Some(Self::inner_instructions_list_from_instruction_trace( &transaction_context, )) } else { @@ -848,4 +849,121 @@ impl TransactionBatchProcessor { } ProgramAccountLoadResult::InvalidAccountData(environments.program_runtime_v1.clone()) } + + /// Extract the InnerInstructionsList from a TransactionContext + fn inner_instructions_list_from_instruction_trace( + transaction_context: &TransactionContext, + ) -> InnerInstructionsList { + debug_assert!(transaction_context + .get_instruction_context_at_index_in_trace(0) + .map(|instruction_context| instruction_context.get_stack_height() + == TRANSACTION_LEVEL_STACK_HEIGHT) + .unwrap_or(true)); + let mut outer_instructions = Vec::new(); + for index_in_trace in 0..transaction_context.get_instruction_trace_length() { + if let Ok(instruction_context) = + transaction_context.get_instruction_context_at_index_in_trace(index_in_trace) + { + let stack_height = instruction_context.get_stack_height(); + if stack_height == TRANSACTION_LEVEL_STACK_HEIGHT { + outer_instructions.push(Vec::new()); + } else if let Some(inner_instructions) = outer_instructions.last_mut() { + let stack_height = u8::try_from(stack_height).unwrap_or(u8::MAX); + let instruction = CompiledInstruction::new_from_raw_parts( + instruction_context + .get_index_of_program_account_in_transaction( + instruction_context + .get_number_of_program_accounts() + .saturating_sub(1), + ) + .unwrap_or_default() as u8, + instruction_context.get_instruction_data().to_vec(), + (0..instruction_context.get_number_of_instruction_accounts()) + .map(|instruction_account_index| { + instruction_context + .get_index_of_instruction_account_in_transaction( + instruction_account_index, + ) + .unwrap_or_default() as u8 + }) + .collect(), + ); + inner_instructions.push(InnerInstruction { + instruction, + stack_height, + }); + } else { + debug_assert!(false); + } + } else { + debug_assert!(false); + } + } + outer_instructions + } +} + +#[cfg(test)] +mod tests { + use { + super::*, + solana_program_runtime::loaded_programs::BlockRelation, + solana_sdk::{sysvar::rent::Rent, transaction_context::TransactionContext}, + }; + + struct TestForkGraph {} + + impl ForkGraph for TestForkGraph { + fn relationship(&self, _a: Slot, _b: Slot) -> BlockRelation { + BlockRelation::Unknown + } + } + + #[test] + fn test_inner_instructions_list_from_instruction_trace() { + let instruction_trace = [1, 2, 1, 1, 2, 3, 2]; + let mut transaction_context = + TransactionContext::new(vec![], Rent::default(), 3, instruction_trace.len()); + for (index_in_trace, stack_height) in instruction_trace.into_iter().enumerate() { + while stack_height <= transaction_context.get_instruction_context_stack_height() { + transaction_context.pop().unwrap(); + } + if stack_height > transaction_context.get_instruction_context_stack_height() { + transaction_context + .get_next_instruction_context() + .unwrap() + .configure(&[], &[], &[index_in_trace as u8]); + transaction_context.push().unwrap(); + } + } + let inner_instructions = + TransactionBatchProcessor::::inner_instructions_list_from_instruction_trace( + &transaction_context, + ); + + assert_eq!( + inner_instructions, + vec![ + vec![InnerInstruction { + instruction: CompiledInstruction::new_from_raw_parts(0, vec![1], vec![]), + stack_height: 2, + }], + vec![], + vec![ + InnerInstruction { + instruction: CompiledInstruction::new_from_raw_parts(0, vec![4], vec![]), + stack_height: 2, + }, + InnerInstruction { + instruction: CompiledInstruction::new_from_raw_parts(0, vec![5], vec![]), + stack_height: 3, + }, + InnerInstruction { + instruction: CompiledInstruction::new_from_raw_parts(0, vec![6], vec![]), + stack_height: 2, + }, + ] + ] + ); + } }