Reduce payer balance needed to deploy programs (#19645)

* Reduce payer balance needed to deploy programs

* Fix test and unbalanced ix error

* fix test

* fix up tests
This commit is contained in:
Justin Starry 2021-09-17 19:49:53 -05:00 committed by GitHub
parent e6b4dd3866
commit efd024510a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 78 additions and 33 deletions

View File

@ -31,11 +31,11 @@ use solana_sdk::{
clock::Clock,
entrypoint::{HEAP_LENGTH, SUCCESS},
feature_set::{
add_missing_program_error_mappings, close_upgradeable_program_accounts,
add_missing_program_error_mappings, close_upgradeable_program_accounts, fix_write_privs,
stop_verify_mul64_imm_nonzero,
},
ic_logger_msg, ic_msg,
instruction::InstructionError,
instruction::{AccountMeta, InstructionError},
keyed_account::{from_keyed_account, keyed_account_at_index, KeyedAccount},
loader_instruction::LoaderInstruction,
loader_upgradeable_instruction::UpgradeableLoaderInstruction,
@ -390,13 +390,27 @@ fn process_loader_upgradeable_instruction(
return Err(InstructionError::InvalidArgument);
}
let instruction = system_instruction::create_account(
if invoke_context.is_feature_active(&fix_write_privs::id()) {
// 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 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.unsigned_key(), false));
let caller_program_id = invoke_context.get_caller()?;
let signers = [&[new_program_id.as_ref(), &[bump_seed]]]
.iter()
@ -405,7 +419,7 @@ fn process_loader_upgradeable_instruction(
InstructionProcessor::native_invoke(
invoke_context,
instruction,
&[0, 1, 6],
&[0, 1, 3, 6],
signers.as_slice(),
)?;
@ -434,11 +448,13 @@ fn process_loader_upgradeable_instruction(
})?;
program.try_account_ref_mut()?.set_executable(true);
// 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);
if !invoke_context.is_feature_active(&fix_write_privs::id()) {
// 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);
}
ic_logger_msg!(logger, "Deployed program {:?}", new_program_id);
}
@ -987,6 +1003,7 @@ mod tests {
instruction::{AccountMeta, InstructionError},
keyed_account::KeyedAccount,
message::Message,
native_token::LAMPORTS_PER_SOL,
process_instruction::{MockComputeMeter, MockInvokeContext},
pubkey::Pubkey,
rent::Rent,
@ -1644,34 +1661,48 @@ mod tests {
let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&bank);
// Setup initial accounts
// Setup keypairs and addresses
let payer_keypair = Keypair::new();
let program_keypair = Keypair::new();
let buffer_address = Pubkey::new_unique();
let (programdata_address, _) = Pubkey::find_program_address(
&[program_keypair.pubkey().as_ref()],
&bpf_loader_upgradeable::id(),
);
let upgrade_authority_keypair = Keypair::new();
// Load program file
let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed");
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();
// Compute rent exempt balances
let program_len = elf.len();
let min_program_balance = bank
.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::program_len().unwrap());
let min_buffer_balance = bank.get_minimum_balance_for_rent_exemption(
UpgradeableLoaderState::buffer_len(program_len).unwrap(),
);
let min_programdata_balance = bank.get_minimum_balance_for_rent_exemption(
UpgradeableLoaderState::programdata_len(elf.len()).unwrap(),
UpgradeableLoaderState::programdata_len(program_len).unwrap(),
);
let buffer_address = Pubkey::new_unique();
let mut buffer_account = AccountSharedData::new(
min_programdata_balance,
UpgradeableLoaderState::buffer_len(elf.len()).unwrap(),
&bpf_loader_upgradeable::id(),
);
buffer_account
.set_state(&UpgradeableLoaderState::Buffer {
authority_address: Some(upgrade_authority_keypair.pubkey()),
})
.unwrap();
buffer_account.data_as_mut_slice()[UpgradeableLoaderState::buffer_data_offset().unwrap()..]
.copy_from_slice(&elf);
// Setup accounts
let buffer_account = {
let mut account = AccountSharedData::new(
min_buffer_balance,
UpgradeableLoaderState::buffer_len(elf.len()).unwrap(),
&bpf_loader_upgradeable::id(),
);
account
.set_state(&UpgradeableLoaderState::Buffer {
authority_address: Some(upgrade_authority_keypair.pubkey()),
})
.unwrap();
account.data_as_mut_slice()[UpgradeableLoaderState::buffer_data_offset().unwrap()..]
.copy_from_slice(&elf);
account
};
let program_account = AccountSharedData::new(
min_programdata_balance,
UpgradeableLoaderState::program_len().unwrap(),
@ -1684,14 +1715,27 @@ mod tests {
);
// Test successful deploy
bank.clear_signatures();
let payer_base_balance = LAMPORTS_PER_SOL;
let deploy_fees = {
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;
bank.store_account(
&payer_keypair.pubkey(),
&AccountSharedData::new(
payer_base_balance + min_payer_balance,
0,
&system_program::id(),
),
);
bank.store_account(&buffer_address, &buffer_account);
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
bank.store_account(&programdata_address, &AccountSharedData::default());
let before = bank.get_balance(&mint_keypair.pubkey());
let message = Message::new(
&bpf_loader_upgradeable::deploy_with_max_program_len(
&mint_keypair.pubkey(),
&payer_keypair.pubkey(),
&program_keypair.pubkey(),
&buffer_address,
&upgrade_authority_keypair.pubkey(),
@ -1699,17 +1743,17 @@ mod tests {
elf.len(),
)
.unwrap(),
Some(&mint_keypair.pubkey()),
Some(&payer_keypair.pubkey()),
);
assert!(bank_client
.send_and_confirm_message(
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair],
&[&payer_keypair, &program_keypair, &upgrade_authority_keypair],
message
)
.is_ok());
assert_eq!(
bank.get_balance(&mint_keypair.pubkey()),
before - min_program_balance
bank.get_balance(&payer_keypair.pubkey()),
payer_base_balance
);
assert_eq!(bank.get_balance(&buffer_address), 0);
assert_eq!(None, bank.get_account(&buffer_address));
@ -1991,11 +2035,12 @@ mod tests {
.unwrap()
);
// Test Insufficient payer funds
// Test Insufficient payer funds (need more funds to cover the
// difference between buffer lamports and programdata lamports)
bank.clear_signatures();
bank.store_account(
&mint_keypair.pubkey(),
&AccountSharedData::new(min_program_balance, 0, &system_program::id()),
&AccountSharedData::new(deploy_fees + min_program_balance, 0, &system_program::id()),
);
bank.store_account(&buffer_address, &buffer_account);
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());