diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 62b1230fee..d91fa1fcef 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -127,17 +127,13 @@ impl Accounts { // If a fee can pay for execution then the program will be scheduled let mut accounts: TransactionAccounts = Vec::with_capacity(message.account_keys.len()); let mut tx_rent: TransactionRent = 0; - for (i, key) in message - .account_keys - .iter() - .enumerate() - .filter(|(_, key)| !message.program_ids().contains(key)) - { + for (i, key) in message.account_keys.iter().enumerate().filter(|(i, key)| { + !message.program_ids().contains(key) || message.is_key_passed_to_program(*i) + }) { let (account, rent) = AccountsDB::load(storage, ancestors, accounts_index, key) .and_then(|(mut account, _)| { - let rent_due: u64; - if message.is_writable(i) { - rent_due = rent_collector.update(&mut account); + if message.is_writable(i) && !account.executable { + let rent_due = rent_collector.update(&mut account); Some((account, rent_due)) } else { Some((account, 0)) @@ -1125,12 +1121,12 @@ mod tests { let loaded_accounts = load_accounts(tx, &accounts, &mut error_counters); - assert_eq!(error_counters.invalid_account_for_fee, 1); + assert_eq!(error_counters.account_not_found, 1); assert_eq!(loaded_accounts.len(), 1); assert_eq!( loaded_accounts[0], ( - Err(TransactionError::InvalidAccountForFee), + Err(TransactionError::AccountNotFound), Some(HashAgeKind::Extant) ) ); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index cd9b1f66cb..7e06bf30dd 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -5568,7 +5568,6 @@ mod tests { } #[test] - #[should_panic(expected = "index out of bounds: the len is 3 but the index is 3")] fn test_transaction_with_program_ids_passed_to_programs() { let (genesis_config, mint_keypair) = create_genesis_config(500); let mut bank = Bank::new(&genesis_config); diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 1d39997d7b..93fe6726d0 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -332,10 +332,6 @@ impl MessageProcessor { .ok_or(TransactionError::InvalidAccountIndex)?; let executable_accounts = &loaders[executable_index]; - // TODO: panics on an index out of bounds if an executable - // account is also included as a regular account for an instruction, because the - // executable account is not passed in as part of the accounts slice - // See test: bank::tests::test_transaction_with_program_ids_passed_to_programs let program_accounts: Vec<_> = instruction .accounts .iter() diff --git a/sdk/src/message.rs b/sdk/src/message.rs index f444ca7867..386fcd46a4 100644 --- a/sdk/src/message.rs +++ b/sdk/src/message.rs @@ -7,6 +7,7 @@ use crate::{ short_vec, system_instruction, }; use itertools::Itertools; +use std::convert::TryFrom; fn position(keys: &[Pubkey], key: &Pubkey) -> u8 { keys.iter().position(|k| k == key).unwrap() as u8 @@ -233,6 +234,17 @@ impl Message { .collect() } + pub fn is_key_passed_to_program(&self, index: usize) -> bool { + if let Ok(index) = u8::try_from(index) { + for ix in self.instructions.iter() { + if ix.accounts.contains(&index) { + return true; + } + } + } + false + } + pub fn program_position(&self, index: usize) -> Option { let program_ids = self.program_ids(); program_ids