Fix program account rent exemption (#14176)
This commit is contained in:
parent
dc0f5adc36
commit
593ad80954
|
@ -8,9 +8,10 @@ use solana_program::{
|
|||
entrypoint!(process_instruction);
|
||||
fn process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
_accounts: &[AccountInfo],
|
||||
accounts: &[AccountInfo],
|
||||
_instruction_data: &[u8],
|
||||
) -> ProgramResult {
|
||||
msg!("Upgradeable program");
|
||||
assert_eq!(accounts.len(), 2);
|
||||
Err(42.into())
|
||||
}
|
||||
|
|
|
@ -8,9 +8,10 @@ use solana_program::{
|
|||
entrypoint!(process_instruction);
|
||||
fn process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
_accounts: &[AccountInfo],
|
||||
accounts: &[AccountInfo],
|
||||
_instruction_data: &[u8],
|
||||
) -> ProgramResult {
|
||||
msg!("Upgraded program");
|
||||
assert_eq!(accounts.len(), 2);
|
||||
Err(43.into())
|
||||
}
|
||||
|
|
|
@ -1483,7 +1483,14 @@ fn test_program_bpf_upgrade() {
|
|||
|
||||
// call upgrade program
|
||||
nonce += 1;
|
||||
let instruction = Instruction::new(program_id, &[nonce], vec![]);
|
||||
let instruction = Instruction::new(
|
||||
program_id,
|
||||
&[nonce],
|
||||
vec![
|
||||
AccountMeta::new(clock::id(), false),
|
||||
AccountMeta::new(fees::id(), false),
|
||||
],
|
||||
);
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
|
@ -1501,7 +1508,14 @@ fn test_program_bpf_upgrade() {
|
|||
|
||||
// call upgraded program
|
||||
nonce += 1;
|
||||
let instruction = Instruction::new(program_id, &[nonce], vec![]);
|
||||
let instruction = Instruction::new(
|
||||
program_id,
|
||||
&[nonce],
|
||||
vec![
|
||||
AccountMeta::new(clock::id(), false),
|
||||
AccountMeta::new(fees::id(), false),
|
||||
],
|
||||
);
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
|
@ -1529,7 +1543,14 @@ fn test_program_bpf_upgrade() {
|
|||
|
||||
// call original program
|
||||
nonce += 1;
|
||||
let instruction = Instruction::new(program_id, &[nonce], vec![]);
|
||||
let instruction = Instruction::new(
|
||||
program_id,
|
||||
&[nonce],
|
||||
vec![
|
||||
AccountMeta::new(clock::id(), false),
|
||||
AccountMeta::new(fees::id(), false),
|
||||
],
|
||||
);
|
||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||
assert_eq!(
|
||||
result.unwrap_err().unwrap(),
|
||||
|
|
|
@ -228,7 +228,7 @@ fn process_instruction_common(
|
|||
let account_iter = &mut keyed_accounts.iter();
|
||||
let first_account = next_keyed_account(account_iter)?;
|
||||
if first_account.executable()? {
|
||||
let (program, offset) = if bpf_loader_upgradeable::check_id(program_id) {
|
||||
let (program, keyed_accounts, offset) = if bpf_loader_upgradeable::check_id(program_id) {
|
||||
if let UpgradeableLoaderState::Program {
|
||||
programdata_address,
|
||||
} = first_account.state()?
|
||||
|
@ -240,6 +240,7 @@ fn process_instruction_common(
|
|||
}
|
||||
(
|
||||
programdata,
|
||||
&keyed_accounts[1..],
|
||||
UpgradeableLoaderState::programdata_data_offset()?,
|
||||
)
|
||||
} else {
|
||||
|
@ -247,7 +248,7 @@ fn process_instruction_common(
|
|||
return Err(InstructionError::InvalidAccountData);
|
||||
}
|
||||
} else {
|
||||
(first_account, 0)
|
||||
(first_account, keyed_accounts, 0)
|
||||
};
|
||||
|
||||
if program.owner()? != *program_id {
|
||||
|
@ -341,8 +342,11 @@ fn process_loader_upgradeable_instruction(
|
|||
log!(logger, "Program account already initialized");
|
||||
return Err(InstructionError::AccountAlreadyInitialized);
|
||||
}
|
||||
|
||||
if program.lamports()? < rent.minimum_balance(UpgradeableLoaderState::program_len()?) {
|
||||
if program.data_len()? < UpgradeableLoaderState::program_len()? {
|
||||
log!(logger, "Program account too small");
|
||||
return Err(InstructionError::AccountDataTooSmall);
|
||||
}
|
||||
if program.lamports()? < rent.minimum_balance(program.data_len()?) {
|
||||
log!(logger, "Program account not rent-exempt");
|
||||
return Err(InstructionError::ExecutableAccountNotRentExempt);
|
||||
}
|
||||
|
@ -506,7 +510,8 @@ fn process_loader_upgradeable_instruction(
|
|||
use_jit,
|
||||
)?;
|
||||
|
||||
// Update the ProgramData account and record the upgraded data
|
||||
// Update the ProgramData account, record the upgraded data, and zero
|
||||
// the rest
|
||||
|
||||
programdata.set_state(&UpgradeableLoaderState::ProgramData {
|
||||
slot: clock.slot,
|
||||
|
@ -515,6 +520,11 @@ fn process_loader_upgradeable_instruction(
|
|||
programdata.try_account_ref_mut()?.data
|
||||
[programdata_data_offset..programdata_data_offset + buffer_data_len]
|
||||
.copy_from_slice(&buffer.try_account_ref()?.data[buffer_data_offset..]);
|
||||
for i in &mut programdata.try_account_ref_mut()?.data
|
||||
[programdata_data_offset + buffer_data_len..]
|
||||
{
|
||||
*i = 0
|
||||
}
|
||||
|
||||
// Fund ProgramData to rent-exemption, spill the rest
|
||||
|
||||
|
@ -1541,6 +1551,66 @@ mod tests {
|
|||
.unwrap()
|
||||
);
|
||||
|
||||
// Test program account not rent exempt because data is larger than needed
|
||||
bank.clear_signatures();
|
||||
bank.store_account(&buffer_address, &buffer_account);
|
||||
bank.store_account(&program_keypair.pubkey(), &Account::default());
|
||||
bank.store_account(&programdata_address, &Account::default());
|
||||
let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len(
|
||||
&mint_keypair.pubkey(),
|
||||
&program_keypair.pubkey(),
|
||||
&buffer_address,
|
||||
None,
|
||||
min_program_balance,
|
||||
elf.len(),
|
||||
)
|
||||
.unwrap();
|
||||
instructions[0] = system_instruction::create_account(
|
||||
&mint_keypair.pubkey(),
|
||||
&program_keypair.pubkey(),
|
||||
min_program_balance,
|
||||
UpgradeableLoaderState::program_len().unwrap() as u64 + 1,
|
||||
&id(),
|
||||
);
|
||||
let message = Message::new(&instructions, Some(&mint_keypair.pubkey()));
|
||||
assert_eq!(
|
||||
TransactionError::InstructionError(1, InstructionError::ExecutableAccountNotRentExempt),
|
||||
bank_client
|
||||
.send_and_confirm_message(&[&mint_keypair, &program_keypair], message)
|
||||
.unwrap_err()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// Test program account too small
|
||||
bank.clear_signatures();
|
||||
bank.store_account(&buffer_address, &buffer_account);
|
||||
bank.store_account(&program_keypair.pubkey(), &Account::default());
|
||||
bank.store_account(&programdata_address, &Account::default());
|
||||
let mut instructions = bpf_loader_upgradeable::deploy_with_max_program_len(
|
||||
&mint_keypair.pubkey(),
|
||||
&program_keypair.pubkey(),
|
||||
&buffer_address,
|
||||
None,
|
||||
min_program_balance,
|
||||
elf.len(),
|
||||
)
|
||||
.unwrap();
|
||||
instructions[0] = system_instruction::create_account(
|
||||
&mint_keypair.pubkey(),
|
||||
&program_keypair.pubkey(),
|
||||
min_program_balance,
|
||||
UpgradeableLoaderState::program_len().unwrap() as u64 - 1,
|
||||
&id(),
|
||||
);
|
||||
let message = Message::new(&instructions, Some(&mint_keypair.pubkey()));
|
||||
assert_eq!(
|
||||
TransactionError::InstructionError(1, InstructionError::AccountDataTooSmall),
|
||||
bank_client
|
||||
.send_and_confirm_message(&[&mint_keypair, &program_keypair], message)
|
||||
.unwrap_err()
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// Test Insufficient payer funds
|
||||
bank.clear_signatures();
|
||||
bank.store_account(
|
||||
|
|
Loading…
Reference in New Issue