diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index e7a867506d..9b7d77458e 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -17,6 +17,7 @@ use solana_sdk::{ account::Account, clock::Slot, hash::Hash, + message::Message, native_loader, nonce, pubkey::Pubkey, transaction::Result, @@ -155,9 +156,12 @@ 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(|(i, key)| { - !message.program_ids().contains(key) || message.is_key_passed_to_program(*i) - }) { + for (i, key) in message + .account_keys + .iter() + .enumerate() + .filter(|(i, key)| Self::is_non_loader_key(message, key, *i)) + { let (account, rent) = AccountsDB::load(storage, ancestors, accounts_index, key) .and_then(|(mut account, _)| { if message.is_writable(i) && !account.executable { @@ -615,6 +619,10 @@ impl Accounts { self.accounts_db.add_root(slot) } + fn is_non_loader_key(message: &Message, key: &Pubkey, key_index: usize) -> bool { + !message.program_ids().contains(&key) || message.is_key_passed_to_program(key_index) + } + fn collect_accounts_to_store<'a>( &self, txs: &'a [Transaction], @@ -650,6 +658,7 @@ impl Accounts { .account_keys .iter() .enumerate() + .filter(|(i, key)| Self::is_non_loader_key(message, key, *i)) .zip(acc.0.iter_mut()) { nonce_utils::prepare_if_nonce_account( diff --git a/runtime/src/bank/mod.rs b/runtime/src/bank/mod.rs index d426dec397..177656ad7a 100644 --- a/runtime/src/bank/mod.rs +++ b/runtime/src/bank/mod.rs @@ -5731,4 +5731,44 @@ mod tests { let result = bank.process_transaction(&tx); assert_eq!(result, Ok(())); } + + #[test] + fn test_account_ids_after_program_ids() { + solana_logger::setup(); + let (genesis_config, mint_keypair) = create_genesis_config(500); + let mut bank = Bank::new(&genesis_config); + + let from_pubkey = Pubkey::new_rand(); + let to_pubkey = Pubkey::new_rand(); + + let account_metas = vec![ + AccountMeta::new(from_pubkey, false), + AccountMeta::new(to_pubkey, false), + ]; + + let instruction = Instruction::new(solana_vote_program::id(), &10, account_metas); + let mut tx = Transaction::new_signed_with_payer( + &[instruction], + Some(&mint_keypair.pubkey()), + &[&mint_keypair], + bank.last_blockhash(), + ); + + tx.message.account_keys.push(Pubkey::new_rand()); + + fn mock_vote_processor( + _pubkey: &Pubkey, + _ka: &[KeyedAccount], + _data: &[u8], + ) -> std::result::Result<(), InstructionError> { + Ok(()) + } + + bank.add_instruction_processor(solana_vote_program::id(), mock_vote_processor); + let result = bank.process_transaction(&tx); + assert_eq!(result, Ok(())); + let account = bank.get_account(&solana_vote_program::id()).unwrap(); + info!("account: {:?}", account); + assert!(account.executable); + } }