Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 20 additions & 77 deletions program-runtime/src/instruction_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -490,7 +467,7 @@ impl InstructionProcessor {

let (
message,
executable_accounts,
program_indices,
accounts,
keyed_account_indices_reordered,
caller_write_privileges,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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())),
Expand Down Expand Up @@ -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,
Expand All @@ -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() {
Expand All @@ -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();
Expand All @@ -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(
Expand Down
20 changes: 5 additions & 15 deletions program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,6 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
let message = Message::new(&[instruction.clone()], None);
let program_id_index = message.instructions[0].program_id_index as usize;
let program_id = message.account_keys[program_id_index];
let program_account_info = || {
for account_info in account_infos {
if account_info.unsigned_key() == &program_id {
return account_info;
}
}
panic!("Program id {} wasn't found in account_infos", program_id);
};
let demote_program_write_locks =
invoke_context.is_feature_active(&demote_program_write_locks::id());
// TODO don't have the caller's keyed_accounts so can't validate writer or signer escalation or deescalation yet
Expand All @@ -274,6 +266,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {

stable_log::program_invoke(&logger, &program_id, invoke_context.invoke_depth());

// Convert AccountInfos into Accounts
fn ai_to_a(ai: &AccountInfo) -> AccountSharedData {
AccountSharedData::from(Account {
lamports: ai.lamports(),
Expand All @@ -283,12 +276,6 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
rent_epoch: ai.rent_epoch,
})
}
let executables = vec![(
program_id,
Rc::new(RefCell::new(ai_to_a(program_account_info()))),
)];

// Convert AccountInfos into Accounts
let mut accounts = vec![];
'outer: for key in &message.account_keys {
for account_info in account_infos {
Expand All @@ -304,6 +291,9 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
message.account_keys.len(),
"Missing or not enough accounts passed to invoke"
);
let (program_account_index, _program_account) =
invoke_context.get_account(&program_id).unwrap();
let program_indices = vec![program_account_index];

// Check Signers
for account_info in account_infos {
Expand Down Expand Up @@ -331,7 +321,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {

InstructionProcessor::process_cross_program_instruction(
&message,
&executables,
&program_indices,
&accounts,
&caller_privileges,
invoke_context,
Expand Down
48 changes: 28 additions & 20 deletions programs/bpf_loader/src/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2229,14 +2229,15 @@ where
let mut accounts = Vec::with_capacity(account_keys.len());
let mut refs = Vec::with_capacity(account_keys.len());
for (i, ref account_key) in account_keys.iter().enumerate() {
let account = invoke_context.get_account(account_key).ok_or_else(|| {
ic_msg!(
invoke_context,
"Instruction references an unknown account {}",
account_key
);
SyscallError::InstructionError(InstructionError::MissingAccount)
})?;
let (_account_index, account) =
invoke_context.get_account(account_key).ok_or_else(|| {
ic_msg!(
invoke_context,
"Instruction references an unknown account {}",
account_key
);
SyscallError::InstructionError(InstructionError::MissingAccount)
})?;

if i == program_account_index || account.borrow().executable() {
// Use the known account
Expand Down Expand Up @@ -2321,14 +2322,16 @@ fn get_upgradeable_executable(
callee_program_id: &Pubkey,
program_account: &Rc<RefCell<AccountSharedData>>,
invoke_context: &Ref<&mut dyn InvokeContext>,
) -> Result<Option<(Pubkey, Rc<RefCell<AccountSharedData>>)>, EbpfError<BpfError>> {
) -> Result<Option<usize>, EbpfError<BpfError>> {
if program_account.borrow().owner() == &bpf_loader_upgradeable::id() {
match program_account.borrow().state() {
Ok(UpgradeableLoaderState::Program {
programdata_address,
}) => {
if let Some(account) = invoke_context.get_account(&programdata_address) {
Ok(Some((programdata_address, account)))
if let Some((programdata_account_index, _programdata_account)) =
invoke_context.get_account(&programdata_address)
{
Ok(Some(programdata_account_index))
} else {
ic_msg!(
invoke_context,
Expand Down Expand Up @@ -2364,7 +2367,7 @@ fn call<'a>(
) -> Result<u64, EbpfError<BpfError>> {
let (
message,
executables,
program_indices,
accounts,
account_refs,
caller_write_privileges,
Expand Down Expand Up @@ -2442,16 +2445,21 @@ fn call<'a>(
let program_account = accounts
.get(callee_program_id_index)
.ok_or_else(|| {
ic_msg!(invoke_context, "Unknown program {}", callee_program_id,);
ic_msg!(invoke_context, "Unknown program {}", callee_program_id);
SyscallError::InstructionError(InstructionError::MissingAccount)
})?
.1
.clone();
let programdata_executable =
get_upgradeable_executable(&callee_program_id, &program_account, &invoke_context)?;
let mut executables = vec![(callee_program_id, program_account)];
if let Some(executable) = programdata_executable {
executables.push(executable);
let (program_account_index, _program_account) =
invoke_context.get_account(&callee_program_id).ok_or(
SyscallError::InstructionError(InstructionError::MissingAccount),
)?;

let mut program_indices = vec![program_account_index];
if let Some(programdata_account_index) =
get_upgradeable_executable(&callee_program_id, &program_account, &invoke_context)?
{
program_indices.push(programdata_account_index);
}

// Record the instruction
Expand All @@ -2460,7 +2468,7 @@ fn call<'a>(

(
message,
executables,
program_indices,
accounts,
account_refs,
caller_write_privileges,
Expand All @@ -2473,7 +2481,7 @@ fn call<'a>(
#[allow(clippy::deref_addrof)]
match InstructionProcessor::process_cross_program_instruction(
&message,
&executables,
&program_indices,
&accounts,
&caller_write_privileges,
*(&mut *(syscall.get_context_mut()?)),
Expand Down
Loading