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()); 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() 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 continue; // Skip duplicate account
} }
if instruction_account.index_in_transaction if instruction_account.index_in_transaction
@ -398,7 +398,8 @@ impl<'a> InvokeContext<'a> {
self.transaction_context self.transaction_context
.get_instruction_context_at(level) .get_instruction_context_at(level)
.and_then(|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) .map(|program_account| program_account.get_key() == program_id)
.unwrap_or(false) .unwrap_or(false)
@ -407,7 +408,7 @@ impl<'a> InvokeContext<'a> {
.transaction_context .transaction_context
.get_current_instruction_context() .get_current_instruction_context()
.and_then(|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) .map(|program_account| program_account.get_key() == program_id)
.unwrap_or(false); .unwrap_or(false);
@ -490,7 +491,7 @@ impl<'a> InvokeContext<'a> {
.get_current_instruction_context() .get_current_instruction_context()
.map_err(|_| InstructionError::CallDepth)?; .map_err(|_| InstructionError::CallDepth)?;
let program_id = instruction_context let program_id = instruction_context
.get_program_key(self.transaction_context) .get_last_program_key(self.transaction_context)
.map_err(|_| InstructionError::CallDepth)?; .map_err(|_| InstructionError::CallDepth)?;
// Verify all executable accounts have zero outstanding refs // Verify all executable accounts have zero outstanding refs
@ -504,8 +505,10 @@ impl<'a> InvokeContext<'a> {
// Verify the per-account instruction results // Verify the per-account instruction results
let (mut pre_sum, mut post_sum) = (0_u128, 0_u128); let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
let mut pre_account_index = 0; let mut pre_account_index = 0;
for (index_in_instruction, instruction_account) in instruction_accounts.iter().enumerate() { for (instruction_account_index, instruction_account) in
if index_in_instruction != instruction_account.index_in_callee { instruction_accounts.iter().enumerate()
{
if instruction_account_index != instruction_account.index_in_callee {
continue; // Skip duplicate account continue; // Skip duplicate account
} }
{ {
@ -581,13 +584,15 @@ impl<'a> InvokeContext<'a> {
let transaction_context = &self.transaction_context; let transaction_context = &self.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_context = transaction_context.get_current_instruction_context()?;
let program_id = instruction_context let program_id = instruction_context
.get_program_key(transaction_context) .get_last_program_key(transaction_context)
.map_err(|_| InstructionError::CallDepth)?; .map_err(|_| InstructionError::CallDepth)?;
// Verify the per-account instruction results // Verify the per-account instruction results
let (mut pre_sum, mut post_sum) = (0_u128, 0_u128); let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
for (index_in_instruction, instruction_account) in instruction_accounts.iter().enumerate() { for (instruction_account_index, instruction_account) in
if index_in_instruction != instruction_account.index_in_callee { instruction_accounts.iter().enumerate()
{
if instruction_account_index != instruction_account.index_in_callee {
continue; // Skip duplicate account continue; // Skip duplicate account
} }
if instruction_account.index_in_transaction if instruction_account.index_in_transaction
@ -599,11 +604,7 @@ impl<'a> InvokeContext<'a> {
.get_account_at_index(instruction_account.index_in_transaction)?; .get_account_at_index(instruction_account.index_in_transaction)?;
let is_writable = if before_instruction_context_push { let is_writable = if before_instruction_context_push {
instruction_context instruction_context
.try_borrow_instruction_account( .is_instruction_account_writable(instruction_account.index_in_caller)?
self.transaction_context,
instruction_account.index_in_caller,
)?
.is_writable()
} else { } else {
instruction_account.is_writable instruction_account.is_writable
}; };
@ -713,7 +714,7 @@ impl<'a> InvokeContext<'a> {
let instruction_context = self.transaction_context.get_current_instruction_context()?; let instruction_context = self.transaction_context.get_current_instruction_context()?;
let mut deduplicated_instruction_accounts: Vec<InstructionAccount> = Vec::new(); let mut deduplicated_instruction_accounts: Vec<InstructionAccount> = Vec::new();
let mut duplicate_indicies = Vec::with_capacity(instruction.accounts.len()); 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 let index_in_transaction = self
.transaction_context .transaction_context
.find_index_of_account(&account_meta.pubkey) .find_index_of_account(&account_meta.pubkey)
@ -740,10 +741,10 @@ impl<'a> InvokeContext<'a> {
instruction_account.is_writable |= account_meta.is_writable; instruction_account.is_writable |= account_meta.is_writable;
} else { } else {
let index_in_caller = instruction_context let index_in_caller = instruction_context
.find_index_of_account(self.transaction_context, &account_meta.pubkey) .find_index_of_instruction_account(
.map(|index| { self.transaction_context,
index.saturating_sub(instruction_context.get_number_of_program_accounts()) &account_meta.pubkey,
}) )
.ok_or_else(|| { .ok_or_else(|| {
ic_msg!( ic_msg!(
self, self,
@ -756,7 +757,7 @@ impl<'a> InvokeContext<'a> {
deduplicated_instruction_accounts.push(InstructionAccount { deduplicated_instruction_accounts.push(InstructionAccount {
index_in_transaction, index_in_transaction,
index_in_caller, index_in_caller,
index_in_callee: index_in_instruction, index_in_callee: instruction_account_index,
is_signer: account_meta.is_signer, is_signer: account_meta.is_signer,
is_writable: account_meta.is_writable, is_writable: account_meta.is_writable,
}); });
@ -804,13 +805,13 @@ impl<'a> InvokeContext<'a> {
// Find and validate executables / program accounts // Find and validate executables / program accounts
let callee_program_id = instruction.program_id; let callee_program_id = instruction.program_id;
let program_account_index = instruction_context 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(|| { .ok_or_else(|| {
ic_msg!(self, "Unknown program {}", callee_program_id); ic_msg!(self, "Unknown program {}", callee_program_id);
InstructionError::MissingAccount InstructionError::MissingAccount
})?; })?;
let borrowed_program_account = instruction_context 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() { if !borrowed_program_account.is_executable() {
ic_msg!(self, "Account {} is not executable", callee_program_id); ic_msg!(self, "Account {} is not executable", callee_program_id);
return Err(InstructionError::AccountNotExecutable); return Err(InstructionError::AccountNotExecutable);
@ -952,7 +953,7 @@ impl<'a> InvokeContext<'a> {
let (first_instruction_account, builtin_id) = { let (first_instruction_account, builtin_id) = {
let borrowed_root_account = instruction_context 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)?; .map_err(|_| InstructionError::UnsupportedProgramId)?;
let owner_id = borrowed_root_account.get_owner(); let owner_id = borrowed_root_account.get_owner();
if solana_sdk::native_loader::check_id(owner_id) { if solana_sdk::native_loader::check_id(owner_id) {
@ -964,7 +965,8 @@ impl<'a> InvokeContext<'a> {
for entry in self.builtin_programs { for entry in self.builtin_programs {
if entry.program_id == builtin_id { 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 { if builtin_id == program_id {
let logger = self.get_log_collector(); let logger = self.get_log_collector();
stable_log::program_invoke(&logger, &program_id, self.get_stack_height()); stable_log::program_invoke(&logger, &program_id, self.get_stack_height());
@ -1123,19 +1125,19 @@ pub fn prepare_mock_invoke_context(
) -> MockInvokeContextPreparation { ) -> MockInvokeContextPreparation {
let mut instruction_accounts: Vec<InstructionAccount> = let mut instruction_accounts: Vec<InstructionAccount> =
Vec::with_capacity(instruction_account_metas.len()); 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 let index_in_transaction = transaction_accounts
.iter() .iter()
.position(|(key, _account)| *key == account_meta.pubkey) .position(|(key, _account)| *key == account_meta.pubkey)
.unwrap_or(transaction_accounts.len()); .unwrap_or(transaction_accounts.len());
let index_in_callee = instruction_accounts let index_in_callee = instruction_accounts
.get(0..index_in_instruction) .get(0..instruction_account_index)
.unwrap() .unwrap()
.iter() .iter()
.position(|instruction_account| { .position(|instruction_account| {
instruction_account.index_in_transaction == index_in_transaction instruction_account.index_in_transaction == index_in_transaction
}) })
.unwrap_or(index_in_instruction); .unwrap_or(instruction_account_index);
instruction_accounts.push(InstructionAccount { instruction_accounts.push(InstructionAccount {
index_in_transaction, index_in_transaction,
index_in_caller: index_in_transaction, index_in_caller: index_in_transaction,
@ -1295,7 +1297,7 @@ mod tests {
let transaction_context = &invoke_context.transaction_context; let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data(); 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!( assert_eq!(
program_id, program_id,
instruction_context instruction_context
@ -1528,12 +1530,12 @@ mod tests {
AccountMeta::new_readonly(accounts.get(2).unwrap().0, false), AccountMeta::new_readonly(accounts.get(2).unwrap().0, false),
]; ];
let instruction_accounts = (0..4) let instruction_accounts = (0..4)
.map(|index_in_instruction| InstructionAccount { .map(|instruction_account_index| InstructionAccount {
index_in_transaction: index_in_instruction, index_in_transaction: instruction_account_index,
index_in_caller: index_in_instruction, index_in_caller: instruction_account_index,
index_in_callee: index_in_instruction, index_in_callee: instruction_account_index,
is_signer: false, is_signer: false,
is_writable: index_in_instruction < 2, is_writable: instruction_account_index < 2,
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut transaction_context = TransactionContext::new(accounts, 2, 8); 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_context: &InstructionContext,
instruction_account_index: usize, instruction_account_index: usize,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if !S::check_id( let index_in_transaction = instruction_context
instruction_context .get_index_of_instruction_account_in_transaction(instruction_account_index)?;
.get_instruction_account_key(transaction_context, instruction_account_index)?, if !S::check_id(transaction_context.get_key_of_account_at_index(index_in_transaction)?) {
) {
return Err(InstructionError::InvalidArgument); return Err(InstructionError::InvalidArgument);
} }
Ok(()) Ok(())
@ -198,12 +197,12 @@ pub mod get_sysvar_with_account_check {
pub fn clock( pub fn clock(
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
instruction_context: &InstructionContext, instruction_context: &InstructionContext,
index_in_instruction: usize, instruction_account_index: usize,
) -> Result<Arc<Clock>, InstructionError> { ) -> Result<Arc<Clock>, InstructionError> {
check_sysvar_account::<Clock>( check_sysvar_account::<Clock>(
invoke_context.transaction_context, invoke_context.transaction_context,
instruction_context, instruction_context,
index_in_instruction, instruction_account_index,
)?; )?;
invoke_context.get_sysvar_cache().get_clock() invoke_context.get_sysvar_cache().get_clock()
} }
@ -211,12 +210,12 @@ pub mod get_sysvar_with_account_check {
pub fn rent( pub fn rent(
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
instruction_context: &InstructionContext, instruction_context: &InstructionContext,
index_in_instruction: usize, instruction_account_index: usize,
) -> Result<Arc<Rent>, InstructionError> { ) -> Result<Arc<Rent>, InstructionError> {
check_sysvar_account::<Rent>( check_sysvar_account::<Rent>(
invoke_context.transaction_context, invoke_context.transaction_context,
instruction_context, instruction_context,
index_in_instruction, instruction_account_index,
)?; )?;
invoke_context.get_sysvar_cache().get_rent() invoke_context.get_sysvar_cache().get_rent()
} }
@ -224,12 +223,12 @@ pub mod get_sysvar_with_account_check {
pub fn slot_hashes( pub fn slot_hashes(
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
instruction_context: &InstructionContext, instruction_context: &InstructionContext,
index_in_instruction: usize, instruction_account_index: usize,
) -> Result<Arc<SlotHashes>, InstructionError> { ) -> Result<Arc<SlotHashes>, InstructionError> {
check_sysvar_account::<SlotHashes>( check_sysvar_account::<SlotHashes>(
invoke_context.transaction_context, invoke_context.transaction_context,
instruction_context, instruction_context,
index_in_instruction, instruction_account_index,
)?; )?;
invoke_context.get_sysvar_cache().get_slot_hashes() invoke_context.get_sysvar_cache().get_slot_hashes()
} }
@ -238,12 +237,12 @@ pub mod get_sysvar_with_account_check {
pub fn recent_blockhashes( pub fn recent_blockhashes(
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
instruction_context: &InstructionContext, instruction_context: &InstructionContext,
index_in_instruction: usize, instruction_account_index: usize,
) -> Result<Arc<RecentBlockhashes>, InstructionError> { ) -> Result<Arc<RecentBlockhashes>, InstructionError> {
check_sysvar_account::<RecentBlockhashes>( check_sysvar_account::<RecentBlockhashes>(
invoke_context.transaction_context, invoke_context.transaction_context,
instruction_context, instruction_context,
index_in_instruction, instruction_account_index,
)?; )?;
invoke_context.get_sysvar_cache().get_recent_blockhashes() invoke_context.get_sysvar_cache().get_recent_blockhashes()
} }
@ -251,12 +250,12 @@ pub mod get_sysvar_with_account_check {
pub fn stake_history( pub fn stake_history(
invoke_context: &InvokeContext, invoke_context: &InvokeContext,
instruction_context: &InstructionContext, instruction_context: &InstructionContext,
index_in_instruction: usize, instruction_account_index: usize,
) -> Result<Arc<StakeHistory>, InstructionError> { ) -> Result<Arc<StakeHistory>, InstructionError> {
check_sysvar_account::<StakeHistory>( check_sysvar_account::<StakeHistory>(
invoke_context.transaction_context, invoke_context.transaction_context,
instruction_context, instruction_context,
index_in_instruction, instruction_account_index,
)?; )?;
invoke_context.get_sysvar_cache().get_stake_history() 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 transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_context = transaction_context.get_current_instruction_context()?;
let instruction_data = instruction_context.get_instruction_data(); let instruction_data = instruction_context.get_instruction_data();
let indices_in_instruction = instruction_context.get_number_of_program_accounts() let instruction_account_indices = 0..instruction_context.get_number_of_instruction_accounts();
..instruction_context.get_number_of_accounts();
let log_collector = invoke_context.get_log_collector(); 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( stable_log::program_invoke(
&log_collector, &log_collector,
program_id, program_id,
@ -113,14 +112,14 @@ pub fn builtin_process_instruction(
); );
// Copy indices_in_instruction into a HashSet to ensure there are no duplicates // 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 // Create copies of the accounts
let mut account_copies = deduplicated_indices let mut account_copies = deduplicated_indices
.iter() .iter()
.map(|index_in_instruction| { .map(|instruction_account_index| {
let borrowed_account = instruction_context let borrowed_account = instruction_context
.try_borrow_account(transaction_context, *index_in_instruction)?; .try_borrow_instruction_account(transaction_context, *instruction_account_index)?;
Ok(( Ok((
*borrowed_account.get_key(), *borrowed_account.get_key(),
*borrowed_account.get_owner(), *borrowed_account.get_owner(),
@ -144,15 +143,15 @@ pub fn builtin_process_instruction(
.collect(); .collect();
// Create AccountInfos // Create AccountInfos
let account_infos = indices_in_instruction let account_infos = instruction_account_indices
.map(|index_in_instruction| { .map(|instruction_account_index| {
let account_copy_index = deduplicated_indices let account_copy_index = deduplicated_indices
.iter() .iter()
.position(|index| *index == index_in_instruction) .position(|index| *index == instruction_account_index)
.unwrap(); .unwrap();
let (key, owner, lamports, data) = &account_refs[account_copy_index]; let (key, owner, lamports, data) = &account_refs[account_copy_index];
let borrowed_account = instruction_context let borrowed_account = instruction_context
.try_borrow_account(transaction_context, index_in_instruction)?; .try_borrow_instruction_account(transaction_context, instruction_account_index)?;
Ok(AccountInfo { Ok(AccountInfo {
key, key,
is_signer: borrowed_account.is_signer(), is_signer: borrowed_account.is_signer(),
@ -175,12 +174,12 @@ pub fn builtin_process_instruction(
stable_log::program_success(&log_collector, program_id); stable_log::program_success(&log_collector, program_id);
// Commit AccountInfo changes back into KeyedAccounts // 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() .into_iter()
.zip(account_copies.into_iter()) .zip(account_copies.into_iter())
{ {
let mut borrowed_account = let mut borrowed_account = instruction_context
instruction_context.try_borrow_account(transaction_context, index_in_instruction)?; .try_borrow_instruction_account(transaction_context, instruction_account_index)?;
if borrowed_account.is_writable() { if borrowed_account.is_writable() {
borrowed_account.set_lamports(lamports)?; borrowed_account.set_lamports(lamports)?;
borrowed_account.set_data(&data)?; borrowed_account.set_data(&data)?;
@ -253,7 +252,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
.get_current_instruction_context() .get_current_instruction_context()
.unwrap(); .unwrap();
let caller = instruction_context let caller = instruction_context
.get_program_key(transaction_context) .get_last_program_key(transaction_context)
.unwrap(); .unwrap();
stable_log::program_invoke( stable_log::program_invoke(
@ -379,7 +378,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
.get_current_instruction_context() .get_current_instruction_context()
.unwrap(); .unwrap();
let caller = *instruction_context let caller = *instruction_context
.get_program_key(transaction_context) .get_last_program_key(transaction_context)
.unwrap(); .unwrap();
transaction_context transaction_context
.set_return_data(caller, data.to_vec()) .set_return_data(caller, data.to_vec())

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -301,16 +301,6 @@ impl InstructionContext {
self.program_accounts.len() 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) /// Number of accounts in this Instruction (without program accounts)
pub fn get_number_of_instruction_accounts(&self) -> usize { pub fn get_number_of_instruction_accounts(&self) -> usize {
self.instruction_accounts.len() 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 /// Data parameter for the programs `process_instruction` handler
pub fn get_instruction_data(&self) -> &[u8] { pub fn get_instruction_data(&self) -> &[u8] {
&self.instruction_data &self.instruction_data
@ -353,8 +336,8 @@ impl InstructionContext {
}) })
} }
/// Searches for an account by its key /// Searches for an instruction account by its key
pub fn find_index_of_account( pub fn find_index_of_instruction_account(
&self, &self,
transaction_context: &TransactionContext, transaction_context: &TransactionContext,
pubkey: &Pubkey, pubkey: &Pubkey,
@ -365,82 +348,75 @@ impl InstructionContext {
&transaction_context.account_keys[instruction_account.index_in_transaction] &transaction_context.account_keys[instruction_account.index_in_transaction]
== pubkey == pubkey
}) })
.map(|index| index.saturating_add(self.program_accounts.len()))
} }
/// Translates the given instruction wide index into a transaction wide index /// Translates the given instruction wide program_account_index into a transaction wide index
pub fn get_index_in_transaction( pub fn get_index_of_program_account_in_transaction(
&self, &self,
index_in_instruction: usize, program_account_index: usize,
) -> Result<usize, InstructionError> { ) -> Result<usize, InstructionError> {
if index_in_instruction < self.program_accounts.len() { Ok(*self
Ok(self.program_accounts[index_in_instruction]) .program_accounts
} else if index_in_instruction < self.get_number_of_accounts() { .get(program_account_index)
Ok(self.instruction_accounts .ok_or(InstructionError::NotEnoughAccountKeys)?)
[index_in_instruction.saturating_sub(self.program_accounts.len())]
.index_in_transaction)
} else {
Err(InstructionError::NotEnoughAccountKeys)
}
} }
/// Returns `Some(index_in_instruction)` if this is a duplicate /// Translates the given instruction wide instruction_account_index into a transaction wide index
/// and `None` if it is the first account with this key pub fn get_index_of_instruction_account_in_transaction(
pub fn is_duplicate(
&self, &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> { ) -> Result<Option<usize>, InstructionError> {
if index_in_instruction < self.program_accounts.len() let index_in_callee = self
|| index_in_instruction >= self.get_number_of_accounts() .instruction_accounts
{ .get(instruction_account_index)
Err(InstructionError::NotEnoughAccountKeys) .ok_or(InstructionError::NotEnoughAccountKeys)?
.index_in_callee;
Ok(if index_in_callee == instruction_account_index {
None
} else { } else {
let index_in_instruction = Some(index_in_callee)
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)
})
}
} }
/// Gets the key of the last program account of this Instruction /// 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, &'a self,
transaction_context: &'b TransactionContext, transaction_context: &'b TransactionContext,
) -> Result<&'b Pubkey, InstructionError> { ) -> Result<&'b Pubkey, InstructionError> {
let index_in_transaction = let result = self
self.get_index_in_transaction(self.program_accounts.len().saturating_sub(1))?; .get_index_of_program_account_in_transaction(
transaction_context.get_key_of_account_at_index(index_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) fn try_borrow_account<'a, 'b: 'a>(
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>(
&'a self, &'a self,
transaction_context: &'b TransactionContext, transaction_context: &'b TransactionContext,
index_in_transaction: usize,
index_in_instruction: usize, index_in_instruction: usize,
) -> Result<BorrowedAccount<'a>, InstructionError> { ) -> Result<BorrowedAccount<'a>, InstructionError> {
let index_in_transaction = self.get_index_in_transaction(index_in_instruction)?; let account = transaction_context
if index_in_transaction >= transaction_context.accounts.len() { .accounts
return Err(InstructionError::MissingAccount); .get(index_in_transaction)
} .ok_or(InstructionError::MissingAccount)?
let account = transaction_context.accounts[index_in_transaction]
.try_borrow_mut() .try_borrow_mut()
.map_err(|_| InstructionError::AccountBorrowFailed)?; .map_err(|_| InstructionError::AccountBorrowFailed)?;
Ok(BorrowedAccount { Ok(BorrowedAccount {
@ -453,13 +429,30 @@ impl InstructionContext {
} }
/// Gets the last program account of this Instruction /// 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, &'a self,
transaction_context: &'b TransactionContext, transaction_context: &'b TransactionContext,
) -> Result<BorrowedAccount<'a>, InstructionError> { ) -> Result<BorrowedAccount<'a>, InstructionError> {
self.try_borrow_account( let result = self.try_borrow_program_account(
transaction_context, transaction_context,
self.program_accounts.len().saturating_sub(1), 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, transaction_context: &'b TransactionContext,
instruction_account_index: usize, instruction_account_index: usize,
) -> Result<BorrowedAccount<'a>, InstructionError> { ) -> Result<BorrowedAccount<'a>, InstructionError> {
let index_in_transaction =
self.get_index_of_instruction_account_in_transaction(instruction_account_index)?;
self.try_borrow_account( self.try_borrow_account(
transaction_context, transaction_context,
index_in_transaction,
self.program_accounts self.program_accounts
.len() .len()
.saturating_add(instruction_account_index), .saturating_add(instruction_account_index),
) )
} }
/// Returns whether an account is a signer /// Returns whether an instruction account is a signer
pub fn is_signer(&self, index_in_instruction: usize) -> Result<bool, InstructionError> { pub fn is_instruction_account_signer(
Ok(if index_in_instruction < self.program_accounts.len() { &self,
false instruction_account_index: usize,
} else { ) -> Result<bool, InstructionError> {
self.instruction_accounts Ok(self
.get(index_in_instruction.saturating_sub(self.program_accounts.len())) .instruction_accounts
.ok_or(InstructionError::MissingAccount)? .get(instruction_account_index)
.is_signer .ok_or(InstructionError::MissingAccount)?
}) .is_signer)
} }
/// Returns whether an account is writable /// Returns whether an instruction account is writable
pub fn is_writable(&self, index_in_instruction: usize) -> Result<bool, InstructionError> { pub fn is_instruction_account_writable(
Ok(if index_in_instruction < self.program_accounts.len() { &self,
false instruction_account_index: usize,
} else { ) -> Result<bool, InstructionError> {
self.instruction_accounts Ok(self
.get(index_in_instruction.saturating_sub(self.program_accounts.len())) .instruction_accounts
.ok_or(InstructionError::MissingAccount)? .get(instruction_account_index)
.is_writable .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> { pub fn get_signers(&self, transaction_context: &TransactionContext) -> HashSet<Pubkey> {
let mut result = HashSet::new(); let mut result = HashSet::new();
for instruction_account in self.instruction_accounts.iter() { for instruction_account in self.instruction_accounts.iter() {
@ -531,11 +527,6 @@ impl<'a> BorrowedAccount<'a> {
self.index_in_transaction 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) /// Returns the public key of this account (transaction wide)
pub fn get_key(&self) -> &Pubkey { pub fn get_key(&self) -> &Pubkey {
&self.transaction_context.account_keys[self.index_in_transaction] &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) /// Returns whether this account is a signer (instruction wide)
pub fn is_signer(&self) -> bool { pub fn is_signer(&self) -> bool {
if self.index_in_instruction < self.instruction_context.program_accounts.len() {
return false;
}
self.instruction_context 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() .unwrap_or_default()
} }
/// Returns whether this account is writable (instruction wide) /// Returns whether this account is writable (instruction wide)
pub fn is_writable(&self) -> bool { pub fn is_writable(&self) -> bool {
if self.index_in_instruction < self.instruction_context.program_accounts.len() {
return false;
}
self.instruction_context 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() .unwrap_or_default()
} }
} }