Index loaders / executable accounts (#19469)

* Appends loaders / executable_accounts to accounts in transaction loading.

* Adds indices to loaders / executable_accounts.

* Moves MessageProcessor::create_keyed_accounts() into InvokeContext::push().

* Removes "executable_accounts",
now referenced by transaction wide index into "accounts".

* Removes create_pre_accounts() from InstructionProcessor,
as it is already in MessageProcessor.

* Collect program account indices directly in load_executable_accounts().
This commit is contained in:
Alexander Meißner
2021-09-10 08:36:21 +02:00
committed by GitHub
parent 4386e09710
commit 88c1b8f047
7 changed files with 344 additions and 384 deletions

View File

@ -342,29 +342,6 @@ impl InstructionProcessor {
}
}
/// Create the KeyedAccounts that will be passed to the program
pub fn create_keyed_accounts<'a>(
message: &'a Message,
instruction: &'a CompiledInstruction,
executable_accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
demote_program_write_locks: bool,
) -> Vec<(bool, bool, &'a Pubkey, &'a RefCell<AccountSharedData>)> {
executable_accounts
.iter()
.map(|(key, account)| (false, false, key, account as &RefCell<AccountSharedData>))
.chain(instruction.accounts.iter().map(|index| {
let index = *index as usize;
(
message.is_signer(index),
message.is_writable(index, demote_program_write_locks),
&accounts[index].0,
&accounts[index].1 as &RefCell<AccountSharedData>,
)
}))
.collect::<Vec<_>>()
}
/// Process an instruction
/// This method calls the instruction's program entrypoint method
pub fn process_instruction(
@ -490,7 +467,7 @@ impl InstructionProcessor {
let (
message,
executable_accounts,
program_indices,
accounts,
keyed_account_indices_reordered,
caller_write_privileges,
@ -535,13 +512,12 @@ impl InstructionProcessor {
invoke_context.record_instruction(&instruction);
let program_account =
invoke_context
.get_account(&callee_program_id)
.ok_or_else(|| {
ic_msg!(invoke_context, "Unknown program {}", callee_program_id);
InstructionError::MissingAccount
})?;
let (program_account_index, program_account) = invoke_context
.get_account(&callee_program_id)
.ok_or_else(|| {
ic_msg!(invoke_context, "Unknown program {}", callee_program_id);
InstructionError::MissingAccount
})?;
if !program_account.borrow().executable() {
ic_msg!(
invoke_context,
@ -550,13 +526,16 @@ impl InstructionProcessor {
);
return Err(InstructionError::AccountNotExecutable);
}
let programdata = if program_account.borrow().owner() == &bpf_loader_upgradeable::id() {
let mut program_indices = vec![];
if program_account.borrow().owner() == &bpf_loader_upgradeable::id() {
if let UpgradeableLoaderState::Program {
programdata_address,
} = program_account.borrow().state()?
{
if let Some(account) = invoke_context.get_account(&programdata_address) {
Some((programdata_address, account))
if let Some((programdata_account_index, _programdata_account)) =
invoke_context.get_account(&programdata_address)
{
program_indices.push(programdata_account_index);
} else {
ic_msg!(
invoke_context,
@ -573,16 +552,11 @@ impl InstructionProcessor {
);
return Err(InstructionError::MissingAccount);
}
} else {
None
};
let mut executable_accounts = vec![(callee_program_id, program_account)];
if let Some(programdata) = programdata {
executable_accounts.push(programdata);
}
program_indices.insert(0, program_account_index);
(
message,
executable_accounts,
program_indices,
accounts,
keyed_account_indices_reordered,
caller_write_privileges,
@ -592,7 +566,7 @@ impl InstructionProcessor {
#[allow(clippy::deref_addrof)]
InstructionProcessor::process_cross_program_instruction(
&message,
&executable_accounts,
&program_indices,
&accounts,
&caller_write_privileges,
*(&mut *(invoke_context.borrow_mut())),
@ -646,7 +620,7 @@ impl InstructionProcessor {
/// This method calls the instruction's program entrypoint function
pub fn process_cross_program_instruction(
message: &Message,
executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
program_indices: &[usize],
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
caller_write_privileges: &[bool],
invoke_context: &mut dyn InvokeContext,
@ -657,19 +631,8 @@ impl InstructionProcessor {
// Verify the calling program hasn't misbehaved
invoke_context.verify_and_update(instruction, accounts, caller_write_privileges)?;
// Construct keyed accounts
let demote_program_write_locks =
invoke_context.is_feature_active(&demote_program_write_locks::id());
let keyed_accounts = Self::create_keyed_accounts(
message,
instruction,
executable_accounts,
accounts,
demote_program_write_locks,
);
// Invoke callee
invoke_context.push(program_id, &keyed_accounts)?;
invoke_context.push(program_id, message, instruction, program_indices, accounts)?;
let mut instruction_processor = InstructionProcessor::default();
for (program_id, process_instruction) in invoke_context.get_programs().iter() {
@ -683,6 +646,8 @@ impl InstructionProcessor {
);
if result.is_ok() {
// Verify the called program has not misbehaved
let demote_program_write_locks =
invoke_context.is_feature_active(&demote_program_write_locks::id());
let write_privileges: Vec<bool> = (0..message.account_keys.len())
.map(|i| message.is_writable(i, demote_program_write_locks))
.collect();
@ -698,28 +663,6 @@ impl InstructionProcessor {
}
}
/// Record the initial state of the accounts so that they can be compared
/// after the instruction is processed
pub fn create_pre_accounts(
message: &Message,
instruction: &CompiledInstruction,
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
) -> Vec<PreAccount> {
let mut pre_accounts = Vec::with_capacity(instruction.accounts.len());
{
let mut work = |_unique_index: usize, account_index: usize| {
if account_index < message.account_keys.len() && account_index < accounts.len() {
let account = accounts[account_index].1.borrow();
pre_accounts.push(PreAccount::new(&accounts[account_index].0, &account));
return Ok(());
}
Err(InstructionError::MissingAccount)
};
let _ = instruction.visit_each_account(&mut work);
}
pre_accounts
}
/// Verify the results of a cross-program instruction
#[allow(clippy::too_many_arguments)]
pub fn verify_and_update(