Restore ability for programs to upgrade themselves (#20265)
* Make helper associated fn * Add feature definition * Add handling to preserve program-id write lock when upgradeable loader is present; restore bpf upgrade-self test * Use single feature
This commit is contained in:
@ -1867,7 +1867,7 @@ fn test_program_bpf_upgrade_and_invoke_in_same_tx() {
|
||||
"solana_bpf_rust_panic",
|
||||
);
|
||||
|
||||
// Attempt to invoke, then upgrade the program in same tx
|
||||
// Invoke, then upgrade the program, and then invoke again in same tx
|
||||
let message = Message::new(
|
||||
&[
|
||||
invoke_instruction.clone(),
|
||||
@ -1886,12 +1886,10 @@ fn test_program_bpf_upgrade_and_invoke_in_same_tx() {
|
||||
message.clone(),
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
// program_id is automatically demoted to readonly, preventing the upgrade, which requires
|
||||
// writeability
|
||||
let (result, _) = process_transaction_and_record_inner(&bank, tx);
|
||||
assert_eq!(
|
||||
result.unwrap_err(),
|
||||
TransactionError::InstructionError(1, InstructionError::InvalidArgument)
|
||||
TransactionError::InstructionError(2, InstructionError::ProgramFailedToComplete)
|
||||
);
|
||||
}
|
||||
|
||||
@ -2187,6 +2185,96 @@ fn test_program_bpf_upgrade_via_cpi() {
|
||||
assert_ne!(programdata, original_programdata);
|
||||
}
|
||||
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
#[test]
|
||||
fn test_program_bpf_upgrade_self_via_cpi() {
|
||||
solana_logger::setup();
|
||||
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(50);
|
||||
let mut bank = Bank::new_for_tests(&genesis_config);
|
||||
let (name, id, entrypoint) = solana_bpf_loader_program!();
|
||||
bank.add_builtin(&name, id, entrypoint);
|
||||
let (name, id, entrypoint) = solana_bpf_loader_upgradeable_program!();
|
||||
bank.add_builtin(&name, id, entrypoint);
|
||||
let bank = Arc::new(bank);
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
let noop_program_id = load_bpf_program(
|
||||
&bank_client,
|
||||
&bpf_loader::id(),
|
||||
&mint_keypair,
|
||||
"solana_bpf_rust_noop",
|
||||
);
|
||||
|
||||
// Deploy upgradeable program
|
||||
let buffer_keypair = Keypair::new();
|
||||
let program_keypair = Keypair::new();
|
||||
let program_id = program_keypair.pubkey();
|
||||
let authority_keypair = Keypair::new();
|
||||
load_upgradeable_bpf_program(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
&buffer_keypair,
|
||||
&program_keypair,
|
||||
&authority_keypair,
|
||||
"solana_bpf_rust_invoke_and_return",
|
||||
);
|
||||
|
||||
let mut invoke_instruction = Instruction::new_with_bytes(
|
||||
program_id,
|
||||
&[0],
|
||||
vec![
|
||||
AccountMeta::new_readonly(noop_program_id, false),
|
||||
AccountMeta::new_readonly(noop_program_id, false),
|
||||
AccountMeta::new_readonly(clock::id(), false),
|
||||
],
|
||||
);
|
||||
|
||||
// Call the upgraded program
|
||||
invoke_instruction.data[0] += 1;
|
||||
let result =
|
||||
bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone());
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Prepare for upgrade
|
||||
let buffer_keypair = Keypair::new();
|
||||
load_upgradeable_buffer(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
&buffer_keypair,
|
||||
&authority_keypair,
|
||||
"solana_bpf_rust_panic",
|
||||
);
|
||||
|
||||
// Invoke, then upgrade the program, and then invoke again in same tx
|
||||
let message = Message::new(
|
||||
&[
|
||||
invoke_instruction.clone(),
|
||||
bpf_loader_upgradeable::upgrade(
|
||||
&program_id,
|
||||
&buffer_keypair.pubkey(),
|
||||
&authority_keypair.pubkey(),
|
||||
&mint_keypair.pubkey(),
|
||||
),
|
||||
invoke_instruction,
|
||||
],
|
||||
Some(&mint_keypair.pubkey()),
|
||||
);
|
||||
let tx = Transaction::new(
|
||||
&[&mint_keypair, &authority_keypair],
|
||||
message.clone(),
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let (result, _) = process_transaction_and_record_inner(&bank, tx);
|
||||
assert_eq!(
|
||||
result.unwrap_err(),
|
||||
TransactionError::InstructionError(2, InstructionError::ProgramFailedToComplete)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
#[test]
|
||||
fn test_program_bpf_set_upgrade_authority_via_cpi() {
|
||||
|
Reference in New Issue
Block a user