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
159 changes: 95 additions & 64 deletions program-runtime/src/invoke_context.rs

Large diffs are not rendered by default.

51 changes: 26 additions & 25 deletions program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,30 +249,30 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
.prepare_instruction(instruction, &signers)
.unwrap();

// Convert AccountInfos into Accounts
let mut accounts = Vec::with_capacity(instruction_accounts.len());
// Copy caller's account_info modifications into invoke_context accounts
let mut account_indices = Vec::with_capacity(instruction_accounts.len());
for instruction_account in instruction_accounts.iter() {
let account_key = invoke_context
.transaction_context
.get_key_of_account_at_index(instruction_account.index);
let account_info = account_infos
.get_key_of_account_at_index(instruction_account.index_in_transaction);
let account_info_index = account_infos
.iter()
.find(|account_info| account_info.unsigned_key() == account_key)
.position(|account_info| account_info.unsigned_key() == account_key)
.ok_or(InstructionError::MissingAccount)
.unwrap();
{
let mut account = invoke_context
.transaction_context
.get_account_at_index(instruction_account.index)
.borrow_mut();
account.copy_into_owner_from_slice(account_info.owner.as_ref());
account.set_data_from_slice(&account_info.try_borrow_data().unwrap());
account.set_lamports(account_info.lamports());
account.set_executable(account_info.executable);
account.set_rent_epoch(account_info.rent_epoch);
}
let account_info = &account_infos[account_info_index];
let mut account = invoke_context
.transaction_context
.get_account_at_index(instruction_account.index_in_transaction)
.borrow_mut();
account.copy_into_owner_from_slice(account_info.owner.as_ref());
account.set_data_from_slice(&account_info.try_borrow_data().unwrap());
account.set_lamports(account_info.lamports());
account.set_executable(account_info.executable);
account.set_rent_epoch(account_info.rent_epoch);
if instruction_account.is_writable {
accounts.push((instruction_account.index, account_info));
account_indices
.push((instruction_account.index_in_transaction, account_info_index));
}
}

Expand All @@ -285,22 +285,23 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
)
.map_err(|err| ProgramError::try_from(err).unwrap_or_else(|err| panic!("{}", err)))?;

// Copy writeable account modifications back into the caller's AccountInfos
for (account_index, account_info) in accounts.into_iter() {
// Copy invoke_context accounts modifications into caller's account_info
for (index_in_transaction, account_info_index) in account_indices.into_iter() {
let account = invoke_context
.transaction_context
.get_account_at_index(account_index);
let account_borrow = account.borrow();
**account_info.try_borrow_mut_lamports().unwrap() = account_borrow.lamports();
.get_account_at_index(index_in_transaction)
.borrow_mut();
let account_info = &account_infos[account_info_index];
**account_info.try_borrow_mut_lamports().unwrap() = account.lamports();
let mut data = account_info.try_borrow_mut_data()?;
let new_data = account_borrow.data();
if account_info.owner != account_borrow.owner() {
let new_data = account.data();
if account_info.owner != account.owner() {
// TODO Figure out a better way to allow the System Program to set the account owner
#[allow(clippy::transmute_ptr_to_ptr)]
#[allow(mutable_transmutes)]
let account_info_mut =
unsafe { transmute::<&Pubkey, &mut Pubkey>(account_info.owner) };
*account_info_mut = *account_borrow.owner();
*account_info_mut = *account.owner();
}
// TODO: Figure out how to allow the System Program to resize the account data
assert!(
Expand Down
7 changes: 5 additions & 2 deletions programs/bpf_loader/src/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,11 @@ mod tests {
];
let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
let program_indices = [0];
let preparation =
prepare_mock_invoke_context(transaction_accounts.clone(), instruction_accounts);
let preparation = prepare_mock_invoke_context(
transaction_accounts.clone(),
instruction_accounts,
&program_indices,
);
let transaction_context = TransactionContext::new(preparation.transaction_accounts, 1);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
invoke_context
Expand Down
34 changes: 15 additions & 19 deletions programs/bpf_loader/src/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2203,8 +2203,13 @@ where
F: Fn(&T, &InvokeContext) -> Result<CallerAccount<'a>, EbpfError<BpfError>>,
{
let keyed_accounts = invoke_context
.get_instruction_keyed_accounts()
.get_keyed_accounts()
.map_err(SyscallError::InstructionError)?;
let number_of_program_accounts = keyed_accounts.len()
- invoke_context
.get_instruction_keyed_accounts()
.map_err(SyscallError::InstructionError)?
.len();
let mut accounts = Vec::with_capacity(instruction_accounts.len().saturating_add(1));

let program_account_index = program_indices
Expand All @@ -2217,13 +2222,13 @@ where
for instruction_account in instruction_accounts.iter() {
let account = invoke_context
.transaction_context
.get_account_at_index(instruction_account.index);
.get_account_at_index(instruction_account.index_in_transaction);
let account_key = invoke_context
.transaction_context
.get_key_of_account_at_index(instruction_account.index);
.get_key_of_account_at_index(instruction_account.index_in_transaction);
if account.borrow().executable() {
// Use the known account
accounts.push((instruction_account.index, None));
accounts.push((instruction_account.index_in_transaction, None));
} else if let Some(caller_account_index) =
account_info_keys.iter().position(|key| *key == account_key)
{
Expand All @@ -2238,20 +2243,11 @@ where
account.set_rent_epoch(caller_account.rent_epoch);
}
let caller_account = if instruction_account.is_writable {
if let Some(orig_data_len_index) = keyed_accounts
.iter()
.position(|keyed_account| keyed_account.unsigned_key() == account_key)
.map(|index| {
// index starts at first instruction account
index - keyed_accounts.len().saturating_sub(orig_data_lens.len())
})
.and_then(|index| {
if index >= orig_data_lens.len() {
None
} else {
Some(index)
}
})
let orig_data_len_index = instruction_account
.index_in_caller
.saturating_sub(number_of_program_accounts);
if keyed_accounts[instruction_account.index_in_caller].unsigned_key() == account_key
&& orig_data_len_index < orig_data_lens.len()
{
caller_account.original_data_len = orig_data_lens[orig_data_len_index];
} else {
Expand All @@ -2269,7 +2265,7 @@ where
} else {
None
};
accounts.push((instruction_account.index, caller_account));
accounts.push((instruction_account.index_in_transaction, caller_account));
} else {
ic_msg!(
invoke_context,
Expand Down
3 changes: 2 additions & 1 deletion rbpf-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,9 @@ native machine code before execting it in the virtual machine.",
input.instruction_data
}
};
let preparation = prepare_mock_invoke_context(transaction_accounts, instruction_accounts);
let program_indices = [0, 1];
let preparation =
prepare_mock_invoke_context(transaction_accounts, instruction_accounts, &program_indices);
let transaction_context = TransactionContext::new(preparation.transaction_accounts, 1);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
invoke_context
Expand Down
11 changes: 6 additions & 5 deletions runtime/src/message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,13 @@ impl MessageProcessor {
let instruction_accounts = instruction
.accounts
.iter()
.map(|account_index| {
let account_index = *account_index as usize;
.map(|index_in_transaction| {
let index_in_transaction = *index_in_transaction as usize;
InstructionAccount {
index: account_index,
is_signer: message.is_signer(account_index),
is_writable: message.is_writable(account_index),
index_in_transaction,
index_in_caller: program_indices.len().saturating_add(index_in_transaction),
is_signer: message.is_signer(index_in_transaction),
is_writable: message.is_writable(index_in_transaction),
}
})
.collect::<Vec<_>>();
Expand Down
Loading