diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index ebe62b7265..0a30af23f5 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -36,8 +36,6 @@ 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}, @@ -48,7 +46,6 @@ use { reduce_required_deploy_balance, reject_callx_r10, requestable_heap_size, }, instruction::{AccountMeta, InstructionError}, - keyed_account::keyed_account_at_index, loader_instruction::LoaderInstruction, loader_upgradeable_instruction::UpgradeableLoaderInstruction, program_error::MAX_ACCOUNTS_DATA_SIZE_EXCEEDED, @@ -430,45 +427,50 @@ fn process_loader_upgradeable_instruction( let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_data = instruction_context.get_instruction_data(); let program_id = instruction_context.get_program_key(transaction_context)?; - let keyed_accounts = invoke_context.get_keyed_accounts()?; match limited_deserialize(instruction_data)? { UpgradeableLoaderInstruction::InitializeBuffer => { instruction_context.check_number_of_instruction_accounts(2)?; - let buffer = keyed_account_at_index(keyed_accounts, first_instruction_account)?; + let mut buffer = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - if UpgradeableLoaderState::Uninitialized != buffer.state()? { + if UpgradeableLoaderState::Uninitialized != buffer.get_state()? { ic_logger_msg!(log_collector, "Buffer account already initialized"); return Err(InstructionError::AccountAlreadyInitialized); } - let authority = keyed_account_at_index( - keyed_accounts, - first_instruction_account.saturating_add(1), - )?; + let authority_key = Some( + *transaction_context.get_key_of_account_at_index( + instruction_context + .get_index_in_transaction(first_instruction_account.saturating_add(1))?, + )?, + ); buffer.set_state(&UpgradeableLoaderState::Buffer { - authority_address: Some(*authority.unsigned_key()), + authority_address: authority_key, })?; } UpgradeableLoaderInstruction::Write { offset, bytes } => { instruction_context.check_number_of_instruction_accounts(2)?; - 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), - )?; + let buffer = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; - if let UpgradeableLoaderState::Buffer { authority_address } = buffer.state()? { + if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_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()) { + let authority_key = + Some(*transaction_context.get_key_of_account_at_index( + instruction_context.get_index_in_transaction( + first_instruction_account.saturating_add(1), + )?, + )?); + if authority_address != authority_key { ic_logger_msg!(log_collector, "Incorrect buffer authority provided"); return Err(InstructionError::IncorrectAuthority); } - if authority.signer_key().is_none() { + if !instruction_context.is_signer(first_instruction_account.saturating_add(1))? { ic_logger_msg!(log_collector, "Buffer authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -476,6 +478,7 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Invalid Buffer account"); return Err(InstructionError::InvalidAccountData); } + drop(buffer); write_program_data( first_instruction_account, UpgradeableLoaderState::buffer_data_offset()?.saturating_add(offset as usize), @@ -485,55 +488,53 @@ fn process_loader_upgradeable_instruction( } UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => { instruction_context.check_number_of_instruction_accounts(4)?; - 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 payer_key = *transaction_context.get_key_of_account_at_index( + instruction_context.get_index_in_transaction(first_instruction_account)?, )?; - 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 programdata_key = *transaction_context.get_key_of_account_at_index( + instruction_context + .get_index_in_transaction(first_instruction_account.saturating_add(1))?, )?; let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?; let clock = get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?; instruction_context.check_number_of_instruction_accounts(8)?; - let authority = 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(); + let authority_key = Some( + *transaction_context.get_key_of_account_at_index( + instruction_context + .get_index_in_transaction(first_instruction_account.saturating_add(7))?, + )?, + ); // Verify Program account - if UpgradeableLoaderState::Uninitialized != program.state()? { + let program = + instruction_context.try_borrow_instruction_account(transaction_context, 2)?; + if UpgradeableLoaderState::Uninitialized != program.get_state()? { ic_logger_msg!(log_collector, "Program account already initialized"); return Err(InstructionError::AccountAlreadyInitialized); } - if program.data_len()? < UpgradeableLoaderState::program_len()? { + if program.get_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()?) { + 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); } - - let new_program_id = *program.unsigned_key(); + let new_program_id = *program.get_key(); + drop(program); // Verify Buffer account - if let UpgradeableLoaderState::Buffer { authority_address } = buffer.state()? { - if authority_address != upgrade_authority_address { + let buffer = + instruction_context.try_borrow_instruction_account(transaction_context, 3)?; + if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? { + if authority_address != authority_key { ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match"); return Err(InstructionError::IncorrectAuthority); } - if upgrade_authority_signer { + if !instruction_context.is_signer(first_instruction_account.saturating_add(7))? { ic_logger_msg!(log_collector, "Upgrade authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -541,18 +542,19 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Invalid Buffer account"); return Err(InstructionError::InvalidArgument); } - + let buffer_key = *buffer.get_key(); + let buffer_lamports = buffer.get_lamports(); let buffer_data_offset = UpgradeableLoaderState::buffer_data_offset()?; - let buffer_data_len = buffer.data_len()?.saturating_sub(buffer_data_offset); + let buffer_data_len = buffer.get_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.data_len()? < UpgradeableLoaderState::buffer_data_offset()? + if buffer.get_data().len() < UpgradeableLoaderState::buffer_data_offset()? || buffer_data_len == 0 { ic_logger_msg!(log_collector, "Buffer account too small"); return Err(InstructionError::InvalidAccountData); } + drop(buffer); if max_data_len < buffer_data_len { ic_logger_msg!( log_collector, @@ -569,7 +571,7 @@ 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.unsigned_key() { + if derived_address != programdata_key { ic_logger_msg!(log_collector, "ProgramData address is not derived"); return Err(InstructionError::InvalidArgument); } @@ -579,15 +581,18 @@ fn process_loader_upgradeable_instruction( .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); + let mut payer = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + payer.checked_add_lamports(buffer_lamports)?; + drop(payer); + let mut buffer = + instruction_context.try_borrow_instruction_account(transaction_context, 3)?; + buffer.set_lamports(0); } let mut instruction = system_instruction::create_account( - payer.unsigned_key(), - programdata.unsigned_key(), + &payer_key, + &programdata_key, 1.max(rent.minimum_balance(programdata_len)), programdata_len as u64, program_id, @@ -596,7 +601,7 @@ fn process_loader_upgradeable_instruction( // pass an extra account to avoid the overly strict UnbalancedInstruction error instruction .accounts - .push(AccountMeta::new(*buffer.unsigned_key(), false)); + .push(AccountMeta::new(buffer_key, false)); let transaction_context = &invoke_context.transaction_context; let instruction_context = transaction_context.get_current_instruction_context()?; @@ -617,81 +622,76 @@ fn process_loader_upgradeable_instruction( )?; invoke_context.update_executor(&new_program_id, executor); - 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), - )?; + let transaction_context = &invoke_context.transaction_context; + let instruction_context = transaction_context.get_current_instruction_context()?; // Update the ProgramData account and record the program bits - 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)?, - ); + { + let mut programdata = + instruction_context.try_borrow_instruction_account(transaction_context, 1)?; + programdata.set_state(&UpgradeableLoaderState::ProgramData { + slot: clock.slot, + upgrade_authority_address: authority_key, + })?; + let dst_slice = programdata + .get_data_mut() + .get_mut( + programdata_data_offset + ..programdata_data_offset.saturating_add(buffer_data_len), + ) + .ok_or(InstructionError::AccountDataTooSmall)?; + let buffer = + instruction_context.try_borrow_instruction_account(transaction_context, 3)?; + let src_slice = buffer + .get_data() + .get(buffer_data_offset..) + .ok_or(InstructionError::AccountDataTooSmall)?; + dst_slice.copy_from_slice(src_slice); + } // Update the Program account + let mut program = + instruction_context.try_borrow_instruction_account(transaction_context, 2)?; program.set_state(&UpgradeableLoaderState::Program { - programdata_address: *programdata.unsigned_key(), + programdata_address: programdata_key, })?; - program.try_account_ref_mut()?.set_executable(true); + program.set_executable(true); + drop(program); if !predrain_buffer { // Drain the Buffer account back to the payer - payer - .try_account_ref_mut()? - .checked_add_lamports(buffer.lamports()?)?; - buffer.try_account_ref_mut()?.set_lamports(0); + let mut payer = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + payer.checked_add_lamports(buffer_lamports)?; + drop(payer); + let mut buffer = + instruction_context.try_borrow_instruction_account(transaction_context, 3)?; + buffer.set_lamports(0); } ic_logger_msg!(log_collector, "Deployed program {:?}", new_program_id); } UpgradeableLoaderInstruction::Upgrade => { instruction_context.check_number_of_instruction_accounts(3)?; - 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 buffer = keyed_account_at_index( - keyed_accounts, - first_instruction_account.saturating_add(2), + let programdata_key = *transaction_context.get_key_of_account_at_index( + instruction_context.get_index_in_transaction(first_instruction_account)?, )?; let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?; let clock = get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?; instruction_context.check_number_of_instruction_accounts(7)?; - let authority = keyed_account_at_index( - keyed_accounts, - first_instruction_account.saturating_add(6), - )?; + let authority_key = Some( + *transaction_context.get_key_of_account_at_index( + instruction_context + .get_index_in_transaction(first_instruction_account.saturating_add(6))?, + )?, + ); // Verify Program account - if !program.executable()? { + let program = + instruction_context.try_borrow_instruction_account(transaction_context, 1)?; + if !program.is_executable() { ic_logger_msg!(log_collector, "Program account not executable"); return Err(InstructionError::AccountNotExecutable); } @@ -699,15 +699,15 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Program account not writeable"); return Err(InstructionError::InvalidArgument); } - if &program.owner()? != program_id { + 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.state()? + } = program.get_state()? { - if programdata_address != *programdata.unsigned_key() { + if programdata_address != programdata_key { ic_logger_msg!(log_collector, "Program and ProgramData account mismatch"); return Err(InstructionError::InvalidArgument); } @@ -715,17 +715,19 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Invalid Program account"); return Err(InstructionError::InvalidAccountData); } - - let new_program_id = *program.unsigned_key(); + let new_program_id = *program.get_key(); + drop(program); // Verify Buffer account - if let UpgradeableLoaderState::Buffer { authority_address } = buffer.state()? { - if authority_address != Some(*authority.unsigned_key()) { + let buffer = + instruction_context.try_borrow_instruction_account(transaction_context, 2)?; + if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? { + if authority_address != authority_key { ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match"); return Err(InstructionError::IncorrectAuthority); } - if authority.signer_key().is_none() { + if !instruction_context.is_signer(first_instruction_account.saturating_add(6))? { ic_logger_msg!(log_collector, "Upgrade authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -733,26 +735,31 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Invalid Buffer account"); return Err(InstructionError::InvalidArgument); } - + let buffer_lamports = buffer.get_lamports(); let buffer_data_offset = UpgradeableLoaderState::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_balance_required = 1.max(rent.minimum_balance(programdata.data_len()?)); - - if buffer.data_len()? < UpgradeableLoaderState::buffer_data_offset()? + let buffer_data_len = buffer.get_data().len().saturating_sub(buffer_data_offset); + if buffer.get_data().len() < UpgradeableLoaderState::buffer_data_offset()? || buffer_data_len == 0 { ic_logger_msg!(log_collector, "Buffer account too small"); return Err(InstructionError::InvalidAccountData); } + drop(buffer); // Verify ProgramData account - if programdata.data_len()? < UpgradeableLoaderState::programdata_len(buffer_data_len)? { + let programdata = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + let programdata_data_offset = UpgradeableLoaderState::programdata_data_offset()?; + let programdata_balance_required = + 1.max(rent.minimum_balance(programdata.get_data().len())); + if programdata.get_data().len() + < UpgradeableLoaderState::programdata_len(buffer_data_len)? + { ic_logger_msg!(log_collector, "ProgramData account not large enough"); return Err(InstructionError::AccountDataTooSmall); } - if programdata.lamports()?.saturating_add(buffer.lamports()?) + if programdata.get_lamports().saturating_add(buffer_lamports) < programdata_balance_required { ic_logger_msg!( @@ -764,17 +771,17 @@ fn process_loader_upgradeable_instruction( if let UpgradeableLoaderState::ProgramData { slot: _, upgrade_authority_address, - } = programdata.state()? + } = programdata.get_state()? { if upgrade_authority_address.is_none() { ic_logger_msg!(log_collector, "Program not upgradeable"); return Err(InstructionError::Immutable); } - if upgrade_authority_address != Some(*authority.unsigned_key()) { + if upgrade_authority_address != authority_key { ic_logger_msg!(log_collector, "Incorrect upgrade authority provided"); return Err(InstructionError::IncorrectAuthority); } - if authority.signer_key().is_none() { + if !instruction_context.is_signer(first_instruction_account.saturating_add(6))? { ic_logger_msg!(log_collector, "Upgrade authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -782,6 +789,7 @@ 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( @@ -793,77 +801,76 @@ fn process_loader_upgradeable_instruction( )?; invoke_context.update_executor(&new_program_id, executor); - 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 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), - )?; + let transaction_context = &invoke_context.transaction_context; + let instruction_context = transaction_context.get_current_instruction_context()?; // Update the ProgramData account, record the upgraded data, and zero // the rest - programdata.set_state(&UpgradeableLoaderState::ProgramData { - slot: clock.slot, - upgrade_authority_address: Some(*authority.unsigned_key()), - })?; + let mut programdata = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + { + programdata.set_state(&UpgradeableLoaderState::ProgramData { + slot: clock.slot, + upgrade_authority_address: authority_key, + })?; + let dst_slice = programdata + .get_data_mut() + .get_mut( + programdata_data_offset + ..programdata_data_offset.saturating_add(buffer_data_len), + ) + .ok_or(InstructionError::AccountDataTooSmall)?; + let buffer = + instruction_context.try_borrow_instruction_account(transaction_context, 2)?; + let src_slice = buffer + .get_data() + .get(buffer_data_offset..) + .ok_or(InstructionError::AccountDataTooSmall)?; + dst_slice.copy_from_slice(src_slice); + } 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)?, - ); - programdata - .try_account_ref_mut()? - .data_as_mut_slice() + .get_data_mut() .get_mut(programdata_data_offset.saturating_add(buffer_data_len)..) .ok_or(InstructionError::AccountDataTooSmall)? .fill(0); // Fund ProgramData to rent-exemption, spill the rest - spill.try_account_ref_mut()?.checked_add_lamports( - programdata - .lamports()? - .saturating_add(buffer.lamports()?) + let programdata_lamports = programdata.get_lamports(); + programdata.set_lamports(programdata_balance_required); + drop(programdata); + + let mut buffer = + instruction_context.try_borrow_instruction_account(transaction_context, 2)?; + buffer.set_lamports(0); + drop(buffer); + + let mut spill = + instruction_context.try_borrow_instruction_account(transaction_context, 3)?; + spill.checked_add_lamports( + programdata_lamports + .saturating_add(buffer_lamports) .saturating_sub(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 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 mut account = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + let present_authority_key = transaction_context.get_key_of_account_at_index( + instruction_context + .get_index_in_transaction(first_instruction_account.saturating_add(1))?, )?; - let new_authority = - keyed_account_at_index(keyed_accounts, first_instruction_account.saturating_add(2)) - .ok() - .map(|account| account.unsigned_key()); + let new_authority = instruction_context + .get_index_in_transaction(first_instruction_account.saturating_add(2)) + .and_then(|index_in_transaction| { + transaction_context.get_key_of_account_at_index(index_in_transaction) + }) + .ok(); - match account.state()? { + match account.get_state()? { UpgradeableLoaderState::Buffer { authority_address } => { if new_authority.is_none() { ic_logger_msg!(log_collector, "Buffer authority is not optional"); @@ -873,11 +880,13 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Buffer is immutable"); return Err(InstructionError::Immutable); } - if authority_address != Some(*present_authority.unsigned_key()) { + if authority_address != Some(*present_authority_key) { ic_logger_msg!(log_collector, "Incorrect buffer authority provided"); return Err(InstructionError::IncorrectAuthority); } - if present_authority.signer_key().is_none() { + if !instruction_context + .is_signer(first_instruction_account.saturating_add(1))? + { ic_logger_msg!(log_collector, "Buffer authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -893,11 +902,13 @@ fn process_loader_upgradeable_instruction( ic_logger_msg!(log_collector, "Program not upgradeable"); return Err(InstructionError::Immutable); } - if upgrade_authority_address != Some(*present_authority.unsigned_key()) { + if upgrade_authority_address != Some(*present_authority_key) { ic_logger_msg!(log_collector, "Incorrect upgrade authority provided"); return Err(InstructionError::IncorrectAuthority); } - if present_authority.signer_key().is_none() { + if !instruction_context + .is_signer(first_instruction_account.saturating_add(1))? + { ic_logger_msg!(log_collector, "Upgrade authority did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -916,34 +927,33 @@ fn process_loader_upgradeable_instruction( } UpgradeableLoaderInstruction::Close => { instruction_context.check_number_of_instruction_accounts(2)?; - 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() { + if instruction_context.get_index_in_transaction(first_instruction_account)? + == instruction_context + .get_index_in_transaction(first_instruction_account.saturating_add(1))? + { ic_logger_msg!( log_collector, "Recipient is the same as the account being closed" ); return Err(InstructionError::InvalidArgument); } - - match close_account.state()? { + let mut close_account = + instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + let close_key = *close_account.get_key(); + match close_account.get_state()? { UpgradeableLoaderState::Uninitialized => { - recipient_account - .try_account_ref_mut()? - .checked_add_lamports(close_account.lamports()?)?; - close_account.try_account_ref_mut()?.set_lamports(0); + let close_lamports = close_account.get_lamports(); + close_account.set_lamports(0); + drop(close_account); + let mut recipient_account = instruction_context + .try_borrow_instruction_account(transaction_context, 1)?; + recipient_account.checked_add_lamports(close_lamports)?; - ic_logger_msg!( - log_collector, - "Closed Uninitialized {}", - close_account.unsigned_key() - ); + ic_logger_msg!(log_collector, "Closed Uninitialized {}", close_key); } UpgradeableLoaderState::Buffer { authority_address } => { instruction_context.check_number_of_instruction_accounts(3)?; + drop(close_account); common_close_account( &authority_address, transaction_context, @@ -951,36 +961,32 @@ fn process_loader_upgradeable_instruction( &log_collector, )?; - ic_logger_msg!( - log_collector, - "Closed Buffer {}", - close_account.unsigned_key() - ); + ic_logger_msg!(log_collector, "Closed Buffer {}", close_key); } UpgradeableLoaderState::ProgramData { slot: _, upgrade_authority_address: authority_address, } => { instruction_context.check_number_of_instruction_accounts(4)?; - let program_account = keyed_account_at_index( - keyed_accounts, - first_instruction_account.saturating_add(3), - )?; + drop(close_account); + let program_account = instruction_context + .try_borrow_instruction_account(transaction_context, 3)?; + let program_key = *program_account.get_key(); if !program_account.is_writable() { ic_logger_msg!(log_collector, "Program account is not writable"); return Err(InstructionError::InvalidArgument); } - if &program_account.owner()? != program_id { + if program_account.get_owner() != program_id { ic_logger_msg!(log_collector, "Program account not owned by loader"); return Err(InstructionError::IncorrectProgramId); } - match program_account.state()? { + match program_account.get_state()? { UpgradeableLoaderState::Program { programdata_address, } => { - if programdata_address != *close_account.unsigned_key() { + if programdata_address != close_key { ic_logger_msg!( log_collector, "ProgramData account does not match ProgramData account" @@ -988,6 +994,7 @@ fn process_loader_upgradeable_instruction( return Err(InstructionError::InvalidArgument); } + drop(program_account); common_close_account( &authority_address, transaction_context, @@ -1001,11 +1008,7 @@ fn process_loader_upgradeable_instruction( } } - ic_logger_msg!( - log_collector, - "Closed Program {}", - program_account.unsigned_key() - ); + ic_logger_msg!(log_collector, "Closed Program {}", program_key); } _ => { ic_logger_msg!(log_collector, "Account does not support closing"); @@ -1062,18 +1065,19 @@ fn process_loader_instruction( let instruction_context = transaction_context.get_current_instruction_context()?; let instruction_data = instruction_context.get_instruction_data(); let program_id = instruction_context.get_program_key(transaction_context)?; - let keyed_accounts = invoke_context.get_keyed_accounts()?; - let program = keyed_account_at_index(keyed_accounts, first_instruction_account)?; - if program.owner()? != *program_id { + let program = instruction_context.try_borrow_instruction_account(transaction_context, 0)?; + if program.get_owner() != program_id { ic_msg!( invoke_context, "Executable account not owned by the BPF loader" ); return Err(InstructionError::IncorrectProgramId); } + let is_program_signer = program.is_signer(); + drop(program); match limited_deserialize(instruction_data)? { LoaderInstruction::Write { offset, bytes } => { - if program.signer_key().is_none() { + if !is_program_signer { ic_msg!(invoke_context, "Program account did not sign"); return Err(InstructionError::MissingRequiredSignature); } @@ -1085,22 +1089,19 @@ fn process_loader_instruction( )?; } LoaderInstruction::Finalize => { - if program.signer_key().is_none() { + if !is_program_signer { 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 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() - ); + 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, 0)?; + invoke_context.update_executor(program.get_key(), executor); + program.set_executable(true); + ic_msg!(invoke_context, "Finalized account {:?}", program.get_key()); } } @@ -1281,6 +1282,7 @@ mod tests { solana_sdk::{ account::{ create_account_shared_data_for_test as create_account_for_test, AccountSharedData, + ReadableAccount, WritableAccount, }, account_utils::StateMut, client::SyncClient,