Refactor: instruction account index (#25825)

* Adds methods based on instruction_account_index to InstructionContext.
Removes methods which are based on index_in_instruction.

* Adjusts program-runtime.

* Adjusts runtime.

* Adjusts bpf loader.

* Adjusts built-in programs.

* Adjusts program-test and bpf tests.
This commit is contained in:
Alexander Meißner 2022-06-16 18:46:17 +02:00 committed by GitHub
parent 8e3fd8a411
commit bf9ca9827e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 559 additions and 548 deletions

View File

@ -368,10 +368,10 @@ impl<'a> InvokeContext<'a> {
self.pre_accounts = Vec::with_capacity(instruction_accounts.len());
for (index_in_instruction, instruction_account) in
for (instruction_account_index, instruction_account) in
instruction_accounts.iter().enumerate()
{
if index_in_instruction != instruction_account.index_in_callee {
if instruction_account_index != instruction_account.index_in_callee {
continue; // Skip duplicate account
}
if instruction_account.index_in_transaction
@ -398,7 +398,8 @@ impl<'a> InvokeContext<'a> {
self.transaction_context
.get_instruction_context_at(level)
.and_then(|instruction_context| {
instruction_context.try_borrow_program_account(self.transaction_context)
instruction_context
.try_borrow_last_program_account(self.transaction_context)
})
.map(|program_account| program_account.get_key() == program_id)
.unwrap_or(false)
@ -407,7 +408,7 @@ impl<'a> InvokeContext<'a> {
.transaction_context
.get_current_instruction_context()
.and_then(|instruction_context| {
instruction_context.try_borrow_program_account(self.transaction_context)
instruction_context.try_borrow_last_program_account(self.transaction_context)
})
.map(|program_account| program_account.get_key() == program_id)
.unwrap_or(false);
@ -490,7 +491,7 @@ impl<'a> InvokeContext<'a> {
.get_current_instruction_context()
.map_err(|_| InstructionError::CallDepth)?;
let program_id = instruction_context
.get_program_key(self.transaction_context)
.get_last_program_key(self.transaction_context)
.map_err(|_| InstructionError::CallDepth)?;
// Verify all executable accounts have zero outstanding refs
@ -504,8 +505,10 @@ impl<'a> InvokeContext<'a> {
// Verify the per-account instruction results
let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
let mut pre_account_index = 0;
for (index_in_instruction, instruction_account) in instruction_accounts.iter().enumerate() {
if index_in_instruction != instruction_account.index_in_callee {
for (instruction_account_index, instruction_account) in
instruction_accounts.iter().enumerate()
{
if instruction_account_index != instruction_account.index_in_callee {
continue; // Skip duplicate account
}
{
@ -581,13 +584,15 @@ impl<'a> InvokeContext<'a> {
let transaction_context = &self.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let program_id = instruction_context
.get_program_key(transaction_context)
.get_last_program_key(transaction_context)
.map_err(|_| InstructionError::CallDepth)?;
// Verify the per-account instruction results
let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
for (index_in_instruction, instruction_account) in instruction_accounts.iter().enumerate() {
if index_in_instruction != instruction_account.index_in_callee {
for (instruction_account_index, instruction_account) in
instruction_accounts.iter().enumerate()
{
if instruction_account_index != instruction_account.index_in_callee {
continue; // Skip duplicate account
}
if instruction_account.index_in_transaction
@ -599,11 +604,7 @@ impl<'a> InvokeContext<'a> {
.get_account_at_index(instruction_account.index_in_transaction)?;
let is_writable = if before_instruction_context_push {
instruction_context
.try_borrow_instruction_account(
self.transaction_context,
instruction_account.index_in_caller,
)?
.is_writable()
.is_instruction_account_writable(instruction_account.index_in_caller)?
} else {
instruction_account.is_writable
};
@ -713,7 +714,7 @@ impl<'a> InvokeContext<'a> {
let instruction_context = self.transaction_context.get_current_instruction_context()?;
let mut deduplicated_instruction_accounts: Vec<InstructionAccount> = Vec::new();
let mut duplicate_indicies = Vec::with_capacity(instruction.accounts.len());
for (index_in_instruction, account_meta) in instruction.accounts.iter().enumerate() {
for (instruction_account_index, account_meta) in instruction.accounts.iter().enumerate() {
let index_in_transaction = self
.transaction_context
.find_index_of_account(&account_meta.pubkey)
@ -740,10 +741,10 @@ impl<'a> InvokeContext<'a> {
instruction_account.is_writable |= account_meta.is_writable;
} else {
let index_in_caller = instruction_context
.find_index_of_account(self.transaction_context, &account_meta.pubkey)
.map(|index| {
index.saturating_sub(instruction_context.get_number_of_program_accounts())
})
.find_index_of_instruction_account(
self.transaction_context,
&account_meta.pubkey,
)
.ok_or_else(|| {
ic_msg!(
self,
@ -756,7 +757,7 @@ impl<'a> InvokeContext<'a> {
deduplicated_instruction_accounts.push(InstructionAccount {
index_in_transaction,
index_in_caller,
index_in_callee: index_in_instruction,
index_in_callee: instruction_account_index,
is_signer: account_meta.is_signer,
is_writable: account_meta.is_writable,
});
@ -804,13 +805,13 @@ impl<'a> InvokeContext<'a> {
// Find and validate executables / program accounts
let callee_program_id = instruction.program_id;
let program_account_index = instruction_context
.find_index_of_account(self.transaction_context, &callee_program_id)
.find_index_of_instruction_account(self.transaction_context, &callee_program_id)
.ok_or_else(|| {
ic_msg!(self, "Unknown program {}", callee_program_id);
InstructionError::MissingAccount
})?;
let borrowed_program_account = instruction_context
.try_borrow_account(self.transaction_context, program_account_index)?;
.try_borrow_instruction_account(self.transaction_context, program_account_index)?;
if !borrowed_program_account.is_executable() {
ic_msg!(self, "Account {} is not executable", callee_program_id);
return Err(InstructionError::AccountNotExecutable);
@ -952,7 +953,7 @@ impl<'a> InvokeContext<'a> {
let (first_instruction_account, builtin_id) = {
let borrowed_root_account = instruction_context
.try_borrow_account(self.transaction_context, 0)
.try_borrow_program_account(self.transaction_context, 0)
.map_err(|_| InstructionError::UnsupportedProgramId)?;
let owner_id = borrowed_root_account.get_owner();
if solana_sdk::native_loader::check_id(owner_id) {
@ -964,7 +965,8 @@ impl<'a> InvokeContext<'a> {
for entry in self.builtin_programs {
if entry.program_id == builtin_id {
let program_id = instruction_context.get_program_id(self.transaction_context);
let program_id =
*instruction_context.get_last_program_key(self.transaction_context)?;
if builtin_id == program_id {
let logger = self.get_log_collector();
stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
@ -1123,19 +1125,19 @@ pub fn prepare_mock_invoke_context(
) -> MockInvokeContextPreparation {
let mut instruction_accounts: Vec<InstructionAccount> =
Vec::with_capacity(instruction_account_metas.len());
for (index_in_instruction, account_meta) in instruction_account_metas.iter().enumerate() {
for (instruction_account_index, account_meta) in instruction_account_metas.iter().enumerate() {
let index_in_transaction = transaction_accounts
.iter()
.position(|(key, _account)| *key == account_meta.pubkey)
.unwrap_or(transaction_accounts.len());
let index_in_callee = instruction_accounts
.get(0..index_in_instruction)
.get(0..instruction_account_index)
.unwrap()
.iter()
.position(|instruction_account| {
instruction_account.index_in_transaction == index_in_transaction
})
.unwrap_or(index_in_instruction);
.unwrap_or(instruction_account_index);
instruction_accounts.push(InstructionAccount {
index_in_transaction,
index_in_caller: index_in_transaction,
@ -1295,7 +1297,7 @@ mod tests {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
let program_id = instruction_context.get_program_key(transaction_context)?;
let program_id = instruction_context.get_last_program_key(transaction_context)?;
assert_eq!(
program_id,
instruction_context
@ -1528,12 +1530,12 @@ mod tests {
AccountMeta::new_readonly(accounts.get(2).unwrap().0, false),
];
let instruction_accounts = (0..4)
.map(|index_in_instruction| InstructionAccount {
index_in_transaction: index_in_instruction,
index_in_caller: index_in_instruction,
index_in_callee: index_in_instruction,
.map(|instruction_account_index| InstructionAccount {
index_in_transaction: instruction_account_index,
index_in_caller: instruction_account_index,
index_in_callee: instruction_account_index,
is_signer: false,
is_writable: index_in_instruction < 2,
is_writable: instruction_account_index < 2,
})
.collect::<Vec<_>>();
let mut transaction_context = TransactionContext::new(accounts, 2, 8);

View File

@ -186,10 +186,9 @@ pub mod get_sysvar_with_account_check {
instruction_context: &InstructionContext,
instruction_account_index: usize,
) -> Result<(), InstructionError> {
if !S::check_id(
instruction_context
.get_instruction_account_key(transaction_context, instruction_account_index)?,
) {
let index_in_transaction = instruction_context
.get_index_of_instruction_account_in_transaction(instruction_account_index)?;
if !S::check_id(transaction_context.get_key_of_account_at_index(index_in_transaction)?) {
return Err(InstructionError::InvalidArgument);
}
Ok(())
@ -198,12 +197,12 @@ pub mod get_sysvar_with_account_check {
pub fn clock(
invoke_context: &InvokeContext,
instruction_context: &InstructionContext,
index_in_instruction: usize,
instruction_account_index: usize,
) -> Result<Arc<Clock>, InstructionError> {
check_sysvar_account::<Clock>(
invoke_context.transaction_context,
instruction_context,
index_in_instruction,
instruction_account_index,
)?;
invoke_context.get_sysvar_cache().get_clock()
}
@ -211,12 +210,12 @@ pub mod get_sysvar_with_account_check {
pub fn rent(
invoke_context: &InvokeContext,
instruction_context: &InstructionContext,
index_in_instruction: usize,
instruction_account_index: usize,
) -> Result<Arc<Rent>, InstructionError> {
check_sysvar_account::<Rent>(
invoke_context.transaction_context,
instruction_context,
index_in_instruction,
instruction_account_index,
)?;
invoke_context.get_sysvar_cache().get_rent()
}
@ -224,12 +223,12 @@ pub mod get_sysvar_with_account_check {
pub fn slot_hashes(
invoke_context: &InvokeContext,
instruction_context: &InstructionContext,
index_in_instruction: usize,
instruction_account_index: usize,
) -> Result<Arc<SlotHashes>, InstructionError> {
check_sysvar_account::<SlotHashes>(
invoke_context.transaction_context,
instruction_context,
index_in_instruction,
instruction_account_index,
)?;
invoke_context.get_sysvar_cache().get_slot_hashes()
}
@ -238,12 +237,12 @@ pub mod get_sysvar_with_account_check {
pub fn recent_blockhashes(
invoke_context: &InvokeContext,
instruction_context: &InstructionContext,
index_in_instruction: usize,
instruction_account_index: usize,
) -> Result<Arc<RecentBlockhashes>, InstructionError> {
check_sysvar_account::<RecentBlockhashes>(
invoke_context.transaction_context,
instruction_context,
index_in_instruction,
instruction_account_index,
)?;
invoke_context.get_sysvar_cache().get_recent_blockhashes()
}
@ -251,12 +250,12 @@ pub mod get_sysvar_with_account_check {
pub fn stake_history(
invoke_context: &InvokeContext,
instruction_context: &InstructionContext,
index_in_instruction: usize,
instruction_account_index: usize,
) -> Result<Arc<StakeHistory>, InstructionError> {
check_sysvar_account::<StakeHistory>(
invoke_context.transaction_context,
instruction_context,
index_in_instruction,
instruction_account_index,
)?;
invoke_context.get_sysvar_cache().get_stake_history()
}

View File

@ -101,11 +101,10 @@ pub fn builtin_process_instruction(
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
let indices_in_instruction = instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts();
let instruction_account_indices = 0..instruction_context.get_number_of_instruction_accounts();
let log_collector = invoke_context.get_log_collector();
let program_id = instruction_context.get_program_key(transaction_context)?;
let program_id = instruction_context.get_last_program_key(transaction_context)?;
stable_log::program_invoke(
&log_collector,
program_id,
@ -113,14 +112,14 @@ pub fn builtin_process_instruction(
);
// Copy indices_in_instruction into a HashSet to ensure there are no duplicates
let deduplicated_indices: HashSet<usize> = indices_in_instruction.clone().collect();
let deduplicated_indices: HashSet<usize> = instruction_account_indices.clone().collect();
// Create copies of the accounts
let mut account_copies = deduplicated_indices
.iter()
.map(|index_in_instruction| {
.map(|instruction_account_index| {
let borrowed_account = instruction_context
.try_borrow_account(transaction_context, *index_in_instruction)?;
.try_borrow_instruction_account(transaction_context, *instruction_account_index)?;
Ok((
*borrowed_account.get_key(),
*borrowed_account.get_owner(),
@ -144,15 +143,15 @@ pub fn builtin_process_instruction(
.collect();
// Create AccountInfos
let account_infos = indices_in_instruction
.map(|index_in_instruction| {
let account_infos = instruction_account_indices
.map(|instruction_account_index| {
let account_copy_index = deduplicated_indices
.iter()
.position(|index| *index == index_in_instruction)
.position(|index| *index == instruction_account_index)
.unwrap();
let (key, owner, lamports, data) = &account_refs[account_copy_index];
let borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?;
.try_borrow_instruction_account(transaction_context, instruction_account_index)?;
Ok(AccountInfo {
key,
is_signer: borrowed_account.is_signer(),
@ -175,12 +174,12 @@ pub fn builtin_process_instruction(
stable_log::program_success(&log_collector, program_id);
// Commit AccountInfo changes back into KeyedAccounts
for (index_in_instruction, (_key, _owner, lamports, data)) in deduplicated_indices
for (instruction_account_index, (_key, _owner, lamports, data)) in deduplicated_indices
.into_iter()
.zip(account_copies.into_iter())
{
let mut borrowed_account =
instruction_context.try_borrow_account(transaction_context, index_in_instruction)?;
let mut borrowed_account = instruction_context
.try_borrow_instruction_account(transaction_context, instruction_account_index)?;
if borrowed_account.is_writable() {
borrowed_account.set_lamports(lamports)?;
borrowed_account.set_data(&data)?;
@ -253,7 +252,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
.get_current_instruction_context()
.unwrap();
let caller = instruction_context
.get_program_key(transaction_context)
.get_last_program_key(transaction_context)
.unwrap();
stable_log::program_invoke(
@ -379,7 +378,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
.get_current_instruction_context()
.unwrap();
let caller = *instruction_context
.get_program_key(transaction_context)
.get_last_program_key(transaction_context)
.unwrap();
transaction_context
.set_return_data(caller, data.to_vec())

View File

@ -18,7 +18,7 @@ use {
};
pub fn process_instruction(
first_instruction_account: usize,
_first_instruction_account: usize,
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
@ -28,24 +28,15 @@ pub fn process_instruction(
ProgramInstruction::CreateLookupTable {
recent_slot,
bump_seed,
} => Processor::create_lookup_table(
invoke_context,
first_instruction_account,
recent_slot,
bump_seed,
),
ProgramInstruction::FreezeLookupTable => {
Processor::freeze_lookup_table(invoke_context, first_instruction_account)
}
} => Processor::create_lookup_table(invoke_context, recent_slot, bump_seed),
ProgramInstruction::FreezeLookupTable => Processor::freeze_lookup_table(invoke_context),
ProgramInstruction::ExtendLookupTable { new_addresses } => {
Processor::extend_lookup_table(invoke_context, first_instruction_account, new_addresses)
Processor::extend_lookup_table(invoke_context, new_addresses)
}
ProgramInstruction::DeactivateLookupTable => {
Processor::deactivate_lookup_table(invoke_context, first_instruction_account)
}
ProgramInstruction::CloseLookupTable => {
Processor::close_lookup_table(invoke_context, first_instruction_account)
Processor::deactivate_lookup_table(invoke_context)
}
ProgramInstruction::CloseLookupTable => Processor::close_lookup_table(invoke_context),
}
}
@ -57,7 +48,6 @@ pub struct Processor;
impl Processor {
fn create_lookup_table(
invoke_context: &mut InvokeContext,
_first_instruction_account: usize,
untrusted_recent_slot: Slot,
bump_seed: u8,
) -> Result<(), InstructionError> {
@ -161,10 +151,7 @@ impl Processor {
Ok(())
}
fn freeze_lookup_table(
invoke_context: &mut InvokeContext,
_first_instruction_account: usize,
) -> Result<(), InstructionError> {
fn freeze_lookup_table(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
@ -217,7 +204,6 @@ impl Processor {
fn extend_lookup_table(
invoke_context: &mut InvokeContext,
_first_instruction_account: usize,
new_addresses: Vec<Pubkey>,
) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
@ -335,10 +321,7 @@ impl Processor {
Ok(())
}
fn deactivate_lookup_table(
invoke_context: &mut InvokeContext,
_first_instruction_account: usize,
) -> Result<(), InstructionError> {
fn deactivate_lookup_table(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
@ -387,10 +370,7 @@ impl Processor {
Ok(())
}
fn close_lookup_table(
invoke_context: &mut InvokeContext,
_first_instruction_account: usize,
) -> Result<(), InstructionError> {
fn close_lookup_table(invoke_context: &mut InvokeContext) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
@ -411,13 +391,8 @@ impl Processor {
drop(authority_account);
instruction_context.check_number_of_instruction_accounts(3)?;
if instruction_context
.get_index_in_transaction(instruction_context.get_number_of_program_accounts())?
== instruction_context.get_index_in_transaction(
instruction_context
.get_number_of_program_accounts()
.saturating_add(2),
)?
if instruction_context.get_index_of_instruction_account_in_transaction(0)?
== instruction_context.get_index_of_instruction_account_in_transaction(2)?
{
ic_msg!(
invoke_context,

View File

@ -246,7 +246,7 @@ fn run_program(name: &str) -> u64 {
.get_current_instruction_context()
.unwrap();
let caller = *instruction_context
.get_program_key(transaction_context)
.get_last_program_key(transaction_context)
.unwrap();
transaction_context
.set_return_data(caller, Vec::new())

View File

@ -92,12 +92,12 @@ fn create_inputs() -> TransactionContext {
.into_iter()
.enumerate()
.map(
|(index_in_instruction, index_in_transaction)| InstructionAccount {
index_in_caller: index_in_instruction,
|(instruction_account_index, index_in_transaction)| InstructionAccount {
index_in_caller: instruction_account_index,
index_in_transaction,
index_in_callee: index_in_instruction,
index_in_callee: instruction_account_index,
is_signer: false,
is_writable: index_in_instruction >= 4,
is_writable: instruction_account_index >= 4,
},
)
.collect::<Vec<_>>();

View File

@ -54,7 +54,7 @@ use {
pubkey::Pubkey,
saturating_add_assign,
system_instruction::{self, MAX_PERMITTED_DATA_LENGTH},
transaction_context::{InstructionContext, TransactionContext},
transaction_context::{BorrowedAccount, InstructionContext, TransactionContext},
},
std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc},
thiserror::Error,
@ -103,6 +103,40 @@ mod executor_metrics {
}
}
// The BPF loader is special in that it is the only place in the runtime and its built-in programs,
// where data comes not only from instruction account but also program accounts.
// Thus, these two helper methods have to distinguish the mixed sources via index_in_instruction.
fn get_index_in_transaction(
instruction_context: &InstructionContext,
index_in_instruction: usize,
) -> Result<usize, InstructionError> {
if index_in_instruction < instruction_context.get_number_of_program_accounts() {
instruction_context.get_index_of_program_account_in_transaction(index_in_instruction)
} else {
instruction_context.get_index_of_instruction_account_in_transaction(
index_in_instruction
.saturating_sub(instruction_context.get_number_of_program_accounts()),
)
}
}
fn try_borrow_account<'a>(
transaction_context: &'a TransactionContext,
instruction_context: &'a InstructionContext,
index_in_instruction: usize,
) -> Result<BorrowedAccount<'a>, InstructionError> {
if index_in_instruction < instruction_context.get_number_of_program_accounts() {
instruction_context.try_borrow_program_account(transaction_context, index_in_instruction)
} else {
instruction_context.try_borrow_instruction_account(
transaction_context,
index_in_instruction
.saturating_sub(instruction_context.get_number_of_program_accounts()),
)
}
}
pub fn create_executor(
programdata_account_index: usize,
programdata_offset: usize,
@ -160,8 +194,11 @@ pub fn create_executor(
let executable = {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let programdata = instruction_context
.try_borrow_account(transaction_context, programdata_account_index)?;
let programdata = try_borrow_account(
transaction_context,
instruction_context,
programdata_account_index,
)?;
create_executor_metrics.program_id = programdata.get_key().to_string();
let mut load_elf_time = Measure::start("load_elf_time");
let executable = Executable::<BpfError, ThisInstructionMeter>::from_elf(
@ -222,8 +259,11 @@ fn write_program_data(
) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let mut program =
instruction_context.try_borrow_account(transaction_context, program_account_index)?;
let mut program = try_borrow_account(
transaction_context,
instruction_context,
program_account_index,
)?;
let data = program.get_data_mut()?;
let write_offset = program_data_offset.saturating_add(bytes.len());
if data.len() < write_offset {
@ -296,15 +336,17 @@ fn process_instruction_common(
let log_collector = invoke_context.get_log_collector();
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let program_id = instruction_context.get_program_key(transaction_context)?;
let program_id = instruction_context.get_last_program_key(transaction_context)?;
let first_account_key = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account)?,
get_index_in_transaction(instruction_context, first_instruction_account)?,
)?;
let second_account_key = instruction_context
.get_index_in_transaction(first_instruction_account.saturating_add(1))
.and_then(|index_in_transaction| {
transaction_context.get_key_of_account_at_index(index_in_transaction)
});
let second_account_key = get_index_in_transaction(
instruction_context,
first_instruction_account.saturating_add(1),
)
.and_then(|index_in_transaction| {
transaction_context.get_key_of_account_at_index(index_in_transaction)
});
let program_account_index = if first_account_key == program_id {
first_instruction_account
@ -314,18 +356,23 @@ fn process_instruction_common(
{
first_instruction_account.saturating_add(1)
} else {
if instruction_context
.try_borrow_account(transaction_context, first_instruction_account)?
.is_executable()
{
let first_account = try_borrow_account(
transaction_context,
instruction_context,
first_instruction_account,
)?;
if first_account.is_executable() {
ic_logger_msg!(log_collector, "BPF loader is executable");
return Err(InstructionError::IncorrectProgramId);
}
first_instruction_account
};
let program =
instruction_context.try_borrow_account(transaction_context, program_account_index)?;
let program = try_borrow_account(
transaction_context,
instruction_context,
program_account_index,
)?;
if program.is_executable() {
// First instruction account can only be zero if called from CPI, which
// means stack height better be greater than one
@ -356,7 +403,7 @@ fn process_instruction_common(
}
if !matches!(
instruction_context
.try_borrow_account(transaction_context, first_instruction_account)?
.try_borrow_program_account(transaction_context, first_instruction_account)?
.get_state()?,
UpgradeableLoaderState::ProgramData {
slot: _,
@ -391,7 +438,7 @@ fn process_instruction_common(
)?;
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let program_id = instruction_context.get_program_key(transaction_context)?;
let program_id = instruction_context.get_last_program_key(transaction_context)?;
invoke_context.add_executor(program_id, executor.clone());
executor
}
@ -438,7 +485,7 @@ fn process_loader_upgradeable_instruction(
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
let program_id = instruction_context.get_program_key(transaction_context)?;
let program_id = instruction_context.get_last_program_key(transaction_context)?;
match limited_deserialize(instruction_data)? {
UpgradeableLoaderInstruction::InitializeBuffer => {
@ -451,12 +498,9 @@ fn process_loader_upgradeable_instruction(
return Err(InstructionError::AccountAlreadyInitialized);
}
let authority_key = Some(
*transaction_context.get_key_of_account_at_index(
instruction_context
.get_index_in_transaction(first_instruction_account.saturating_add(1))?,
)?,
);
let authority_key = Some(*transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
)?);
buffer.set_state(&UpgradeableLoaderState::Buffer {
authority_address: authority_key,
@ -472,17 +516,14 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "Buffer is immutable");
return Err(InstructionError::Immutable); // TODO better error code
}
let authority_key =
Some(*transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(
first_instruction_account.saturating_add(1),
)?,
)?);
let authority_key = Some(*transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
)?);
if authority_address != authority_key {
ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
return Err(InstructionError::IncorrectAuthority);
}
if !instruction_context.is_signer(first_instruction_account.saturating_add(1))? {
if !instruction_context.is_instruction_account_signer(1)? {
ic_logger_msg!(log_collector, "Buffer authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
@ -501,22 +542,18 @@ fn process_loader_upgradeable_instruction(
UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => {
instruction_context.check_number_of_instruction_accounts(4)?;
let payer_key = *transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account)?,
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
)?;
let programdata_key = *transaction_context.get_key_of_account_at_index(
instruction_context
.get_index_in_transaction(first_instruction_account.saturating_add(1))?,
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
)?;
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
let clock =
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
instruction_context.check_number_of_instruction_accounts(8)?;
let authority_key = Some(
*transaction_context.get_key_of_account_at_index(
instruction_context
.get_index_in_transaction(first_instruction_account.saturating_add(7))?,
)?,
);
let authority_key = Some(*transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(7)?,
)?);
// Verify Program account
@ -546,7 +583,7 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
return Err(InstructionError::IncorrectAuthority);
}
if !instruction_context.is_signer(first_instruction_account.saturating_add(7))? {
if !instruction_context.is_instruction_account_signer(7)? {
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
@ -617,7 +654,8 @@ fn process_loader_upgradeable_instruction(
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let caller_program_id = instruction_context.get_program_key(transaction_context)?;
let caller_program_id =
instruction_context.get_last_program_key(transaction_context)?;
let signers = [&[new_program_id.as_ref(), &[bump_seed]]]
.iter()
.map(|seeds| Pubkey::create_program_address(*seeds, caller_program_id))
@ -689,18 +727,15 @@ fn process_loader_upgradeable_instruction(
UpgradeableLoaderInstruction::Upgrade => {
instruction_context.check_number_of_instruction_accounts(3)?;
let programdata_key = *transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account)?,
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
)?;
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
let clock =
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
instruction_context.check_number_of_instruction_accounts(7)?;
let authority_key = Some(
*transaction_context.get_key_of_account_at_index(
instruction_context
.get_index_in_transaction(first_instruction_account.saturating_add(6))?,
)?,
);
let authority_key = Some(*transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(6)?,
)?);
// Verify Program account
@ -742,7 +777,7 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
return Err(InstructionError::IncorrectAuthority);
}
if !instruction_context.is_signer(first_instruction_account.saturating_add(6))? {
if !instruction_context.is_instruction_account_signer(6)? {
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
@ -796,7 +831,7 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
return Err(InstructionError::IncorrectAuthority);
}
if !instruction_context.is_signer(first_instruction_account.saturating_add(6))? {
if !instruction_context.is_instruction_account_signer(6)? {
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
@ -878,11 +913,10 @@ fn process_loader_upgradeable_instruction(
let mut account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let present_authority_key = transaction_context.get_key_of_account_at_index(
instruction_context
.get_index_in_transaction(first_instruction_account.saturating_add(1))?,
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
)?;
let new_authority = instruction_context
.get_index_in_transaction(first_instruction_account.saturating_add(2))
.get_index_of_instruction_account_in_transaction(2)
.and_then(|index_in_transaction| {
transaction_context.get_key_of_account_at_index(index_in_transaction)
})
@ -902,9 +936,7 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
return Err(InstructionError::IncorrectAuthority);
}
if !instruction_context
.is_signer(first_instruction_account.saturating_add(1))?
{
if !instruction_context.is_instruction_account_signer(1)? {
ic_logger_msg!(log_collector, "Buffer authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
@ -924,9 +956,7 @@ fn process_loader_upgradeable_instruction(
ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
return Err(InstructionError::IncorrectAuthority);
}
if !instruction_context
.is_signer(first_instruction_account.saturating_add(1))?
{
if !instruction_context.is_instruction_account_signer(1)? {
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
@ -945,9 +975,8 @@ fn process_loader_upgradeable_instruction(
}
UpgradeableLoaderInstruction::Close => {
instruction_context.check_number_of_instruction_accounts(2)?;
if instruction_context.get_index_in_transaction(first_instruction_account)?
== instruction_context
.get_index_in_transaction(first_instruction_account.saturating_add(1))?
if instruction_context.get_index_of_instruction_account_in_transaction(0)?
== instruction_context.get_index_of_instruction_account_in_transaction(1)?
{
ic_logger_msg!(
log_collector,
@ -1050,16 +1079,14 @@ fn common_close_account(
return Err(InstructionError::Immutable);
}
if *authority_address
!= Some(*instruction_context.get_instruction_account_key(transaction_context, 2)?)
!= Some(*transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(2)?,
)?)
{
ic_logger_msg!(log_collector, "Incorrect authority provided");
return Err(InstructionError::IncorrectAuthority);
}
if !instruction_context.is_signer(
instruction_context
.get_number_of_program_accounts()
.saturating_add(2),
)? {
if !instruction_context.is_instruction_account_signer(2)? {
ic_logger_msg!(log_collector, "Authority did not sign");
return Err(InstructionError::MissingRequiredSignature);
}
@ -1082,7 +1109,7 @@ fn process_loader_instruction(
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data();
let program_id = instruction_context.get_program_key(transaction_context)?;
let program_id = instruction_context.get_last_program_key(transaction_context)?;
let program = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
if program.get_owner() != program_id {
ic_msg!(
@ -1178,7 +1205,7 @@ impl Executor for BpfExecutor {
let stack_height = invoke_context.get_stack_height();
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let program_id = *instruction_context.get_program_key(transaction_context)?;
let program_id = *instruction_context.get_last_program_key(transaction_context)?;
let mut serialize_time = Measure::start("serialize");
let (mut parameter_bytes, account_lengths) =

View File

@ -19,7 +19,7 @@ pub fn serialize_parameters(
instruction_context: &InstructionContext,
) -> Result<(AlignedMemory, Vec<usize>), InstructionError> {
let is_loader_deprecated = *instruction_context
.try_borrow_program_account(transaction_context)?
.try_borrow_last_program_account(transaction_context)?
.get_owner()
== bpf_loader_deprecated::id();
if is_loader_deprecated {
@ -28,11 +28,10 @@ pub fn serialize_parameters(
serialize_parameters_aligned(transaction_context, instruction_context)
}
.and_then(|buffer| {
let account_lengths = (instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts())
.map(|index_in_instruction| {
let account_lengths = (0..instruction_context.get_number_of_instruction_accounts())
.map(|instruction_account_index| {
Ok(instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?
.try_borrow_instruction_account(transaction_context, instruction_account_index)?
.get_data()
.len())
})
@ -48,7 +47,7 @@ pub fn deserialize_parameters(
account_lengths: &[usize],
) -> Result<(), InstructionError> {
let is_loader_deprecated = *instruction_context
.try_borrow_program_account(transaction_context)?
.try_borrow_last_program_account(transaction_context)?
.get_owner()
== bpf_loader_deprecated::id();
if is_loader_deprecated {
@ -74,14 +73,13 @@ pub fn serialize_parameters_unaligned(
) -> Result<AlignedMemory, InstructionError> {
// Calculate size in order to alloc once
let mut size = size_of::<u64>();
for index_in_instruction in instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts()
{
let duplicate = instruction_context.is_duplicate(index_in_instruction)?;
for instruction_account_index in 0..instruction_context.get_number_of_instruction_accounts() {
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
size += 1; // dup
if duplicate.is_none() {
let data_len = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?
.try_borrow_instruction_account(transaction_context, instruction_account_index)?
.get_data()
.len();
size += size_of::<u8>() // is_signer
@ -102,16 +100,15 @@ pub fn serialize_parameters_unaligned(
v.write_u64::<LittleEndian>(instruction_context.get_number_of_instruction_accounts() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
for index_in_instruction in instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts()
{
let duplicate = instruction_context.is_duplicate(index_in_instruction)?;
for instruction_account_index in 0..instruction_context.get_number_of_instruction_accounts() {
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
if let Some(position) = duplicate {
v.write_u8(position as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
} else {
let borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?;
.try_borrow_instruction_account(transaction_context, instruction_account_index)?;
v.write_u8(std::u8::MAX)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(borrowed_account.is_signer() as u8)
@ -140,7 +137,7 @@ pub fn serialize_parameters_unaligned(
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(
instruction_context
.try_borrow_program_account(transaction_context)?
.try_borrow_last_program_account(transaction_context)?
.get_key()
.as_ref(),
)
@ -155,15 +152,15 @@ pub fn deserialize_parameters_unaligned(
account_lengths: &[usize],
) -> Result<(), InstructionError> {
let mut start = size_of::<u64>(); // number of accounts
for (index_in_instruction, pre_len) in (instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts())
.zip(account_lengths.iter())
for (instruction_account_index, pre_len) in
(0..instruction_context.get_number_of_instruction_accounts()).zip(account_lengths.iter())
{
let duplicate = instruction_context.is_duplicate(index_in_instruction)?;
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
start += 1; // is_dup
if duplicate.is_none() {
let mut borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?;
.try_borrow_instruction_account(transaction_context, instruction_account_index)?;
start += size_of::<u8>(); // is_signer
start += size_of::<u8>(); // is_writable
start += size_of::<Pubkey>(); // key
@ -194,16 +191,15 @@ pub fn serialize_parameters_aligned(
) -> Result<AlignedMemory, InstructionError> {
// Calculate size in order to alloc once
let mut size = size_of::<u64>();
for index_in_instruction in instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts()
{
let duplicate = instruction_context.is_duplicate(index_in_instruction)?;
for instruction_account_index in 0..instruction_context.get_number_of_instruction_accounts() {
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
size += 1; // dup
if duplicate.is_some() {
size += 7; // padding to 64-bit aligned
} else {
let data_len = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?
.try_borrow_instruction_account(transaction_context, instruction_account_index)?
.get_data()
.len();
size += size_of::<u8>() // is_signer
@ -228,10 +224,9 @@ pub fn serialize_parameters_aligned(
// Serialize into the buffer
v.write_u64::<LittleEndian>(instruction_context.get_number_of_instruction_accounts() as u64)
.map_err(|_| InstructionError::InvalidArgument)?;
for index_in_instruction in instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts()
{
let duplicate = instruction_context.is_duplicate(index_in_instruction)?;
for instruction_account_index in 0..instruction_context.get_number_of_instruction_accounts() {
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
if let Some(position) = duplicate {
v.write_u8(position as u8)
.map_err(|_| InstructionError::InvalidArgument)?;
@ -239,7 +234,7 @@ pub fn serialize_parameters_aligned(
.map_err(|_| InstructionError::InvalidArgument)?; // 7 bytes of padding to make 64-bit aligned
} else {
let borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?;
.try_borrow_instruction_account(transaction_context, instruction_account_index)?;
v.write_u8(std::u8::MAX)
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_u8(borrowed_account.is_signer() as u8)
@ -276,7 +271,7 @@ pub fn serialize_parameters_aligned(
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(
instruction_context
.try_borrow_program_account(transaction_context)?
.try_borrow_last_program_account(transaction_context)?
.get_key()
.as_ref(),
)
@ -291,17 +286,17 @@ pub fn deserialize_parameters_aligned(
account_lengths: &[usize],
) -> Result<(), InstructionError> {
let mut start = size_of::<u64>(); // number of accounts
for (index_in_instruction, pre_len) in (instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts())
.zip(account_lengths.iter())
for (instruction_account_index, pre_len) in
(0..instruction_context.get_number_of_instruction_accounts()).zip(account_lengths.iter())
{
let duplicate = instruction_context.is_duplicate(index_in_instruction)?;
let duplicate =
instruction_context.is_instruction_account_duplicate(instruction_account_index)?;
start += size_of::<u8>(); // position
if duplicate.is_some() {
start += 7; // padding to 64-bit aligned
} else {
let mut borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?;
.try_borrow_instruction_account(transaction_context, instruction_account_index)?;
start += size_of::<u8>() // is_signer
+ size_of::<u8>() // is_writable
+ size_of::<u8>() // executable
@ -442,11 +437,13 @@ mod tests {
let instruction_accounts = [1, 1, 2, 3, 4, 4, 5, 6]
.into_iter()
.enumerate()
.map(|(index_in_instruction, index_in_transaction)| AccountMeta {
pubkey: transaction_accounts.get(index_in_transaction).unwrap().0,
is_signer: false,
is_writable: index_in_instruction >= 4,
})
.map(
|(instruction_account_index, index_in_transaction)| AccountMeta {
pubkey: transaction_accounts.get(index_in_transaction).unwrap().0,
is_signer: false,
is_writable: instruction_account_index >= 4,
},
)
.collect();
let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
let program_indices = [0];
@ -552,7 +549,7 @@ mod tests {
.transaction_context
.get_current_instruction_context()
.unwrap()
.try_borrow_account(invoke_context.transaction_context, 0)
.try_borrow_program_account(invoke_context.transaction_context, 0)
.unwrap()
.set_owner(bpf_loader_deprecated::id().as_ref());

View File

@ -369,7 +369,8 @@ pub fn bind_syscall_context_objects<'a, 'b>(
.transaction_context
.get_current_instruction_context()
.and_then(|instruction_context| {
instruction_context.try_borrow_program_account(invoke_context.transaction_context)
instruction_context
.try_borrow_last_program_account(invoke_context.transaction_context)
})
.map(|program_account| *program_account.get_owner())
.map_err(SyscallError::InstructionError)?;
@ -2946,8 +2947,9 @@ where
))?;
accounts.push((*program_account_index, None));
for (index_in_instruction, instruction_account) in instruction_accounts.iter().enumerate() {
if index_in_instruction != instruction_account.index_in_callee {
for (instruction_account_index, instruction_account) in instruction_accounts.iter().enumerate()
{
if instruction_account_index != instruction_account.index_in_callee {
continue; // Skip duplicate account
}
let mut callee_account = instruction_context
@ -3121,7 +3123,7 @@ fn call<'a, 'b: 'a>(
.get_current_instruction_context()
.map_err(SyscallError::InstructionError)?;
let caller_program_id = instruction_context
.get_program_key(transaction_context)
.get_last_program_key(transaction_context)
.map_err(SyscallError::InstructionError)?;
let signers = syscall.translate_signers(
caller_program_id,
@ -3288,9 +3290,8 @@ declare_syscall!(
let program_id = *question_mark!(
transaction_context
.get_current_instruction_context()
.and_then(
|instruction_context| instruction_context.get_program_key(transaction_context)
)
.and_then(|instruction_context| instruction_context
.get_last_program_key(transaction_context))
.map_err(SyscallError::InstructionError),
result
);
@ -3570,19 +3571,26 @@ declare_syscall!(
result
);
*program_id =
instruction_context.get_program_id(invoke_context.transaction_context);
*program_id = *question_mark!(
instruction_context
.get_last_program_key(invoke_context.transaction_context)
.map_err(SyscallError::InstructionError),
result
);
data.clone_from_slice(instruction_context.get_instruction_data());
let account_metas = question_mark!(
(instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts())
.map(|index_in_instruction| Ok(AccountMeta {
(0..instruction_context.get_number_of_instruction_accounts())
.map(|instruction_account_index| Ok(AccountMeta {
pubkey: *invoke_context.get_key_of_account_at_index(
instruction_context
.get_index_in_transaction(index_in_instruction)?
.get_index_of_instruction_account_in_transaction(
instruction_account_index
)?
)?,
is_signer: instruction_context.is_signer(index_in_instruction)?,
is_writable: instruction_context.is_writable(index_in_instruction)?,
is_signer: instruction_context
.is_instruction_account_signer(instruction_account_index)?,
is_writable: instruction_context
.is_instruction_account_writable(instruction_account_index)?,
}))
.collect::<Result<Vec<_>, InstructionError>>()
.map_err(SyscallError::InstructionError),

View File

@ -20,11 +20,9 @@ pub fn process_instruction(
let data = instruction_context.get_instruction_data();
let key_list: ConfigKeys = limited_deserialize(data)?;
let config_account_key =
transaction_context
.get_key_of_account_at_index(instruction_context.get_index_in_transaction(
instruction_context.get_number_of_program_accounts(),
)?)?;
let config_account_key = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
)?;
let config_account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let is_config_account_signer = config_account.is_signer();

View File

@ -28,17 +28,23 @@ use {
fn get_optional_pubkey<'a>(
transaction_context: &'a TransactionContext,
instruction_context: &'a InstructionContext,
index_in_instruction: usize,
instruction_account_index: usize,
should_be_signer: bool,
) -> Result<Option<&'a Pubkey>, InstructionError> {
Ok(
if instruction_context.get_number_of_accounts() > index_in_instruction {
if should_be_signer && !instruction_context.is_signer(index_in_instruction)? {
if instruction_account_index < instruction_context.get_number_of_instruction_accounts() {
if should_be_signer
&& !instruction_context.is_instruction_account_signer(instruction_account_index)?
{
return Err(InstructionError::MissingRequiredSignature);
}
Some(transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(index_in_instruction)?,
)?)
Some(
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_of_instruction_account_in_transaction(
instruction_account_index,
)?,
)?,
)
} else {
None
},
@ -46,7 +52,7 @@ fn get_optional_pubkey<'a>(
}
pub fn process_instruction(
first_instruction_account: usize,
_first_instruction_account: usize,
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
@ -86,12 +92,8 @@ pub fn process_instruction(
let clock =
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
instruction_context.check_number_of_instruction_accounts(3)?;
let custodian_pubkey = get_optional_pubkey(
transaction_context,
instruction_context,
first_instruction_account + 3,
false,
)?;
let custodian_pubkey =
get_optional_pubkey(transaction_context, instruction_context, 3, false)?;
authorize(
&mut me,
@ -123,18 +125,14 @@ pub fn process_instruction(
if require_custodian_for_locked_stake_authorize {
let clock =
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
let custodian_pubkey = get_optional_pubkey(
transaction_context,
instruction_context,
first_instruction_account + 3,
false,
)?;
let custodian_pubkey =
get_optional_pubkey(transaction_context, instruction_context, 3, false)?;
authorize_with_seed(
transaction_context,
instruction_context,
&mut me,
first_instruction_account + 1,
1,
&args.authority_seed,
&args.authority_owner,
&args.new_authorized_pubkey,
@ -148,7 +146,7 @@ pub fn process_instruction(
transaction_context,
instruction_context,
&mut me,
first_instruction_account + 1,
1,
&args.authority_seed,
&args.authority_owner,
&args.new_authorized_pubkey,
@ -181,8 +179,8 @@ pub fn process_instruction(
delegate(
transaction_context,
instruction_context,
first_instruction_account,
first_instruction_account + 1,
0,
1,
&clock,
&stake_history,
&config,
@ -198,9 +196,9 @@ pub fn process_instruction(
invoke_context,
transaction_context,
instruction_context,
first_instruction_account,
0,
lamports,
first_instruction_account + 1,
1,
&signers,
)
}
@ -219,8 +217,8 @@ pub fn process_instruction(
invoke_context,
transaction_context,
instruction_context,
first_instruction_account,
first_instruction_account + 1,
0,
1,
&clock,
&stake_history,
&signers,
@ -241,14 +239,14 @@ pub fn process_instruction(
withdraw(
transaction_context,
instruction_context,
first_instruction_account,
0,
lamports,
first_instruction_account + 1,
1,
&clock,
&stake_history,
first_instruction_account + 4,
4,
if instruction_context.get_number_of_instruction_accounts() >= 6 {
Some(first_instruction_account + 5)
Some(5)
} else {
None
},
@ -274,12 +272,12 @@ pub fn process_instruction(
{
instruction_context.check_number_of_instruction_accounts(4)?;
let staker_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account + 2)?,
instruction_context.get_index_of_instruction_account_in_transaction(2)?,
)?;
let withdrawer_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account + 3)?,
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
)?;
if !instruction_context.is_signer(first_instruction_account + 3)? {
if !instruction_context.is_instruction_account_signer(3)? {
return Err(InstructionError::MissingRequiredSignature);
}
@ -311,17 +309,13 @@ pub fn process_instruction(
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
instruction_context.check_number_of_instruction_accounts(4)?;
let authorized_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account + 3)?,
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
)?;
if !instruction_context.is_signer(first_instruction_account + 3)? {
if !instruction_context.is_instruction_account_signer(3)? {
return Err(InstructionError::MissingRequiredSignature);
}
let custodian_pubkey = get_optional_pubkey(
transaction_context,
instruction_context,
first_instruction_account + 4,
false,
)?;
let custodian_pubkey =
get_optional_pubkey(transaction_context, instruction_context, 4, false)?;
authorize(
&mut me,
@ -347,23 +341,19 @@ pub fn process_instruction(
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 2)?;
instruction_context.check_number_of_instruction_accounts(4)?;
let authorized_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account + 3)?,
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
)?;
if !instruction_context.is_signer(first_instruction_account + 3)? {
if !instruction_context.is_instruction_account_signer(3)? {
return Err(InstructionError::MissingRequiredSignature);
}
let custodian_pubkey = get_optional_pubkey(
transaction_context,
instruction_context,
first_instruction_account + 4,
false,
)?;
let custodian_pubkey =
get_optional_pubkey(transaction_context, instruction_context, 4, false)?;
authorize_with_seed(
transaction_context,
instruction_context,
&mut me,
first_instruction_account + 1,
1,
&args.authority_seed,
&args.authority_owner,
authorized_pubkey,
@ -382,12 +372,8 @@ pub fn process_instruction(
.feature_set
.is_active(&feature_set::vote_stake_checked_instructions::id())
{
let custodian_pubkey = get_optional_pubkey(
transaction_context,
instruction_context,
first_instruction_account + 2,
true,
)?;
let custodian_pubkey =
get_optional_pubkey(transaction_context, instruction_context, 2, true)?;
let lockup = LockupArgs {
unix_timestamp: lockup_checked.unix_timestamp,
@ -430,8 +416,8 @@ pub fn process_instruction(
transaction_context,
instruction_context,
&mut me,
first_instruction_account + 1,
first_instruction_account + 2,
1,
2,
clock.epoch,
)
} else {

View File

@ -534,9 +534,10 @@ pub fn authorize_with_seed(
custodian: Option<&Pubkey>,
) -> Result<(), InstructionError> {
let mut signers = HashSet::default();
if instruction_context.is_signer(authority_base_index)? {
if instruction_context.is_instruction_account_signer(authority_base_index)? {
let base_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(authority_base_index)?,
instruction_context
.get_index_of_instruction_account_in_transaction(authority_base_index)?,
)?;
signers.insert(Pubkey::create_with_seed(
base_pubkey,
@ -566,8 +567,8 @@ pub fn delegate(
signers: &HashSet<Pubkey>,
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let vote_account =
instruction_context.try_borrow_account(transaction_context, vote_account_index)?;
let vote_account = instruction_context
.try_borrow_instruction_account(transaction_context, vote_account_index)?;
if *vote_account.get_owner() != solana_vote_program::id() {
return Err(InstructionError::IncorrectProgramId);
}
@ -575,8 +576,8 @@ pub fn delegate(
let vote_state = vote_account.get_state::<VoteStateVersions>();
drop(vote_account);
let mut stake_account =
instruction_context.try_borrow_account(transaction_context, stake_account_index)?;
let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
match stake_account.get_state()? {
StakeState::Initialized(meta) => {
meta.authorized.check(signers, StakeAuthorize::Staker)?;
@ -653,7 +654,8 @@ pub fn split(
split_index: usize,
signers: &HashSet<Pubkey>,
) -> Result<(), InstructionError> {
let split = instruction_context.try_borrow_account(transaction_context, split_index)?;
let split =
instruction_context.try_borrow_instruction_account(transaction_context, split_index)?;
if *split.get_owner() != id() {
return Err(InstructionError::IncorrectProgramId);
}
@ -665,8 +667,8 @@ pub fn split(
}
let split_lamport_balance = split.get_lamports();
drop(split);
let stake_account =
instruction_context.try_borrow_account(transaction_context, stake_account_index)?;
let stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
if lamports > stake_account.get_lamports() {
return Err(InstructionError::InsufficientFunds);
}
@ -724,12 +726,12 @@ pub fn split(
let mut split_meta = meta;
split_meta.rent_exempt_reserve = validated_split_info.destination_rent_exempt_reserve;
let mut stake_account =
instruction_context.try_borrow_account(transaction_context, stake_account_index)?;
let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
stake_account.set_state(&StakeState::Stake(meta, stake))?;
drop(stake_account);
let mut split =
instruction_context.try_borrow_account(transaction_context, split_index)?;
let mut split = instruction_context
.try_borrow_instruction_account(transaction_context, split_index)?;
split.set_state(&StakeState::Stake(split_meta, split_stake))?;
}
StakeState::Initialized(meta) => {
@ -755,13 +757,14 @@ pub fn split(
)?;
let mut split_meta = meta;
split_meta.rent_exempt_reserve = validated_split_info.destination_rent_exempt_reserve;
let mut split =
instruction_context.try_borrow_account(transaction_context, split_index)?;
let mut split = instruction_context
.try_borrow_instruction_account(transaction_context, split_index)?;
split.set_state(&StakeState::Initialized(split_meta))?;
}
StakeState::Uninitialized => {
let stake_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(stake_account_index)?,
instruction_context
.get_index_of_instruction_account_in_transaction(stake_account_index)?,
)?;
if !signers.contains(stake_pubkey) {
return Err(InstructionError::MissingRequiredSignature);
@ -771,18 +774,19 @@ pub fn split(
}
// Deinitialize state upon zero balance
let mut stake_account =
instruction_context.try_borrow_account(transaction_context, stake_account_index)?;
let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
if lamports == stake_account.get_lamports() {
stake_account.set_state(&StakeState::Uninitialized)?;
}
drop(stake_account);
let mut split = instruction_context.try_borrow_account(transaction_context, split_index)?;
let mut split =
instruction_context.try_borrow_instruction_account(transaction_context, split_index)?;
split.checked_add_lamports(lamports)?;
drop(split);
let mut stake_account =
instruction_context.try_borrow_account(transaction_context, stake_account_index)?;
let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
stake_account.checked_sub_lamports(lamports)?;
Ok(())
}
@ -797,20 +801,21 @@ pub fn merge(
stake_history: &StakeHistory,
signers: &HashSet<Pubkey>,
) -> Result<(), InstructionError> {
let mut source_account =
instruction_context.try_borrow_account(transaction_context, source_account_index)?;
let mut source_account = instruction_context
.try_borrow_instruction_account(transaction_context, source_account_index)?;
// Ensure source isn't spoofed
if *source_account.get_owner() != id() {
return Err(InstructionError::IncorrectProgramId);
}
// Close the stake_account-reference loophole
if instruction_context.get_index_in_transaction(stake_account_index)?
== instruction_context.get_index_in_transaction(source_account_index)?
if instruction_context.get_index_of_instruction_account_in_transaction(stake_account_index)?
== instruction_context
.get_index_of_instruction_account_in_transaction(source_account_index)?
{
return Err(InstructionError::InvalidArgument);
}
let mut stake_account =
instruction_context.try_borrow_account(transaction_context, stake_account_index)?;
let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
ic_msg!(invoke_context, "Checking if destination stake is mergeable");
let stake_merge_kind = MergeKind::get_if_mergeable(
@ -865,16 +870,17 @@ pub fn withdraw(
feature_set: &FeatureSet,
) -> Result<(), InstructionError> {
let withdraw_authority_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(withdraw_authority_index)?,
instruction_context
.get_index_of_instruction_account_in_transaction(withdraw_authority_index)?,
)?;
if !instruction_context.is_signer(withdraw_authority_index)? {
if !instruction_context.is_instruction_account_signer(withdraw_authority_index)? {
return Err(InstructionError::MissingRequiredSignature);
}
let mut signers = HashSet::new();
signers.insert(*withdraw_authority_pubkey);
let mut stake_account =
instruction_context.try_borrow_account(transaction_context, stake_account_index)?;
let mut stake_account = instruction_context
.try_borrow_instruction_account(transaction_context, stake_account_index)?;
let (lockup, reserve, is_staked) = match stake_account.get_state()? {
StakeState::Stake(meta, stake) => {
meta.authorized
@ -919,10 +925,13 @@ pub fn withdraw(
// verify that lockup has expired or that the withdrawal is signed by
// the custodian, both epoch and unix_timestamp must have passed
let custodian_pubkey = if let Some(custodian_index) = custodian_index {
if instruction_context.is_signer(custodian_index)? {
Some(transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(custodian_index)?,
)?)
if instruction_context.is_instruction_account_signer(custodian_index)? {
Some(
transaction_context.get_key_of_account_at_index(
instruction_context
.get_index_of_instruction_account_in_transaction(custodian_index)?,
)?,
)
} else {
None
}
@ -955,7 +964,8 @@ pub fn withdraw(
stake_account.checked_sub_lamports(lamports)?;
drop(stake_account);
let mut to = instruction_context.try_borrow_account(transaction_context, to_index)?;
let mut to =
instruction_context.try_borrow_instruction_account(transaction_context, to_index)?;
to.checked_add_lamports(lamports)?;
Ok(())
}
@ -969,10 +979,11 @@ pub(crate) fn deactivate_delinquent(
current_epoch: Epoch,
) -> Result<(), InstructionError> {
let delinquent_vote_account_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(delinquent_vote_account_index)?,
instruction_context
.get_index_of_instruction_account_in_transaction(delinquent_vote_account_index)?,
)?;
let delinquent_vote_account = instruction_context
.try_borrow_account(transaction_context, delinquent_vote_account_index)?;
.try_borrow_instruction_account(transaction_context, delinquent_vote_account_index)?;
if *delinquent_vote_account.get_owner() != solana_vote_program::id() {
return Err(InstructionError::IncorrectProgramId);
}
@ -981,7 +992,7 @@ pub(crate) fn deactivate_delinquent(
.convert_to_current();
let reference_vote_account = instruction_context
.try_borrow_account(transaction_context, reference_vote_account_index)?;
.try_borrow_instruction_account(transaction_context, reference_vote_account_index)?;
if *reference_vote_account.get_owner() != solana_vote_program::id() {
return Err(InstructionError::IncorrectProgramId);
}
@ -1062,13 +1073,13 @@ fn validate_split_amount(
source_stake: Option<&Stake>,
additional_required_lamports: u64,
) -> Result<ValidatedSplitInfo, InstructionError> {
let source_account =
instruction_context.try_borrow_account(transaction_context, source_account_index)?;
let source_account = instruction_context
.try_borrow_instruction_account(transaction_context, source_account_index)?;
let source_lamports = source_account.get_lamports();
let source_data_len = source_account.get_data().len();
drop(source_account);
let destination_account =
instruction_context.try_borrow_account(transaction_context, destination_account_index)?;
let destination_account = instruction_context
.try_borrow_instruction_account(transaction_context, destination_account_index)?;
let destination_lamports = destination_account.get_lamports();
let destination_data_len = destination_account.get_data().len();
drop(destination_account);

View File

@ -81,10 +81,10 @@ fn create_accounts() -> (
(authority_pubkey, AccountSharedData::default()),
];
let mut instruction_accounts = (0..4)
.map(|index_in_instruction| InstructionAccount {
index_in_transaction: 1usize.saturating_add(index_in_instruction),
index_in_caller: index_in_instruction,
index_in_callee: index_in_instruction,
.map(|index_in_callee| InstructionAccount {
index_in_transaction: 1usize.saturating_add(index_in_callee),
index_in_caller: index_in_callee,
index_in_callee,
is_signer: false,
is_writable: false,
})

View File

@ -24,7 +24,6 @@ fn process_authorize_with_seed_instruction(
invoke_context: &InvokeContext,
instruction_context: &InstructionContext,
transaction_context: &TransactionContext,
first_instruction_account: usize,
vote_account: &mut BorrowedAccount,
new_authority: &Pubkey,
authorization_type: VoteAuthorize,
@ -39,10 +38,9 @@ fn process_authorize_with_seed_instruction(
}
let clock = get_sysvar_with_account_check::clock(invoke_context, instruction_context, 1)?;
let mut expected_authority_keys: HashSet<Pubkey> = HashSet::default();
let authority_base_key_index = first_instruction_account + 2;
if instruction_context.is_signer(authority_base_key_index)? {
if instruction_context.is_instruction_account_signer(2)? {
let base_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(authority_base_key_index)?,
instruction_context.get_index_of_instruction_account_in_transaction(2)?,
)?;
expected_authority_keys.insert(Pubkey::create_with_seed(
base_pubkey,
@ -61,7 +59,7 @@ fn process_authorize_with_seed_instruction(
}
pub fn process_instruction(
first_instruction_account: usize,
_first_instruction_account: usize,
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
@ -70,8 +68,7 @@ pub fn process_instruction(
trace!("process_instruction: {:?}", data);
let mut me =
instruction_context.try_borrow_account(transaction_context, first_instruction_account)?;
let mut me = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
if *me.get_owner() != id() {
return Err(InstructionError::InvalidAccountOwner);
}
@ -105,7 +102,6 @@ pub fn process_instruction(
invoke_context,
instruction_context,
transaction_context,
first_instruction_account,
&mut me,
&args.new_authority,
args.authorization_type,
@ -115,18 +111,16 @@ pub fn process_instruction(
}
VoteInstruction::AuthorizeCheckedWithSeed(args) => {
instruction_context.check_number_of_instruction_accounts(4)?;
let new_authority_index = first_instruction_account + 3;
let new_authority = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(new_authority_index)?,
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
)?;
if !instruction_context.is_signer(new_authority_index)? {
if !instruction_context.is_instruction_account_signer(3)? {
return Err(InstructionError::MissingRequiredSignature);
}
process_authorize_with_seed_instruction(
invoke_context,
instruction_context,
transaction_context,
first_instruction_account,
&mut me,
new_authority,
args.authorization_type,
@ -137,7 +131,7 @@ pub fn process_instruction(
VoteInstruction::UpdateValidatorIdentity => {
instruction_context.check_number_of_instruction_accounts(2)?;
let node_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account + 1)?,
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
)?;
vote_state::update_validator_identity(&mut me, node_pubkey, &signers)
}
@ -203,9 +197,9 @@ pub fn process_instruction(
vote_state::withdraw(
transaction_context,
instruction_context,
first_instruction_account,
0,
lamports,
first_instruction_account + 1,
1,
&signers,
rent_sysvar.as_deref(),
clock_if_feature_active.as_deref(),
@ -218,9 +212,9 @@ pub fn process_instruction(
{
instruction_context.check_number_of_instruction_accounts(4)?;
let voter_pubkey = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account + 3)?,
instruction_context.get_index_of_instruction_account_in_transaction(3)?,
)?;
if !instruction_context.is_signer(first_instruction_account + 3)? {
if !instruction_context.is_instruction_account_signer(3)? {
return Err(InstructionError::MissingRequiredSignature);
}
let clock =

View File

@ -1309,8 +1309,8 @@ pub fn withdraw<S: std::hash::BuildHasher>(
rent_sysvar: Option<&Rent>,
clock: Option<&Clock>,
) -> Result<(), InstructionError> {
let mut vote_account =
instruction_context.try_borrow_account(transaction_context, vote_account_index)?;
let mut vote_account = instruction_context
.try_borrow_instruction_account(transaction_context, vote_account_index)?;
let vote_state: VoteState = vote_account
.get_state::<VoteStateVersions>()?
.convert_to_current();
@ -1351,8 +1351,8 @@ pub fn withdraw<S: std::hash::BuildHasher>(
vote_account.checked_sub_lamports(lamports)?;
drop(vote_account);
let mut to_account =
instruction_context.try_borrow_account(transaction_context, to_account_index)?;
let mut to_account = instruction_context
.try_borrow_instruction_account(transaction_context, to_account_index)?;
to_account.checked_add_lamports(lamports)?;
Ok(())
}

View File

@ -770,13 +770,20 @@ pub fn inner_instructions_list_from_instruction_trace(
.skip(1)
.map(|instruction_context| {
CompiledInstruction::new_from_raw_parts(
instruction_context.get_program_id_index() as u8,
instruction_context.get_instruction_data().to_vec(),
(instruction_context.get_number_of_program_accounts()
..instruction_context.get_number_of_accounts())
.map(|index_in_instruction| {
instruction_context
.get_index_of_program_account_in_transaction(
instruction_context
.get_index_in_transaction(index_in_instruction)
.get_number_of_program_accounts()
.saturating_sub(1),
)
.unwrap_or_default() as u8,
instruction_context.get_instruction_data().to_vec(),
(0..instruction_context.get_number_of_instruction_accounts())
.map(|instruction_account_index| {
instruction_context
.get_index_of_instruction_account_in_transaction(
instruction_account_index,
)
.unwrap_or_default() as u8
})
.collect(),
@ -12207,7 +12214,7 @@ pub(crate) mod tests {
) -> std::result::Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let program_id = instruction_context.get_program_key(transaction_context)?;
let program_id = instruction_context.get_last_program_key(transaction_context)?;
if mock_vote_program_id() != *program_id {
return Err(InstructionError::IncorrectProgramId);
}
@ -14108,7 +14115,7 @@ pub(crate) mod tests {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let _ = instruction_context
.try_borrow_account(transaction_context, 1)?
.try_borrow_program_account(transaction_context, 1)?
.checked_add_lamports(1);
Ok(())
}

View File

@ -120,16 +120,16 @@ impl MessageProcessor {
}
let mut instruction_accounts = Vec::with_capacity(instruction.accounts.len());
for (index_in_instruction, index_in_transaction) in
for (instruction_account_index, index_in_transaction) in
instruction.accounts.iter().enumerate()
{
let index_in_callee = instruction
.accounts
.get(0..index_in_instruction)
.get(0..instruction_account_index)
.ok_or(TransactionError::InvalidAccountIndex)?
.iter()
.position(|account_index| account_index == index_in_transaction)
.unwrap_or(index_in_instruction);
.unwrap_or(instruction_account_index);
let index_in_transaction = *index_in_transaction as usize;
instruction_accounts.push(InstructionAccount {
index_in_transaction,

View File

@ -104,8 +104,8 @@ pub fn withdraw_nonce_account(
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
) -> Result<(), InstructionError> {
let mut from =
instruction_context.try_borrow_account(transaction_context, from_account_index)?;
let mut from = instruction_context
.try_borrow_instruction_account(transaction_context, from_account_index)?;
let merge_nonce_error_into_system_error = invoke_context
.feature_set
.is_active(&feature_set::merge_nonce_error_into_system_error::id());
@ -180,7 +180,8 @@ pub fn withdraw_nonce_account(
from.checked_sub_lamports(lamports)
.map_err(|_| InstructionError::ArithmeticOverflow)?;
drop(from);
let mut to = instruction_context.try_borrow_account(transaction_context, to_account_index)?;
let mut to = instruction_context
.try_borrow_instruction_account(transaction_context, to_account_index)?;
to.checked_add_lamports(lamports)
.map_err(|_| InstructionError::ArithmeticOverflow)?;
@ -450,9 +451,9 @@ mod test {
drop(nonce_account);
drop(to_account);
withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -621,9 +622,9 @@ mod test {
drop(nonce_account);
drop(to_account);
withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -666,9 +667,9 @@ mod test {
drop(nonce_account);
drop(to_account);
let result = withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -698,9 +699,9 @@ mod test {
let withdraw_lamports = nonce_account.get_lamports() + 1;
drop(nonce_account);
let result = withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -734,9 +735,9 @@ mod test {
drop(nonce_account);
drop(to_account);
withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -760,9 +761,9 @@ mod test {
drop(nonce_account);
drop(to_account);
withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -815,9 +816,9 @@ mod test {
drop(nonce_account);
drop(to_account);
withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -847,9 +848,9 @@ mod test {
drop(nonce_account);
drop(to_account);
withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -893,9 +894,9 @@ mod test {
drop(nonce_account);
drop(to_account);
let result = withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -926,9 +927,9 @@ mod test {
let withdraw_lamports = nonce_account.get_lamports() + 1;
drop(nonce_account);
let result = withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -959,9 +960,9 @@ mod test {
let withdraw_lamports = 42 + 1;
drop(nonce_account);
let result = withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,
@ -992,9 +993,9 @@ mod test {
let withdraw_lamports = u64::MAX - 54;
drop(nonce_account);
let result = withdraw_nonce_account(
1 + NONCE_ACCOUNT_INDEX,
NONCE_ACCOUNT_INDEX,
withdraw_lamports,
1 + WITHDRAW_TO_ACCOUNT_INDEX,
WITHDRAW_TO_ACCOUNT_INDEX,
&rent,
&signers,
&invoke_context,

View File

@ -158,8 +158,8 @@ fn create_account(
) -> Result<(), InstructionError> {
// if it looks like the `to` account is already in use, bail
{
let mut to =
instruction_context.try_borrow_account(transaction_context, to_account_index)?;
let mut to = instruction_context
.try_borrow_instruction_account(transaction_context, to_account_index)?;
if to.get_lamports() > 0 {
ic_msg!(
invoke_context,
@ -189,8 +189,8 @@ fn transfer_verified(
transaction_context: &TransactionContext,
instruction_context: &InstructionContext,
) -> Result<(), InstructionError> {
let mut from =
instruction_context.try_borrow_account(transaction_context, from_account_index)?;
let mut from = instruction_context
.try_borrow_instruction_account(transaction_context, from_account_index)?;
if !from.get_data().is_empty() {
ic_msg!(invoke_context, "Transfer: `from` must not carry data");
return Err(InstructionError::InvalidArgument);
@ -207,7 +207,8 @@ fn transfer_verified(
from.checked_sub_lamports(lamports)?;
drop(from);
let mut to = instruction_context.try_borrow_account(transaction_context, to_account_index)?;
let mut to = instruction_context
.try_borrow_instruction_account(transaction_context, to_account_index)?;
to.checked_add_lamports(lamports)?;
Ok(())
}
@ -228,12 +229,13 @@ fn transfer(
return Ok(());
}
if !instruction_context.is_signer(from_account_index)? {
if !instruction_context.is_instruction_account_signer(from_account_index)? {
ic_msg!(
invoke_context,
"Transfer: `from` account {} must sign",
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(from_account_index)?,
instruction_context
.get_index_of_instruction_account_in_transaction(from_account_index)?,
)?,
);
return Err(InstructionError::MissingRequiredSignature);
@ -268,26 +270,28 @@ fn transfer_with_seed(
return Ok(());
}
if !instruction_context.is_signer(from_base_account_index)? {
if !instruction_context.is_instruction_account_signer(from_base_account_index)? {
ic_msg!(
invoke_context,
"Transfer: 'from' account {:?} must sign",
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(from_base_account_index)?,
instruction_context
.get_index_of_instruction_account_in_transaction(from_base_account_index)?,
)?,
);
return Err(InstructionError::MissingRequiredSignature);
}
let address_from_seed = Pubkey::create_with_seed(
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(from_base_account_index)?,
instruction_context
.get_index_of_instruction_account_in_transaction(from_base_account_index)?,
)?,
from_seed,
from_owner,
)?;
let from_key = transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(from_account_index)?,
instruction_context.get_index_of_instruction_account_in_transaction(from_account_index)?,
)?;
if *from_key != address_from_seed {
ic_msg!(
@ -310,7 +314,7 @@ fn transfer_with_seed(
}
pub fn process_instruction(
first_instruction_account: usize,
_first_instruction_account: usize,
invoke_context: &mut InvokeContext,
) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
@ -330,14 +334,14 @@ pub fn process_instruction(
instruction_context.check_number_of_instruction_accounts(2)?;
let to_address = Address::create(
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account + 1)?,
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
)?,
None,
invoke_context,
)?;
create_account(
first_instruction_account,
first_instruction_account + 1,
0,
1,
&to_address,
lamports,
space,
@ -358,14 +362,14 @@ pub fn process_instruction(
instruction_context.check_number_of_instruction_accounts(2)?;
let to_address = Address::create(
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account + 1)?,
instruction_context.get_index_of_instruction_account_in_transaction(1)?,
)?,
Some((&base, &seed, &owner)),
invoke_context,
)?;
create_account(
first_instruction_account,
first_instruction_account + 1,
0,
1,
&to_address,
lamports,
space,
@ -378,11 +382,11 @@ pub fn process_instruction(
}
SystemInstruction::Assign { owner } => {
instruction_context.check_number_of_instruction_accounts(1)?;
let mut account = instruction_context
.try_borrow_account(transaction_context, first_instruction_account)?;
let mut account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let address = Address::create(
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account)?,
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
)?,
None,
invoke_context,
@ -392,8 +396,8 @@ pub fn process_instruction(
SystemInstruction::Transfer { lamports } => {
instruction_context.check_number_of_instruction_accounts(2)?;
transfer(
first_instruction_account,
first_instruction_account + 1,
0,
1,
lamports,
invoke_context,
transaction_context,
@ -407,11 +411,11 @@ pub fn process_instruction(
} => {
instruction_context.check_number_of_instruction_accounts(3)?;
transfer_with_seed(
first_instruction_account,
first_instruction_account + 1,
0,
1,
&from_seed,
&from_owner,
first_instruction_account + 2,
2,
lamports,
invoke_context,
transaction_context,
@ -447,9 +451,9 @@ pub fn process_instruction(
)?;
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?;
withdraw_nonce_account(
first_instruction_account,
0,
lamports,
first_instruction_account + 1,
1,
&rent,
&signers,
invoke_context,
@ -507,11 +511,11 @@ pub fn process_instruction(
}
SystemInstruction::Allocate { space } => {
instruction_context.check_number_of_instruction_accounts(1)?;
let mut account = instruction_context
.try_borrow_account(transaction_context, first_instruction_account)?;
let mut account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let address = Address::create(
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account)?,
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
)?,
None,
invoke_context,
@ -525,11 +529,11 @@ pub fn process_instruction(
owner,
} => {
instruction_context.check_number_of_instruction_accounts(1)?;
let mut account = instruction_context
.try_borrow_account(transaction_context, first_instruction_account)?;
let mut account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let address = Address::create(
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account)?,
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
)?,
Some((&base, &seed, &owner)),
invoke_context,
@ -545,11 +549,11 @@ pub fn process_instruction(
}
SystemInstruction::AssignWithSeed { base, seed, owner } => {
instruction_context.check_number_of_instruction_accounts(1)?;
let mut account = instruction_context
.try_borrow_account(transaction_context, first_instruction_account)?;
let mut account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let address = Address::create(
transaction_context.get_key_of_account_at_index(
instruction_context.get_index_in_transaction(first_instruction_account)?,
instruction_context.get_index_of_instruction_account_in_transaction(0)?,
)?,
Some((&base, &seed, &owner)),
invoke_context,

View File

@ -301,16 +301,6 @@ impl InstructionContext {
self.program_accounts.len()
}
/// Get the index of the instruction's program id
pub fn get_program_id_index(&self) -> usize {
self.program_accounts.last().cloned().unwrap_or_default()
}
/// Get the instruction's program id
pub fn get_program_id(&self, transaction_context: &TransactionContext) -> Pubkey {
transaction_context.account_keys[self.program_accounts.last().cloned().unwrap_or_default()]
}
/// Number of accounts in this Instruction (without program accounts)
pub fn get_number_of_instruction_accounts(&self) -> usize {
self.instruction_accounts.len()
@ -328,13 +318,6 @@ impl InstructionContext {
}
}
/// Number of accounts in this Instruction
pub fn get_number_of_accounts(&self) -> usize {
self.program_accounts
.len()
.saturating_add(self.instruction_accounts.len())
}
/// Data parameter for the programs `process_instruction` handler
pub fn get_instruction_data(&self) -> &[u8] {
&self.instruction_data
@ -353,8 +336,8 @@ impl InstructionContext {
})
}
/// Searches for an account by its key
pub fn find_index_of_account(
/// Searches for an instruction account by its key
pub fn find_index_of_instruction_account(
&self,
transaction_context: &TransactionContext,
pubkey: &Pubkey,
@ -365,82 +348,75 @@ impl InstructionContext {
&transaction_context.account_keys[instruction_account.index_in_transaction]
== pubkey
})
.map(|index| index.saturating_add(self.program_accounts.len()))
}
/// Translates the given instruction wide index into a transaction wide index
pub fn get_index_in_transaction(
/// Translates the given instruction wide program_account_index into a transaction wide index
pub fn get_index_of_program_account_in_transaction(
&self,
index_in_instruction: usize,
program_account_index: usize,
) -> Result<usize, InstructionError> {
if index_in_instruction < self.program_accounts.len() {
Ok(self.program_accounts[index_in_instruction])
} else if index_in_instruction < self.get_number_of_accounts() {
Ok(self.instruction_accounts
[index_in_instruction.saturating_sub(self.program_accounts.len())]
.index_in_transaction)
} else {
Err(InstructionError::NotEnoughAccountKeys)
}
Ok(*self
.program_accounts
.get(program_account_index)
.ok_or(InstructionError::NotEnoughAccountKeys)?)
}
/// Returns `Some(index_in_instruction)` if this is a duplicate
/// and `None` if it is the first account with this key
pub fn is_duplicate(
/// Translates the given instruction wide instruction_account_index into a transaction wide index
pub fn get_index_of_instruction_account_in_transaction(
&self,
index_in_instruction: usize,
instruction_account_index: usize,
) -> Result<usize, InstructionError> {
Ok(self
.instruction_accounts
.get(instruction_account_index)
.ok_or(InstructionError::NotEnoughAccountKeys)?
.index_in_transaction)
}
/// Returns `Some(instruction_account_index)` if this is a duplicate
/// and `None` if it is the first account with this key
pub fn is_instruction_account_duplicate(
&self,
instruction_account_index: usize,
) -> Result<Option<usize>, InstructionError> {
if index_in_instruction < self.program_accounts.len()
|| index_in_instruction >= self.get_number_of_accounts()
{
Err(InstructionError::NotEnoughAccountKeys)
let index_in_callee = self
.instruction_accounts
.get(instruction_account_index)
.ok_or(InstructionError::NotEnoughAccountKeys)?
.index_in_callee;
Ok(if index_in_callee == instruction_account_index {
None
} else {
let index_in_instruction =
index_in_instruction.saturating_sub(self.program_accounts.len());
let index_in_callee = self.instruction_accounts[index_in_instruction].index_in_callee;
Ok(if index_in_callee == index_in_instruction {
None
} else {
Some(index_in_callee)
})
}
Some(index_in_callee)
})
}
/// Gets the key of the last program account of this Instruction
pub fn get_program_key<'a, 'b: 'a>(
pub fn get_last_program_key<'a, 'b: 'a>(
&'a self,
transaction_context: &'b TransactionContext,
) -> Result<&'b Pubkey, InstructionError> {
let index_in_transaction =
self.get_index_in_transaction(self.program_accounts.len().saturating_sub(1))?;
transaction_context.get_key_of_account_at_index(index_in_transaction)
let result = self
.get_index_of_program_account_in_transaction(
self.program_accounts.len().saturating_sub(1),
)
.and_then(|index_in_transaction| {
transaction_context.get_key_of_account_at_index(index_in_transaction)
});
debug_assert!(result.is_ok());
result
}
/// Gets the key of an instruction account (skipping program accounts)
pub fn get_instruction_account_key<'a, 'b: 'a>(
&'a self,
transaction_context: &'b TransactionContext,
instruction_account_index: usize,
) -> Result<&'b Pubkey, InstructionError> {
let index_in_transaction = self.get_index_in_transaction(
self.program_accounts
.len()
.saturating_add(instruction_account_index),
)?;
transaction_context.get_key_of_account_at_index(index_in_transaction)
}
/// Tries to borrow an account from this Instruction
pub fn try_borrow_account<'a, 'b: 'a>(
fn try_borrow_account<'a, 'b: 'a>(
&'a self,
transaction_context: &'b TransactionContext,
index_in_transaction: usize,
index_in_instruction: usize,
) -> Result<BorrowedAccount<'a>, InstructionError> {
let index_in_transaction = self.get_index_in_transaction(index_in_instruction)?;
if index_in_transaction >= transaction_context.accounts.len() {
return Err(InstructionError::MissingAccount);
}
let account = transaction_context.accounts[index_in_transaction]
let account = transaction_context
.accounts
.get(index_in_transaction)
.ok_or(InstructionError::MissingAccount)?
.try_borrow_mut()
.map_err(|_| InstructionError::AccountBorrowFailed)?;
Ok(BorrowedAccount {
@ -453,13 +429,30 @@ impl InstructionContext {
}
/// Gets the last program account of this Instruction
pub fn try_borrow_program_account<'a, 'b: 'a>(
pub fn try_borrow_last_program_account<'a, 'b: 'a>(
&'a self,
transaction_context: &'b TransactionContext,
) -> Result<BorrowedAccount<'a>, InstructionError> {
self.try_borrow_account(
let result = self.try_borrow_program_account(
transaction_context,
self.program_accounts.len().saturating_sub(1),
);
debug_assert!(result.is_ok());
result
}
/// Tries to borrow a program account from this Instruction
pub fn try_borrow_program_account<'a, 'b: 'a>(
&'a self,
transaction_context: &'b TransactionContext,
program_account_index: usize,
) -> Result<BorrowedAccount<'a>, InstructionError> {
let index_in_transaction =
self.get_index_of_program_account_in_transaction(program_account_index)?;
self.try_borrow_account(
transaction_context,
index_in_transaction,
program_account_index,
)
}
@ -469,39 +462,42 @@ impl InstructionContext {
transaction_context: &'b TransactionContext,
instruction_account_index: usize,
) -> Result<BorrowedAccount<'a>, InstructionError> {
let index_in_transaction =
self.get_index_of_instruction_account_in_transaction(instruction_account_index)?;
self.try_borrow_account(
transaction_context,
index_in_transaction,
self.program_accounts
.len()
.saturating_add(instruction_account_index),
)
}
/// Returns whether an account is a signer
pub fn is_signer(&self, index_in_instruction: usize) -> Result<bool, InstructionError> {
Ok(if index_in_instruction < self.program_accounts.len() {
false
} else {
self.instruction_accounts
.get(index_in_instruction.saturating_sub(self.program_accounts.len()))
.ok_or(InstructionError::MissingAccount)?
.is_signer
})
/// Returns whether an instruction account is a signer
pub fn is_instruction_account_signer(
&self,
instruction_account_index: usize,
) -> Result<bool, InstructionError> {
Ok(self
.instruction_accounts
.get(instruction_account_index)
.ok_or(InstructionError::MissingAccount)?
.is_signer)
}
/// Returns whether an account is writable
pub fn is_writable(&self, index_in_instruction: usize) -> Result<bool, InstructionError> {
Ok(if index_in_instruction < self.program_accounts.len() {
false
} else {
self.instruction_accounts
.get(index_in_instruction.saturating_sub(self.program_accounts.len()))
.ok_or(InstructionError::MissingAccount)?
.is_writable
})
/// Returns whether an instruction account is writable
pub fn is_instruction_account_writable(
&self,
instruction_account_index: usize,
) -> Result<bool, InstructionError> {
Ok(self
.instruction_accounts
.get(instruction_account_index)
.ok_or(InstructionError::MissingAccount)?
.is_writable)
}
/// Calculates the set of all keys of signer accounts in this Instruction
/// Calculates the set of all keys of signer instruction accounts in this Instruction
pub fn get_signers(&self, transaction_context: &TransactionContext) -> HashSet<Pubkey> {
let mut result = HashSet::new();
for instruction_account in self.instruction_accounts.iter() {
@ -531,11 +527,6 @@ impl<'a> BorrowedAccount<'a> {
self.index_in_transaction
}
/// Returns the index of this account (instruction wide)
pub fn get_index_in_instruction(&self) -> usize {
self.index_in_instruction
}
/// Returns the public key of this account (transaction wide)
pub fn get_key(&self) -> &Pubkey {
&self.transaction_context.account_keys[self.index_in_transaction]
@ -646,15 +637,27 @@ impl<'a> BorrowedAccount<'a> {
/// Returns whether this account is a signer (instruction wide)
pub fn is_signer(&self) -> bool {
if self.index_in_instruction < self.instruction_context.program_accounts.len() {
return false;
}
self.instruction_context
.is_signer(self.index_in_instruction)
.is_instruction_account_signer(
self.index_in_instruction
.saturating_sub(self.instruction_context.program_accounts.len()),
)
.unwrap_or_default()
}
/// Returns whether this account is writable (instruction wide)
pub fn is_writable(&self) -> bool {
if self.index_in_instruction < self.instruction_context.program_accounts.len() {
return false;
}
self.instruction_context
.is_writable(self.index_in_instruction)
.is_instruction_account_writable(
self.index_in_instruction
.saturating_sub(self.instruction_context.program_accounts.len()),
)
.unwrap_or_default()
}
}