Reduce payer balance needed to deploy programs (backport #19645) (#19998)

* 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

(cherry picked from commit efd024510a)

# Conflicts:
#	programs/bpf_loader/src/lib.rs

* fix conflicts

Co-authored-by: Justin Starry <justin@solana.com>
This commit is contained in:
mergify[bot]
2021-09-18 04:46:42 +00:00
committed by GitHub
parent 3e870a40f2
commit d0143dad8f

View File

@ -33,11 +33,11 @@ use solana_sdk::{
clock::Clock, clock::Clock,
entrypoint::{HEAP_LENGTH, SUCCESS}, entrypoint::{HEAP_LENGTH, SUCCESS},
feature_set::{ feature_set::{
add_missing_program_error_mappings, close_upgradeable_program_accounts, add_missing_program_error_mappings, close_upgradeable_program_accounts, fix_write_privs,
upgradeable_close_instruction, upgradeable_close_instruction,
}, },
ic_logger_msg, ic_msg, ic_logger_msg, ic_msg,
instruction::InstructionError, instruction::{AccountMeta, InstructionError},
keyed_account::{from_keyed_account, keyed_account_at_index, KeyedAccount}, keyed_account::{from_keyed_account, keyed_account_at_index, KeyedAccount},
loader_instruction::LoaderInstruction, loader_instruction::LoaderInstruction,
loader_upgradeable_instruction::UpgradeableLoaderInstruction, loader_upgradeable_instruction::UpgradeableLoaderInstruction,
@ -391,13 +391,27 @@ fn process_loader_upgradeable_instruction(
return Err(InstructionError::InvalidArgument); 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(), payer.unsigned_key(),
programdata.unsigned_key(), programdata.unsigned_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,
); );
// 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 caller_program_id = invoke_context.get_caller()?;
let signers = [&[new_program_id.as_ref(), &[bump_seed]]] let signers = [&[new_program_id.as_ref(), &[bump_seed]]]
.iter() .iter()
@ -406,7 +420,7 @@ fn process_loader_upgradeable_instruction(
MessageProcessor::native_invoke( MessageProcessor::native_invoke(
invoke_context, invoke_context,
instruction, instruction,
&[0, 1, 6], &[0, 1, 3, 6],
signers.as_slice(), signers.as_slice(),
)?; )?;
@ -435,11 +449,13 @@ fn process_loader_upgradeable_instruction(
})?; })?;
program.try_account_ref_mut()?.set_executable(true); program.try_account_ref_mut()?.set_executable(true);
// Drain the Buffer account back to the payer if !invoke_context.is_feature_active(&fix_write_privs::id()) {
payer // Drain the Buffer account back to the payer
.try_account_ref_mut()? payer
.checked_add_lamports(buffer.lamports()?)?; .try_account_ref_mut()?
buffer.try_account_ref_mut()?.set_lamports(0); .checked_add_lamports(buffer.lamports()?)?;
buffer.try_account_ref_mut()?.set_lamports(0);
}
ic_logger_msg!(logger, "Deployed program {:?}", new_program_id); ic_logger_msg!(logger, "Deployed program {:?}", new_program_id);
} }
@ -985,6 +1001,7 @@ mod tests {
instruction::{AccountMeta, InstructionError}, instruction::{AccountMeta, InstructionError},
keyed_account::KeyedAccount, keyed_account::KeyedAccount,
message::Message, message::Message,
native_token::LAMPORTS_PER_SOL,
process_instruction::{ process_instruction::{
BpfComputeBudget, InvokeContextStackFrame, MockComputeMeter, MockInvokeContext, BpfComputeBudget, InvokeContextStackFrame, MockComputeMeter, MockInvokeContext,
MockLogger, MockLogger,
@ -1656,34 +1673,48 @@ mod tests {
let bank = Arc::new(bank); let bank = Arc::new(bank);
let bank_client = BankClient::new_shared(&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 program_keypair = Keypair::new();
let buffer_address = Pubkey::new_unique();
let (programdata_address, _) = Pubkey::find_program_address( let (programdata_address, _) = Pubkey::find_program_address(
&[program_keypair.pubkey().as_ref()], &[program_keypair.pubkey().as_ref()],
&bpf_loader_upgradeable::id(), &bpf_loader_upgradeable::id(),
); );
let upgrade_authority_keypair = Keypair::new(); 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 file = File::open("test_elfs/noop_aligned.so").expect("file open failed");
let mut elf = Vec::new(); let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap(); file.read_to_end(&mut elf).unwrap();
// Compute rent exempt balances
let program_len = elf.len();
let min_program_balance = bank let min_program_balance = bank
.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::program_len().unwrap()); .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( 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( // Setup accounts
min_programdata_balance, let buffer_account = {
UpgradeableLoaderState::buffer_len(elf.len()).unwrap(), let mut account = AccountSharedData::new(
&bpf_loader_upgradeable::id(), min_buffer_balance,
); UpgradeableLoaderState::buffer_len(elf.len()).unwrap(),
buffer_account &bpf_loader_upgradeable::id(),
.set_state(&UpgradeableLoaderState::Buffer { );
authority_address: Some(upgrade_authority_keypair.pubkey()), account
}) .set_state(&UpgradeableLoaderState::Buffer {
.unwrap(); authority_address: Some(upgrade_authority_keypair.pubkey()),
buffer_account.data_as_mut_slice()[UpgradeableLoaderState::buffer_data_offset().unwrap()..] })
.copy_from_slice(&elf); .unwrap();
account.data_as_mut_slice()[UpgradeableLoaderState::buffer_data_offset().unwrap()..]
.copy_from_slice(&elf);
account
};
let program_account = AccountSharedData::new( let program_account = AccountSharedData::new(
min_programdata_balance, min_programdata_balance,
UpgradeableLoaderState::program_len().unwrap(), UpgradeableLoaderState::program_len().unwrap(),
@ -1696,14 +1727,27 @@ mod tests {
); );
// Test successful deploy // 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(&buffer_address, &buffer_account);
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());
bank.store_account(&programdata_address, &AccountSharedData::default()); bank.store_account(&programdata_address, &AccountSharedData::default());
let before = bank.get_balance(&mint_keypair.pubkey());
let message = Message::new( let message = Message::new(
&bpf_loader_upgradeable::deploy_with_max_program_len( &bpf_loader_upgradeable::deploy_with_max_program_len(
&mint_keypair.pubkey(), &payer_keypair.pubkey(),
&program_keypair.pubkey(), &program_keypair.pubkey(),
&buffer_address, &buffer_address,
&upgrade_authority_keypair.pubkey(), &upgrade_authority_keypair.pubkey(),
@ -1711,17 +1755,17 @@ mod tests {
elf.len(), elf.len(),
) )
.unwrap(), .unwrap(),
Some(&mint_keypair.pubkey()), Some(&payer_keypair.pubkey()),
); );
assert!(bank_client assert!(bank_client
.send_and_confirm_message( .send_and_confirm_message(
&[&mint_keypair, &program_keypair, &upgrade_authority_keypair], &[&payer_keypair, &program_keypair, &upgrade_authority_keypair],
message message
) )
.is_ok()); .is_ok());
assert_eq!( assert_eq!(
bank.get_balance(&mint_keypair.pubkey()), bank.get_balance(&payer_keypair.pubkey()),
before - min_program_balance payer_base_balance
); );
assert_eq!(bank.get_balance(&buffer_address), 0); assert_eq!(bank.get_balance(&buffer_address), 0);
assert_eq!(None, bank.get_account(&buffer_address)); assert_eq!(None, bank.get_account(&buffer_address));
@ -2003,11 +2047,12 @@ mod tests {
.unwrap() .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.clear_signatures();
bank.store_account( bank.store_account(
&mint_keypair.pubkey(), &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(&buffer_address, &buffer_account);
bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default()); bank.store_account(&program_keypair.pubkey(), &AccountSharedData::default());