From 7ced0050cf62dcec397b09f11e5afd27515aa747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Tue, 15 Mar 2022 00:06:52 +0100 Subject: [PATCH 1/6] Revert "Replaces KeyedAccount by BorrowedAccount in the BPF loader. (#23056)" 6c56eb9663ef0280cf7f53202425d6530d9e6ca4 --- programs/bpf_loader/src/lib.rs | 918 ++++++++++++++------------------- 1 file changed, 385 insertions(+), 533 deletions(-) diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index b1d52b60654c38..735f56ba0e40ac 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -25,7 +25,7 @@ use { invoke_context::{ComputeMeter, Executor, InvokeContext}, log_collector::LogCollector, stable_log, - sysvar_cache::get_sysvar_with_account_check2, + sysvar_cache::get_sysvar_with_account_check, }, solana_rbpf::{ aligned_memory::AlignedMemory, @@ -37,6 +37,8 @@ use { vm::{Config, EbpfVm, InstructionMeter}, }, solana_sdk::{ + account::{ReadableAccount, WritableAccount}, + account_utils::State, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, entrypoint::{HEAP_LENGTH, SUCCESS}, @@ -46,6 +48,7 @@ use { reduce_required_deploy_balance, requestable_heap_size, }, instruction::{AccountMeta, InstructionError}, + keyed_account::{keyed_account_at_index, KeyedAccount}, loader_instruction::LoaderInstruction, loader_upgradeable_instruction::UpgradeableLoaderInstruction, program_error::MAX_ACCOUNTS_DATA_SIZE_EXCEEDED, @@ -53,7 +56,6 @@ use { pubkey::Pubkey, saturating_add_assign, system_instruction::{self, MAX_PERMITTED_DATA_LENGTH}, - transaction_context::{BorrowedAccount, InstructionContext, TransactionContext}, }, std::{cell::RefCell, fmt::Debug, pin::Pin, rc::Rc, sync::Arc}, thiserror::Error, @@ -137,15 +139,14 @@ pub fn create_executor( }; let mut create_executor_metrics = executor_metrics::CreateMetrics::default(); let mut executable = { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let programdata = instruction_context - .try_borrow_account(transaction_context, programdata_account_index)?; - create_executor_metrics.program_id = programdata.get_key().to_string(); + let keyed_accounts = invoke_context.get_keyed_accounts()?; + let programdata = keyed_account_at_index(keyed_accounts, programdata_account_index)?; + create_executor_metrics.program_id = programdata.unsigned_key().to_string(); let mut load_elf_time = Measure::start("load_elf_time"); let executable = Executable::::from_elf( programdata - .get_data() + .try_account_ref()? + .data() .get(programdata_offset..) .ok_or(InstructionError::AccountDataTooSmall)?, None, @@ -193,24 +194,27 @@ pub fn create_executor( })) } -fn write_program_data<'a>( - program: &mut BorrowedAccount<'a>, +fn write_program_data( + program_account_index: usize, program_data_offset: usize, bytes: &[u8], - log_collector: Option>>, + invoke_context: &mut InvokeContext, ) -> Result<(), InstructionError> { - let data = program.get_data_mut(); - let write_offset = program_data_offset.saturating_add(bytes.len()); - if data.len() < write_offset || (program_data_offset..write_offset).len() != bytes.len() { - ic_logger_msg!( - log_collector, + let keyed_accounts = invoke_context.get_keyed_accounts()?; + let program = keyed_account_at_index(keyed_accounts, program_account_index)?; + let mut account = program.try_account_ref_mut()?; + let data = &mut account.data_as_mut_slice(); + let len = bytes.len(); + if data.len() < program_data_offset.saturating_add(len) { + ic_msg!( + invoke_context, "Write overflow: {} < {}", data.len(), - write_offset + program_data_offset.saturating_add(len), ); return Err(InstructionError::AccountDataTooSmall); } - data.get_mut(program_data_offset..write_offset) + data.get_mut(program_data_offset..program_data_offset.saturating_add(len)) .ok_or(InstructionError::AccountDataTooSmall)? .copy_from_slice(bytes); Ok(()) @@ -284,36 +288,28 @@ fn process_instruction_common( let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let program_id = instruction_context.get_program_key(transaction_context)?; - let first_account_key = transaction_context.get_key_of_account_at_index( - instruction_context.get_index_in_transaction(first_instruction_account)?, - )?; - let second_account_key = instruction_context - .get_index_in_transaction(first_instruction_account.saturating_add(1)) - .and_then(|index_in_transaction| { - transaction_context.get_key_of_account_at_index(index_in_transaction) - }); - let program_account_index = if first_account_key == program_id { - first_instruction_account - } else if second_account_key - .map(|key| key == program_id) + let keyed_accounts = invoke_context.get_keyed_accounts()?; + let first_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let second_account = + keyed_account_at_index(keyed_accounts, first_instruction_account.saturating_add(1)); + let (program, next_first_instruction_account) = if first_account.unsigned_key() == program_id { + (first_account, first_instruction_account) + } else if second_account + .as_ref() + .map(|keyed_account| keyed_account.unsigned_key() == program_id) .unwrap_or(false) { - first_instruction_account.saturating_add(1) + (second_account?, first_instruction_account.saturating_add(1)) } else { - if instruction_context - .try_borrow_account(transaction_context, first_instruction_account)? - .is_executable() - { + if first_account.executable()? { ic_logger_msg!(log_collector, "BPF loader is executable"); return Err(InstructionError::IncorrectProgramId); } - first_instruction_account + (first_account, first_instruction_account) }; - let program = - instruction_context.try_borrow_account(transaction_context, program_account_index)?; - if program.is_executable() { + if program.executable()? { // First instruction account can only be zero if called from CPI, which // means stack height better be greater than one debug_assert_eq!( @@ -321,7 +317,7 @@ fn process_instruction_common( invoke_context.get_stack_height() > 1 ); - if !check_loader_id(program.get_owner()) { + if !check_loader_id(&program.owner()?) { ic_logger_msg!( log_collector, "Executable account not owned by the BPF loader" @@ -329,12 +325,12 @@ fn process_instruction_common( return Err(InstructionError::IncorrectProgramId); } - let program_data_offset = if bpf_loader_upgradeable::check_id(program.get_owner()) { + let program_data_offset = if bpf_loader_upgradeable::check_id(&program.owner()?) { if let UpgradeableLoaderState::Program { programdata_address, - } = program.get_state()? + } = program.state()? { - if programdata_address != *first_account_key { + if programdata_address != *first_account.unsigned_key() { ic_logger_msg!( log_collector, "Wrong ProgramData account for this Program account" @@ -342,9 +338,7 @@ fn process_instruction_common( return Err(InstructionError::InvalidArgument); } if !matches!( - instruction_context - .try_borrow_account(transaction_context, first_instruction_account)? - .get_state()?, + first_account.state()?, UpgradeableLoaderState::ProgramData { slot: _, upgrade_authority_address: _, @@ -361,7 +355,6 @@ fn process_instruction_common( } else { 0 }; - drop(program); let mut get_or_create_executor_time = Measure::start("get_or_create_executor_time"); let executor = match invoke_context.get_executor(program_id) { @@ -387,9 +380,12 @@ fn process_instruction_common( get_or_create_executor_time.as_us() ); - executor.execute(program_account_index, instruction_data, invoke_context) + executor.execute( + next_first_instruction_account, + instruction_data, + invoke_context, + ) } else { - drop(program); debug_assert_eq!(first_instruction_account, 1); if bpf_loader_upgradeable::check_id(program_id) { process_loader_upgradeable_instruction( @@ -412,52 +408,6 @@ fn process_instruction_common( } } -pub mod upgradeable_ins_acc_idx { - pub enum InitializeBuffer { - Buffer = 0, - Authority = 1, - } - - pub enum Write { - Buffer = 0, - Authority = 1, - } - - pub enum DeployWithMaxDataLen { - Payer = 0, - ProgramData = 1, - Program = 2, - Buffer = 3, - Rent = 4, - Clock = 5, - // Ignored = 6, - UpgradeAuthority = 7, - } - - pub enum Upgrade { - ProgramData = 0, - Program = 1, - Buffer = 2, - Spill = 3, - Rent = 4, - Clock = 5, - UpgradeAuthority = 6, - } - - pub enum SetAuthority { - Account = 0, - CurrentAuthority = 1, - NewAuthority = 2, - } - - pub enum Close { - Account = 0, - Recipient = 1, - Authority = 2, - Program = 3, - } -} - fn process_loader_upgradeable_instruction( first_instruction_account: usize, instruction_data: &[u8], @@ -468,137 +418,117 @@ fn process_loader_upgradeable_instruction( let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let program_id = instruction_context.get_program_key(transaction_context)?; + let keyed_accounts = invoke_context.get_keyed_accounts()?; match limited_deserialize(instruction_data)? { UpgradeableLoaderInstruction::InitializeBuffer => { - instruction_context.check_number_of_instruction_accounts(2)?; - let mut buffer = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::InitializeBuffer::Buffer as usize, - )?; - if UpgradeableLoaderState::Uninitialized != buffer.get_state()? { + let buffer = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + + if UpgradeableLoaderState::Uninitialized != buffer.state()? { ic_logger_msg!(log_collector, "Buffer account already initialized"); return Err(InstructionError::AccountAlreadyInitialized); } - let authority_address = Some(*instruction_context.get_instruction_account_key( - transaction_context, - upgradeable_ins_acc_idx::InitializeBuffer::Authority as usize, - )?); - buffer.set_state(&UpgradeableLoaderState::Buffer { authority_address })?; + let authority = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(1), + )?; + + buffer.set_state(&UpgradeableLoaderState::Buffer { + authority_address: Some(*authority.unsigned_key()), + })?; } UpgradeableLoaderInstruction::Write { offset, bytes } => { - instruction_context.check_number_of_instruction_accounts(2)?; - let authority_address = if let UpgradeableLoaderState::Buffer { authority_address } = - instruction_context - .try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Write::Buffer as usize, - )? - .get_state()? - { - if let Some(authority_address) = authority_address { - authority_address - } else { + let buffer = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let authority = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(1), + )?; + + if let UpgradeableLoaderState::Buffer { authority_address } = buffer.state()? { + if authority_address.is_none() { ic_logger_msg!(log_collector, "Buffer is immutable"); return Err(InstructionError::Immutable); // TODO better error code } + if authority_address != Some(*authority.unsigned_key()) { + ic_logger_msg!(log_collector, "Incorrect buffer authority provided"); + return Err(InstructionError::IncorrectAuthority); + } + if authority.signer_key().is_none() { + ic_logger_msg!(log_collector, "Buffer authority did not sign"); + return Err(InstructionError::MissingRequiredSignature); + } } else { ic_logger_msg!(log_collector, "Invalid Buffer account"); return Err(InstructionError::InvalidAccountData); - }; - let current_authority_address = instruction_context.get_instruction_account_key( - transaction_context, - upgradeable_ins_acc_idx::Write::Authority as usize, - )?; - if authority_address != *current_authority_address { - ic_logger_msg!(log_collector, "Incorrect buffer authority provided"); - return Err(InstructionError::IncorrectAuthority); - } - if !instruction_context.is_signer( - instruction_context - .get_number_of_program_accounts() - .saturating_add(upgradeable_ins_acc_idx::Write::Authority as usize), - )? { - ic_logger_msg!(log_collector, "Buffer authority did not sign"); - return Err(InstructionError::MissingRequiredSignature); } - let mut program = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Write::Buffer as usize, - )?; write_program_data( - &mut program, + first_instruction_account, UpgradeableLoaderState::buffer_data_offset()?.saturating_add(offset as usize), &bytes, - invoke_context.get_log_collector(), + invoke_context, )?; } UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => { - instruction_context.check_number_of_instruction_accounts(4)?; - let programdata_address = *instruction_context.get_instruction_account_key( - transaction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::ProgramData as usize, + let payer = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let programdata = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(1), )?; - let rent = get_sysvar_with_account_check2::rent( + let program = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(2), + )?; + let buffer = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(3), + )?; + let rent = get_sysvar_with_account_check::rent( + keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(4), + )?, invoke_context, - instruction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::Rent as usize, )?; - let clock = get_sysvar_with_account_check2::clock( + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(5), + )?, invoke_context, - instruction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::Clock as usize, )?; - instruction_context.check_number_of_instruction_accounts(8)?; - let upgrade_authority_address = - Some(*instruction_context.get_instruction_account_key( - transaction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::UpgradeAuthority as usize, - )?); - let predrain_buffer = invoke_context - .feature_set - .is_active(&reduce_required_deploy_balance::id()); + let authority = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(7), + )?; + let upgrade_authority_address = Some(*authority.unsigned_key()); + let upgrade_authority_signer = authority.signer_key().is_none(); // Verify Program account - let new_program_id = { - let program = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::Program as usize, - )?; - if UpgradeableLoaderState::Uninitialized != program.get_state()? { - ic_logger_msg!(log_collector, "Program account already initialized"); - return Err(InstructionError::AccountAlreadyInitialized); - } - if program.get_data().len() < UpgradeableLoaderState::program_len()? { - ic_logger_msg!(log_collector, "Program account too small"); - return Err(InstructionError::AccountDataTooSmall); - } - if program.get_lamports() < rent.minimum_balance(program.get_data().len()) { - ic_logger_msg!(log_collector, "Program account not rent-exempt"); - return Err(InstructionError::ExecutableAccountNotRentExempt); - } - *program.get_key() - }; + + if UpgradeableLoaderState::Uninitialized != program.state()? { + ic_logger_msg!(log_collector, "Program account already initialized"); + return Err(InstructionError::AccountAlreadyInitialized); + } + if program.data_len()? < UpgradeableLoaderState::program_len()? { + ic_logger_msg!(log_collector, "Program account too small"); + return Err(InstructionError::AccountDataTooSmall); + } + if program.lamports()? < rent.minimum_balance(program.data_len()?) { + ic_logger_msg!(log_collector, "Program account not rent-exempt"); + return Err(InstructionError::ExecutableAccountNotRentExempt); + } + + let new_program_id = *program.unsigned_key(); // Verify Buffer account - let mut buffer = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::Buffer as usize, - )?; - if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? { + + if let UpgradeableLoaderState::Buffer { authority_address } = buffer.state()? { if authority_address != upgrade_authority_address { ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match"); return Err(InstructionError::IncorrectAuthority); } - if !instruction_context.is_signer( - instruction_context - .get_number_of_program_accounts() - .saturating_add( - upgradeable_ins_acc_idx::DeployWithMaxDataLen::UpgradeAuthority - as usize, - ), - )? { + if upgrade_authority_signer { ic_logger_msg!(log_collector, "Upgrade authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -607,12 +537,12 @@ fn process_loader_upgradeable_instruction( return Err(InstructionError::InvalidArgument); } - let buffer_address = *buffer.get_key(); let buffer_data_offset = UpgradeableLoaderState::buffer_data_offset()?; - let buffer_data_len = buffer.get_data().len().saturating_sub(buffer_data_offset); + let buffer_data_len = buffer.data_len()?.saturating_sub(buffer_data_offset); let programdata_data_offset = UpgradeableLoaderState::programdata_data_offset()?; let programdata_len = UpgradeableLoaderState::programdata_len(max_data_len)?; - if buffer.get_data().len() < UpgradeableLoaderState::buffer_data_offset()? + + if buffer.data_len()? < UpgradeableLoaderState::buffer_data_offset()? || buffer_data_len == 0 { ic_logger_msg!(log_collector, "Buffer account too small"); @@ -634,36 +564,34 @@ fn process_loader_upgradeable_instruction( let (derived_address, bump_seed) = Pubkey::find_program_address(&[new_program_id.as_ref()], program_id); - if derived_address != programdata_address { + if derived_address != *programdata.unsigned_key() { ic_logger_msg!(log_collector, "ProgramData address is not derived"); return Err(InstructionError::InvalidArgument); } - let mut instruction = { - let mut payer = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::Payer as usize, - )?; - if predrain_buffer { - // Drain the Buffer account to payer before paying for programdata account - payer.checked_add_lamports(buffer.get_lamports())?; - buffer.set_lamports(0); - } + let predrain_buffer = invoke_context + .feature_set + .is_active(&reduce_required_deploy_balance::id()); + if predrain_buffer { + // Drain the Buffer account to payer before paying for programdata account + payer + .try_account_ref_mut()? + .checked_add_lamports(buffer.lamports()?)?; + buffer.try_account_ref_mut()?.set_lamports(0); + } - system_instruction::create_account( - payer.get_key(), - &programdata_address, - 1.max(rent.minimum_balance(programdata_len)), - programdata_len as u64, - program_id, - ) - }; - drop(buffer); + let mut instruction = system_instruction::create_account( + payer.unsigned_key(), + programdata.unsigned_key(), + 1.max(rent.minimum_balance(programdata_len)), + programdata_len as u64, + program_id, + ); // pass an extra account to avoid the overly strict UnbalancedInstruction error instruction .accounts - .push(AccountMeta::new(buffer_address, false)); + .push(AccountMeta::new(*buffer.unsigned_key(), false)); let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; @@ -684,138 +612,124 @@ fn process_loader_upgradeable_instruction( )?; invoke_context.update_executor(&new_program_id, executor); - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let mut buffer = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::Buffer as usize, + let keyed_accounts = invoke_context.get_keyed_accounts()?; + let payer = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let programdata = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(1), + )?; + let program = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(2), + )?; + let buffer = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(3), )?; // Update the ProgramData account and record the program bits - { - let mut programdata = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::ProgramData as usize, - )?; - programdata.set_state(&UpgradeableLoaderState::ProgramData { - slot: clock.slot, - upgrade_authority_address, - })?; - - let to_slice = programdata - .get_data_mut() - .get_mut( - programdata_data_offset - ..programdata_data_offset.saturating_add(buffer_data_len), - ) - .ok_or(InstructionError::AccountDataTooSmall)?; - let from_slice = buffer - .get_data() - .get(buffer_data_offset..) - .ok_or(InstructionError::AccountDataTooSmall)?; - if to_slice.len() != from_slice.len() { - return Err(InstructionError::AccountDataTooSmall); - } - to_slice.copy_from_slice(from_slice); - } + programdata.set_state(&UpgradeableLoaderState::ProgramData { + slot: clock.slot, + upgrade_authority_address, + })?; + programdata + .try_account_ref_mut()? + .data_as_mut_slice() + .get_mut( + programdata_data_offset + ..programdata_data_offset.saturating_add(buffer_data_len), + ) + .ok_or(InstructionError::AccountDataTooSmall)? + .copy_from_slice( + buffer + .try_account_ref()? + .data() + .get(buffer_data_offset..) + .ok_or(InstructionError::AccountDataTooSmall)?, + ); // Update the Program account - { - let mut program = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::Program as usize, - )?; - program.set_state(&UpgradeableLoaderState::Program { - programdata_address, - })?; - program.set_executable(true); - } + program.set_state(&UpgradeableLoaderState::Program { + programdata_address: *programdata.unsigned_key(), + })?; + program.try_account_ref_mut()?.set_executable(true); if !predrain_buffer { // Drain the Buffer account back to the payer - let mut payer = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::DeployWithMaxDataLen::Payer as usize, - )?; - payer.checked_add_lamports(buffer.get_lamports())?; - buffer.set_lamports(0); + payer + .try_account_ref_mut()? + .checked_add_lamports(buffer.lamports()?)?; + buffer.try_account_ref_mut()?.set_lamports(0); } ic_logger_msg!(log_collector, "Deployed program {:?}", new_program_id); } UpgradeableLoaderInstruction::Upgrade => { - instruction_context.check_number_of_instruction_accounts(3)?; - let current_programdata_address = *instruction_context.get_instruction_account_key( - transaction_context, - upgradeable_ins_acc_idx::Upgrade::ProgramData as usize, + let programdata = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let program = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(1), )?; - let rent = get_sysvar_with_account_check2::rent( + let buffer = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(2), + )?; + let rent = get_sysvar_with_account_check::rent( + keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(4), + )?, invoke_context, - instruction_context, - upgradeable_ins_acc_idx::Upgrade::Rent as usize, )?; - let clock = get_sysvar_with_account_check2::clock( + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(5), + )?, invoke_context, - instruction_context, - upgradeable_ins_acc_idx::Upgrade::Clock as usize, )?; - instruction_context.check_number_of_instruction_accounts(7)?; - let current_upgrade_authority_address = - Some(*instruction_context.get_instruction_account_key( - transaction_context, - upgradeable_ins_acc_idx::Upgrade::UpgradeAuthority as usize, - )?); + let authority = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(6), + )?; // Verify Program account - let new_program_id = { - let program = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Upgrade::Program as usize, - )?; - if !program.is_executable() { - ic_logger_msg!(log_collector, "Program account not executable"); - return Err(InstructionError::AccountNotExecutable); - } - if !program.is_writable() { - ic_logger_msg!(log_collector, "Program account not writeable"); + + if !program.executable()? { + ic_logger_msg!(log_collector, "Program account not executable"); + return Err(InstructionError::AccountNotExecutable); + } + if !program.is_writable() { + ic_logger_msg!(log_collector, "Program account not writeable"); + return Err(InstructionError::InvalidArgument); + } + if &program.owner()? != program_id { + ic_logger_msg!(log_collector, "Program account not owned by loader"); + return Err(InstructionError::IncorrectProgramId); + } + if let UpgradeableLoaderState::Program { + programdata_address, + } = program.state()? + { + if programdata_address != *programdata.unsigned_key() { + ic_logger_msg!(log_collector, "Program and ProgramData account mismatch"); return Err(InstructionError::InvalidArgument); } - if program.get_owner() != program_id { - ic_logger_msg!(log_collector, "Program account not owned by loader"); - return Err(InstructionError::IncorrectProgramId); - } - if let UpgradeableLoaderState::Program { - programdata_address, - } = program.get_state()? - { - if current_programdata_address != programdata_address { - ic_logger_msg!(log_collector, "Program and ProgramData account mismatch"); - return Err(InstructionError::InvalidArgument); - } - } else { - ic_logger_msg!(log_collector, "Invalid Program account"); - return Err(InstructionError::InvalidAccountData); - } - *program.get_key() - }; + } else { + ic_logger_msg!(log_collector, "Invalid Program account"); + return Err(InstructionError::InvalidAccountData); + } + + let new_program_id = *program.unsigned_key(); // Verify Buffer account - let buffer = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Upgrade::Buffer as usize, - )?; - if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? { - if authority_address != current_upgrade_authority_address { + + if let UpgradeableLoaderState::Buffer { authority_address } = buffer.state()? { + if authority_address != Some(*authority.unsigned_key()) { ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match"); return Err(InstructionError::IncorrectAuthority); } - if !instruction_context.is_signer( - instruction_context - .get_number_of_program_accounts() - .saturating_add( - upgradeable_ins_acc_idx::Upgrade::UpgradeAuthority as usize, - ), - )? { + if authority.signer_key().is_none() { ic_logger_msg!(log_collector, "Upgrade authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -825,15 +739,11 @@ fn process_loader_upgradeable_instruction( } let buffer_data_offset = UpgradeableLoaderState::buffer_data_offset()?; - let buffer_data_len = buffer.get_data().len().saturating_sub(buffer_data_offset); - let programdata = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Upgrade::ProgramData as usize, - )?; + let buffer_data_len = buffer.data_len()?.saturating_sub(buffer_data_offset); let programdata_data_offset = UpgradeableLoaderState::programdata_data_offset()?; - let programdata_balance_required = - 1.max(rent.minimum_balance(programdata.get_data().len())); - if buffer.get_data().len() < UpgradeableLoaderState::buffer_data_offset()? + let programdata_balance_required = 1.max(rent.minimum_balance(programdata.data_len()?)); + + if buffer.data_len()? < UpgradeableLoaderState::buffer_data_offset()? || buffer_data_len == 0 { ic_logger_msg!(log_collector, "Buffer account too small"); @@ -841,15 +751,12 @@ fn process_loader_upgradeable_instruction( } // Verify ProgramData account - if programdata.get_data().len() - < UpgradeableLoaderState::programdata_len(buffer_data_len)? - { + + if programdata.data_len()? < UpgradeableLoaderState::programdata_len(buffer_data_len)? { ic_logger_msg!(log_collector, "ProgramData account not large enough"); return Err(InstructionError::AccountDataTooSmall); } - if programdata - .get_lamports() - .saturating_add(buffer.get_lamports()) + if programdata.lamports()?.saturating_add(buffer.lamports()?) < programdata_balance_required { ic_logger_msg!( @@ -858,27 +765,20 @@ fn process_loader_upgradeable_instruction( ); return Err(InstructionError::InsufficientFunds); } - drop(buffer); if let UpgradeableLoaderState::ProgramData { slot: _, upgrade_authority_address, - } = programdata.get_state()? + } = programdata.state()? { if upgrade_authority_address.is_none() { ic_logger_msg!(log_collector, "Program not upgradeable"); return Err(InstructionError::Immutable); } - if upgrade_authority_address != current_upgrade_authority_address { + if upgrade_authority_address != Some(*authority.unsigned_key()) { ic_logger_msg!(log_collector, "Incorrect upgrade authority provided"); return Err(InstructionError::IncorrectAuthority); } - if !instruction_context.is_signer( - instruction_context - .get_number_of_program_accounts() - .saturating_add( - upgradeable_ins_acc_idx::Upgrade::UpgradeAuthority as usize, - ), - )? { + if authority.signer_key().is_none() { ic_logger_msg!(log_collector, "Upgrade authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -886,7 +786,6 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Invalid ProgramData account"); return Err(InstructionError::InvalidAccountData); } - drop(programdata); // Load and verify the program bits let executor = create_executor( @@ -898,80 +797,76 @@ fn process_loader_upgradeable_instruction( )?; invoke_context.update_executor(&new_program_id, executor); - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let mut programdata = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Upgrade::ProgramData as usize, + let keyed_accounts = invoke_context.get_keyed_accounts()?; + let programdata = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let buffer = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(2), )?; - let mut buffer = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Upgrade::Buffer as usize, + let spill = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(3), + )?; + let authority = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(6), )?; - // Update the ProgramData account, record the upgraded data, and zero the rest + // Update the ProgramData account, record the upgraded data, and zero + // the rest programdata.set_state(&UpgradeableLoaderState::ProgramData { slot: clock.slot, - upgrade_authority_address: current_upgrade_authority_address, + upgrade_authority_address: Some(*authority.unsigned_key()), })?; - let to_slice = programdata - .get_data_mut() + programdata + .try_account_ref_mut()? + .data_as_mut_slice() .get_mut( programdata_data_offset ..programdata_data_offset.saturating_add(buffer_data_len), ) - .ok_or(InstructionError::AccountDataTooSmall)?; - let from_slice = buffer - .get_data() - .get(buffer_data_offset..) - .ok_or(InstructionError::AccountDataTooSmall)?; - if to_slice.len() != from_slice.len() { - return Err(InstructionError::AccountDataTooSmall); - } - to_slice.copy_from_slice(from_slice); + .ok_or(InstructionError::AccountDataTooSmall)? + .copy_from_slice( + buffer + .try_account_ref()? + .data() + .get(buffer_data_offset..) + .ok_or(InstructionError::AccountDataTooSmall)?, + ); programdata - .get_data_mut() + .try_account_ref_mut()? + .data_as_mut_slice() .get_mut(programdata_data_offset.saturating_add(buffer_data_len)..) .ok_or(InstructionError::AccountDataTooSmall)? .fill(0); // Fund ProgramData to rent-exemption, spill the rest - { - let mut spill = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Upgrade::Spill as usize, - )?; - spill.checked_add_lamports( - (programdata - .get_lamports() - .saturating_add(buffer.get_lamports())) + + spill.try_account_ref_mut()?.checked_add_lamports( + programdata + .lamports()? + .saturating_add(buffer.lamports()?) .saturating_sub(programdata_balance_required), - )?; - buffer.set_lamports(0); - programdata.set_lamports(programdata_balance_required); - } + )?; + buffer.try_account_ref_mut()?.set_lamports(0); + programdata + .try_account_ref_mut()? + .set_lamports(programdata_balance_required); ic_logger_msg!(log_collector, "Upgraded program {:?}", new_program_id); } UpgradeableLoaderInstruction::SetAuthority => { - instruction_context.check_number_of_instruction_accounts(2)?; - let mut account = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::SetAuthority::Account as usize, + let account = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let present_authority = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(1), )?; - let present_authority = Some(*instruction_context.get_instruction_account_key( - transaction_context, - upgradeable_ins_acc_idx::SetAuthority::CurrentAuthority as usize, - )?); - let new_authority = instruction_context - .get_instruction_account_key( - transaction_context, - upgradeable_ins_acc_idx::SetAuthority::NewAuthority as usize, - ) - .ok() - .cloned(); + let new_authority = + keyed_account_at_index(keyed_accounts, first_instruction_account.saturating_add(2)) + .ok() + .map(|account| account.unsigned_key()); - match account.get_state()? { + match account.state()? { UpgradeableLoaderState::Buffer { authority_address } => { if new_authority.is_none() { ic_logger_msg!(log_collector, "Buffer authority is not optional"); @@ -981,22 +876,16 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Buffer is immutable"); return Err(InstructionError::Immutable); } - if authority_address != present_authority { + if authority_address != Some(*present_authority.unsigned_key()) { ic_logger_msg!(log_collector, "Incorrect buffer authority provided"); return Err(InstructionError::IncorrectAuthority); } - if !instruction_context.is_signer( - instruction_context - .get_number_of_program_accounts() - .saturating_add( - upgradeable_ins_acc_idx::SetAuthority::CurrentAuthority as usize, - ), - )? { + if present_authority.signer_key().is_none() { ic_logger_msg!(log_collector, "Buffer authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } account.set_state(&UpgradeableLoaderState::Buffer { - authority_address: new_authority, + authority_address: new_authority.cloned(), })?; } UpgradeableLoaderState::ProgramData { @@ -1007,23 +896,17 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Program not upgradeable"); return Err(InstructionError::Immutable); } - if upgrade_authority_address != present_authority { + if upgrade_authority_address != Some(*present_authority.unsigned_key()) { ic_logger_msg!(log_collector, "Incorrect upgrade authority provided"); return Err(InstructionError::IncorrectAuthority); } - if !instruction_context.is_signer( - instruction_context - .get_number_of_program_accounts() - .saturating_add( - upgradeable_ins_acc_idx::SetAuthority::CurrentAuthority as usize, - ), - )? { + if present_authority.signer_key().is_none() { ic_logger_msg!(log_collector, "Upgrade authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } account.set_state(&UpgradeableLoaderState::ProgramData { slot, - upgrade_authority_address: new_authority, + upgrade_authority_address: new_authority.cloned(), })?; } _ => { @@ -1035,82 +918,75 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "New authority {:?}", new_authority); } UpgradeableLoaderInstruction::Close => { - instruction_context.check_number_of_instruction_accounts(2)?; - if instruction_context.get_index_in_transaction( - first_instruction_account - .saturating_add(upgradeable_ins_acc_idx::Close::Account as usize), - )? == instruction_context.get_index_in_transaction( - first_instruction_account - .saturating_add(upgradeable_ins_acc_idx::Close::Recipient as usize), - )? { + let close_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let recipient_account = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(1), + )?; + if close_account.unsigned_key() == recipient_account.unsigned_key() { ic_logger_msg!( log_collector, "Recipient is the same as the account being closed" ); return Err(InstructionError::InvalidArgument); } - let mut close_account = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Close::Account as usize, - )?; - match close_account.get_state()? { + match close_account.state()? { UpgradeableLoaderState::Uninitialized => { - let mut recipient_account = instruction_context - .try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Close::Recipient as usize, - )?; - recipient_account.checked_add_lamports(close_account.get_lamports())?; - close_account.set_lamports(0); + recipient_account + .try_account_ref_mut()? + .checked_add_lamports(close_account.lamports()?)?; + close_account.try_account_ref_mut()?.set_lamports(0); ic_logger_msg!( log_collector, "Closed Uninitialized {}", - close_account.get_key() + close_account.unsigned_key() ); } UpgradeableLoaderState::Buffer { authority_address } => { - instruction_context.check_number_of_instruction_accounts(3)?; - drop(close_account); + let authority = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(2), + )?; + common_close_account( &authority_address, - transaction_context, - instruction_context, + authority, + close_account, + recipient_account, &log_collector, )?; - let close_account = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Close::Account as usize, - )?; - ic_logger_msg!(log_collector, "Closed Buffer {}", close_account.get_key()); + ic_logger_msg!( + log_collector, + "Closed Buffer {}", + close_account.unsigned_key() + ); } UpgradeableLoaderState::ProgramData { slot: _, upgrade_authority_address: authority_address, } => { - instruction_context.check_number_of_instruction_accounts(4)?; - if !instruction_context.is_writable( - instruction_context - .get_number_of_program_accounts() - .saturating_add(upgradeable_ins_acc_idx::Close::Program as usize), - )? { + let program_account = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(3), + )?; + + if !program_account.is_writable() { ic_logger_msg!(log_collector, "Program account is not writable"); return Err(InstructionError::InvalidArgument); } - let program_account = instruction_context - .try_borrow_instruction_account(transaction_context, 3)?; - if program_account.get_owner() != program_id { + if &program_account.owner()? != program_id { ic_logger_msg!(log_collector, "Program account not owned by loader"); return Err(InstructionError::IncorrectProgramId); } - match program_account.get_state()? { + match program_account.state()? { UpgradeableLoaderState::Program { programdata_address, } => { - if programdata_address != *close_account.get_key() { + if programdata_address != *close_account.unsigned_key() { ic_logger_msg!( log_collector, "ProgramData account does not match ProgramData account" @@ -1118,11 +994,15 @@ fn process_loader_upgradeable_instruction( return Err(InstructionError::InvalidArgument); } - drop(close_account); + let authority = keyed_account_at_index( + keyed_accounts, + first_instruction_account.saturating_add(2), + )?; common_close_account( &authority_address, - transaction_context, - instruction_context, + authority, + close_account, + recipient_account, &log_collector, )?; } @@ -1135,7 +1015,7 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!( log_collector, "Closed Program {}", - program_account.get_key() + program_account.unsigned_key() ); } _ => { @@ -1151,55 +1031,32 @@ fn process_loader_upgradeable_instruction( fn common_close_account( authority_address: &Option, - transaction_context: &TransactionContext, - instruction_context: &InstructionContext, + authority_account: &KeyedAccount, + close_account: &KeyedAccount, + recipient_account: &KeyedAccount, log_collector: &Option>>, ) -> Result<(), InstructionError> { if authority_address.is_none() { ic_logger_msg!(log_collector, "Account is immutable"); return Err(InstructionError::Immutable); } - if *authority_address - != Some(*instruction_context.get_instruction_account_key( - transaction_context, - upgradeable_ins_acc_idx::Close::Authority as usize, - )?) - { + if *authority_address != Some(*authority_account.unsigned_key()) { ic_logger_msg!(log_collector, "Incorrect authority provided"); return Err(InstructionError::IncorrectAuthority); } - if !instruction_context.is_signer( - instruction_context - .get_number_of_program_accounts() - .saturating_add(upgradeable_ins_acc_idx::Close::Authority as usize), - )? { + if authority_account.signer_key().is_none() { ic_logger_msg!(log_collector, "Authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } - let mut close_account = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Close::Account as usize, - )?; - let mut recipient_account = instruction_context.try_borrow_instruction_account( - transaction_context, - upgradeable_ins_acc_idx::Close::Recipient as usize, - )?; - recipient_account.checked_add_lamports(close_account.get_lamports())?; - close_account.set_lamports(0); + + recipient_account + .try_account_ref_mut()? + .checked_add_lamports(close_account.lamports()?)?; + close_account.try_account_ref_mut()?.set_lamports(0); close_account.set_state(&UpgradeableLoaderState::Uninitialized)?; Ok(()) } -pub mod deprecated_ins_acc_idx { - pub enum Write { - Program = 0, - } - - pub enum Finalize { - Program = 0, - } -} - fn process_loader_instruction( first_instruction_account: usize, instruction_data: &[u8], @@ -1209,11 +1066,9 @@ fn process_loader_instruction( let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; let program_id = instruction_context.get_program_key(transaction_context)?; - if instruction_context - .try_borrow_instruction_account(transaction_context, 0)? - .get_owner() - != program_id - { + let keyed_accounts = invoke_context.get_keyed_accounts()?; + let program = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + if program.owner()? != *program_id { ic_msg!( invoke_context, "Executable account not owned by the BPF loader" @@ -1222,44 +1077,34 @@ fn process_loader_instruction( } match limited_deserialize(instruction_data)? { LoaderInstruction::Write { offset, bytes } => { - if !instruction_context.is_signer( - instruction_context - .get_number_of_program_accounts() - .saturating_add(deprecated_ins_acc_idx::Write::Program as usize), - )? { + if program.signer_key().is_none() { ic_msg!(invoke_context, "Program account did not sign"); return Err(InstructionError::MissingRequiredSignature); } write_program_data( - &mut instruction_context.try_borrow_instruction_account( - transaction_context, - deprecated_ins_acc_idx::Write::Program as usize, - )?, + first_instruction_account, offset as usize, &bytes, - invoke_context.get_log_collector(), + invoke_context, )?; } LoaderInstruction::Finalize => { - if !instruction_context.is_signer( - instruction_context - .get_number_of_program_accounts() - .saturating_add(deprecated_ins_acc_idx::Finalize::Program as usize), - )? { - ic_msg!(invoke_context, "Program account did not sign"); + if program.signer_key().is_none() { + ic_msg!(invoke_context, "key[0] did not sign the transaction"); return Err(InstructionError::MissingRequiredSignature); } + let executor = create_executor(first_instruction_account, 0, invoke_context, use_jit, true)?; - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; - let mut program = instruction_context.try_borrow_instruction_account( - transaction_context, - deprecated_ins_acc_idx::Finalize::Program as usize, - )?; - invoke_context.update_executor(program.get_key(), executor); - program.set_executable(true); - ic_msg!(invoke_context, "Finalized account {:?}", program.get_key()); + let keyed_accounts = invoke_context.get_keyed_accounts()?; + let program = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + invoke_context.update_executor(program.unsigned_key(), executor); + program.try_account_ref_mut()?.set_executable(true); + ic_msg!( + invoke_context, + "Finalized account {:?}", + program.unsigned_key() + ); } } @@ -1441,7 +1286,6 @@ mod tests { solana_sdk::{ account::{ create_account_shared_data_for_test as create_account_for_test, AccountSharedData, - ReadableAccount, WritableAccount, }, account_utils::StateMut, client::SyncClient, @@ -2241,12 +2085,13 @@ mod tests { let fee_calculator = genesis_config.fee_rate_governor.create_fee_calculator(); 3 * fee_calculator.lamports_per_signature }; - let min_payer_balance = - min_program_balance + min_programdata_balance - min_buffer_balance + deploy_fees; + let min_payer_balance = min_program_balance + .saturating_add(min_programdata_balance) + .saturating_sub(min_buffer_balance.saturating_add(deploy_fees)); bank.store_account( &payer_keypair.pubkey(), &AccountSharedData::new( - payer_base_balance + min_payer_balance, + payer_base_balance.saturating_add(min_payer_balance), 0, &system_program::id(), ), @@ -2488,7 +2333,7 @@ mod tests { &program_keypair.pubkey(), &buffer_address, &upgrade_authority_keypair.pubkey(), - min_program_balance - 1, + min_program_balance.saturating_sub(1), elf.len(), ) .unwrap(), @@ -2523,7 +2368,7 @@ mod tests { &mint_keypair.pubkey(), &program_keypair.pubkey(), min_program_balance, - UpgradeableLoaderState::program_len().unwrap() as u64 + 1, + (UpgradeableLoaderState::program_len().unwrap() as u64).saturating_add(1), &id(), ); let message = Message::new(&instructions, Some(&mint_keypair.pubkey())); @@ -2556,7 +2401,7 @@ mod tests { &mint_keypair.pubkey(), &program_keypair.pubkey(), min_program_balance, - UpgradeableLoaderState::program_len().unwrap() as u64 - 1, + (UpgradeableLoaderState::program_len().unwrap() as u64).saturating_sub(1), &id(), ); let message = Message::new(&instructions, Some(&mint_keypair.pubkey())); @@ -2576,7 +2421,11 @@ mod tests { bank.clear_signatures(); bank.store_account( &mint_keypair.pubkey(), - &AccountSharedData::new(deploy_fees + min_program_balance, 0, &system_program::id()), + &AccountSharedData::new( + deploy_fees.saturating_add(min_program_balance), + 0, + &system_program::id(), + ), ); bank.store_account(&buffer_address, &buffer_account); bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); @@ -2620,7 +2469,7 @@ mod tests { &buffer_address, &upgrade_authority_keypair.pubkey(), min_program_balance, - elf.len() - 1, + elf.len().saturating_sub(1), ) .unwrap(), Some(&mint_keypair.pubkey()), @@ -3040,7 +2889,9 @@ mod tests { .data() .get( UpgradeableLoaderState::programdata_data_offset().unwrap() - ..UpgradeableLoaderState::programdata_data_offset().unwrap() + elf_new.len(), + ..UpgradeableLoaderState::programdata_data_offset() + .unwrap() + .saturating_add(elf_new.len()), ) .unwrap() .iter() @@ -3224,7 +3075,8 @@ mod tests { ); transaction_accounts.get_mut(2).unwrap().1 = AccountSharedData::new( 1, - UpgradeableLoaderState::buffer_len(elf_orig.len().max(elf_new.len()) + 1).unwrap(), + UpgradeableLoaderState::buffer_len(elf_orig.len().max(elf_new.len()).saturating_add(1)) + .unwrap(), &bpf_loader_upgradeable::id(), ); transaction_accounts From d443fa98f8355f52483a3d050cd5d7718f91970c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Mon, 14 Mar 2022 15:23:22 +0100 Subject: [PATCH 2/6] Revert "Replaces `KeyedAccount` by `BorrowedAccount` in `system_instruction_processor`. (#23217)" ee7e411d68381d4176649d810c8ebb0ed66b9bf9 --- runtime/src/nonce_keyed_account.rs | 6 +- runtime/src/system_instruction_processor.rs | 351 +++++++------------- 2 files changed, 120 insertions(+), 237 deletions(-) diff --git a/runtime/src/nonce_keyed_account.rs b/runtime/src/nonce_keyed_account.rs index 5f36111d4a73c4..089f27a8813868 100644 --- a/runtime/src/nonce_keyed_account.rs +++ b/runtime/src/nonce_keyed_account.rs @@ -12,6 +12,9 @@ use { std::collections::HashSet, }; +pub const NONCE_ACCOUNT_INDEX: usize = 0; +pub const WITHDRAW_TO_ACCOUNT_INDEX: usize = 1; + pub fn advance_nonce_account( invoke_context: &InvokeContext, instruction_context: &InstructionContext, @@ -350,9 +353,6 @@ mod test { }; } - const NONCE_ACCOUNT_INDEX: usize = 0; - const WITHDRAW_TO_ACCOUNT_INDEX: usize = 1; - macro_rules! set_invoke_context_blockhash { ($invoke_context:expr, $seed:expr) => { $invoke_context.blockhash = hash(&bincode::serialize(&$seed).unwrap()); diff --git a/runtime/src/system_instruction_processor.rs b/runtime/src/system_instruction_processor.rs index af1237e591266b..f280cf141eddcc 100644 --- a/runtime/src/system_instruction_processor.rs +++ b/runtime/src/system_instruction_processor.rs @@ -1,17 +1,18 @@ use { crate::nonce_keyed_account::{ advance_nonce_account, authorize_nonce_account, initialize_nonce_account, - withdraw_nonce_account, + withdraw_nonce_account, NONCE_ACCOUNT_INDEX, WITHDRAW_TO_ACCOUNT_INDEX, }, log::*, solana_program_runtime::{ ic_msg, invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check2, }, solana_sdk::{ - account::{AccountSharedData, ReadableAccount}, + account::{AccountSharedData, ReadableAccount, WritableAccount}, account_utils::StateMut, feature_set, instruction::InstructionError, + keyed_account::{keyed_account_at_index, KeyedAccount}, nonce, program_utils::limited_deserialize, pubkey::Pubkey, @@ -19,7 +20,6 @@ use { NonceError, SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH, }, system_program, - transaction_context::{BorrowedAccount, InstructionContext}, }, std::collections::HashSet, }; @@ -70,11 +70,11 @@ impl Address { } fn allocate( - invoke_context: &InvokeContext, - signers: &HashSet, - account: &mut BorrowedAccount, + account: &mut AccountSharedData, address: &Address, space: u64, + signers: &HashSet, + invoke_context: &InvokeContext, ) -> Result<(), InstructionError> { if !address.is_signer(signers) { ic_msg!( @@ -87,7 +87,7 @@ fn allocate( // if it looks like the `to` account is already in use, bail // (note that the id check is also enforced by message_processor) - if !account.get_data().is_empty() || !system_program::check_id(account.get_owner()) { + if !account.data().is_empty() || !system_program::check_id(account.owner()) { ic_msg!( invoke_context, "Allocate: account {:?} already in use", @@ -106,20 +106,20 @@ fn allocate( return Err(SystemError::InvalidAccountDataLength.into()); } - account.set_data(vec![0; space as usize].as_slice()); + account.set_data(vec![0; space as usize]); Ok(()) } fn assign( - invoke_context: &InvokeContext, - signers: &HashSet, - account: &mut BorrowedAccount, + account: &mut AccountSharedData, address: &Address, owner: &Pubkey, + signers: &HashSet, + invoke_context: &InvokeContext, ) -> Result<(), InstructionError> { // no work to do, just return - if account.get_owner() == owner { + if account.owner() == owner { return Ok(()); } @@ -128,38 +128,36 @@ fn assign( return Err(InstructionError::MissingRequiredSignature); } - account.set_owner(&owner.to_bytes()); + account.set_owner(*owner); Ok(()) } fn allocate_and_assign( - invoke_context: &InvokeContext, - signers: &HashSet, - to_account: &mut BorrowedAccount, + to: &mut AccountSharedData, to_address: &Address, space: u64, owner: &Pubkey, + signers: &HashSet, + invoke_context: &InvokeContext, ) -> Result<(), InstructionError> { - allocate(invoke_context, signers, to_account, to_address, space)?; - assign(invoke_context, signers, to_account, to_address, owner) + allocate(to, to_address, space, signers, invoke_context)?; + assign(to, to_address, owner, signers, invoke_context) } fn create_account( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - from_account_index: usize, - to_account_index: usize, + from: &KeyedAccount, + to: &KeyedAccount, to_address: &Address, lamports: u64, space: u64, owner: &Pubkey, + signers: &HashSet, + invoke_context: &InvokeContext, ) -> Result<(), InstructionError> { // if it looks like the `to` account is already in use, bail { - let mut to_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, to_account_index)?; - if to_account.get_lamports() > 0 { + let to = &mut to.try_account_ref_mut()?; + if to.lamports() > 0 { ic_msg!( invoke_context, "Create Account: account {:?} already in use", @@ -167,60 +165,42 @@ fn create_account( ); return Err(SystemError::AccountAlreadyInUse.into()); } - allocate_and_assign( - invoke_context, - signers, - &mut to_account, - to_address, - space, - owner, - )?; - } - transfer( - invoke_context, - instruction_context, - from_account_index, - to_account_index, - lamports, - ) + + allocate_and_assign(to, to_address, space, owner, signers, invoke_context)?; + } + transfer(from, to, lamports, invoke_context) } fn transfer_verified( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - from_account_index: usize, - to_account_index: usize, + from: &KeyedAccount, + to: &KeyedAccount, lamports: u64, + invoke_context: &InvokeContext, ) -> Result<(), InstructionError> { - let mut from_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, from_account_index)?; - if !from_account.get_data().is_empty() { + if !from.data_is_empty()? { ic_msg!(invoke_context, "Transfer: `from` must not carry data"); return Err(InstructionError::InvalidArgument); } - if lamports > from_account.get_lamports() { + if lamports > from.lamports()? { ic_msg!( invoke_context, "Transfer: insufficient lamports {}, need {}", - from_account.get_lamports(), + from.lamports()?, lamports ); return Err(SystemError::ResultWithNegativeLamports.into()); } - from_account.checked_sub_lamports(lamports)?; - drop(from_account); - let mut to_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, to_account_index)?; - to_account.checked_add_lamports(lamports)?; + + from.try_account_ref_mut()?.checked_sub_lamports(lamports)?; + to.try_account_ref_mut()?.checked_add_lamports(lamports)?; Ok(()) } fn transfer( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - from_account_index: usize, - to_account_index: usize, + from: &KeyedAccount, + to: &KeyedAccount, lamports: u64, + invoke_context: &InvokeContext, ) -> Result<(), InstructionError> { if !invoke_context .feature_set @@ -230,38 +210,26 @@ fn transfer( return Ok(()); } - if !instruction_context - .is_signer(instruction_context.get_number_of_program_accounts() + from_account_index)? - { + if from.signer_key().is_none() { ic_msg!( invoke_context, "Transfer: `from` account {} must sign", - instruction_context.get_instruction_account_key( - invoke_context.transaction_context, - from_account_index - )?, + from.unsigned_key() ); return Err(InstructionError::MissingRequiredSignature); } - transfer_verified( - invoke_context, - instruction_context, - from_account_index, - to_account_index, - lamports, - ) + transfer_verified(from, to, lamports, invoke_context) } fn transfer_with_seed( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - from_account_index: usize, - from_base_account_index: usize, - to_account_index: usize, + from: &KeyedAccount, + from_base: &KeyedAccount, from_seed: &str, from_owner: &Pubkey, + to: &KeyedAccount, lamports: u64, + invoke_context: &InvokeContext, ) -> Result<(), InstructionError> { if !invoke_context .feature_set @@ -271,112 +239,42 @@ fn transfer_with_seed( return Ok(()); } - let from_base_key = instruction_context - .get_instruction_account_key(invoke_context.transaction_context, from_base_account_index)?; - if !instruction_context - .is_signer(instruction_context.get_number_of_program_accounts() + from_base_account_index)? - { + if from_base.signer_key().is_none() { ic_msg!( invoke_context, "Transfer: 'from' account {:?} must sign", - from_base_key, + from_base ); return Err(InstructionError::MissingRequiredSignature); } - let from_key = instruction_context - .get_instruction_account_key(invoke_context.transaction_context, from_account_index)?; - let address_from_seed = Pubkey::create_with_seed(from_base_key, from_seed, from_owner)?; - if *from_key != address_from_seed { + let address_from_seed = + Pubkey::create_with_seed(from_base.unsigned_key(), from_seed, from_owner)?; + if *from.unsigned_key() != address_from_seed { ic_msg!( invoke_context, "Transfer: 'from' address {} does not match derived address {}", - from_key, - address_from_seed, + from.unsigned_key(), + address_from_seed ); return Err(SystemError::AddressWithSeedMismatch.into()); } - transfer_verified( - invoke_context, - instruction_context, - from_account_index, - to_account_index, - lamports, - ) -} - -pub mod instruction_account_indices { - pub enum CreateAccount { - From = 0, - To = 1, - } - - pub enum CreateAccountWithSeed { - From = 0, - To = 1, - } - - pub enum Assign { - Account = 0, - } - - pub enum Transfer { - From = 0, - To = 1, - } - - pub enum TransferWithSeed { - From = 0, - Base = 1, - To = 2, - } - - pub enum AdvanceNonceAccount { - Nonce = 0, - RecentBlockhashes = 1, - } - - pub enum WithdrawNonceAccount { - From = 0, - To = 1, - RecentBlockhashes = 2, - Rent = 3, - } - - pub enum InitializeNonceAccount { - Nonce = 0, - RecentBlockhashes = 1, - Rent = 2, - } - - pub enum AuthorizeNonceAccount { - Nonce = 0, - } - - pub enum Allocate { - Account = 0, - } - - pub enum AllocateWithSeed { - Account = 0, - } - - pub enum AssignWithSeed { - Account = 0, - } + transfer_verified(from, to, lamports, invoke_context) } pub fn process_instruction( - _first_instruction_account: usize, + first_instruction_account: usize, instruction_data: &[u8], invoke_context: &mut InvokeContext, ) -> Result<(), InstructionError> { let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; + let keyed_accounts = invoke_context.get_keyed_accounts()?; let instruction = limited_deserialize(instruction_data)?; trace!("process_instruction: {:?}", instruction); + trace!("keyed_accounts: {:?}", keyed_accounts); let signers = instruction_context.get_signers(transaction_context); match instruction { @@ -385,22 +283,18 @@ pub fn process_instruction( space, owner, } => { - instruction_context.check_number_of_instruction_accounts(2)?; - let to_key = instruction_context.get_instruction_account_key( - invoke_context.transaction_context, - instruction_account_indices::CreateAccount::To as usize, - )?; - let to_address = Address::create(to_key, None, invoke_context)?; + let from = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let to = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + let to_address = Address::create(to.unsigned_key(), None, invoke_context)?; create_account( - invoke_context, - instruction_context, - &signers, - instruction_account_indices::CreateAccount::From as usize, - instruction_account_indices::CreateAccount::To as usize, + from, + to, &to_address, lamports, space, &owner, + &signers, + invoke_context, ) } SystemInstruction::CreateAccountWithSeed { @@ -410,66 +304,60 @@ pub fn process_instruction( space, owner, } => { - instruction_context.check_number_of_instruction_accounts(2)?; - let to_key = instruction_context.get_instruction_account_key( - invoke_context.transaction_context, - instruction_account_indices::CreateAccountWithSeed::To as usize, + let from = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let to = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + let to_address = Address::create( + to.unsigned_key(), + Some((&base, &seed, &owner)), + invoke_context, )?; - let to_address = Address::create(to_key, Some((&base, &seed, &owner)), invoke_context)?; create_account( - invoke_context, - instruction_context, - &signers, - instruction_account_indices::CreateAccountWithSeed::From as usize, - instruction_account_indices::CreateAccountWithSeed::To as usize, + from, + to, &to_address, lamports, space, &owner, + &signers, + invoke_context, ) } SystemInstruction::Assign { owner } => { - let mut account = instruction_context.try_borrow_instruction_account( - invoke_context.transaction_context, - instruction_account_indices::Assign::Account as usize, - )?; - let address = Address::create(account.get_key(), None, invoke_context)?; - assign(invoke_context, &signers, &mut account, &address, &owner) + let keyed_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let mut account = keyed_account.try_account_ref_mut()?; + let address = Address::create(keyed_account.unsigned_key(), None, invoke_context)?; + assign(&mut account, &address, &owner, &signers, invoke_context) } SystemInstruction::Transfer { lamports } => { - instruction_context.check_number_of_instruction_accounts(2)?; - transfer( - invoke_context, - instruction_context, - instruction_account_indices::Transfer::From as usize, - instruction_account_indices::Transfer::To as usize, - lamports, - ) + let from = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let to = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + transfer(from, to, lamports, invoke_context) } SystemInstruction::TransferWithSeed { lamports, from_seed, from_owner, } => { - instruction_context.check_number_of_instruction_accounts(3)?; + let from = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let base = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + let to = keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?; transfer_with_seed( - invoke_context, - instruction_context, - instruction_account_indices::TransferWithSeed::From as usize, - instruction_account_indices::TransferWithSeed::Base as usize, - instruction_account_indices::TransferWithSeed::To as usize, + from, + base, &from_seed, &from_owner, + to, lamports, + invoke_context, ) } SystemInstruction::AdvanceNonceAccount => { - instruction_context.check_number_of_instruction_accounts(1)?; + let _me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; #[allow(deprecated)] let recent_blockhashes = get_sysvar_with_account_check2::recent_blockhashes( invoke_context, instruction_context, - instruction_account_indices::AdvanceNonceAccount::RecentBlockhashes as usize, + first_instruction_account + 1, )?; if recent_blockhashes.is_empty() { ic_msg!( @@ -482,39 +370,40 @@ pub fn process_instruction( invoke_context, instruction_context, &signers, - instruction_account_indices::AdvanceNonceAccount::Nonce as usize, + NONCE_ACCOUNT_INDEX, ) } SystemInstruction::WithdrawNonceAccount(lamports) => { - instruction_context.check_number_of_instruction_accounts(2)?; + let _me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let _to = &mut keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; #[allow(deprecated)] let _recent_blockhashes = get_sysvar_with_account_check2::recent_blockhashes( invoke_context, instruction_context, - instruction_account_indices::WithdrawNonceAccount::RecentBlockhashes as usize, + first_instruction_account + 2, )?; let rent = get_sysvar_with_account_check2::rent( invoke_context, instruction_context, - instruction_account_indices::WithdrawNonceAccount::Rent as usize, + first_instruction_account + 3, )?; withdraw_nonce_account( invoke_context, instruction_context, &signers, - instruction_account_indices::WithdrawNonceAccount::From as usize, - instruction_account_indices::WithdrawNonceAccount::To as usize, + NONCE_ACCOUNT_INDEX, + WITHDRAW_TO_ACCOUNT_INDEX, lamports, &rent, ) } SystemInstruction::InitializeNonceAccount(authorized) => { - instruction_context.check_number_of_instruction_accounts(1)?; + let _me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; #[allow(deprecated)] let recent_blockhashes = get_sysvar_with_account_check2::recent_blockhashes( invoke_context, instruction_context, - instruction_account_indices::InitializeNonceAccount::RecentBlockhashes as usize, + first_instruction_account + 1, )?; if recent_blockhashes.is_empty() { ic_msg!( @@ -526,33 +415,31 @@ pub fn process_instruction( let rent = get_sysvar_with_account_check2::rent( invoke_context, instruction_context, - instruction_account_indices::InitializeNonceAccount::Rent as usize, + first_instruction_account + 2, )?; initialize_nonce_account( invoke_context, instruction_context, - instruction_account_indices::InitializeNonceAccount::Nonce as usize, + NONCE_ACCOUNT_INDEX, &authorized, &rent, ) } SystemInstruction::AuthorizeNonceAccount(nonce_authority) => { - instruction_context.check_number_of_instruction_accounts(1)?; + let _me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; authorize_nonce_account( invoke_context, instruction_context, &signers, - instruction_account_indices::AuthorizeNonceAccount::Nonce as usize, + NONCE_ACCOUNT_INDEX, &nonce_authority, ) } SystemInstruction::Allocate { space } => { - let mut account = instruction_context.try_borrow_instruction_account( - invoke_context.transaction_context, - instruction_account_indices::Allocate::Account as usize, - )?; - let address = Address::create(account.get_key(), None, invoke_context)?; - allocate(invoke_context, &signers, &mut account, &address, space) + let keyed_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let mut account = keyed_account.try_account_ref_mut()?; + let address = Address::create(keyed_account.unsigned_key(), None, invoke_context)?; + allocate(&mut account, &address, space, &signers, invoke_context) } SystemInstruction::AllocateWithSeed { base, @@ -560,35 +447,31 @@ pub fn process_instruction( space, owner, } => { - let mut account = instruction_context.try_borrow_instruction_account( - invoke_context.transaction_context, - instruction_account_indices::AllocateWithSeed::Account as usize, - )?; + let keyed_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let mut account = keyed_account.try_account_ref_mut()?; let address = Address::create( - account.get_key(), + keyed_account.unsigned_key(), Some((&base, &seed, &owner)), invoke_context, )?; allocate_and_assign( - invoke_context, - &signers, &mut account, &address, space, &owner, + &signers, + invoke_context, ) } SystemInstruction::AssignWithSeed { base, seed, owner } => { - let mut account = instruction_context.try_borrow_instruction_account( - invoke_context.transaction_context, - instruction_account_indices::AssignWithSeed::Account as usize, - )?; + let keyed_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let mut account = keyed_account.try_account_ref_mut()?; let address = Address::create( - account.get_key(), + keyed_account.unsigned_key(), Some((&base, &seed, &owner)), invoke_context, )?; - assign(invoke_context, &signers, &mut account, &address, &owner) + assign(&mut account, &address, &owner, &signers, invoke_context) } } } From edc650d7773338cba52b5fa8f37c873e961ea361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Mon, 14 Mar 2022 15:31:56 +0100 Subject: [PATCH 3/6] Revert "Replaces `KeyedAccount` by `BorrowedAccount` in `nonce_keyed_account`. (#23214)" 1a68f81f89c63ce7d8c41d7731ee99734c188f26 --- runtime/src/nonce_keyed_account.rs | 986 +++++++++----------- runtime/src/system_instruction_processor.rs | 82 +- 2 files changed, 457 insertions(+), 611 deletions(-) diff --git a/runtime/src/nonce_keyed_account.rs b/runtime/src/nonce_keyed_account.rs index 089f27a8813868..c41b9798bd6367 100644 --- a/runtime/src/nonce_keyed_account.rs +++ b/runtime/src/nonce_keyed_account.rs @@ -1,292 +1,314 @@ use { solana_program_runtime::{ic_msg, invoke_context::InvokeContext}, solana_sdk::{ + account::{ReadableAccount, WritableAccount}, + account_utils::State as AccountUtilsState, feature_set::{self, nonce_must_be_writable}, instruction::{checked_add, InstructionError}, + keyed_account::KeyedAccount, nonce::{self, state::Versions, State}, pubkey::Pubkey, system_instruction::{nonce_to_instruction_error, NonceError}, sysvar::rent::Rent, - transaction_context::InstructionContext, }, std::collections::HashSet, }; -pub const NONCE_ACCOUNT_INDEX: usize = 0; -pub const WITHDRAW_TO_ACCOUNT_INDEX: usize = 1; +pub trait NonceKeyedAccount { + fn advance_nonce_account( + &self, + signers: &HashSet, + invoke_context: &InvokeContext, + ) -> Result<(), InstructionError>; + fn withdraw_nonce_account( + &self, + lamports: u64, + to: &KeyedAccount, + rent: &Rent, + signers: &HashSet, + invoke_context: &InvokeContext, + ) -> Result<(), InstructionError>; + fn initialize_nonce_account( + &self, + nonce_authority: &Pubkey, + rent: &Rent, + invoke_context: &InvokeContext, + ) -> Result<(), InstructionError>; + fn authorize_nonce_account( + &self, + nonce_authority: &Pubkey, + signers: &HashSet, + invoke_context: &InvokeContext, + ) -> Result<(), InstructionError>; +} -pub fn advance_nonce_account( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - nonce_account_index: usize, -) -> Result<(), InstructionError> { - let mut account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, nonce_account_index)?; - let merge_nonce_error_into_system_error = invoke_context - .feature_set - .is_active(&feature_set::merge_nonce_error_into_system_error::id()); +impl<'a> NonceKeyedAccount for KeyedAccount<'a> { + fn advance_nonce_account( + &self, + signers: &HashSet, + invoke_context: &InvokeContext, + ) -> Result<(), InstructionError> { + let merge_nonce_error_into_system_error = invoke_context + .feature_set + .is_active(&feature_set::merge_nonce_error_into_system_error::id()); - if invoke_context - .feature_set - .is_active(&nonce_must_be_writable::id()) - && !account.is_writable() - { - ic_msg!( - invoke_context, - "Advance nonce account: Account {} must be writeable", - account.get_key() - ); - return Err(InstructionError::InvalidArgument); - } + if invoke_context + .feature_set + .is_active(&nonce_must_be_writable::id()) + && !self.is_writable() + { + ic_msg!( + invoke_context, + "Advance nonce account: Account {} must be writeable", + self.unsigned_key() + ); + return Err(InstructionError::InvalidArgument); + } - let state = account.get_state::()?.convert_to_current(); - match state { - State::Initialized(data) => { - if !signers.contains(&data.authority) { - ic_msg!( - invoke_context, - "Advance nonce account: Account {} must be a signer", - data.authority + let state = AccountUtilsState::::state(self)?.convert_to_current(); + match state { + State::Initialized(data) => { + if !signers.contains(&data.authority) { + ic_msg!( + invoke_context, + "Advance nonce account: Account {} must be a signer", + data.authority + ); + return Err(InstructionError::MissingRequiredSignature); + } + let recent_blockhash = invoke_context.blockhash; + if data.blockhash == recent_blockhash { + ic_msg!( + invoke_context, + "Advance nonce account: nonce can only advance once per slot" + ); + return Err(nonce_to_instruction_error( + NonceError::NotExpired, + merge_nonce_error_into_system_error, + )); + } + + let new_data = nonce::state::Data::new( + data.authority, + recent_blockhash, + invoke_context.lamports_per_signature, ); - return Err(InstructionError::MissingRequiredSignature); + self.set_state(&Versions::new_current(State::Initialized(new_data))) } - let recent_blockhash = invoke_context.blockhash; - if data.blockhash == recent_blockhash { + _ => { ic_msg!( invoke_context, - "Advance nonce account: nonce can only advance once per slot" + "Advance nonce account: Account {} state is invalid", + self.unsigned_key() ); - return Err(nonce_to_instruction_error( - NonceError::NotExpired, + Err(nonce_to_instruction_error( + NonceError::BadAccountState, merge_nonce_error_into_system_error, - )); + )) } - - let new_data = nonce::state::Data::new( - data.authority, - recent_blockhash, - invoke_context.lamports_per_signature, - ); - account.set_state(&Versions::new_current(State::Initialized(new_data))) } - _ => { + } + + fn withdraw_nonce_account( + &self, + lamports: u64, + to: &KeyedAccount, + rent: &Rent, + signers: &HashSet, + invoke_context: &InvokeContext, + ) -> Result<(), InstructionError> { + let merge_nonce_error_into_system_error = invoke_context + .feature_set + .is_active(&feature_set::merge_nonce_error_into_system_error::id()); + + if invoke_context + .feature_set + .is_active(&nonce_must_be_writable::id()) + && !self.is_writable() + { ic_msg!( invoke_context, - "Advance nonce account: Account {} state is invalid", - account.get_key() + "Withdraw nonce account: Account {} must be writeable", + self.unsigned_key() ); - Err(nonce_to_instruction_error( - NonceError::BadAccountState, - merge_nonce_error_into_system_error, - )) + return Err(InstructionError::InvalidArgument); } - } -} -pub fn withdraw_nonce_account( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - nonce_account_index: usize, - withdraw_to_account_index: usize, - lamports: u64, - rent: &Rent, -) -> Result<(), InstructionError> { - let mut nonce_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, nonce_account_index)?; - let merge_nonce_error_into_system_error = invoke_context - .feature_set - .is_active(&feature_set::merge_nonce_error_into_system_error::id()); - - if invoke_context - .feature_set - .is_active(&nonce_must_be_writable::id()) - && !nonce_account.is_writable() - { - ic_msg!( - invoke_context, - "Withdraw nonce account: Account {} must be writeable", - nonce_account.get_key() - ); - return Err(InstructionError::InvalidArgument); - } - - let signer = match nonce_account.get_state::()?.convert_to_current() { - State::Uninitialized => { - if lamports > nonce_account.get_lamports() { - ic_msg!( - invoke_context, - "Withdraw nonce account: insufficient lamports {}, need {}", - nonce_account.get_lamports(), - lamports, - ); - return Err(InstructionError::InsufficientFunds); - } - *nonce_account.get_key() - } - State::Initialized(ref data) => { - if lamports == nonce_account.get_lamports() { - if data.blockhash == invoke_context.blockhash { - ic_msg!( - invoke_context, - "Withdraw nonce account: nonce can only advance once per slot" - ); - return Err(nonce_to_instruction_error( - NonceError::NotExpired, - merge_nonce_error_into_system_error, - )); - } - nonce_account.set_state(&Versions::new_current(State::Uninitialized))?; - } else { - let min_balance = rent.minimum_balance(nonce_account.get_data().len()); - let amount = checked_add(lamports, min_balance)?; - if amount > nonce_account.get_lamports() { + let signer = match AccountUtilsState::::state(self)?.convert_to_current() { + State::Uninitialized => { + if lamports > self.lamports()? { ic_msg!( invoke_context, "Withdraw nonce account: insufficient lamports {}, need {}", - nonce_account.get_lamports(), - amount, + self.lamports()?, + lamports, ); return Err(InstructionError::InsufficientFunds); } + *self.unsigned_key() + } + State::Initialized(ref data) => { + if lamports == self.lamports()? { + if data.blockhash == invoke_context.blockhash { + ic_msg!( + invoke_context, + "Withdraw nonce account: nonce can only advance once per slot" + ); + return Err(nonce_to_instruction_error( + NonceError::NotExpired, + merge_nonce_error_into_system_error, + )); + } + self.set_state(&Versions::new_current(State::Uninitialized))?; + } else { + let min_balance = rent.minimum_balance(self.data_len()?); + let amount = checked_add(lamports, min_balance)?; + if amount > self.lamports()? { + ic_msg!( + invoke_context, + "Withdraw nonce account: insufficient lamports {}, need {}", + self.lamports()?, + amount, + ); + return Err(InstructionError::InsufficientFunds); + } + } + data.authority } - data.authority + }; + + if !signers.contains(&signer) { + ic_msg!( + invoke_context, + "Withdraw nonce account: Account {} must sign", + signer + ); + return Err(InstructionError::MissingRequiredSignature); } - }; - if !signers.contains(&signer) { - ic_msg!( - invoke_context, - "Withdraw nonce account: Account {} must sign", - signer + let nonce_balance = self.try_account_ref_mut()?.lamports(); + self.try_account_ref_mut()?.set_lamports( + nonce_balance + .checked_sub(lamports) + .ok_or(InstructionError::ArithmeticOverflow)?, + ); + let to_balance = to.try_account_ref_mut()?.lamports(); + to.try_account_ref_mut()?.set_lamports( + to_balance + .checked_add(lamports) + .ok_or(InstructionError::ArithmeticOverflow)?, ); - return Err(InstructionError::MissingRequiredSignature); - } - - nonce_account.checked_sub_lamports(lamports)?; - drop(nonce_account); - let mut withdraw_to_account = instruction_context.try_borrow_instruction_account( - invoke_context.transaction_context, - withdraw_to_account_index, - )?; - withdraw_to_account.checked_add_lamports(lamports)?; - Ok(()) -} + Ok(()) + } -pub fn initialize_nonce_account( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - nonce_account_index: usize, - nonce_authority: &Pubkey, - rent: &Rent, -) -> Result<(), InstructionError> { - let mut account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, nonce_account_index)?; - let merge_nonce_error_into_system_error = invoke_context - .feature_set - .is_active(&feature_set::merge_nonce_error_into_system_error::id()); + fn initialize_nonce_account( + &self, + nonce_authority: &Pubkey, + rent: &Rent, + invoke_context: &InvokeContext, + ) -> Result<(), InstructionError> { + let merge_nonce_error_into_system_error = invoke_context + .feature_set + .is_active(&feature_set::merge_nonce_error_into_system_error::id()); - if invoke_context - .feature_set - .is_active(&nonce_must_be_writable::id()) - && !account.is_writable() - { - ic_msg!( - invoke_context, - "Initialize nonce account: Account {} must be writeable", - account.get_key() - ); - return Err(InstructionError::InvalidArgument); - } + if invoke_context + .feature_set + .is_active(&nonce_must_be_writable::id()) + && !self.is_writable() + { + ic_msg!( + invoke_context, + "Initialize nonce account: Account {} must be writeable", + self.unsigned_key() + ); + return Err(InstructionError::InvalidArgument); + } - match account.get_state::()?.convert_to_current() { - State::Uninitialized => { - let min_balance = rent.minimum_balance(account.get_data().len()); - if account.get_lamports() < min_balance { + match AccountUtilsState::::state(self)?.convert_to_current() { + State::Uninitialized => { + let min_balance = rent.minimum_balance(self.data_len()?); + if self.lamports()? < min_balance { + ic_msg!( + invoke_context, + "Initialize nonce account: insufficient lamports {}, need {}", + self.lamports()?, + min_balance + ); + return Err(InstructionError::InsufficientFunds); + } + let data = nonce::state::Data::new( + *nonce_authority, + invoke_context.blockhash, + invoke_context.lamports_per_signature, + ); + self.set_state(&Versions::new_current(State::Initialized(data))) + } + _ => { ic_msg!( invoke_context, - "Initialize nonce account: insufficient lamports {}, need {}", - account.get_lamports(), - min_balance + "Initialize nonce account: Account {} state is invalid", + self.unsigned_key() ); - return Err(InstructionError::InsufficientFunds); + Err(nonce_to_instruction_error( + NonceError::BadAccountState, + merge_nonce_error_into_system_error, + )) } - let data = nonce::state::Data::new( - *nonce_authority, - invoke_context.blockhash, - invoke_context.lamports_per_signature, - ); - account.set_state(&Versions::new_current(State::Initialized(data))) } - _ => { + } + + fn authorize_nonce_account( + &self, + nonce_authority: &Pubkey, + signers: &HashSet, + invoke_context: &InvokeContext, + ) -> Result<(), InstructionError> { + let merge_nonce_error_into_system_error = invoke_context + .feature_set + .is_active(&feature_set::merge_nonce_error_into_system_error::id()); + + if invoke_context + .feature_set + .is_active(&nonce_must_be_writable::id()) + && !self.is_writable() + { ic_msg!( invoke_context, - "Initialize nonce account: Account {} state is invalid", - account.get_key() + "Authorize nonce account: Account {} must be writeable", + self.unsigned_key() ); - Err(nonce_to_instruction_error( - NonceError::BadAccountState, - merge_nonce_error_into_system_error, - )) + return Err(InstructionError::InvalidArgument); } - } -} -pub fn authorize_nonce_account( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - nonce_account_index: usize, - nonce_authority: &Pubkey, -) -> Result<(), InstructionError> { - let mut account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, nonce_account_index)?; - let merge_nonce_error_into_system_error = invoke_context - .feature_set - .is_active(&feature_set::merge_nonce_error_into_system_error::id()); - - if invoke_context - .feature_set - .is_active(&nonce_must_be_writable::id()) - && !account.is_writable() - { - ic_msg!( - invoke_context, - "Authorize nonce account: Account {} must be writeable", - account.get_key() - ); - return Err(InstructionError::InvalidArgument); - } - - match account.get_state::()?.convert_to_current() { - State::Initialized(data) => { - if !signers.contains(&data.authority) { + match AccountUtilsState::::state(self)?.convert_to_current() { + State::Initialized(data) => { + if !signers.contains(&data.authority) { + ic_msg!( + invoke_context, + "Authorize nonce account: Account {} must sign", + data.authority + ); + return Err(InstructionError::MissingRequiredSignature); + } + let new_data = nonce::state::Data::new( + *nonce_authority, + data.blockhash, + data.get_lamports_per_signature(), + ); + self.set_state(&Versions::new_current(State::Initialized(new_data))) + } + _ => { ic_msg!( invoke_context, - "Authorize nonce account: Account {} must sign", - data.authority + "Authorize nonce account: Account {} state is invalid", + self.unsigned_key() ); - return Err(InstructionError::MissingRequiredSignature); + Err(nonce_to_instruction_error( + NonceError::BadAccountState, + merge_nonce_error_into_system_error, + )) } - let new_data = nonce::state::Data::new( - *nonce_authority, - data.blockhash, - data.get_lamports_per_signature(), - ); - account.set_state(&Versions::new_current(State::Initialized(new_data))) - } - _ => { - ic_msg!( - invoke_context, - "Authorize nonce account: Account {} state is invalid", - account.get_key() - ); - Err(nonce_to_instruction_error( - NonceError::BadAccountState, - merge_nonce_error_into_system_error, - )) } } } @@ -307,6 +329,9 @@ mod test { }, }; + pub const NONCE_ACCOUNT_INDEX: usize = 0; + pub const WITHDRAW_TO_ACCOUNT_INDEX: usize = 1; + macro_rules! push_instruction_context { ($invoke_context:expr, $transaction_context:ident, $instruction_context:ident, $instruction_accounts:ident) => { $invoke_context @@ -392,14 +417,9 @@ mod test { set_invoke_context_blockhash!(invoke_context, 95); let authorized = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -416,13 +436,9 @@ mod test { assert_eq!(state, State::Initialized(data.clone())); set_invoke_context_blockhash!(invoke_context, 63); drop(nonce_account); - advance_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .advance_nonce_account(&signers, &invoke_context) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -439,13 +455,9 @@ mod test { assert_eq!(state, State::Initialized(data.clone())); set_invoke_context_blockhash!(invoke_context, 31); drop(nonce_account); - advance_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .advance_nonce_account(&signers, &invoke_context) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -470,16 +482,15 @@ mod test { let expect_to_lamports = to_account.get_lamports() + withdraw_lamports; drop(nonce_account); drop(to_account); - withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -513,14 +524,9 @@ mod test { set_invoke_context_blockhash!(invoke_context, 31); let authority = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authority, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authority, &rent, &invoke_context) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -538,12 +544,8 @@ mod test { // Nonce account did not sign let signers = HashSet::new(); set_invoke_context_blockhash!(invoke_context, 0); - let result = advance_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .advance_nonce_account(&signers, &invoke_context); assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); } @@ -564,20 +566,11 @@ mod test { set_invoke_context_blockhash!(invoke_context, 63); let authorized = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); - let result = advance_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - ); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .advance_nonce_account(&signers, &invoke_context); assert_eq!(result, Err(SystemError::NonceBlockhashNotExpired.into())); } @@ -597,12 +590,8 @@ mod test { signers.insert(*nonce_account.get_key()); set_invoke_context_blockhash!(invoke_context, 63); drop(nonce_account); - let result = advance_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .advance_nonce_account(&signers, &invoke_context); assert_eq!(result, Err(InstructionError::InvalidAccountData)); } @@ -627,23 +616,14 @@ mod test { let authorized = *nonce_authority.get_key(); drop(nonce_account); drop(nonce_authority); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); let mut signers = HashSet::new(); signers.insert(authorized); set_invoke_context_blockhash!(invoke_context, 31); - let result = advance_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .advance_nonce_account(&signers, &invoke_context); assert_eq!(result, Ok(())); } @@ -668,20 +648,11 @@ mod test { let authorized = *nonce_authority.get_key(); drop(nonce_account); drop(nonce_authority); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); - let result = advance_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - ); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .advance_nonce_account(&signers, &invoke_context); assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); } @@ -713,16 +684,15 @@ mod test { let expect_to_lamports = to_account.get_lamports() + withdraw_lamports; drop(nonce_account); drop(to_account); - withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -763,15 +733,14 @@ mod test { let withdraw_lamports = nonce_account.get_lamports(); drop(nonce_account); drop(to_account); - let result = withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ); assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); } @@ -797,15 +766,14 @@ mod test { set_invoke_context_blockhash!(invoke_context, 0); let withdraw_lamports = nonce_account.get_lamports() + 1; drop(nonce_account); - let result = withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ); assert_eq!(result, Err(InstructionError::InsufficientFunds)); } @@ -832,16 +800,15 @@ mod test { let to_expect_lamports = to_account.get_lamports() + withdraw_lamports; drop(nonce_account); drop(to_account); - withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -860,16 +827,15 @@ mod test { let to_expect_lamports = to_account.get_lamports() + withdraw_lamports; drop(nonce_account); drop(to_account); - withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -906,14 +872,9 @@ mod test { let authority = *nonce_account.get_key(); drop(nonce_account); drop(to_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authority, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authority, &rent, &invoke_context) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -935,16 +896,15 @@ mod test { let to_expect_lamports = to_account.get_lamports() + withdraw_lamports; drop(nonce_account); drop(to_account); - withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -969,16 +929,15 @@ mod test { let to_expect_lamports = to_account.get_lamports() + withdraw_lamports; drop(nonce_account); drop(to_account); - withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -1013,14 +972,9 @@ mod test { let authorized = *nonce_account.get_key(); drop(nonce_account); drop(to_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -1028,15 +982,14 @@ mod test { signers.insert(*nonce_account.get_key()); let withdraw_lamports = nonce_account.get_lamports(); drop(nonce_account); - let result = withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ); assert_eq!(result, Err(SystemError::NonceBlockhashNotExpired.into())); } @@ -1055,14 +1008,9 @@ mod test { set_invoke_context_blockhash!(invoke_context, 95); let authorized = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); set_invoke_context_blockhash!(invoke_context, 63); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) @@ -1071,15 +1019,14 @@ mod test { signers.insert(*nonce_account.get_key()); let withdraw_lamports = nonce_account.get_lamports() + 1; drop(nonce_account); - let result = withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ); assert_eq!(result, Err(InstructionError::InsufficientFunds)); } @@ -1098,14 +1045,9 @@ mod test { set_invoke_context_blockhash!(invoke_context, 95); let authorized = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -1114,15 +1056,14 @@ mod test { signers.insert(*nonce_account.get_key()); let withdraw_lamports = 42 + 1; drop(nonce_account); - let result = withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ); assert_eq!(result, Err(InstructionError::InsufficientFunds)); } @@ -1141,14 +1082,9 @@ mod test { set_invoke_context_blockhash!(invoke_context, 95); let authorized = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -1157,15 +1093,14 @@ mod test { signers.insert(*nonce_account.get_key()); let withdraw_lamports = u64::MAX - 54; drop(nonce_account); - let result = withdraw_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - withdraw_lamports, - &rent, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .withdraw_nonce_account( + withdraw_lamports, + &invoke_context.get_keyed_accounts().unwrap()[1 + WITHDRAW_TO_ACCOUNT_INDEX], + &rent, + &signers, + &invoke_context, + ); assert_eq!(result, Err(InstructionError::InsufficientFunds)); } @@ -1191,13 +1126,8 @@ mod test { set_invoke_context_blockhash!(invoke_context, 0); let authorized = *nonce_account.get_key(); drop(nonce_account); - let result = initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -1229,22 +1159,12 @@ mod test { set_invoke_context_blockhash!(invoke_context, 31); let authorized = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); set_invoke_context_blockhash!(invoke_context, 0); - let result = initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context); assert_eq!(result, Err(InstructionError::InvalidAccountData)); } @@ -1264,13 +1184,8 @@ mod test { set_invoke_context_blockhash!(invoke_context, 63); let authorized = *nonce_account.get_key(); drop(nonce_account); - let result = initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context); assert_eq!(result, Err(InstructionError::InsufficientFunds)); } @@ -1291,28 +1206,18 @@ mod test { set_invoke_context_blockhash!(invoke_context, 31); let authorized = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); let authority = Pubkey::default(); let data = nonce::state::Data::new( authority, invoke_context.blockhash, invoke_context.lamports_per_signature, ); - authorize_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - &authority, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .authorize_nonce_account(&authority, &signers, &invoke_context) + .unwrap(); let nonce_account = instruction_context .try_borrow_instruction_account(transaction_context, NONCE_ACCOUNT_INDEX) .unwrap(); @@ -1338,13 +1243,8 @@ mod test { let mut signers = HashSet::new(); signers.insert(*nonce_account.get_key()); drop(nonce_account); - let result = authorize_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - &Pubkey::default(), - ); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .authorize_nonce_account(&Pubkey::default(), &signers, &invoke_context); assert_eq!(result, Err(InstructionError::InvalidAccountData)); } @@ -1365,21 +1265,11 @@ mod test { set_invoke_context_blockhash!(invoke_context, 31); let authorized = Pubkey::default(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); - let result = authorize_nonce_account( - &invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - &authorized, - ); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); + let result = invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .authorize_nonce_account(&authorized, &signers, &invoke_context); assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); } @@ -1403,14 +1293,9 @@ mod test { set_invoke_context_blockhash!(invoke_context, 0); let authorized = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &rent, &invoke_context) + .unwrap(); assert!(verify_nonce_account( &transaction_context .get_account_at_index(NONCE_ACCOUNT_INDEX) @@ -1458,14 +1343,9 @@ mod test { set_invoke_context_blockhash!(invoke_context, 0); let authorized = *nonce_account.get_key(); drop(nonce_account); - initialize_nonce_account( - &invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &Rent::free(), - ) - .unwrap(); + invoke_context.get_keyed_accounts().unwrap()[1 + NONCE_ACCOUNT_INDEX] + .initialize_nonce_account(&authorized, &Rent::free(), &invoke_context) + .unwrap(); set_invoke_context_blockhash!(invoke_context, 1); assert!(!verify_nonce_account( &transaction_context diff --git a/runtime/src/system_instruction_processor.rs b/runtime/src/system_instruction_processor.rs index f280cf141eddcc..1314ac4e34965a 100644 --- a/runtime/src/system_instruction_processor.rs +++ b/runtime/src/system_instruction_processor.rs @@ -1,18 +1,15 @@ use { - crate::nonce_keyed_account::{ - advance_nonce_account, authorize_nonce_account, initialize_nonce_account, - withdraw_nonce_account, NONCE_ACCOUNT_INDEX, WITHDRAW_TO_ACCOUNT_INDEX, - }, + crate::nonce_keyed_account::NonceKeyedAccount, log::*, solana_program_runtime::{ - ic_msg, invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check2, + ic_msg, invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check, }, solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, account_utils::StateMut, feature_set, instruction::InstructionError, - keyed_account::{keyed_account_at_index, KeyedAccount}, + keyed_account::{get_signers, keyed_account_at_index, KeyedAccount}, nonce, program_utils::limited_deserialize, pubkey::Pubkey, @@ -268,15 +265,14 @@ pub fn process_instruction( instruction_data: &[u8], invoke_context: &mut InvokeContext, ) -> Result<(), InstructionError> { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; let keyed_accounts = invoke_context.get_keyed_accounts()?; let instruction = limited_deserialize(instruction_data)?; trace!("process_instruction: {:?}", instruction); trace!("keyed_accounts: {:?}", keyed_accounts); - let signers = instruction_context.get_signers(transaction_context); + let _ = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let signers = get_signers(&keyed_accounts[first_instruction_account..]); match instruction { SystemInstruction::CreateAccount { lamports, @@ -352,12 +348,11 @@ pub fn process_instruction( ) } SystemInstruction::AdvanceNonceAccount => { - let _me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; #[allow(deprecated)] - let recent_blockhashes = get_sysvar_with_account_check2::recent_blockhashes( + let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - first_instruction_account + 1, )?; if recent_blockhashes.is_empty() { ic_msg!( @@ -366,44 +361,28 @@ pub fn process_instruction( ); return Err(NonceError::NoRecentBlockhashes.into()); } - advance_nonce_account( - invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - ) + me.advance_nonce_account(&signers, invoke_context) } SystemInstruction::WithdrawNonceAccount(lamports) => { - let _me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; - let _to = &mut keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + let me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let to = &mut keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; #[allow(deprecated)] - let _recent_blockhashes = get_sysvar_with_account_check2::recent_blockhashes( + let _recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes( + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, - instruction_context, - first_instruction_account + 2, )?; - let rent = get_sysvar_with_account_check2::rent( + let rent = get_sysvar_with_account_check::rent( + keyed_account_at_index(keyed_accounts, first_instruction_account + 3)?, invoke_context, - instruction_context, - first_instruction_account + 3, )?; - withdraw_nonce_account( - invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - WITHDRAW_TO_ACCOUNT_INDEX, - lamports, - &rent, - ) + me.withdraw_nonce_account(lamports, to, &rent, &signers, invoke_context) } SystemInstruction::InitializeNonceAccount(authorized) => { - let _me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; #[allow(deprecated)] - let recent_blockhashes = get_sysvar_with_account_check2::recent_blockhashes( + let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - first_instruction_account + 1, )?; if recent_blockhashes.is_empty() { ic_msg!( @@ -412,28 +391,15 @@ pub fn process_instruction( ); return Err(NonceError::NoRecentBlockhashes.into()); } - let rent = get_sysvar_with_account_check2::rent( + let rent = get_sysvar_with_account_check::rent( + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, - instruction_context, - first_instruction_account + 2, )?; - initialize_nonce_account( - invoke_context, - instruction_context, - NONCE_ACCOUNT_INDEX, - &authorized, - &rent, - ) + me.initialize_nonce_account(&authorized, &rent, invoke_context) } SystemInstruction::AuthorizeNonceAccount(nonce_authority) => { - let _me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; - authorize_nonce_account( - invoke_context, - instruction_context, - &signers, - NONCE_ACCOUNT_INDEX, - &nonce_authority, - ) + let me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; + me.authorize_nonce_account(&nonce_authority, &signers, invoke_context) } SystemInstruction::Allocate { space } => { let keyed_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?; From d6eb615581020dbbcb43416fa2e8bcd3cb97184f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Mon, 14 Mar 2022 16:30:46 +0100 Subject: [PATCH 4/6] Revert "Replaces KeyedAccount by BorrowedAccount in the config processor. (#23302)" a14c7c37ee8f46912f4ac25447e3e68649f42877 --- programs/config/src/config_processor.rs | 52 +++++++++++++------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/programs/config/src/config_processor.rs b/programs/config/src/config_processor.rs index 5ce3c515050762..05accbf99c96e0 100644 --- a/programs/config/src/config_processor.rs +++ b/programs/config/src/config_processor.rs @@ -5,29 +5,33 @@ use { bincode::deserialize, solana_program_runtime::{ic_msg, invoke_context::InvokeContext}, solana_sdk::{ - feature_set, instruction::InstructionError, program_utils::limited_deserialize, + account::{ReadableAccount, WritableAccount}, + feature_set, + instruction::InstructionError, + keyed_account::keyed_account_at_index, + program_utils::limited_deserialize, pubkey::Pubkey, }, std::collections::BTreeSet, }; pub fn process_instruction( - _first_instruction_account: usize, + first_instruction_account: usize, data: &[u8], invoke_context: &mut InvokeContext, ) -> Result<(), InstructionError> { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; + let keyed_accounts = invoke_context.get_keyed_accounts()?; let key_list: ConfigKeys = limited_deserialize(data)?; + let config_keyed_account = + &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; let current_data: ConfigKeys = { - let config_account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - if config_account.get_owner() != &crate::id() { + let config_account = config_keyed_account.try_account_ref_mut()?; + if config_account.owner() != &crate::id() { return Err(InstructionError::InvalidAccountOwner); } - deserialize(config_account.get_data()).map_err(|err| { + deserialize(config_account.data()).map_err(|err| { ic_msg!( invoke_context, "Unable to deserialize config account: {}", @@ -46,7 +50,7 @@ pub fn process_instruction( if current_signer_keys.is_empty() { // Config account keypair must be a signer on account initialization, // or when no signers specified in Config data - if !instruction_context.is_signer(instruction_context.get_number_of_program_accounts())? { + if config_keyed_account.signer_key().is_none() { return Err(InstructionError::MissingRequiredSignature); } } @@ -54,10 +58,9 @@ pub fn process_instruction( let mut counter = 0; for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) { counter += 1; - if signer != instruction_context.get_instruction_account_key(transaction_context, 0)? { - let is_signer = instruction_context - .is_signer(instruction_context.get_number_of_program_accounts() + counter) - .map_err(|_| { + if signer != config_keyed_account.unsigned_key() { + let signer_account = + keyed_account_at_index(keyed_accounts, counter + 1).map_err(|_| { ic_msg!( invoke_context, "account {:?} is not in account list", @@ -65,7 +68,8 @@ pub fn process_instruction( ); InstructionError::MissingRequiredSignature })?; - if !is_signer { + let signer_key = signer_account.signer_key(); + if signer_key.is_none() { ic_msg!( invoke_context, "account {:?} signer_key().is_none()", @@ -73,9 +77,7 @@ pub fn process_instruction( ); return Err(InstructionError::MissingRequiredSignature); } - if instruction_context.get_instruction_account_key(transaction_context, counter)? - != signer - { + if signer_key.unwrap() != signer { ic_msg!( invoke_context, "account[{:?}].signer_key() does not match Config data)", @@ -94,9 +96,7 @@ pub fn process_instruction( ); return Err(InstructionError::MissingRequiredSignature); } - } else if !instruction_context - .is_signer(instruction_context.get_number_of_program_accounts())? - { + } else if config_keyed_account.signer_key().is_none() { ic_msg!(invoke_context, "account[0].signer_key().is_none()"); return Err(InstructionError::MissingRequiredSignature); } @@ -125,13 +125,15 @@ pub fn process_instruction( return Err(InstructionError::MissingRequiredSignature); } - let mut config_account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - if config_account.get_data().len() < data.len() { + if config_keyed_account.data_len()? < data.len() { ic_msg!(invoke_context, "instruction data too large"); return Err(InstructionError::InvalidInstructionData); } - config_account.get_data_mut()[..data.len()].copy_from_slice(data); + + config_keyed_account + .try_account_ref_mut()? + .data_as_mut_slice()[..data.len()] + .copy_from_slice(data); Ok(()) } @@ -144,7 +146,7 @@ mod tests { serde_derive::{Deserialize, Serialize}, solana_program_runtime::invoke_context::mock_process_instruction, solana_sdk::{ - account::{AccountSharedData, ReadableAccount}, + account::AccountSharedData, instruction::AccountMeta, pubkey::Pubkey, signature::{Keypair, Signer}, From d7b65e031c94c34f0cf1fb453549c2f1065d9556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Mon, 14 Mar 2022 17:10:10 +0100 Subject: [PATCH 5/6] Revert "Replaces `KeyedAccount` by `BorrowedAccount` in vote processor (#23348)" e2fa6a0f7a906a6f58925ba282115f08b9dfd487 --- programs/vote/src/vote_processor.rs | 242 +++++++++++----------------- programs/vote/src/vote_state/mod.rs | 164 +++++++------------ 2 files changed, 152 insertions(+), 254 deletions(-) diff --git a/programs/vote/src/vote_processor.rs b/programs/vote/src/vote_processor.rs index cb40f229e0f030..24cc8f054203ac 100644 --- a/programs/vote/src/vote_processor.rs +++ b/programs/vote/src/vote_processor.rs @@ -5,157 +5,87 @@ use { log::*, solana_metrics::inc_new_counter_info, solana_program_runtime::{ - invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check2, + invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check, }, - solana_sdk::{feature_set, instruction::InstructionError, program_utils::limited_deserialize}, + solana_sdk::{ + feature_set, + instruction::InstructionError, + keyed_account::{get_signers, keyed_account_at_index, KeyedAccount}, + program_utils::limited_deserialize, + pubkey::Pubkey, + sysvar::rent::Rent, + }, + std::collections::HashSet, }; -pub mod instruction_account_indices { - pub enum InitializeAccount { - VoteAccount = 0, - Rent = 1, - Clock = 2, - } - - pub enum Authorize { - VoteAccount = 0, - Clock = 1, - } - - pub enum UpdateValidatorIdentity { - VoteAccount = 0, - Node = 1, - } - - pub enum UpdateCommission { - VoteAccount = 0, - } - - pub enum Vote { - VoteAccount = 0, - SlotHashes = 1, - Clock = 2, - } - - pub enum UpdateVoteState { - VoteAccount = 0, - } - - pub enum Withdraw { - VoteAccount = 0, - Recipient = 1, - } - - pub enum AuthorizeChecked { - VoteAccount = 0, - Clock = 1, - // Ignores = 2, - Voter = 3, - } -} - pub fn process_instruction( - _first_instruction_account: usize, + first_instruction_account: usize, data: &[u8], invoke_context: &mut InvokeContext, ) -> Result<(), InstructionError> { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; + let keyed_accounts = invoke_context.get_keyed_accounts()?; trace!("process_instruction: {:?}", data); + trace!("keyed_accounts: {:?}", keyed_accounts); - { - let vote_account = - instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - if vote_account.get_owner() != &id() { - return Err(InstructionError::InvalidAccountOwner); - } + let me = &mut keyed_account_at_index(keyed_accounts, first_instruction_account)?; + if me.owner()? != id() { + return Err(InstructionError::InvalidAccountOwner); } - let signers = instruction_context.get_signers(transaction_context); + let signers: HashSet = get_signers(&keyed_accounts[first_instruction_account..]); match limited_deserialize(data)? { VoteInstruction::InitializeAccount(vote_init) => { - let rent = get_sysvar_with_account_check2::rent( + let rent = get_sysvar_with_account_check::rent( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - instruction_account_indices::InitializeAccount::Rent as usize, )?; - { - // Verify rent exemption - let vote_account = instruction_context.try_borrow_instruction_account( - transaction_context, - instruction_account_indices::InitializeAccount::VoteAccount as usize, - )?; - if !rent.is_exempt(vote_account.get_lamports(), vote_account.get_data().len()) { - return Err(InstructionError::InsufficientFunds); - } - } - let _clock = get_sysvar_with_account_check2::clock( + verify_rent_exemption(me, &rent)?; + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, - instruction_context, - instruction_account_indices::InitializeAccount::Clock as usize, )?; - vote_state::initialize_account( - invoke_context, - instruction_context, - &signers, - instruction_account_indices::InitializeAccount::VoteAccount as usize, - &vote_init, - ) + vote_state::initialize_account(me, &vote_init, &signers, &clock) } VoteInstruction::Authorize(voter_pubkey, vote_authorize) => { - let _clock = get_sysvar_with_account_check2::clock( + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - instruction_account_indices::Authorize::Clock as usize, )?; vote_state::authorize( - invoke_context, - instruction_context, - &signers, - instruction_account_indices::Authorize::VoteAccount as usize, + me, &voter_pubkey, vote_authorize, - ) - } - VoteInstruction::UpdateValidatorIdentity => { - instruction_context.check_number_of_instruction_accounts(2)?; - vote_state::update_validator_identity( - invoke_context, - instruction_context, &signers, - instruction_account_indices::UpdateValidatorIdentity::VoteAccount as usize, - instruction_context.get_instruction_account_key( - transaction_context, - instruction_account_indices::UpdateValidatorIdentity::Node as usize, - )?, + &clock, + &invoke_context.feature_set, ) } - VoteInstruction::UpdateCommission(commission) => vote_state::update_commission( - invoke_context, - instruction_context, + VoteInstruction::UpdateValidatorIdentity => vote_state::update_validator_identity( + me, + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?.unsigned_key(), &signers, - instruction_account_indices::UpdateCommission::VoteAccount as usize, - commission, ), + VoteInstruction::UpdateCommission(commission) => { + vote_state::update_commission(me, commission, &signers) + } VoteInstruction::Vote(vote) | VoteInstruction::VoteSwitch(vote, _) => { inc_new_counter_info!("vote-native", 1); - let _slot_hashes = get_sysvar_with_account_check2::slot_hashes( + let slot_hashes = get_sysvar_with_account_check::slot_hashes( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - instruction_account_indices::Vote::SlotHashes as usize, )?; - let _clock = get_sysvar_with_account_check2::clock( + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, - instruction_context, - instruction_account_indices::Vote::Clock as usize, )?; vote_state::process_vote( - invoke_context, - instruction_context, - &signers, - instruction_account_indices::Vote::VoteAccount as usize, + me, + &slot_hashes, + &clock, &vote, + &signers, + &invoke_context.feature_set, ) } VoteInstruction::UpdateVoteState(vote_state_update) @@ -165,26 +95,47 @@ pub fn process_instruction( .is_active(&feature_set::allow_votes_to_directly_update_vote_state::id()) { inc_new_counter_info!("vote-state-native", 1); + let sysvar_cache = invoke_context.get_sysvar_cache(); + let slot_hashes = sysvar_cache.get_slot_hashes()?; + let clock = sysvar_cache.get_clock()?; vote_state::process_vote_state_update( - invoke_context, - instruction_context, - &signers, - instruction_account_indices::UpdateVoteState::VoteAccount as usize, + me, + slot_hashes.slot_hashes(), + &clock, vote_state_update, + &signers, ) } else { Err(InstructionError::InvalidInstructionData) } } VoteInstruction::Withdraw(lamports) => { - instruction_context.check_number_of_instruction_accounts(2)?; + let to = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + let rent_sysvar = if invoke_context + .feature_set + .is_active(&feature_set::reject_non_rent_exempt_vote_withdraws::id()) + { + Some(invoke_context.get_sysvar_cache().get_rent()?) + } else { + None + }; + + let clock_if_feature_active = if invoke_context + .feature_set + .is_active(&feature_set::reject_vote_account_close_unless_zero_credit_epoch::id()) + { + Some(invoke_context.get_sysvar_cache().get_clock()?) + } else { + None + }; + vote_state::withdraw( - invoke_context, - instruction_context, - &signers, - instruction_account_indices::Withdraw::VoteAccount as usize, - instruction_account_indices::Withdraw::Recipient as usize, + me, lamports, + to, + &signers, + rent_sysvar.as_deref(), + clock_if_feature_active.as_deref(), ) } VoteInstruction::AuthorizeChecked(vote_authorize) => { @@ -192,28 +143,21 @@ pub fn process_instruction( .feature_set .is_active(&feature_set::vote_stake_checked_instructions::id()) { - instruction_context.check_number_of_instruction_accounts(4)?; - if !instruction_context.is_signer( - instruction_context.get_number_of_program_accounts() - + instruction_account_indices::AuthorizeChecked::Voter as usize, - )? { - return Err(InstructionError::MissingRequiredSignature); - } - let _clock = get_sysvar_with_account_check2::clock( + let voter_pubkey = + &keyed_account_at_index(keyed_accounts, first_instruction_account + 3)? + .signer_key() + .ok_or(InstructionError::MissingRequiredSignature)?; + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - instruction_account_indices::AuthorizeChecked::Clock as usize, )?; vote_state::authorize( - invoke_context, - instruction_context, - &signers, - instruction_account_indices::AuthorizeChecked::VoteAccount as usize, - instruction_context.get_instruction_account_key( - transaction_context, - instruction_account_indices::AuthorizeChecked::Voter as usize, - )?, + me, + voter_pubkey, vote_authorize, + &signers, + &clock, + &invoke_context.feature_set, ) } else { Err(InstructionError::InvalidInstructionData) @@ -222,6 +166,17 @@ pub fn process_instruction( } } +fn verify_rent_exemption( + keyed_account: &KeyedAccount, + rent: &Rent, +) -> Result<(), InstructionError> { + if !rent.is_exempt(keyed_account.lamports()?, keyed_account.data_len()?) { + Err(InstructionError::InsufficientFunds) + } else { + Ok(()) + } +} + #[cfg(test)] mod tests { use { @@ -246,10 +201,9 @@ mod tests { feature_set::FeatureSet, hash::Hash, instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - sysvar::{self, clock::Clock, rent::Rent, slot_hashes::SlotHashes}, + sysvar::{self, clock::Clock, slot_hashes::SlotHashes}, }, - std::{collections::HashSet, str::FromStr}, + std::str::FromStr, }; fn create_default_account() -> AccountSharedData { diff --git a/programs/vote/src/vote_state/mod.rs b/programs/vote/src/vote_state/mod.rs index 1b61ecbe0c56d6..187e11a403507a 100644 --- a/programs/vote/src/vote_state/mod.rs +++ b/programs/vote/src/vote_state/mod.rs @@ -5,19 +5,19 @@ use { bincode::{deserialize, serialize_into, serialized_size, ErrorKind}, log::*, serde_derive::{Deserialize, Serialize}, - solana_program_runtime::invoke_context::InvokeContext, solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, + account_utils::State, clock::{Epoch, Slot, UnixTimestamp}, epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET, feature_set::{self, filter_votes_outside_slot_hashes, FeatureSet}, hash::Hash, instruction::InstructionError, + keyed_account::KeyedAccount, pubkey::Pubkey, rent::Rent, slot_hashes::SlotHash, sysvar::clock::Clock, - transaction_context::{BorrowedAccount, InstructionContext}, }, std::{ cmp::Ordering, @@ -1165,24 +1165,19 @@ impl VoteState { /// but will implicitly withdraw authorization from the previously authorized /// key pub fn authorize( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - vote_account_index: usize, + vote_account: &KeyedAccount, authorized: &Pubkey, vote_authorize: VoteAuthorize, + signers: &HashSet, + clock: &Clock, + feature_set: &FeatureSet, ) -> Result<(), InstructionError> { - let mut vote_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?; - let clock = invoke_context.get_sysvar_cache().get_clock()?; - let mut vote_state: VoteState = vote_account - .get_state::()? - .convert_to_current(); + let mut vote_state: VoteState = + State::::state(vote_account)?.convert_to_current(); match vote_authorize { VoteAuthorize::Voter => { - let authorized_withdrawer_signer = if invoke_context - .feature_set + let authorized_withdrawer_signer = if feature_set .is_active(&feature_set::vote_withdraw_authority_may_change_authorized_voter::id()) { verify_authorized_signer(&vote_state.authorized_withdrawer, signers).is_ok() @@ -1216,17 +1211,12 @@ pub fn authorize( /// Update the node_pubkey, requires signature of the authorized voter pub fn update_validator_identity( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - vote_account_index: usize, + vote_account: &KeyedAccount, node_pubkey: &Pubkey, + signers: &HashSet, ) -> Result<(), InstructionError> { - let mut vote_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?; - let mut vote_state: VoteState = vote_account - .get_state::()? - .convert_to_current(); + let mut vote_state: VoteState = + State::::state(vote_account)?.convert_to_current(); // current authorized withdrawer must say "yay" verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?; @@ -1241,17 +1231,12 @@ pub fn update_validator_identity( /// Update the vote account's commission pub fn update_commission( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - vote_account_index: usize, + vote_account: &KeyedAccount, commission: u8, + signers: &HashSet, ) -> Result<(), InstructionError> { - let mut vote_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?; - let mut vote_state: VoteState = vote_account - .get_state::()? - .convert_to_current(); + let mut vote_state: VoteState = + State::::state(vote_account)?.convert_to_current(); // current authorized withdrawer must say "yay" verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?; @@ -1274,42 +1259,20 @@ fn verify_authorized_signer( /// Withdraw funds from the vote account pub fn withdraw( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - vote_account_index: usize, - recipient_account_index: usize, + vote_account: &KeyedAccount, lamports: u64, + to_account: &KeyedAccount, + signers: &HashSet, + rent_sysvar: Option<&Rent>, + clock: Option<&Clock>, ) -> Result<(), InstructionError> { - let mut vote_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?; - - let rent_sysvar = if invoke_context - .feature_set - .is_active(&feature_set::reject_non_rent_exempt_vote_withdraws::id()) - { - Some(invoke_context.get_sysvar_cache().get_rent()?) - } else { - None - }; - - let clock = if invoke_context - .feature_set - .is_active(&feature_set::reject_vote_account_close_unless_zero_credit_epoch::id()) - { - Some(invoke_context.get_sysvar_cache().get_clock()?) - } else { - None - }; - - let vote_state: VoteState = vote_account - .get_state::()? - .convert_to_current(); + let vote_state: VoteState = + State::::state(vote_account)?.convert_to_current(); verify_authorized_signer(&vote_state.authorized_withdrawer, signers)?; let remaining_balance = vote_account - .get_lamports() + .lamports()? .checked_sub(lamports) .ok_or(InstructionError::InsufficientFunds)?; @@ -1332,19 +1295,18 @@ pub fn withdraw( vote_account.set_state(&VoteStateVersions::new_current(VoteState::default()))?; } } else if let Some(rent_sysvar) = rent_sysvar { - let min_rent_exempt_balance = rent_sysvar.minimum_balance(vote_account.get_data().len()); + let min_rent_exempt_balance = rent_sysvar.minimum_balance(vote_account.data_len()?); if remaining_balance < min_rent_exempt_balance { return Err(InstructionError::InsufficientFunds); } } - vote_account.checked_sub_lamports(lamports)?; - drop(vote_account); - let mut recipient_account = instruction_context.try_borrow_instruction_account( - invoke_context.transaction_context, - recipient_account_index, - )?; - recipient_account.checked_add_lamports(lamports)?; + vote_account + .try_account_ref_mut()? + .checked_sub_lamports(lamports)?; + to_account + .try_account_ref_mut()? + .checked_add_lamports(lamports)?; Ok(()) } @@ -1352,19 +1314,15 @@ pub fn withdraw( /// Assumes that the account is being init as part of a account creation or balance transfer and /// that the transaction must be signed by the staker's keys pub fn initialize_account( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - vote_account_index: usize, + vote_account: &KeyedAccount, vote_init: &VoteInit, + signers: &HashSet, + clock: &Clock, ) -> Result<(), InstructionError> { - let mut vote_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?; - let clock = invoke_context.get_sysvar_cache().get_clock()?; - if vote_account.get_data().len() != VoteState::size_of() { + if vote_account.data_len()? != VoteState::size_of() { return Err(InstructionError::InvalidAccountData); } - let versioned = vote_account.get_state::()?; + let versioned = State::::state(vote_account)?; if !versioned.is_uninitialized() { return Err(InstructionError::AccountAlreadyInitialized); @@ -1374,16 +1332,16 @@ pub fn initialize_account( verify_authorized_signer(&vote_init.node_pubkey, signers)?; vote_account.set_state(&VoteStateVersions::new_current(VoteState::new( - vote_init, &clock, + vote_init, clock, ))) } fn verify_and_get_vote_state( - vote_account: &BorrowedAccount, + vote_account: &KeyedAccount, clock: &Clock, signers: &HashSet, ) -> Result { - let versioned = vote_account.get_state::()?; + let versioned = State::::state(vote_account)?; if versioned.is_uninitialized() { return Err(InstructionError::UninitializedAccount); @@ -1397,25 +1355,16 @@ fn verify_and_get_vote_state( } pub fn process_vote( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - vote_account_index: usize, + vote_account: &KeyedAccount, + slot_hashes: &[SlotHash], + clock: &Clock, vote: &Vote, + signers: &HashSet, + feature_set: &FeatureSet, ) -> Result<(), InstructionError> { - let mut vote_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?; - let sysvar_cache = invoke_context.get_sysvar_cache(); - let slot_hashes = sysvar_cache.get_slot_hashes()?; - let clock = sysvar_cache.get_clock()?; - let mut vote_state = verify_and_get_vote_state(&vote_account, &clock, signers)?; - - vote_state.process_vote( - vote, - slot_hashes.slot_hashes(), - clock.epoch, - Some(&invoke_context.feature_set), - )?; + let mut vote_state = verify_and_get_vote_state(vote_account, clock, signers)?; + + vote_state.process_vote(vote, slot_hashes, clock.epoch, Some(feature_set))?; if let Some(timestamp) = vote.timestamp { vote.slots .iter() @@ -1427,19 +1376,14 @@ pub fn process_vote( } pub fn process_vote_state_update( - invoke_context: &InvokeContext, - instruction_context: &InstructionContext, - signers: &HashSet, - vote_account_index: usize, + vote_account: &KeyedAccount, + slot_hashes: &[SlotHash], + clock: &Clock, mut vote_state_update: VoteStateUpdate, + signers: &HashSet, ) -> Result<(), InstructionError> { - let mut vote_account = instruction_context - .try_borrow_instruction_account(invoke_context.transaction_context, vote_account_index)?; - let sysvar_cache = invoke_context.get_sysvar_cache(); - let slot_hashes = sysvar_cache.get_slot_hashes()?; - let clock = sysvar_cache.get_clock()?; - let mut vote_state = verify_and_get_vote_state(&vote_account, &clock, signers)?; - vote_state.check_update_vote_state_slots_are_valid(&mut vote_state_update, &slot_hashes)?; + let mut vote_state = verify_and_get_vote_state(vote_account, clock, signers)?; + vote_state.check_update_vote_state_slots_are_valid(&mut vote_state_update, slot_hashes)?; vote_state.process_new_vote_state( vote_state_update.lockouts, vote_state_update.root, From a69207cb6f3df545b38afa033698fad8912c7ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Tue, 15 Mar 2022 15:55:32 +0100 Subject: [PATCH 6/6] Revert "Refactor: Prepare stake_instruction.rs to remove `KeyedAccount`s (#23375)" ee3fc39f1c33a044a8f83cd538b133bf4015d421 --- programs/stake/src/stake_instruction.rs | 326 ++++++------------------ 1 file changed, 78 insertions(+), 248 deletions(-) diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index 49c89cce9b7d6b..212193104d9ecd 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -7,12 +7,12 @@ use { crate::{config, stake_state::StakeAccount}, log::*, solana_program_runtime::{ - invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check2, + invoke_context::InvokeContext, sysvar_cache::get_sysvar_with_account_check, }, solana_sdk::{ feature_set, instruction::InstructionError, - keyed_account::keyed_account_at_index, + keyed_account::{get_signers, keyed_account_at_index}, program_utils::limited_deserialize, stake::{ instruction::StakeInstruction, @@ -23,140 +23,46 @@ use { }, }; -pub mod instruction_account_indices { - pub enum Initialize { - StakeAccount = 0, - Rent = 1, - } - - pub enum Authorize { - StakeAccount = 0, - Clock = 1, - // CurrentAuthority = 2, - Custodian = 3, - } - - pub enum AuthorizeWithSeed { - StakeAccount = 0, - AuthorityBase = 1, - Clock = 2, - Custodian = 3, - } - - pub enum DelegateStake { - StakeAccount = 0, - VoteAccount = 1, - Clock = 2, - StakeHistory = 3, - ConfigAccount = 4, - } - - pub enum Split { - StakeAccount = 0, - SplitTo = 1, - } - - pub enum Merge { - StakeAccount = 0, - MergeFrom = 1, - Clock = 2, - StakeHistory = 3, - } - - pub enum Withdraw { - StakeAccount = 0, - Recipient = 1, - Clock = 2, - StakeHistory = 3, - WithdrawAuthority = 4, - Custodian = 5, - } - - pub enum Deactivate { - StakeAccount = 0, - Clock = 1, - } - - pub enum SetLockup { - StakeAccount = 0, - // Clock = 1, - } - - pub enum InitializeChecked { - StakeAccount = 0, - Rent = 1, - AuthorizedStaker = 2, - AuthorizedWithdrawer = 3, - } - - pub enum AuthorizeChecked { - StakeAccount = 0, - Clock = 1, - // CurrentAuthority = 2, - Authorized = 3, - Custodian = 4, - } - - pub enum AuthorizeCheckedWithSeed { - StakeAccount = 0, - AuthorityBase = 1, - Clock = 2, - Authorized = 3, - Custodian = 4, - } - - pub enum SetLockupChecked { - StakeAccount = 0, - // Clock = 1, - Custodian = 2, - } -} - pub fn process_instruction( first_instruction_account: usize, data: &[u8], invoke_context: &mut InvokeContext, ) -> Result<(), InstructionError> { - let transaction_context = &invoke_context.transaction_context; - let instruction_context = transaction_context.get_current_instruction_context()?; let keyed_accounts = invoke_context.get_keyed_accounts()?; trace!("process_instruction: {:?}", data); + trace!("keyed_accounts: {:?}", keyed_accounts); let me = &keyed_account_at_index(keyed_accounts, first_instruction_account)?; if me.owner()? != id() { return Err(InstructionError::InvalidAccountOwner); } - let signers = instruction_context.get_signers(transaction_context); + let signers = get_signers(&keyed_accounts[first_instruction_account..]); match limited_deserialize(data)? { StakeInstruction::Initialize(authorized, lockup) => { - let rent = get_sysvar_with_account_check2::rent( + let rent = get_sysvar_with_account_check::rent( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - instruction_account_indices::Initialize::Rent as usize, )?; me.initialize(&authorized, &lockup, &rent) } StakeInstruction::Authorize(authorized_pubkey, stake_authorize) => { - instruction_context.check_number_of_instruction_accounts(3)?; let require_custodian_for_locked_stake_authorize = invoke_context .feature_set .is_active(&feature_set::require_custodian_for_locked_stake_authorize::id()); if require_custodian_for_locked_stake_authorize { - let clock = get_sysvar_with_account_check2::clock( + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - instruction_account_indices::Authorize::Clock as usize, )?; - let custodian = keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::Authorize::Custodian as usize, - ) - .ok() - .map(|ka| ka.unsigned_key()); + let _current_authority = + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?; + let custodian = + keyed_account_at_index(keyed_accounts, first_instruction_account + 3) + .ok() + .map(|ka| ka.unsigned_key()); me.authorize( &signers, @@ -178,29 +84,21 @@ pub fn process_instruction( } } StakeInstruction::AuthorizeWithSeed(args) => { - instruction_context.check_number_of_instruction_accounts(2)?; - let authority_base = keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::AuthorizeWithSeed::AuthorityBase as usize, - )?; + let authority_base = + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; let require_custodian_for_locked_stake_authorize = invoke_context .feature_set .is_active(&feature_set::require_custodian_for_locked_stake_authorize::id()); if require_custodian_for_locked_stake_authorize { - let clock = get_sysvar_with_account_check2::clock( + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, - instruction_context, - instruction_account_indices::AuthorizeWithSeed::Clock as usize, )?; - let custodian = keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::AuthorizeWithSeed::Custodian as usize, - ) - .ok() - .map(|ka| ka.unsigned_key()); + let custodian = + keyed_account_at_index(keyed_accounts, first_instruction_account + 3) + .ok() + .map(|ka| ka.unsigned_key()); me.authorize_with_seed( authority_base, @@ -226,28 +124,17 @@ pub fn process_instruction( } } StakeInstruction::DelegateStake => { - instruction_context.check_number_of_instruction_accounts(2)?; - let vote = keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::DelegateStake::VoteAccount as usize, - )?; - let clock = get_sysvar_with_account_check2::clock( + let vote = keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, - instruction_context, - instruction_account_indices::DelegateStake::Clock as usize, )?; - let stake_history = get_sysvar_with_account_check2::stake_history( + let stake_history = get_sysvar_with_account_check::stake_history( + keyed_account_at_index(keyed_accounts, first_instruction_account + 3)?, invoke_context, - instruction_context, - instruction_account_indices::DelegateStake::StakeHistory as usize, - )?; - instruction_context.check_number_of_instruction_accounts(5)?; - let config_account = keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::DelegateStake::ConfigAccount as usize, )?; + let config_account = + keyed_account_at_index(keyed_accounts, first_instruction_account + 4)?; if !config::check_id(config_account.unsigned_key()) { return Err(InstructionError::InvalidArgument); } @@ -256,28 +143,20 @@ pub fn process_instruction( me.delegate(vote, &clock, &stake_history, &config, &signers) } StakeInstruction::Split(lamports) => { - instruction_context.check_number_of_instruction_accounts(2)?; - let split_stake = &keyed_account_at_index( - keyed_accounts, - first_instruction_account + instruction_account_indices::Split::SplitTo as usize, - )?; + let split_stake = + &keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; me.split(lamports, split_stake, &signers) } StakeInstruction::Merge => { - instruction_context.check_number_of_instruction_accounts(2)?; - let source_stake = &keyed_account_at_index( - keyed_accounts, - first_instruction_account + instruction_account_indices::Merge::MergeFrom as usize, - )?; - let clock = get_sysvar_with_account_check2::clock( + let source_stake = + &keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, - instruction_context, - instruction_account_indices::Merge::Clock as usize, )?; - let stake_history = get_sysvar_with_account_check2::stake_history( + let stake_history = get_sysvar_with_account_check::stake_history( + keyed_account_at_index(keyed_accounts, first_instruction_account + 3)?, invoke_context, - instruction_context, - instruction_account_indices::Merge::StakeHistory as usize, )?; me.merge( invoke_context, @@ -288,46 +167,28 @@ pub fn process_instruction( ) } StakeInstruction::Withdraw(lamports) => { - instruction_context.check_number_of_instruction_accounts(2)?; - let to = &keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::Withdraw::Recipient as usize, - )?; - let clock = get_sysvar_with_account_check2::clock( + let to = &keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, - instruction_context, - instruction_account_indices::Withdraw::Clock as usize, )?; - let stake_history = get_sysvar_with_account_check2::stake_history( + let stake_history = get_sysvar_with_account_check::stake_history( + keyed_account_at_index(keyed_accounts, first_instruction_account + 3)?, invoke_context, - instruction_context, - instruction_account_indices::Withdraw::StakeHistory as usize, )?; - instruction_context.check_number_of_instruction_accounts(5)?; me.withdraw( lamports, to, &clock, &stake_history, - keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::Withdraw::WithdrawAuthority as usize, - )?, - keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::Withdraw::Custodian as usize, - ) - .ok(), + keyed_account_at_index(keyed_accounts, first_instruction_account + 4)?, + keyed_account_at_index(keyed_accounts, first_instruction_account + 5).ok(), ) } StakeInstruction::Deactivate => { - let clock = get_sysvar_with_account_check2::clock( + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - instruction_account_indices::Deactivate::Clock as usize, )?; me.deactivate(&clock, &signers) } @@ -340,29 +201,20 @@ pub fn process_instruction( .feature_set .is_active(&feature_set::vote_stake_checked_instructions::id()) { - instruction_context.check_number_of_instruction_accounts(4)?; let authorized = Authorized { - staker: *keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::InitializeChecked::AuthorizedStaker - as usize, - )? - .unsigned_key(), + staker: *keyed_account_at_index(keyed_accounts, first_instruction_account + 2)? + .unsigned_key(), withdrawer: *keyed_account_at_index( keyed_accounts, - first_instruction_account - + instruction_account_indices::InitializeChecked::AuthorizedWithdrawer - as usize, + first_instruction_account + 3, )? .signer_key() .ok_or(InstructionError::MissingRequiredSignature)?, }; - let rent = get_sysvar_with_account_check2::rent( + let rent = get_sysvar_with_account_check::rent( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - instruction_account_indices::InitializeChecked::Rent as usize, )?; me.initialize(&authorized, &Lockup::default(), &rent) } else { @@ -374,26 +226,20 @@ pub fn process_instruction( .feature_set .is_active(&feature_set::vote_stake_checked_instructions::id()) { - let clock = get_sysvar_with_account_check2::clock( + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?, invoke_context, - instruction_context, - instruction_account_indices::AuthorizeChecked::Clock as usize, )?; - instruction_context.check_number_of_instruction_accounts(4)?; - let authorized_pubkey = &keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::AuthorizeChecked::Authorized as usize, - )? - .signer_key() - .ok_or(InstructionError::MissingRequiredSignature)?; - let custodian = keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::AuthorizeChecked::Custodian as usize, - ) - .ok() - .map(|ka| ka.unsigned_key()); + let _current_authority = + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?; + let authorized_pubkey = + &keyed_account_at_index(keyed_accounts, first_instruction_account + 3)? + .signer_key() + .ok_or(InstructionError::MissingRequiredSignature)?; + let custodian = + keyed_account_at_index(keyed_accounts, first_instruction_account + 4) + .ok() + .map(|ka| ka.unsigned_key()); me.authorize( &signers, @@ -412,34 +258,20 @@ pub fn process_instruction( .feature_set .is_active(&feature_set::vote_stake_checked_instructions::id()) { - instruction_context.check_number_of_instruction_accounts(2)?; - let authority_base = keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::AuthorizeCheckedWithSeed::AuthorityBase - as usize, - )?; - let clock = get_sysvar_with_account_check2::clock( + let authority_base = + keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?; + let clock = get_sysvar_with_account_check::clock( + keyed_account_at_index(keyed_accounts, first_instruction_account + 2)?, invoke_context, - instruction_context, - instruction_account_indices::AuthorizeCheckedWithSeed::Clock as usize, )?; - instruction_context.check_number_of_instruction_accounts(4)?; - let authorized_pubkey = &keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::AuthorizeCheckedWithSeed::Authorized - as usize, - )? - .signer_key() - .ok_or(InstructionError::MissingRequiredSignature)?; - let custodian = keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::AuthorizeCheckedWithSeed::Custodian as usize, - ) - .ok() - .map(|ka| ka.unsigned_key()); + let authorized_pubkey = + &keyed_account_at_index(keyed_accounts, first_instruction_account + 3)? + .signer_key() + .ok_or(InstructionError::MissingRequiredSignature)?; + let custodian = + keyed_account_at_index(keyed_accounts, first_instruction_account + 4) + .ok() + .map(|ka| ka.unsigned_key()); me.authorize_with_seed( authority_base, @@ -460,11 +292,9 @@ pub fn process_instruction( .feature_set .is_active(&feature_set::vote_stake_checked_instructions::id()) { - let custodian = if let Ok(custodian) = keyed_account_at_index( - keyed_accounts, - first_instruction_account - + instruction_account_indices::SetLockupChecked::Custodian as usize, - ) { + let custodian = if let Ok(custodian) = + keyed_account_at_index(keyed_accounts, first_instruction_account + 2) + { Some( *custodian .signer_key()