@ -127,17 +127,13 @@ impl Accounts {
|
|||||||
// If a fee can pay for execution then the program will be scheduled
|
// 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 accounts: TransactionAccounts = Vec::with_capacity(message.account_keys.len());
|
||||||
let mut tx_rent: TransactionRent = 0;
|
let mut tx_rent: TransactionRent = 0;
|
||||||
for (i, key) in message
|
for (i, key) in message.account_keys.iter().enumerate().filter(|(i, key)| {
|
||||||
.account_keys
|
!message.program_ids().contains(key) || message.is_key_passed_to_program(*i)
|
||||||
.iter()
|
}) {
|
||||||
.enumerate()
|
|
||||||
.filter(|(_, key)| !message.program_ids().contains(key))
|
|
||||||
{
|
|
||||||
let (account, rent) = AccountsDB::load(storage, ancestors, accounts_index, key)
|
let (account, rent) = AccountsDB::load(storage, ancestors, accounts_index, key)
|
||||||
.and_then(|(mut account, _)| {
|
.and_then(|(mut account, _)| {
|
||||||
let rent_due: u64;
|
if message.is_writable(i) && !account.executable {
|
||||||
if message.is_writable(i) {
|
let rent_due = rent_collector.update(&mut account);
|
||||||
rent_due = rent_collector.update(&mut account);
|
|
||||||
Some((account, rent_due))
|
Some((account, rent_due))
|
||||||
} else {
|
} else {
|
||||||
Some((account, 0))
|
Some((account, 0))
|
||||||
@ -1125,12 +1121,12 @@ mod tests {
|
|||||||
|
|
||||||
let loaded_accounts = load_accounts(tx, &accounts, &mut error_counters);
|
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.len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
loaded_accounts[0],
|
loaded_accounts[0],
|
||||||
(
|
(
|
||||||
Err(TransactionError::InvalidAccountForFee),
|
Err(TransactionError::AccountNotFound),
|
||||||
Some(HashAgeKind::Extant)
|
Some(HashAgeKind::Extant)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -5566,4 +5566,46 @@ mod tests {
|
|||||||
assert_eq!(bank.get_balance(&from_pubkey), 80);
|
assert_eq!(bank.get_balance(&from_pubkey), 80);
|
||||||
assert_eq!(bank.get_balance(&to_pubkey), 20);
|
assert_eq!(bank.get_balance(&to_pubkey), 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
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);
|
||||||
|
|
||||||
|
fn mock_process_instruction(
|
||||||
|
_program_id: &Pubkey,
|
||||||
|
_keyed_accounts: &[KeyedAccount],
|
||||||
|
_data: &[u8],
|
||||||
|
) -> result::Result<(), InstructionError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let mock_program_id = Pubkey::new(&[2u8; 32]);
|
||||||
|
bank.add_instruction_processor(mock_program_id, mock_process_instruction);
|
||||||
|
|
||||||
|
let from_pubkey = Pubkey::new_rand();
|
||||||
|
let to_pubkey = Pubkey::new_rand();
|
||||||
|
let dup_pubkey = from_pubkey.clone();
|
||||||
|
let from_account = Account::new(100, 1, &mock_program_id);
|
||||||
|
let to_account = Account::new(0, 1, &mock_program_id);
|
||||||
|
bank.store_account(&from_pubkey, &from_account);
|
||||||
|
bank.store_account(&to_pubkey, &to_account);
|
||||||
|
|
||||||
|
let account_metas = vec![
|
||||||
|
AccountMeta::new(from_pubkey, false),
|
||||||
|
AccountMeta::new(to_pubkey, false),
|
||||||
|
AccountMeta::new(dup_pubkey, false),
|
||||||
|
AccountMeta::new(mock_program_id, false),
|
||||||
|
];
|
||||||
|
let instruction = Instruction::new(mock_program_id, &10, account_metas);
|
||||||
|
let tx = Transaction::new_signed_with_payer(
|
||||||
|
vec![instruction],
|
||||||
|
Some(&mint_keypair.pubkey()),
|
||||||
|
&[&mint_keypair],
|
||||||
|
bank.last_blockhash(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = bank.process_transaction(&tx);
|
||||||
|
assert_eq!(result, Ok(()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,9 +336,6 @@ impl MessageProcessor {
|
|||||||
.ok_or(TransactionError::InvalidAccountIndex)?;
|
.ok_or(TransactionError::InvalidAccountIndex)?;
|
||||||
let executable_accounts = &loaders[executable_index];
|
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
|
|
||||||
let program_accounts: Vec<_> = instruction
|
let program_accounts: Vec<_> = instruction
|
||||||
.accounts
|
.accounts
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -7,6 +7,7 @@ use crate::{
|
|||||||
short_vec, system_instruction,
|
short_vec, system_instruction,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
fn position(keys: &[Pubkey], key: &Pubkey) -> u8 {
|
fn position(keys: &[Pubkey], key: &Pubkey) -> u8 {
|
||||||
keys.iter().position(|k| k == key).unwrap() as u8
|
keys.iter().position(|k| k == key).unwrap() as u8
|
||||||
@ -233,6 +234,17 @@ impl Message {
|
|||||||
.collect()
|
.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<usize> {
|
pub fn program_position(&self, index: usize) -> Option<usize> {
|
||||||
let program_ids = self.program_ids();
|
let program_ids = self.program_ids();
|
||||||
program_ids
|
program_ids
|
||||||
|
Reference in New Issue
Block a user