diff --git a/program-runtime/src/instruction_processor.rs b/program-runtime/src/instruction_processor.rs index 95e3804a1..072c0374b 100644 --- a/program-runtime/src/instruction_processor.rs +++ b/program-runtime/src/instruction_processor.rs @@ -377,7 +377,8 @@ impl InstructionProcessor { invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { let keyed_accounts = invoke_context.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)?; let root_id = root_account.unsigned_key(); let owner_id = &root_account.owner()?; if solana_sdk::native_loader::check_id(owner_id) { diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index 5868e3cc1..79201397d 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -327,38 +327,21 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { return Err(InstructionError::CallDepth); } - let program_id = if let Some(index_of_program_id) = program_indices.last() { - let program_id = &self.accounts[*index_of_program_id].0; - let contains = self - .invoke_stack - .iter() - .any(|frame| frame.program_id() == Some(program_id)); - let is_last = if let Some(last_frame) = self.invoke_stack.last() { - last_frame.program_id() == Some(program_id) - } else { - false - }; - if contains && !is_last { - // Reentrancy not allowed unless caller is calling itself - return Err(InstructionError::ReentrancyNotAllowed); - } - *program_id - } else { - return Err(InstructionError::UnsupportedProgramId); - }; - + let program_id = program_indices + .last() + .map(|index_of_program_id| &self.accounts[*index_of_program_id].0); if self.invoke_stack.is_empty() { let mut compute_budget = self.compute_budget; if !self.is_feature_active(&tx_wide_compute_cap::id()) && self.is_feature_active(&neon_evm_compute_budget::id()) - && program_id == crate::neon_evm_program::id() + && program_id == Some(&crate::neon_evm_program::id()) { // Bump the compute budget for neon_evm compute_budget.max_units = compute_budget.max_units.max(500_000); } if !self.is_feature_active(&requestable_heap_size::id()) && self.is_feature_active(&neon_evm_compute_budget::id()) - && program_id == crate::neon_evm_program::id() + && program_id == Some(&crate::neon_evm_program::id()) { // Bump the compute budget for neon_evm compute_budget.heap_size = Some(256_usize.saturating_mul(1024)); @@ -381,6 +364,20 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { Err(InstructionError::MissingAccount) }; instruction.visit_each_account(&mut work)?; + } else { + let contains = self + .invoke_stack + .iter() + .any(|frame| frame.program_id() == program_id); + let is_last = if let Some(last_frame) = self.invoke_stack.last() { + last_frame.program_id() == program_id + } else { + false + }; + if contains && !is_last { + // Reentrancy not allowed unless caller is calling itself + return Err(InstructionError::ReentrancyNotAllowed); + } } // Create the KeyedAccounts that will be passed to the program diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 73c539534..260cec464 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -15391,4 +15391,18 @@ pub(crate) mod tests { .unwrap(); assert_eq!(Bank::calculate_fee(&message, 1), 11); } + + #[test] + fn test_an_empty_transaction_without_program() { + let (genesis_config, mint_keypair) = create_genesis_config(1); + let bank = Bank::new_for_tests(&genesis_config); + + let destination = solana_sdk::pubkey::new_rand(); + let mut ix = system_instruction::transfer(&mint_keypair.pubkey(), &destination, 0); + ix.program_id = native_loader::id(); // Empty executable account chain + + let message = Message::new(&[ix], Some(&mint_keypair.pubkey())); + let tx = Transaction::new(&[&mint_keypair], message, genesis_config.hash()); + bank.process_transaction(&tx).unwrap(); + } } diff --git a/runtime/src/builtins.rs b/runtime/src/builtins.rs index ed3d17834..a32b7122f 100644 --- a/runtime/src/builtins.rs +++ b/runtime/src/builtins.rs @@ -17,8 +17,6 @@ fn process_instruction_with_program_logging( instruction_data: &[u8], invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { - debug_assert_eq!(first_instruction_account, 1); - let logger = invoke_context.get_logger(); let program_id = invoke_context.get_caller()?; stable_log::program_invoke(&logger, program_id, invoke_context.invoke_depth());