Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Removes search for accounts and unsafe lifetime transmute in InvokeCo…
Browse files Browse the repository at this point in the history
…ntext::push().
  • Loading branch information
Lichtso committed Sep 20, 2021
1 parent 7a785e0 commit 87cf637
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 43 deletions.
20 changes: 19 additions & 1 deletion program-runtime/src/instruction_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,16 @@ impl InstructionProcessor {
caller_write_privileges.push(caller_keyed_accounts[*index].is_writable());
}
};
let account_indices = message
.account_keys
.iter()
.map(|account_key| {
invoke_context
.get_account(account_key)
.ok_or(InstructionError::MissingAccount)
.map(|(account_index, _account)| account_index)
})
.collect::<Result<Vec<_>, InstructionError>>()?;
let accounts = message
.account_keys
.iter()
Expand All @@ -538,6 +548,7 @@ impl InstructionProcessor {
InstructionProcessor::process_cross_program_instruction(
&message,
&program_indices,
&account_indices,
&accounts,
&caller_write_privileges,
*invoke_context,
Expand All @@ -564,6 +575,7 @@ impl InstructionProcessor {
pub fn process_cross_program_instruction(
message: &Message,
program_indices: &[usize],
account_indices: &[usize],
accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
caller_write_privileges: &[bool],
invoke_context: &mut dyn InvokeContext,
Expand All @@ -583,7 +595,13 @@ impl InstructionProcessor {
invoke_context.set_return_data(None);

// Invoke callee
invoke_context.push(program_id, message, instruction, program_indices, accounts)?;
invoke_context.push(
program_id,
message,
instruction,
program_indices,
account_indices,
)?;

let mut instruction_processor = InstructionProcessor::default();
for (program_id, process_instruction) in invoke_context.get_programs().iter() {
Expand Down
12 changes: 12 additions & 0 deletions program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,17 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
message.account_keys.len(),
"Missing or not enough accounts passed to invoke"
);
let account_indices = message
.account_keys
.iter()
.map(|account_key| {
invoke_context
.get_account(account_key)
.ok_or(InstructionError::MissingAccount)
.map(|(account_index, _account)| account_index)
})
.collect::<Result<Vec<_>, InstructionError>>()
.unwrap();
let (program_account_index, _program_account) =
invoke_context.get_account(&program_id).unwrap();
let program_indices = vec![program_account_index];
Expand Down Expand Up @@ -322,6 +333,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
InstructionProcessor::process_cross_program_instruction(
&message,
&program_indices,
&account_indices,
&accounts,
&caller_privileges,
invoke_context,
Expand Down
11 changes: 8 additions & 3 deletions programs/bpf_loader/src/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,7 @@ struct AccountReferences<'a> {
rent_epoch: u64,
}
type TranslatedAccounts<'a> = (
Vec<usize>,
Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>,
Vec<Option<AccountReferences<'a>>>,
);
Expand Down Expand Up @@ -2052,14 +2053,16 @@ where
{
let demote_program_write_locks =
invoke_context.is_feature_active(&demote_program_write_locks::id());
let mut account_indices = Vec::with_capacity(message.account_keys.len());
let mut accounts = Vec::with_capacity(message.account_keys.len());
let mut refs = Vec::with_capacity(message.account_keys.len());
for (i, account_key) in message.account_keys.iter().enumerate() {
if let Some((_account_index, account)) = invoke_context.get_account(account_key) {
if let Some((account_index, account)) = invoke_context.get_account(account_key) {
if i == message.instructions[0].program_id_index as usize
|| account.borrow().executable()
{
// Use the known account
account_indices.push(account_index);
accounts.push((*account_key, account));
refs.push(None);
continue;
Expand All @@ -2075,6 +2078,7 @@ where
account.set_executable(account_ref.executable);
account.set_rent_epoch(account_ref.rent_epoch);
}
account_indices.push(account_index);
accounts.push((*account_key, account));
refs.push(if message.is_writable(i, demote_program_write_locks) {
Some(account_ref)
Expand All @@ -2092,7 +2096,7 @@ where
return Err(SyscallError::InstructionError(InstructionError::MissingAccount).into());
}

Ok((accounts, refs))
Ok((account_indices, accounts, refs))
}

fn check_instruction_size(
Expand Down Expand Up @@ -2176,7 +2180,7 @@ fn call<'a>(
&instruction.data,
invoke_context.is_feature_active(&close_upgradeable_program_accounts::id()),
)?;
let (accounts, account_refs) = syscall.translate_accounts(
let (account_indices, accounts, account_refs) = syscall.translate_accounts(
&message,
account_infos_addr,
account_infos_len,
Expand All @@ -2191,6 +2195,7 @@ fn call<'a>(
InstructionProcessor::process_cross_program_instruction(
&message,
&program_indices,
&account_indices,
&accounts,
&caller_write_privileges,
*invoke_context,
Expand Down
59 changes: 22 additions & 37 deletions runtime/src/message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,14 @@ impl<'a> ThisInvokeContext<'a> {
fee_calculator,
return_data: None,
};
invoke_context.push(program_id, message, instruction, program_indices, accounts)?;
let account_indices = (0..accounts.len()).collect::<Vec<usize>>();
invoke_context.push(
program_id,
message,
instruction,
program_indices,
&account_indices,
)?;
Ok(invoke_context)
}
}
Expand All @@ -130,7 +137,7 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
message: &Message,
instruction: &CompiledInstruction,
program_indices: &[usize],
instruction_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
account_indices: &[usize],
) -> Result<(), InstructionError> {
if self.invoke_stack.len() > self.compute_budget.max_invoke_depth {
return Err(InstructionError::CallDepth);
Expand Down Expand Up @@ -161,44 +168,17 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
&self.accounts[*account_index].1 as &RefCell<AccountSharedData>,
)
})
.chain(instruction.accounts.iter().map(|index| {
let index = *index as usize;
.chain(instruction.accounts.iter().map(|index_in_instruction| {
let index_in_instruction = *index_in_instruction as usize;
let account_index = account_indices[index_in_instruction];
(
message.is_signer(index),
message.is_writable(index, demote_program_write_locks),
&instruction_accounts[index].0,
&instruction_accounts[index].1 as &RefCell<AccountSharedData>,
message.is_signer(index_in_instruction),
message.is_writable(index_in_instruction, demote_program_write_locks),
&self.accounts[account_index].0,
&self.accounts[account_index].1 as &RefCell<AccountSharedData>,
)
}))
.collect::<Vec<_>>();

// Alias the keys and account references in the provided keyed_accounts
// with the ones already existing in self, so that the lifetime 'a matches.
fn transmute_lifetime<'a, 'b, T: Sized>(value: &'a T) -> &'b T {
unsafe { std::mem::transmute(value) }
}
let keyed_accounts = keyed_accounts
.iter()
.map(|(is_signer, is_writable, search_key, account)| {
self.accounts
.iter()
.position(|(key, _account)| key == *search_key)
.map(|index| {
// TODO
// Currently we are constructing new accounts on the stack
// before calling MessageProcessor::process_cross_program_instruction
// Ideally we would recycle the existing accounts here.
(
*is_signer,
*is_writable,
&self.accounts[index].0,
// &self.accounts[index] as &RefCell<AccountSharedData>
transmute_lifetime(*account),
)
})
})
.collect::<Option<Vec<_>>>()
.ok_or(InstructionError::InvalidArgument)?;
self.invoke_stack.push(InvokeContextStackFrame::new(
*key,
create_keyed_accounts_unified(keyed_accounts.as_slice()),
Expand Down Expand Up @@ -671,6 +651,7 @@ mod tests {
));
metas.push(AccountMeta::new(*program_id, false));
}
let account_indices = (0..accounts.len()).collect::<Vec<usize>>();

let message = Message::new(
&[Instruction::new_with_bytes(invoke_stack[0], &[0], metas)],
Expand Down Expand Up @@ -709,7 +690,7 @@ mod tests {
&message,
&message.instructions[0],
&[],
&accounts,
&account_indices,
)
{
break;
Expand Down Expand Up @@ -1217,6 +1198,7 @@ mod tests {
),
(callee_program_id, Rc::new(RefCell::new(program_account))),
];
let account_indices = [0, 1, 2];
let program_indices = vec![3];

let programs: Vec<(_, ProcessInstructionWithContext)> =
Expand Down Expand Up @@ -1274,6 +1256,7 @@ mod tests {
InstructionProcessor::process_cross_program_instruction(
&message,
&program_indices,
&account_indices,
&accounts,
&caller_write_privileges,
&mut invoke_context,
Expand All @@ -1288,6 +1271,7 @@ mod tests {
InstructionProcessor::process_cross_program_instruction(
&message,
&program_indices,
&account_indices,
&accounts,
&caller_write_privileges,
&mut invoke_context,
Expand Down Expand Up @@ -1348,6 +1332,7 @@ mod tests {
InstructionProcessor::process_cross_program_instruction(
&message,
&program_indices,
&account_indices,
&accounts,
&caller_write_privileges,
&mut invoke_context,
Expand Down
4 changes: 2 additions & 2 deletions sdk/src/process_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub trait InvokeContext {
message: &Message,
instruction: &CompiledInstruction,
program_indices: &[usize],
instruction_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
account_indices: &[usize],
) -> Result<(), InstructionError>;
/// Pop a stack frame from the invocation stack
///
Expand Down Expand Up @@ -478,7 +478,7 @@ impl<'a> InvokeContext for MockInvokeContext<'a> {
_message: &Message,
_instruction: &CompiledInstruction,
_program_indices: &[usize],
_instruction_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
_account_indices: &[usize],
) -> Result<(), InstructionError> {
self.invoke_stack.push(InvokeContextStackFrame::new(
*_key,
Expand Down

0 comments on commit 87cf637

Please sign in to comment.