Allow passing of program_id to programs (bp #8639) (#8670)

automerge
This commit is contained in:
mergify[bot]
2020-03-09 12:36:34 -07:00
committed by GitHub
parent f511296ee8
commit 889b06e1d4
4 changed files with 61 additions and 14 deletions

View File

@ -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)
) )
); );

View File

@ -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(()));
}
} }

View File

@ -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()

View File

@ -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