diff --git a/cli/src/program.rs b/cli/src/program.rs index 65bfcef83e..a93a3d7aa7 100644 --- a/cli/src/program.rs +++ b/cli/src/program.rs @@ -1991,7 +1991,7 @@ fn read_and_verify_elf(program_location: &str) -> Result, Box { compute_meter: Rc>, accounts_data_meter: AccountsDataMeter, executors: Rc>, - pub instruction_recorder: Option>>, pub feature_set: Arc, pub timings: ExecuteDetailsTimings, pub blockhash: Hash, @@ -209,7 +207,6 @@ impl<'a> InvokeContext<'a> { log_collector: Option>>, compute_budget: ComputeBudget, executors: Rc>, - instruction_recorder: Option>>, feature_set: Arc, blockhash: Hash, lamports_per_signature: u64, @@ -228,7 +225,6 @@ impl<'a> InvokeContext<'a> { compute_meter: ComputeMeter::new_ref(compute_budget.max_units), accounts_data_meter: AccountsDataMeter::new(current_accounts_data_len), executors, - instruction_recorder, feature_set, timings: ExecuteDetailsTimings::default(), blockhash, @@ -249,7 +245,6 @@ impl<'a> InvokeContext<'a> { Some(LogCollector::new_ref()), ComputeBudget::default(), Rc::new(RefCell::new(Executors::default())), - None, feature_set, Hash::default(), 0, @@ -269,7 +264,6 @@ impl<'a> InvokeContext<'a> { Some(LogCollector::new_ref()), ComputeBudget::default(), Rc::new(RefCell::new(Executors::default())), - None, Arc::new(FeatureSet::all_enabled()), Hash::default(), 0, @@ -811,11 +805,7 @@ impl<'a> InvokeContext<'a> { .transaction_context .get_instruction_context_stack_height() == 0; - if is_lowest_invocation_level { - if let Some(instruction_recorder) = &self.instruction_recorder { - instruction_recorder.borrow_mut().begin_next_recording(); - } - } else { + if !is_lowest_invocation_level { // Verify the calling program hasn't misbehaved let mut verify_caller_time = Measure::start("verify_caller_time"); let verify_caller_result = self.verify_and_update(instruction_accounts, true); @@ -830,23 +820,19 @@ impl<'a> InvokeContext<'a> { verify_caller_result?; // Record instruction - if let Some(instruction_recorder) = &self.instruction_recorder { - let compiled_instruction = CompiledInstruction { - program_id_index: self - .transaction_context - .find_index_of_account(&program_id) - .unwrap_or(0) as u8, - data: instruction_data.to_vec(), - accounts: instruction_accounts - .iter() - .map(|instruction_account| instruction_account.index_in_transaction as u8) - .collect(), - }; - - instruction_recorder - .borrow_mut() - .record_compiled_instruction(compiled_instruction); - } + let compiled_instruction = CompiledInstruction { + program_id_index: self + .transaction_context + .find_index_of_account(&program_id) + .unwrap_or(0) as u8, + data: instruction_data.to_vec(), + accounts: instruction_accounts + .iter() + .map(|instruction_account| instruction_account.index_in_transaction as u8) + .collect(), + }; + self.transaction_context + .record_compiled_instruction(compiled_instruction); } let result = self @@ -1075,6 +1061,7 @@ pub fn with_mock_invoke_context R>( let mut transaction_context = TransactionContext::new( preparation.transaction_accounts, ComputeBudget::default().max_invoke_depth.saturating_add(1), + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context @@ -1103,6 +1090,7 @@ pub fn mock_process_instruction_with_sysvars( let mut transaction_context = TransactionContext::new( preparation.transaction_accounts, ComputeBudget::default().max_invoke_depth.saturating_add(1), + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.sysvar_cache = Cow::Borrowed(sysvar_cache); @@ -1351,7 +1339,7 @@ mod tests { is_writable: false, }); } - let mut transaction_context = TransactionContext::new(accounts, MAX_DEPTH); + let mut transaction_context = TransactionContext::new(accounts, MAX_DEPTH, 1); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // Check call depth increases and has a limit @@ -1430,7 +1418,7 @@ mod tests { let accounts = vec![(solana_sdk::pubkey::new_rand(), AccountSharedData::default())]; let instruction_accounts = vec![]; let program_indices = vec![0]; - let mut transaction_context = TransactionContext::new(accounts, 1); + let mut transaction_context = TransactionContext::new(accounts, 1, 1); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context .push(&instruction_accounts, &program_indices, &[]) @@ -1474,7 +1462,7 @@ mod tests { is_writable: index_in_transaction < 2, }) .collect::>(); - let mut transaction_context = TransactionContext::new(accounts, 2); + let mut transaction_context = TransactionContext::new(accounts, 2, 8); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, builtin_programs); @@ -1600,7 +1588,7 @@ mod tests { let mut feature_set = FeatureSet::all_enabled(); feature_set.deactivate(&tx_wide_compute_cap::id()); feature_set.deactivate(&requestable_heap_size::id()); - let mut transaction_context = TransactionContext::new(accounts, 1); + let mut transaction_context = TransactionContext::new(accounts, 1, 3); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.feature_set = Arc::new(feature_set); @@ -1652,7 +1640,7 @@ mod tests { process_instruction: mock_process_instruction, }]; - let mut transaction_context = TransactionContext::new(accounts, 1); + let mut transaction_context = TransactionContext::new(accounts, 1, 3); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &builtin_programs); diff --git a/program-runtime/src/lib.rs b/program-runtime/src/lib.rs index db911ab810..4404effa70 100644 --- a/program-runtime/src/lib.rs +++ b/program-runtime/src/lib.rs @@ -2,7 +2,6 @@ pub mod accounts_data_meter; pub mod compute_budget; -pub mod instruction_recorder; pub mod invoke_context; pub mod log_collector; pub mod native_loader; diff --git a/programs/bpf_loader/benches/serialization.rs b/programs/bpf_loader/benches/serialization.rs index 900f39df8e..703a32bc35 100644 --- a/programs/bpf_loader/benches/serialization.rs +++ b/programs/bpf_loader/benches/serialization.rs @@ -100,7 +100,7 @@ fn create_inputs() -> TransactionContext { }, ) .collect::>(); - let mut transaction_context = TransactionContext::new(transaction_accounts, 1); + let mut transaction_context = TransactionContext::new(transaction_accounts, 1, 1); let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; transaction_context .push(&[0], &instruction_accounts, &instruction_data) diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index 26af36e1d8..9cf3485a4d 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -456,7 +456,8 @@ mod tests { instruction_accounts, &program_indices, ); - let mut transaction_context = TransactionContext::new(preparation.transaction_accounts, 1); + let mut transaction_context = + TransactionContext::new(preparation.transaction_accounts, 1, 1); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context .push( diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index de40f1dec7..0c66c321e3 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -3285,6 +3285,7 @@ mod tests { let mut transaction_context = TransactionContext::new( vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))], 1, + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.push(&[], &[0], &[]).unwrap(); @@ -3358,6 +3359,7 @@ mod tests { let mut transaction_context = TransactionContext::new( vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))], 1, + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.push(&[], &[0], &[]).unwrap(); @@ -3458,6 +3460,7 @@ mod tests { let mut transaction_context = TransactionContext::new( vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))], 1, + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.push(&[], &[0], &[]).unwrap(); @@ -3496,6 +3499,7 @@ mod tests { let mut transaction_context = TransactionContext::new( vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))], 1, + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.push(&[], &[0], &[]).unwrap(); @@ -3707,6 +3711,7 @@ mod tests { AccountSharedData::new(0, 0, &bpf_loader_deprecated::id()), )], 1, + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.push(&[], &[0], &[]).unwrap(); @@ -3864,6 +3869,7 @@ mod tests { let mut transaction_context = TransactionContext::new( vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))], 1, + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.sysvar_cache = Cow::Owned(sysvar_cache); @@ -4114,6 +4120,7 @@ mod tests { let mut transaction_context = TransactionContext::new( vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))], 1, + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.push(&[], &[0], &[]).unwrap(); @@ -4226,6 +4233,7 @@ mod tests { let mut transaction_context = TransactionContext::new( vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))], 1, + 1, ); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context.push(&[], &[0], &[]).unwrap(); diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index b2c591122b..f8baa600ec 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -4999,7 +4999,7 @@ mod tests { #[test] fn test_merge() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let stake_pubkey = solana_sdk::pubkey::new_rand(); let source_stake_pubkey = solana_sdk::pubkey::new_rand(); @@ -5110,7 +5110,7 @@ mod tests { #[test] fn test_merge_self_fails() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let stake_address = Pubkey::new_unique(); let authority_pubkey = Pubkey::new_unique(); @@ -5156,7 +5156,7 @@ mod tests { #[test] fn test_merge_incorrect_authorized_staker() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let stake_pubkey = solana_sdk::pubkey::new_rand(); let source_stake_pubkey = solana_sdk::pubkey::new_rand(); @@ -5226,7 +5226,7 @@ mod tests { #[test] fn test_merge_invalid_account_data() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let stake_pubkey = solana_sdk::pubkey::new_rand(); let source_stake_pubkey = solana_sdk::pubkey::new_rand(); @@ -5277,7 +5277,7 @@ mod tests { #[test] fn test_merge_fake_stake_source() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let stake_pubkey = solana_sdk::pubkey::new_rand(); let source_stake_pubkey = solana_sdk::pubkey::new_rand(); @@ -5320,7 +5320,7 @@ mod tests { #[test] fn test_merge_active_stake() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let base_lamports = 4242424242; let stake_address = Pubkey::new_unique(); @@ -5943,7 +5943,7 @@ mod tests { #[test] fn test_things_can_merge() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let good_stake = Stake { credits_observed: 4242, @@ -6042,7 +6042,7 @@ mod tests { #[test] fn test_metas_can_merge_pre_v4() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // Identical Metas can merge assert!(MergeKind::metas_can_merge( @@ -6129,7 +6129,7 @@ mod tests { #[test] fn test_metas_can_merge_v4() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // Identical Metas can merge assert!(MergeKind::metas_can_merge( @@ -6276,7 +6276,7 @@ mod tests { #[test] fn test_merge_kind_get_if_mergeable() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let authority_pubkey = Pubkey::new_unique(); let initial_lamports = 4242424242; @@ -6509,7 +6509,7 @@ mod tests { #[test] fn test_merge_kind_merge() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let lamports = 424242; let meta = Meta { @@ -6588,7 +6588,7 @@ mod tests { #[test] fn test_active_stake_merge() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let delegation_a = 4_242_424_242u64; let delegation_b = 6_200_000_000u64; diff --git a/programs/vote/benches/process_vote.rs b/programs/vote/benches/process_vote.rs index 16454ddea9..e101e63cda 100644 --- a/programs/vote/benches/process_vote.rs +++ b/programs/vote/benches/process_vote.rs @@ -139,6 +139,7 @@ fn do_bench(bencher: &mut Bencher, feature: Option) { (solana_vote_program::id(), AccountSharedData::default()), ], 1, + 1, ); let mut invoke_context = InvokeContext::new_mock_with_sysvars_and_features( diff --git a/rbpf-cli/src/main.rs b/rbpf-cli/src/main.rs index ed9575198a..98a2951ba2 100644 --- a/rbpf-cli/src/main.rs +++ b/rbpf-cli/src/main.rs @@ -212,7 +212,7 @@ native machine code before execting it in the virtual machine.", let program_indices = [0, 1]; let preparation = prepare_mock_invoke_context(transaction_accounts, instruction_accounts, &program_indices); - let mut transaction_context = TransactionContext::new(preparation.transaction_accounts, 1); + let mut transaction_context = TransactionContext::new(preparation.transaction_accounts, 1, 1); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); invoke_context .push( diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 2537778873..5a04f6417d 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -75,7 +75,6 @@ use { solana_metrics::{inc_new_counter_debug, inc_new_counter_info}, solana_program_runtime::{ compute_budget::ComputeBudget, - instruction_recorder::InstructionRecorder, invoke_context::{ BuiltinProgram, Executor, Executors, ProcessInstructionWithContext, TransactionExecutor, }, @@ -3661,19 +3660,12 @@ impl Bank { let mut transaction_context = TransactionContext::new( transaction_accounts, compute_budget.max_invoke_depth.saturating_add(1), + tx.message().instructions().len(), ); let pre_account_state_info = self.get_transaction_account_state_info(&transaction_context, tx.message()); - let instruction_recorder = if enable_cpi_recording { - Some(InstructionRecorder::new_ref( - tx.message().instructions().len(), - )) - } else { - None - }; - let log_collector = if enable_log_recording { Some(LogCollector::new_ref()) } else { @@ -3691,7 +3683,6 @@ impl Bank { self.rent_collector.rent, log_collector.clone(), executors.clone(), - instruction_recorder.clone(), self.feature_set.clone(), compute_budget, timings, @@ -3747,16 +3738,17 @@ impl Bank { .ok() }); - let inner_instructions = instruction_recorder - .and_then(|instruction_recorder| Rc::try_unwrap(instruction_recorder).ok()) - .map(|instruction_recorder| instruction_recorder.into_inner().deconstruct()); - - loaded_transaction.accounts = transaction_context.deconstruct(); + let (accounts, instruction_trace) = transaction_context.deconstruct(); + loaded_transaction.accounts = accounts; TransactionExecutionResult::Executed(TransactionExecutionDetails { status, log_messages, - inner_instructions, + inner_instructions: if enable_cpi_recording { + Some(instruction_trace) + } else { + None + }, durable_nonce_fee, }) } @@ -15657,6 +15649,7 @@ pub(crate) mod tests { sol_to_lamports(1.), bank.last_blockhash(), ); + let number_of_instructions_at_transaction_level = tx.message().instructions.len(); let num_accounts = tx.message().account_keys.len(); let sanitized_tx = SanitizedTransaction::try_from_legacy_transaction(tx).unwrap(); let mut error_counters = ErrorCounters::default(); @@ -15674,6 +15667,7 @@ pub(crate) mod tests { let transaction_context = TransactionContext::new( loaded_txs[0].0.as_ref().unwrap().accounts.clone(), compute_budget.max_invoke_depth.saturating_add(1), + number_of_instructions_at_transaction_level, ); assert_eq!( diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index cb7aee2f59..df8f8e82d4 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -3,7 +3,6 @@ use { solana_measure::measure::Measure, solana_program_runtime::{ compute_budget::ComputeBudget, - instruction_recorder::InstructionRecorder, invoke_context::{BuiltinProgram, Executors, InvokeContext}, log_collector::LogCollector, sysvar_cache::SysvarCache, @@ -58,7 +57,6 @@ impl MessageProcessor { rent: Rent, log_collector: Option>>, executors: Rc>, - instruction_recorder: Option>>, feature_set: Arc, compute_budget: ComputeBudget, timings: &mut ExecuteTimings, @@ -75,7 +73,6 @@ impl MessageProcessor { log_collector, compute_budget, executors, - instruction_recorder, feature_set, blockhash, lamports_per_signature, @@ -242,7 +239,7 @@ mod tests { create_loadable_account_for_test("mock_system_program"), ), ]; - let mut transaction_context = TransactionContext::new(accounts, 1); + let mut transaction_context = TransactionContext::new(accounts, 1, 3); let program_indices = vec![vec![2]]; let executors = Rc::new(RefCell::new(Executors::default())); let account_metas = vec![ @@ -267,7 +264,6 @@ mod tests { rent_collector.rent, None, executors.clone(), - None, Arc::new(FeatureSet::all_enabled()), ComputeBudget::new(), &mut ExecuteTimings::default(), @@ -308,7 +304,6 @@ mod tests { rent_collector.rent, None, executors.clone(), - None, Arc::new(FeatureSet::all_enabled()), ComputeBudget::new(), &mut ExecuteTimings::default(), @@ -341,7 +336,6 @@ mod tests { rent_collector.rent, None, executors, - None, Arc::new(FeatureSet::all_enabled()), ComputeBudget::new(), &mut ExecuteTimings::default(), @@ -441,7 +435,7 @@ mod tests { create_loadable_account_for_test("mock_system_program"), ), ]; - let mut transaction_context = TransactionContext::new(accounts, 1); + let mut transaction_context = TransactionContext::new(accounts, 1, 3); let program_indices = vec![vec![2]]; let executors = Rc::new(RefCell::new(Executors::default())); let account_metas = vec![ @@ -468,7 +462,6 @@ mod tests { rent_collector.rent, None, executors.clone(), - None, Arc::new(FeatureSet::all_enabled()), ComputeBudget::new(), &mut ExecuteTimings::default(), @@ -502,7 +495,6 @@ mod tests { rent_collector.rent, None, executors.clone(), - None, Arc::new(FeatureSet::all_enabled()), ComputeBudget::new(), &mut ExecuteTimings::default(), @@ -533,7 +525,6 @@ mod tests { rent_collector.rent, None, executors, - None, Arc::new(FeatureSet::all_enabled()), ComputeBudget::new(), &mut ExecuteTimings::default(), @@ -586,7 +577,7 @@ mod tests { (secp256k1_program::id(), secp256k1_account), (mock_program_id, mock_program_account), ]; - let mut transaction_context = TransactionContext::new(accounts, 1); + let mut transaction_context = TransactionContext::new(accounts, 1, 1); let message = SanitizedMessage::Legacy(Message::new( &[ @@ -607,7 +598,6 @@ mod tests { RentCollector::default().rent, None, Rc::new(RefCell::new(Executors::default())), - None, Arc::new(FeatureSet::all_enabled()), ComputeBudget::new(), &mut ExecuteTimings::default(), diff --git a/runtime/src/nonce_keyed_account.rs b/runtime/src/nonce_keyed_account.rs index 591db87635..181c7e7d4b 100644 --- a/runtime/src/nonce_keyed_account.rs +++ b/runtime/src/nonce_keyed_account.rs @@ -334,7 +334,7 @@ mod test { where F: FnMut(&mut InvokeContext, &KeyedAccount), { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let pubkey = Pubkey::new_unique(); let account = create_account(lamports); diff --git a/runtime/src/system_instruction_processor.rs b/runtime/src/system_instruction_processor.rs index 0126e2d6b4..0e1fa88250 100644 --- a/runtime/src/system_instruction_processor.rs +++ b/runtime/src/system_instruction_processor.rs @@ -661,7 +661,7 @@ mod tests { #[test] fn test_address_create_with_seed_mismatch() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let from = Pubkey::new_unique(); let seed = "dull boy"; @@ -676,7 +676,7 @@ mod tests { #[test] fn test_create_account_with_seed_missing_sig() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let new_owner = Pubkey::new(&[9; 32]); let from = Pubkey::new_unique(); @@ -707,7 +707,7 @@ mod tests { #[test] fn test_create_with_zero_lamports() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // create account with zero lamports transferred let new_owner = Pubkey::new(&[9; 32]); @@ -742,7 +742,7 @@ mod tests { #[test] fn test_create_negative_lamports() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // Attempt to create account with more lamports than remaining in from_account let new_owner = Pubkey::new(&[9; 32]); @@ -767,7 +767,7 @@ mod tests { #[test] fn test_request_more_than_allowed_data_length() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id())); let from = Pubkey::new_unique(); @@ -815,7 +815,7 @@ mod tests { #[test] fn test_create_already_in_use() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // Attempt to create system account in account already owned by another program let new_owner = Pubkey::new(&[9; 32]); @@ -884,7 +884,7 @@ mod tests { #[test] fn test_create_unsigned() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // Attempt to create an account without signing the transfer let new_owner = Pubkey::new(&[9; 32]); @@ -940,7 +940,7 @@ mod tests { #[test] fn test_create_sysvar_invalid_id_with_feature() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // Attempt to create system account in account already owned by another program let from = Pubkey::new_unique(); @@ -968,7 +968,7 @@ mod tests { #[test] fn test_create_data_populated() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); // Attempt to create system account in account with populated data let new_owner = Pubkey::new(&[9; 32]); @@ -1002,7 +1002,7 @@ mod tests { #[test] fn test_create_from_account_is_nonce_fail() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let nonce = Pubkey::new_unique(); let nonce_account = RefCell::new( @@ -1041,7 +1041,7 @@ mod tests { #[test] fn test_assign() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let new_owner = Pubkey::new(&[9; 32]); let pubkey = Pubkey::new_unique(); @@ -1084,7 +1084,7 @@ mod tests { #[test] fn test_assign_to_sysvar_with_feature() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let new_owner = sysvar::id(); let from = Pubkey::new_unique(); @@ -1135,7 +1135,7 @@ mod tests { #[test] fn test_transfer_lamports() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let from = Pubkey::new_unique(); let from_account = RefCell::new(AccountSharedData::new(100, 0, &Pubkey::new(&[2; 32]))); // account owner should not matter @@ -1174,7 +1174,7 @@ mod tests { #[test] fn test_transfer_with_seed() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let base = Pubkey::new_unique(); let base_account = RefCell::new(AccountSharedData::new(100, 0, &Pubkey::new(&[2; 32]))); // account owner should not matter @@ -1235,7 +1235,7 @@ mod tests { #[test] fn test_transfer_lamports_from_nonce_account_fail() { - let mut transaction_context = TransactionContext::new(Vec::new(), 1); + let mut transaction_context = TransactionContext::new(Vec::new(), 1, 1); let invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]); let from = Pubkey::new_unique(); let from_account = RefCell::new( diff --git a/sdk/src/transaction_context.rs b/sdk/src/transaction_context.rs index 318c6e1fc7..bef162d96f 100644 --- a/sdk/src/transaction_context.rs +++ b/sdk/src/transaction_context.rs @@ -2,7 +2,7 @@ use crate::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, - instruction::InstructionError, + instruction::{CompiledInstruction, InstructionError}, lamports::LamportsError, pubkey::Pubkey, }; @@ -31,6 +31,8 @@ pub struct TransactionContext { accounts: Pin]>>, instruction_context_capacity: usize, instruction_context_stack: Vec, + number_of_instructions_at_transaction_level: usize, + instruction_trace: Vec>, return_data: (Pubkey, Vec), } @@ -39,6 +41,7 @@ impl TransactionContext { pub fn new( transaction_accounts: Vec, instruction_context_capacity: usize, + number_of_instructions_at_transaction_level: usize, ) -> Self { let (account_keys, accounts): (Vec, Vec>) = transaction_accounts @@ -50,20 +53,25 @@ impl TransactionContext { accounts: Pin::new(accounts.into_boxed_slice()), instruction_context_capacity, instruction_context_stack: Vec::with_capacity(instruction_context_capacity), + number_of_instructions_at_transaction_level, + instruction_trace: Vec::with_capacity(number_of_instructions_at_transaction_level), return_data: (Pubkey::default(), Vec::new()), } } - /// Used by the bank in the runtime to write back the processed accounts - pub fn deconstruct(self) -> Vec { - Vec::from(Pin::into_inner(self.account_keys)) - .into_iter() - .zip( - Vec::from(Pin::into_inner(self.accounts)) - .into_iter() - .map(|account| account.into_inner()), - ) - .collect() + /// Used by the bank in the runtime to write back the processed accounts and recorded instructions + pub fn deconstruct(self) -> (Vec, Vec>) { + ( + Vec::from(Pin::into_inner(self.account_keys)) + .into_iter() + .zip( + Vec::from(Pin::into_inner(self.accounts)) + .into_iter() + .map(|account| account.into_inner()), + ) + .collect(), + self.instruction_trace, + ) } /// Used in mock_process_instruction @@ -143,6 +151,12 @@ impl TransactionContext { if self.instruction_context_stack.len() >= self.instruction_context_capacity { return Err(InstructionError::CallDepth); } + if self.instruction_context_stack.is_empty() { + debug_assert!( + self.instruction_trace.len() < self.number_of_instructions_at_transaction_level + ); + self.instruction_trace.push(Vec::new()); + } self.instruction_context_stack.push(InstructionContext { program_accounts: program_accounts.to_vec(), instruction_accounts: instruction_accounts.to_vec(), @@ -188,6 +202,13 @@ impl TransactionContext { self.return_data = (program_id, data); Ok(()) } + + /// Used by the runtime when a new CPI instruction begins + pub fn record_compiled_instruction(&mut self, instruction: CompiledInstruction) { + if let Some(records) = self.instruction_trace.last_mut() { + records.push(instruction); + } + } } /// Loaded instruction shared between runtime and programs.