Skip to content

Commit

Permalink
Reduce payer balance needed to deploy programs (#19645)
Browse files Browse the repository at this point in the history
* Reduce payer balance needed to deploy programs

* Fix test and unbalanced ix error

* fix test

* fix up tests

(cherry picked from commit efd0245)

# Conflicts:
#	programs/bpf_loader/src/lib.rs
  • Loading branch information
jstarry authored and mergify-bot committed Sep 18, 2021
1 parent 3e870a4 commit 778c71b
Showing 1 changed file with 86 additions and 32 deletions.
118 changes: 86 additions & 32 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@ use solana_sdk::{
clock::Clock,
entrypoint::{HEAP_LENGTH, SUCCESS},
feature_set::{
<<<<<<< HEAD
add_missing_program_error_mappings, close_upgradeable_program_accounts,
upgradeable_close_instruction,
=======
add_missing_program_error_mappings, close_upgradeable_program_accounts, fix_write_privs,
stop_verify_mul64_imm_nonzero,
>>>>>>> efd024510 (Reduce payer balance needed to deploy programs (#19645))
},
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,
Expand Down Expand Up @@ -391,13 +396,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()
Expand All @@ -406,7 +425,7 @@ fn process_loader_upgradeable_instruction(
MessageProcessor::native_invoke(
invoke_context,
instruction,
&[0, 1, 6],
&[0, 1, 3, 6],
signers.as_slice(),
)?;

Expand Down Expand Up @@ -435,11 +454,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);
}
Expand Down Expand Up @@ -985,10 +1006,15 @@ mod tests {
instruction::{AccountMeta, InstructionError},
keyed_account::KeyedAccount,
message::Message,
<<<<<<< HEAD
process_instruction::{
BpfComputeBudget, InvokeContextStackFrame, MockComputeMeter, MockInvokeContext,
MockLogger,
},
=======
native_token::LAMPORTS_PER_SOL,
process_instruction::{MockComputeMeter, MockInvokeContext},
>>>>>>> efd024510 (Reduce payer balance needed to deploy programs (#19645))
pubkey::Pubkey,
rent::Rent,
signature::{Keypair, Signer},
Expand Down Expand Up @@ -1656,34 +1682,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_programdata_balance = bank.get_minimum_balance_for_rent_exemption(
UpgradeableLoaderState::programdata_len(elf.len()).unwrap(),
let min_buffer_balance = bank.get_minimum_balance_for_rent_exemption(
UpgradeableLoaderState::buffer_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(),
let min_programdata_balance = bank.get_minimum_balance_for_rent_exemption(
UpgradeableLoaderState::programdata_len(program_len).unwrap(),
);
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(),
Expand All @@ -1696,32 +1736,45 @@ 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(),
min_program_balance,
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));
Expand Down Expand Up @@ -2003,11 +2056,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());
Expand Down

0 comments on commit 778c71b

Please sign in to comment.