diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index e20ecfdd6c..a2b684b0ef 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -18,6 +18,7 @@ use solana_sdk::{ account::Account, clock::Slot, hash::Hash, + message::Message, native_loader, nonce, pubkey::Pubkey, transaction::Result, @@ -156,9 +157,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 { @@ -616,6 +620,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], @@ -651,6 +659,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.rs b/runtime/src/bank.rs index 781e4e342b..9d096f4b2b 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -5758,4 +5758,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( + vec![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); + } }