Remove `KeyedAccount` in builtin program "BPF loader" (#24381)
* Uses transaction_context.get_key_of_account_at_index() when only the key is needed. * Uses "!instruction_context.is_signer()" instead of ".signer_key().is_none()". * Uses instruction_context.get_index_in_transaction() to detect account aliasing. * Makes sure that there is only one KeyedAccount at a time. Everywhere except for DeployWithMaxDataLen and Upgrade. * Makes sure that there is only one KeyedAccount at a time. In DeployWithMaxDataLen and Upgrade. * Replaces KeyedAccount by BorrowedAccount. * Removes unused code.
This commit is contained in:
parent
697c9e1969
commit
998cdd1c29
|
@ -36,8 +36,6 @@ use {
|
||||||
vm::{Config, EbpfVm, InstructionMeter},
|
vm::{Config, EbpfVm, InstructionMeter},
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{ReadableAccount, WritableAccount},
|
|
||||||
account_utils::State,
|
|
||||||
bpf_loader, bpf_loader_deprecated,
|
bpf_loader, bpf_loader_deprecated,
|
||||||
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
||||||
entrypoint::{HEAP_LENGTH, SUCCESS},
|
entrypoint::{HEAP_LENGTH, SUCCESS},
|
||||||
|
@ -48,7 +46,6 @@ use {
|
||||||
reduce_required_deploy_balance, reject_callx_r10, requestable_heap_size,
|
reduce_required_deploy_balance, reject_callx_r10, requestable_heap_size,
|
||||||
},
|
},
|
||||||
instruction::{AccountMeta, InstructionError},
|
instruction::{AccountMeta, InstructionError},
|
||||||
keyed_account::keyed_account_at_index,
|
|
||||||
loader_instruction::LoaderInstruction,
|
loader_instruction::LoaderInstruction,
|
||||||
loader_upgradeable_instruction::UpgradeableLoaderInstruction,
|
loader_upgradeable_instruction::UpgradeableLoaderInstruction,
|
||||||
program_error::MAX_ACCOUNTS_DATA_SIZE_EXCEEDED,
|
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_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
let program_id = instruction_context.get_program_key(transaction_context)?;
|
let program_id = instruction_context.get_program_key(transaction_context)?;
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
|
||||||
|
|
||||||
match limited_deserialize(instruction_data)? {
|
match limited_deserialize(instruction_data)? {
|
||||||
UpgradeableLoaderInstruction::InitializeBuffer => {
|
UpgradeableLoaderInstruction::InitializeBuffer => {
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
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");
|
ic_logger_msg!(log_collector, "Buffer account already initialized");
|
||||||
return Err(InstructionError::AccountAlreadyInitialized);
|
return Err(InstructionError::AccountAlreadyInitialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
let authority = keyed_account_at_index(
|
let authority_key = Some(
|
||||||
keyed_accounts,
|
*transaction_context.get_key_of_account_at_index(
|
||||||
first_instruction_account.saturating_add(1),
|
instruction_context
|
||||||
)?;
|
.get_index_in_transaction(first_instruction_account.saturating_add(1))?,
|
||||||
|
)?,
|
||||||
|
);
|
||||||
|
|
||||||
buffer.set_state(&UpgradeableLoaderState::Buffer {
|
buffer.set_state(&UpgradeableLoaderState::Buffer {
|
||||||
authority_address: Some(*authority.unsigned_key()),
|
authority_address: authority_key,
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
UpgradeableLoaderInstruction::Write { offset, bytes } => {
|
UpgradeableLoaderInstruction::Write { offset, bytes } => {
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
let buffer = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
let buffer =
|
||||||
let authority = keyed_account_at_index(
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
keyed_accounts,
|
|
||||||
first_instruction_account.saturating_add(1),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer.state()? {
|
if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
|
||||||
if authority_address.is_none() {
|
if authority_address.is_none() {
|
||||||
ic_logger_msg!(log_collector, "Buffer is immutable");
|
ic_logger_msg!(log_collector, "Buffer is immutable");
|
||||||
return Err(InstructionError::Immutable); // TODO better error code
|
return Err(InstructionError::Immutable); // TODO better error code
|
||||||
}
|
}
|
||||||
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");
|
ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
|
||||||
return Err(InstructionError::IncorrectAuthority);
|
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");
|
ic_logger_msg!(log_collector, "Buffer authority did not sign");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
@ -476,6 +478,7 @@ fn process_loader_upgradeable_instruction(
|
||||||
ic_logger_msg!(log_collector, "Invalid Buffer account");
|
ic_logger_msg!(log_collector, "Invalid Buffer account");
|
||||||
return Err(InstructionError::InvalidAccountData);
|
return Err(InstructionError::InvalidAccountData);
|
||||||
}
|
}
|
||||||
|
drop(buffer);
|
||||||
write_program_data(
|
write_program_data(
|
||||||
first_instruction_account,
|
first_instruction_account,
|
||||||
UpgradeableLoaderState::buffer_data_offset()?.saturating_add(offset as usize),
|
UpgradeableLoaderState::buffer_data_offset()?.saturating_add(offset as usize),
|
||||||
|
@ -485,55 +488,53 @@ fn process_loader_upgradeable_instruction(
|
||||||
}
|
}
|
||||||
UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => {
|
UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => {
|
||||||
instruction_context.check_number_of_instruction_accounts(4)?;
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
||||||
let payer = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
let payer_key = *transaction_context.get_key_of_account_at_index(
|
||||||
let programdata = keyed_account_at_index(
|
instruction_context.get_index_in_transaction(first_instruction_account)?,
|
||||||
keyed_accounts,
|
|
||||||
first_instruction_account.saturating_add(1),
|
|
||||||
)?;
|
)?;
|
||||||
let program = keyed_account_at_index(
|
let programdata_key = *transaction_context.get_key_of_account_at_index(
|
||||||
keyed_accounts,
|
instruction_context
|
||||||
first_instruction_account.saturating_add(2),
|
.get_index_in_transaction(first_instruction_account.saturating_add(1))?,
|
||||||
)?;
|
|
||||||
let buffer = keyed_account_at_index(
|
|
||||||
keyed_accounts,
|
|
||||||
first_instruction_account.saturating_add(3),
|
|
||||||
)?;
|
)?;
|
||||||
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
|
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
|
||||||
let clock =
|
let clock =
|
||||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
|
||||||
instruction_context.check_number_of_instruction_accounts(8)?;
|
instruction_context.check_number_of_instruction_accounts(8)?;
|
||||||
let authority = keyed_account_at_index(
|
let authority_key = Some(
|
||||||
keyed_accounts,
|
*transaction_context.get_key_of_account_at_index(
|
||||||
first_instruction_account.saturating_add(7),
|
instruction_context
|
||||||
)?;
|
.get_index_in_transaction(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
|
// 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");
|
ic_logger_msg!(log_collector, "Program account already initialized");
|
||||||
return Err(InstructionError::AccountAlreadyInitialized);
|
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");
|
ic_logger_msg!(log_collector, "Program account too small");
|
||||||
return Err(InstructionError::AccountDataTooSmall);
|
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");
|
ic_logger_msg!(log_collector, "Program account not rent-exempt");
|
||||||
return Err(InstructionError::ExecutableAccountNotRentExempt);
|
return Err(InstructionError::ExecutableAccountNotRentExempt);
|
||||||
}
|
}
|
||||||
|
let new_program_id = *program.get_key();
|
||||||
let new_program_id = *program.unsigned_key();
|
drop(program);
|
||||||
|
|
||||||
// Verify Buffer account
|
// Verify Buffer account
|
||||||
|
|
||||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer.state()? {
|
let buffer =
|
||||||
if authority_address != upgrade_authority_address {
|
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");
|
ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
|
||||||
return Err(InstructionError::IncorrectAuthority);
|
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");
|
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
@ -541,18 +542,19 @@ fn process_loader_upgradeable_instruction(
|
||||||
ic_logger_msg!(log_collector, "Invalid Buffer account");
|
ic_logger_msg!(log_collector, "Invalid Buffer account");
|
||||||
return Err(InstructionError::InvalidArgument);
|
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_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_data_offset = UpgradeableLoaderState::programdata_data_offset()?;
|
||||||
let programdata_len = UpgradeableLoaderState::programdata_len(max_data_len)?;
|
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
|
|| buffer_data_len == 0
|
||||||
{
|
{
|
||||||
ic_logger_msg!(log_collector, "Buffer account too small");
|
ic_logger_msg!(log_collector, "Buffer account too small");
|
||||||
return Err(InstructionError::InvalidAccountData);
|
return Err(InstructionError::InvalidAccountData);
|
||||||
}
|
}
|
||||||
|
drop(buffer);
|
||||||
if max_data_len < buffer_data_len {
|
if max_data_len < buffer_data_len {
|
||||||
ic_logger_msg!(
|
ic_logger_msg!(
|
||||||
log_collector,
|
log_collector,
|
||||||
|
@ -569,7 +571,7 @@ fn process_loader_upgradeable_instruction(
|
||||||
|
|
||||||
let (derived_address, bump_seed) =
|
let (derived_address, bump_seed) =
|
||||||
Pubkey::find_program_address(&[new_program_id.as_ref()], program_id);
|
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");
|
ic_logger_msg!(log_collector, "ProgramData address is not derived");
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(InstructionError::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
@ -579,15 +581,18 @@ fn process_loader_upgradeable_instruction(
|
||||||
.is_active(&reduce_required_deploy_balance::id());
|
.is_active(&reduce_required_deploy_balance::id());
|
||||||
if predrain_buffer {
|
if predrain_buffer {
|
||||||
// Drain the Buffer account to payer before paying for programdata account
|
// Drain the Buffer account to payer before paying for programdata account
|
||||||
payer
|
let mut payer =
|
||||||
.try_account_ref_mut()?
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
.checked_add_lamports(buffer.lamports()?)?;
|
payer.checked_add_lamports(buffer_lamports)?;
|
||||||
buffer.try_account_ref_mut()?.set_lamports(0);
|
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(
|
let mut instruction = system_instruction::create_account(
|
||||||
payer.unsigned_key(),
|
&payer_key,
|
||||||
programdata.unsigned_key(),
|
&programdata_key,
|
||||||
1.max(rent.minimum_balance(programdata_len)),
|
1.max(rent.minimum_balance(programdata_len)),
|
||||||
programdata_len as u64,
|
programdata_len as u64,
|
||||||
program_id,
|
program_id,
|
||||||
|
@ -596,7 +601,7 @@ fn process_loader_upgradeable_instruction(
|
||||||
// pass an extra account to avoid the overly strict UnbalancedInstruction error
|
// pass an extra account to avoid the overly strict UnbalancedInstruction error
|
||||||
instruction
|
instruction
|
||||||
.accounts
|
.accounts
|
||||||
.push(AccountMeta::new(*buffer.unsigned_key(), false));
|
.push(AccountMeta::new(buffer_key, false));
|
||||||
|
|
||||||
let transaction_context = &invoke_context.transaction_context;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let instruction_context = transaction_context.get_current_instruction_context()?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
|
@ -617,81 +622,76 @@ fn process_loader_upgradeable_instruction(
|
||||||
)?;
|
)?;
|
||||||
invoke_context.update_executor(&new_program_id, executor);
|
invoke_context.update_executor(&new_program_id, executor);
|
||||||
|
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let payer = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
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
|
// Update the ProgramData account and record the program bits
|
||||||
|
{
|
||||||
|
let mut programdata =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
|
||||||
programdata.set_state(&UpgradeableLoaderState::ProgramData {
|
programdata.set_state(&UpgradeableLoaderState::ProgramData {
|
||||||
slot: clock.slot,
|
slot: clock.slot,
|
||||||
upgrade_authority_address,
|
upgrade_authority_address: authority_key,
|
||||||
})?;
|
})?;
|
||||||
programdata
|
let dst_slice = programdata
|
||||||
.try_account_ref_mut()?
|
.get_data_mut()
|
||||||
.data_as_mut_slice()
|
|
||||||
.get_mut(
|
.get_mut(
|
||||||
programdata_data_offset
|
programdata_data_offset
|
||||||
..programdata_data_offset.saturating_add(buffer_data_len),
|
..programdata_data_offset.saturating_add(buffer_data_len),
|
||||||
)
|
)
|
||||||
.ok_or(InstructionError::AccountDataTooSmall)?
|
.ok_or(InstructionError::AccountDataTooSmall)?;
|
||||||
.copy_from_slice(
|
let buffer =
|
||||||
buffer
|
instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
|
||||||
.try_account_ref()?
|
let src_slice = buffer
|
||||||
.data()
|
.get_data()
|
||||||
.get(buffer_data_offset..)
|
.get(buffer_data_offset..)
|
||||||
.ok_or(InstructionError::AccountDataTooSmall)?,
|
.ok_or(InstructionError::AccountDataTooSmall)?;
|
||||||
);
|
dst_slice.copy_from_slice(src_slice);
|
||||||
|
}
|
||||||
|
|
||||||
// Update the Program account
|
// Update the Program account
|
||||||
|
let mut program =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
|
||||||
program.set_state(&UpgradeableLoaderState::Program {
|
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 {
|
if !predrain_buffer {
|
||||||
// Drain the Buffer account back to the payer
|
// Drain the Buffer account back to the payer
|
||||||
payer
|
let mut payer =
|
||||||
.try_account_ref_mut()?
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
.checked_add_lamports(buffer.lamports()?)?;
|
payer.checked_add_lamports(buffer_lamports)?;
|
||||||
buffer.try_account_ref_mut()?.set_lamports(0);
|
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);
|
ic_logger_msg!(log_collector, "Deployed program {:?}", new_program_id);
|
||||||
}
|
}
|
||||||
UpgradeableLoaderInstruction::Upgrade => {
|
UpgradeableLoaderInstruction::Upgrade => {
|
||||||
instruction_context.check_number_of_instruction_accounts(3)?;
|
instruction_context.check_number_of_instruction_accounts(3)?;
|
||||||
let programdata = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
let programdata_key = *transaction_context.get_key_of_account_at_index(
|
||||||
let program = keyed_account_at_index(
|
instruction_context.get_index_in_transaction(first_instruction_account)?,
|
||||||
keyed_accounts,
|
|
||||||
first_instruction_account.saturating_add(1),
|
|
||||||
)?;
|
|
||||||
let buffer = keyed_account_at_index(
|
|
||||||
keyed_accounts,
|
|
||||||
first_instruction_account.saturating_add(2),
|
|
||||||
)?;
|
)?;
|
||||||
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
|
let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
|
||||||
let clock =
|
let clock =
|
||||||
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
|
get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
|
||||||
instruction_context.check_number_of_instruction_accounts(7)?;
|
instruction_context.check_number_of_instruction_accounts(7)?;
|
||||||
let authority = keyed_account_at_index(
|
let authority_key = Some(
|
||||||
keyed_accounts,
|
*transaction_context.get_key_of_account_at_index(
|
||||||
first_instruction_account.saturating_add(6),
|
instruction_context
|
||||||
)?;
|
.get_index_in_transaction(first_instruction_account.saturating_add(6))?,
|
||||||
|
)?,
|
||||||
|
);
|
||||||
|
|
||||||
// Verify Program account
|
// 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");
|
ic_logger_msg!(log_collector, "Program account not executable");
|
||||||
return Err(InstructionError::AccountNotExecutable);
|
return Err(InstructionError::AccountNotExecutable);
|
||||||
}
|
}
|
||||||
|
@ -699,15 +699,15 @@ fn process_loader_upgradeable_instruction(
|
||||||
ic_logger_msg!(log_collector, "Program account not writeable");
|
ic_logger_msg!(log_collector, "Program account not writeable");
|
||||||
return Err(InstructionError::InvalidArgument);
|
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");
|
ic_logger_msg!(log_collector, "Program account not owned by loader");
|
||||||
return Err(InstructionError::IncorrectProgramId);
|
return Err(InstructionError::IncorrectProgramId);
|
||||||
}
|
}
|
||||||
if let UpgradeableLoaderState::Program {
|
if let UpgradeableLoaderState::Program {
|
||||||
programdata_address,
|
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");
|
ic_logger_msg!(log_collector, "Program and ProgramData account mismatch");
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(InstructionError::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
@ -715,17 +715,19 @@ fn process_loader_upgradeable_instruction(
|
||||||
ic_logger_msg!(log_collector, "Invalid Program account");
|
ic_logger_msg!(log_collector, "Invalid Program account");
|
||||||
return Err(InstructionError::InvalidAccountData);
|
return Err(InstructionError::InvalidAccountData);
|
||||||
}
|
}
|
||||||
|
let new_program_id = *program.get_key();
|
||||||
let new_program_id = *program.unsigned_key();
|
drop(program);
|
||||||
|
|
||||||
// Verify Buffer account
|
// Verify Buffer account
|
||||||
|
|
||||||
if let UpgradeableLoaderState::Buffer { authority_address } = buffer.state()? {
|
let buffer =
|
||||||
if authority_address != Some(*authority.unsigned_key()) {
|
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");
|
ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
|
||||||
return Err(InstructionError::IncorrectAuthority);
|
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");
|
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
@ -733,26 +735,31 @@ fn process_loader_upgradeable_instruction(
|
||||||
ic_logger_msg!(log_collector, "Invalid Buffer account");
|
ic_logger_msg!(log_collector, "Invalid Buffer account");
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(InstructionError::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
let buffer_lamports = buffer.get_lamports();
|
||||||
let buffer_data_offset = UpgradeableLoaderState::buffer_data_offset()?;
|
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()?;
|
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
|
|| buffer_data_len == 0
|
||||||
{
|
{
|
||||||
ic_logger_msg!(log_collector, "Buffer account too small");
|
ic_logger_msg!(log_collector, "Buffer account too small");
|
||||||
return Err(InstructionError::InvalidAccountData);
|
return Err(InstructionError::InvalidAccountData);
|
||||||
}
|
}
|
||||||
|
drop(buffer);
|
||||||
|
|
||||||
// Verify ProgramData account
|
// 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");
|
ic_logger_msg!(log_collector, "ProgramData account not large enough");
|
||||||
return Err(InstructionError::AccountDataTooSmall);
|
return Err(InstructionError::AccountDataTooSmall);
|
||||||
}
|
}
|
||||||
if programdata.lamports()?.saturating_add(buffer.lamports()?)
|
if programdata.get_lamports().saturating_add(buffer_lamports)
|
||||||
< programdata_balance_required
|
< programdata_balance_required
|
||||||
{
|
{
|
||||||
ic_logger_msg!(
|
ic_logger_msg!(
|
||||||
|
@ -764,17 +771,17 @@ fn process_loader_upgradeable_instruction(
|
||||||
if let UpgradeableLoaderState::ProgramData {
|
if let UpgradeableLoaderState::ProgramData {
|
||||||
slot: _,
|
slot: _,
|
||||||
upgrade_authority_address,
|
upgrade_authority_address,
|
||||||
} = programdata.state()?
|
} = programdata.get_state()?
|
||||||
{
|
{
|
||||||
if upgrade_authority_address.is_none() {
|
if upgrade_authority_address.is_none() {
|
||||||
ic_logger_msg!(log_collector, "Program not upgradeable");
|
ic_logger_msg!(log_collector, "Program not upgradeable");
|
||||||
return Err(InstructionError::Immutable);
|
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");
|
ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
|
||||||
return Err(InstructionError::IncorrectAuthority);
|
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");
|
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
@ -782,6 +789,7 @@ fn process_loader_upgradeable_instruction(
|
||||||
ic_logger_msg!(log_collector, "Invalid ProgramData account");
|
ic_logger_msg!(log_collector, "Invalid ProgramData account");
|
||||||
return Err(InstructionError::InvalidAccountData);
|
return Err(InstructionError::InvalidAccountData);
|
||||||
}
|
}
|
||||||
|
drop(programdata);
|
||||||
|
|
||||||
// Load and verify the program bits
|
// Load and verify the program bits
|
||||||
let executor = create_executor(
|
let executor = create_executor(
|
||||||
|
@ -793,77 +801,76 @@ fn process_loader_upgradeable_instruction(
|
||||||
)?;
|
)?;
|
||||||
invoke_context.update_executor(&new_program_id, executor);
|
invoke_context.update_executor(&new_program_id, executor);
|
||||||
|
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let programdata = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
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),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Update the ProgramData account, record the upgraded data, and zero
|
// Update the ProgramData account, record the upgraded data, and zero
|
||||||
// the rest
|
// the rest
|
||||||
|
let mut programdata =
|
||||||
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
|
{
|
||||||
programdata.set_state(&UpgradeableLoaderState::ProgramData {
|
programdata.set_state(&UpgradeableLoaderState::ProgramData {
|
||||||
slot: clock.slot,
|
slot: clock.slot,
|
||||||
upgrade_authority_address: Some(*authority.unsigned_key()),
|
upgrade_authority_address: authority_key,
|
||||||
})?;
|
})?;
|
||||||
programdata
|
let dst_slice = programdata
|
||||||
.try_account_ref_mut()?
|
.get_data_mut()
|
||||||
.data_as_mut_slice()
|
|
||||||
.get_mut(
|
.get_mut(
|
||||||
programdata_data_offset
|
programdata_data_offset
|
||||||
..programdata_data_offset.saturating_add(buffer_data_len),
|
..programdata_data_offset.saturating_add(buffer_data_len),
|
||||||
)
|
)
|
||||||
.ok_or(InstructionError::AccountDataTooSmall)?
|
.ok_or(InstructionError::AccountDataTooSmall)?;
|
||||||
.copy_from_slice(
|
let buffer =
|
||||||
buffer
|
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
|
||||||
.try_account_ref()?
|
let src_slice = buffer
|
||||||
.data()
|
.get_data()
|
||||||
.get(buffer_data_offset..)
|
.get(buffer_data_offset..)
|
||||||
.ok_or(InstructionError::AccountDataTooSmall)?,
|
.ok_or(InstructionError::AccountDataTooSmall)?;
|
||||||
);
|
dst_slice.copy_from_slice(src_slice);
|
||||||
|
}
|
||||||
programdata
|
programdata
|
||||||
.try_account_ref_mut()?
|
.get_data_mut()
|
||||||
.data_as_mut_slice()
|
|
||||||
.get_mut(programdata_data_offset.saturating_add(buffer_data_len)..)
|
.get_mut(programdata_data_offset.saturating_add(buffer_data_len)..)
|
||||||
.ok_or(InstructionError::AccountDataTooSmall)?
|
.ok_or(InstructionError::AccountDataTooSmall)?
|
||||||
.fill(0);
|
.fill(0);
|
||||||
|
|
||||||
// Fund ProgramData to rent-exemption, spill the rest
|
// Fund ProgramData to rent-exemption, spill the rest
|
||||||
|
|
||||||
spill.try_account_ref_mut()?.checked_add_lamports(
|
let programdata_lamports = programdata.get_lamports();
|
||||||
programdata
|
programdata.set_lamports(programdata_balance_required);
|
||||||
.lamports()?
|
drop(programdata);
|
||||||
.saturating_add(buffer.lamports()?)
|
|
||||||
|
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),
|
.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);
|
ic_logger_msg!(log_collector, "Upgraded program {:?}", new_program_id);
|
||||||
}
|
}
|
||||||
UpgradeableLoaderInstruction::SetAuthority => {
|
UpgradeableLoaderInstruction::SetAuthority => {
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
let account = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
let mut account =
|
||||||
let present_authority = keyed_account_at_index(
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
keyed_accounts,
|
let present_authority_key = transaction_context.get_key_of_account_at_index(
|
||||||
first_instruction_account.saturating_add(1),
|
instruction_context
|
||||||
|
.get_index_in_transaction(first_instruction_account.saturating_add(1))?,
|
||||||
)?;
|
)?;
|
||||||
let new_authority =
|
let new_authority = instruction_context
|
||||||
keyed_account_at_index(keyed_accounts, first_instruction_account.saturating_add(2))
|
.get_index_in_transaction(first_instruction_account.saturating_add(2))
|
||||||
.ok()
|
.and_then(|index_in_transaction| {
|
||||||
.map(|account| account.unsigned_key());
|
transaction_context.get_key_of_account_at_index(index_in_transaction)
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
match account.state()? {
|
match account.get_state()? {
|
||||||
UpgradeableLoaderState::Buffer { authority_address } => {
|
UpgradeableLoaderState::Buffer { authority_address } => {
|
||||||
if new_authority.is_none() {
|
if new_authority.is_none() {
|
||||||
ic_logger_msg!(log_collector, "Buffer authority is not optional");
|
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");
|
ic_logger_msg!(log_collector, "Buffer is immutable");
|
||||||
return Err(InstructionError::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");
|
ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
|
||||||
return Err(InstructionError::IncorrectAuthority);
|
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");
|
ic_logger_msg!(log_collector, "Buffer authority did not sign");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
@ -893,11 +902,13 @@ fn process_loader_upgradeable_instruction(
|
||||||
ic_logger_msg!(log_collector, "Program not upgradeable");
|
ic_logger_msg!(log_collector, "Program not upgradeable");
|
||||||
return Err(InstructionError::Immutable);
|
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");
|
ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
|
||||||
return Err(InstructionError::IncorrectAuthority);
|
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");
|
ic_logger_msg!(log_collector, "Upgrade authority did not sign");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
@ -916,34 +927,33 @@ fn process_loader_upgradeable_instruction(
|
||||||
}
|
}
|
||||||
UpgradeableLoaderInstruction::Close => {
|
UpgradeableLoaderInstruction::Close => {
|
||||||
instruction_context.check_number_of_instruction_accounts(2)?;
|
instruction_context.check_number_of_instruction_accounts(2)?;
|
||||||
let close_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
if instruction_context.get_index_in_transaction(first_instruction_account)?
|
||||||
let recipient_account = keyed_account_at_index(
|
== instruction_context
|
||||||
keyed_accounts,
|
.get_index_in_transaction(first_instruction_account.saturating_add(1))?
|
||||||
first_instruction_account.saturating_add(1),
|
{
|
||||||
)?;
|
|
||||||
if close_account.unsigned_key() == recipient_account.unsigned_key() {
|
|
||||||
ic_logger_msg!(
|
ic_logger_msg!(
|
||||||
log_collector,
|
log_collector,
|
||||||
"Recipient is the same as the account being closed"
|
"Recipient is the same as the account being closed"
|
||||||
);
|
);
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(InstructionError::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
let mut close_account =
|
||||||
match close_account.state()? {
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
|
let close_key = *close_account.get_key();
|
||||||
|
match close_account.get_state()? {
|
||||||
UpgradeableLoaderState::Uninitialized => {
|
UpgradeableLoaderState::Uninitialized => {
|
||||||
recipient_account
|
let close_lamports = close_account.get_lamports();
|
||||||
.try_account_ref_mut()?
|
close_account.set_lamports(0);
|
||||||
.checked_add_lamports(close_account.lamports()?)?;
|
drop(close_account);
|
||||||
close_account.try_account_ref_mut()?.set_lamports(0);
|
let mut recipient_account = instruction_context
|
||||||
|
.try_borrow_instruction_account(transaction_context, 1)?;
|
||||||
|
recipient_account.checked_add_lamports(close_lamports)?;
|
||||||
|
|
||||||
ic_logger_msg!(
|
ic_logger_msg!(log_collector, "Closed Uninitialized {}", close_key);
|
||||||
log_collector,
|
|
||||||
"Closed Uninitialized {}",
|
|
||||||
close_account.unsigned_key()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
UpgradeableLoaderState::Buffer { authority_address } => {
|
UpgradeableLoaderState::Buffer { authority_address } => {
|
||||||
instruction_context.check_number_of_instruction_accounts(3)?;
|
instruction_context.check_number_of_instruction_accounts(3)?;
|
||||||
|
drop(close_account);
|
||||||
common_close_account(
|
common_close_account(
|
||||||
&authority_address,
|
&authority_address,
|
||||||
transaction_context,
|
transaction_context,
|
||||||
|
@ -951,36 +961,32 @@ fn process_loader_upgradeable_instruction(
|
||||||
&log_collector,
|
&log_collector,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
ic_logger_msg!(
|
ic_logger_msg!(log_collector, "Closed Buffer {}", close_key);
|
||||||
log_collector,
|
|
||||||
"Closed Buffer {}",
|
|
||||||
close_account.unsigned_key()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
UpgradeableLoaderState::ProgramData {
|
UpgradeableLoaderState::ProgramData {
|
||||||
slot: _,
|
slot: _,
|
||||||
upgrade_authority_address: authority_address,
|
upgrade_authority_address: authority_address,
|
||||||
} => {
|
} => {
|
||||||
instruction_context.check_number_of_instruction_accounts(4)?;
|
instruction_context.check_number_of_instruction_accounts(4)?;
|
||||||
let program_account = keyed_account_at_index(
|
drop(close_account);
|
||||||
keyed_accounts,
|
let program_account = instruction_context
|
||||||
first_instruction_account.saturating_add(3),
|
.try_borrow_instruction_account(transaction_context, 3)?;
|
||||||
)?;
|
let program_key = *program_account.get_key();
|
||||||
|
|
||||||
if !program_account.is_writable() {
|
if !program_account.is_writable() {
|
||||||
ic_logger_msg!(log_collector, "Program account is not writable");
|
ic_logger_msg!(log_collector, "Program account is not writable");
|
||||||
return Err(InstructionError::InvalidArgument);
|
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");
|
ic_logger_msg!(log_collector, "Program account not owned by loader");
|
||||||
return Err(InstructionError::IncorrectProgramId);
|
return Err(InstructionError::IncorrectProgramId);
|
||||||
}
|
}
|
||||||
|
|
||||||
match program_account.state()? {
|
match program_account.get_state()? {
|
||||||
UpgradeableLoaderState::Program {
|
UpgradeableLoaderState::Program {
|
||||||
programdata_address,
|
programdata_address,
|
||||||
} => {
|
} => {
|
||||||
if programdata_address != *close_account.unsigned_key() {
|
if programdata_address != close_key {
|
||||||
ic_logger_msg!(
|
ic_logger_msg!(
|
||||||
log_collector,
|
log_collector,
|
||||||
"ProgramData account does not match ProgramData account"
|
"ProgramData account does not match ProgramData account"
|
||||||
|
@ -988,6 +994,7 @@ fn process_loader_upgradeable_instruction(
|
||||||
return Err(InstructionError::InvalidArgument);
|
return Err(InstructionError::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drop(program_account);
|
||||||
common_close_account(
|
common_close_account(
|
||||||
&authority_address,
|
&authority_address,
|
||||||
transaction_context,
|
transaction_context,
|
||||||
|
@ -1001,11 +1008,7 @@ fn process_loader_upgradeable_instruction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ic_logger_msg!(
|
ic_logger_msg!(log_collector, "Closed Program {}", program_key);
|
||||||
log_collector,
|
|
||||||
"Closed Program {}",
|
|
||||||
program_account.unsigned_key()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
ic_logger_msg!(log_collector, "Account does not support closing");
|
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_context = transaction_context.get_current_instruction_context()?;
|
||||||
let instruction_data = instruction_context.get_instruction_data();
|
let instruction_data = instruction_context.get_instruction_data();
|
||||||
let program_id = instruction_context.get_program_key(transaction_context)?;
|
let program_id = instruction_context.get_program_key(transaction_context)?;
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let program = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
let program = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
if program.get_owner() != program_id {
|
||||||
if program.owner()? != *program_id {
|
|
||||||
ic_msg!(
|
ic_msg!(
|
||||||
invoke_context,
|
invoke_context,
|
||||||
"Executable account not owned by the BPF loader"
|
"Executable account not owned by the BPF loader"
|
||||||
);
|
);
|
||||||
return Err(InstructionError::IncorrectProgramId);
|
return Err(InstructionError::IncorrectProgramId);
|
||||||
}
|
}
|
||||||
|
let is_program_signer = program.is_signer();
|
||||||
|
drop(program);
|
||||||
match limited_deserialize(instruction_data)? {
|
match limited_deserialize(instruction_data)? {
|
||||||
LoaderInstruction::Write { offset, bytes } => {
|
LoaderInstruction::Write { offset, bytes } => {
|
||||||
if program.signer_key().is_none() {
|
if !is_program_signer {
|
||||||
ic_msg!(invoke_context, "Program account did not sign");
|
ic_msg!(invoke_context, "Program account did not sign");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
@ -1085,22 +1089,19 @@ fn process_loader_instruction(
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
LoaderInstruction::Finalize => {
|
LoaderInstruction::Finalize => {
|
||||||
if program.signer_key().is_none() {
|
if !is_program_signer {
|
||||||
ic_msg!(invoke_context, "key[0] did not sign the transaction");
|
ic_msg!(invoke_context, "key[0] did not sign the transaction");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
let executor =
|
let executor =
|
||||||
create_executor(first_instruction_account, 0, invoke_context, use_jit, true)?;
|
create_executor(first_instruction_account, 0, invoke_context, use_jit, true)?;
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let transaction_context = &invoke_context.transaction_context;
|
||||||
let program = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
||||||
invoke_context.update_executor(program.unsigned_key(), executor);
|
let mut program =
|
||||||
program.try_account_ref_mut()?.set_executable(true);
|
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
|
||||||
ic_msg!(
|
invoke_context.update_executor(program.get_key(), executor);
|
||||||
invoke_context,
|
program.set_executable(true);
|
||||||
"Finalized account {:?}",
|
ic_msg!(invoke_context, "Finalized account {:?}", program.get_key());
|
||||||
program.unsigned_key()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1281,6 +1282,7 @@ mod tests {
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{
|
account::{
|
||||||
create_account_shared_data_for_test as create_account_for_test, AccountSharedData,
|
create_account_shared_data_for_test as create_account_for_test, AccountSharedData,
|
||||||
|
ReadableAccount, WritableAccount,
|
||||||
},
|
},
|
||||||
account_utils::StateMut,
|
account_utils::StateMut,
|
||||||
client::SyncClient,
|
client::SyncClient,
|
||||||
|
|
Loading…
Reference in New Issue