diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 3c8a91e0f2b2a9..39cfcbbc432518 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -245,7 +245,10 @@ impl Accounts { feature_set.is_active(&feature_set::demote_program_write_locks::id()); for (i, key) in message.account_keys_iter().enumerate() { - let account = if message.is_non_loader_key(i) { + let account = if !message.is_non_loader_key(i) { + // Fill in an empty account for the program slots. + AccountSharedData::default() + } else { if payer_index.is_none() { payer_index = Some(i); } @@ -285,12 +288,11 @@ impl Accounts { programdata_address, }) = account.state() { - if let Some(account) = self + if let Some((programdata_account, _)) = self .accounts_db .load_with_fixed_root(ancestors, &programdata_address) - .map(|(account, _)| account) { - account_deps.push((programdata_address, account)); + account_deps.push((programdata_address, programdata_account)); } else { error_counters.account_not_found += 1; return Err(TransactionError::ProgramAccountNotFound); @@ -306,9 +308,6 @@ impl Accounts { account } - } else { - // Fill in an empty account for the program slots. - AccountSharedData::default() }; accounts.push((*key, account)); } @@ -327,50 +326,47 @@ impl Accounts { let payer_account = &mut accounts[payer_index].1; if payer_account.lamports() == 0 { error_counters.account_not_found += 1; - Err(TransactionError::AccountNotFound) - } else { - let min_balance = - match get_system_account_kind(payer_account).ok_or_else(|| { - error_counters.invalid_account_for_fee += 1; - TransactionError::InvalidAccountForFee - })? { - SystemAccountKind::System => 0, - SystemAccountKind::Nonce => { - // Should we ever allow a fees charge to zero a nonce account's - // balance. The state MUST be set to uninitialized in that case - rent_collector.rent.minimum_balance(nonce::State::size()) - } - }; - - if payer_account.lamports() < fee + min_balance { - error_counters.insufficient_funds += 1; - Err(TransactionError::InsufficientFundsForFee) - } else { - payer_account - .checked_sub_lamports(fee) - .map_err(|_| TransactionError::InsufficientFundsForFee)?; - - let message = tx.message(); - let program_indices = message - .program_instructions_iter() - .map(|(program_id, _ix)| { - self.load_executable_accounts(ancestors, program_id, error_counters) - .map(|programs| { - let base_index = accounts.len(); - accounts.append(&mut programs.clone()); - (base_index..base_index + programs.len()) - .collect::>() - }) - }) - .collect::>>>()?; - Ok(LoadedTransaction { - accounts, - program_indices, - rent: tx_rent, - rent_debits, - }) + return Err(TransactionError::AccountNotFound); + } + let min_balance = match get_system_account_kind(payer_account).ok_or_else(|| { + error_counters.invalid_account_for_fee += 1; + TransactionError::InvalidAccountForFee + })? { + SystemAccountKind::System => 0, + SystemAccountKind::Nonce => { + // Should we ever allow a fees charge to zero a nonce account's + // balance. The state MUST be set to uninitialized in that case + rent_collector.rent.minimum_balance(nonce::State::size()) } + }; + + if payer_account.lamports() < fee + min_balance { + error_counters.insufficient_funds += 1; + return Err(TransactionError::InsufficientFundsForFee); } + payer_account + .checked_sub_lamports(fee) + .map_err(|_| TransactionError::InsufficientFundsForFee)?; + + let message = tx.message(); + let program_indices = message + .instructions() + .iter() + .map(|instruction| { + self.load_executable_accounts( + ancestors, + &mut accounts, + instruction.program_id_index as usize, + error_counters, + ) + }) + .collect::>>>()?; + Ok(LoadedTransaction { + accounts, + program_indices, + rent: tx_rent, + rent_debits, + }) } else { error_counters.account_not_found += 1; Err(TransactionError::AccountNotFound) @@ -381,35 +377,35 @@ impl Accounts { fn load_executable_accounts( &self, ancestors: &Ancestors, - program_id: &Pubkey, + accounts: &mut Vec<(Pubkey, AccountSharedData)>, + mut program_account_index: usize, error_counters: &mut ErrorCounters, - ) -> Result> { - let mut accounts = Vec::new(); + ) -> Result> { + let mut account_indices = Vec::new(); + let mut program_id = accounts[program_account_index].0; let mut depth = 0; - let mut program_id = *program_id; - loop { - if native_loader::check_id(&program_id) { - // At the root of the chain, ready to dispatch - break; - } - + while !native_loader::check_id(&program_id) { if depth >= 5 { error_counters.call_chain_too_deep += 1; return Err(TransactionError::CallChainTooDeep); } depth += 1; - let program = match self + program_account_index = match self .accounts_db .load_with_fixed_root(ancestors, &program_id) - .map(|(account, _)| account) { - Some(program) => program, + Some((program_account, _)) => { + let account_index = accounts.len(); + accounts.push((program_id, program_account)); + account_index + } None => { error_counters.account_not_found += 1; return Err(TransactionError::ProgramAccountNotFound); } }; + let program = &accounts[program_account_index].1; if !program.executable() { error_counters.invalid_program_for_execution += 1; return Err(TransactionError::InvalidProgramForExecution); @@ -424,26 +420,31 @@ impl Accounts { programdata_address, }) = program.state() { - if let Some(program) = self + let programdata_account_index = match self .accounts_db .load_with_fixed_root(ancestors, &programdata_address) - .map(|(account, _)| account) { - accounts.insert(0, (programdata_address, program)); - } else { - error_counters.account_not_found += 1; - return Err(TransactionError::ProgramAccountNotFound); - } + Some((programdata_account, _)) => { + let account_index = accounts.len(); + accounts.push((programdata_address, programdata_account)); + account_index + } + None => { + error_counters.account_not_found += 1; + return Err(TransactionError::ProgramAccountNotFound); + } + }; + account_indices.insert(0, programdata_account_index); } else { error_counters.invalid_program_for_execution += 1; return Err(TransactionError::InvalidProgramForExecution); } } - accounts.insert(0, (program_id, program)); + account_indices.insert(0, program_account_index); program_id = program_owner; } - Ok(accounts) + Ok(account_indices) } pub fn load_accounts( @@ -1707,10 +1708,16 @@ mod tests { let mut error_counters = ErrorCounters::default(); let ancestors = vec![(0, 0)].into_iter().collect(); + let keypair = Keypair::new(); + let mut account = AccountSharedData::new(1, 0, &Pubkey::default()); + account.set_executable(true); + accounts.store_slow_uncached(0, &keypair.pubkey(), &account); + assert_eq!( accounts.load_executable_accounts( &ancestors, - &solana_sdk::pubkey::new_rand(), + &mut vec![(keypair.pubkey(), account)], + 0, &mut error_counters ), Err(TransactionError::ProgramAccountNotFound)