Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce payer balance needed to deploy programs #19645

Merged
merged 4 commits into from
Sep 18, 2021
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 53 additions & 19 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI @jackcmay I'm bumping into this issue now: #9711

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 @@ -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(),
)?;

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -1645,17 +1661,37 @@ mod tests {
let bank_client = BankClient::new_shared(&bank);

// Setup initial accounts
let payer_keypair = Keypair::new();
let program_keypair = Keypair::new();
let (programdata_address, _) = Pubkey::find_program_address(
&[program_keypair.pubkey().as_ref()],
&bpf_loader_upgradeable::id(),
);
let upgrade_authority_keypair = Keypair::new();

// Payer balance just needs to be high enough to create the (small)
// program account and cover fees
let min_program_balance = bank
.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::program_len().unwrap());
let fee_calculator = genesis_config.fee_rate_governor.create_fee_calculator();
let min_payer_balance = min_program_balance + 3 * fee_calculator.lamports_per_signature;

// Fund payer with required deploy funds
let message = Message::new(
&[system_instruction::transfer(
&mint_keypair.pubkey(),
&payer_keypair.pubkey(),
min_payer_balance,
)],
Some(&mint_keypair.pubkey()),
);
assert!(bank_client
.send_and_confirm_message(&[&mint_keypair], message)
.is_ok());

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();
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(),
);
Expand Down Expand Up @@ -1688,29 +1724,27 @@ mod tests {
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 before = bank.get_balance(&payer_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
);
let balance = bank.get_balance(&payer_keypair.pubkey());
assert_eq!(bank.get_balance(&payer_address), 0);
assert_eq!(bank.get_balance(&buffer_address), 0);
assert_eq!(None, bank.get_account(&buffer_address));
let post_program_account = bank.get_account(&program_keypair.pubkey()).unwrap();
Expand Down