Adds symmetric tests for all cases of un-/re-/deployment inside the same transaction (#29725)
Unifies test_program_sbf_upgrade_and_invoke_in_same_tx() and test_program_sbf_upgrade_self_via_cpi() into test_program_sbf_invoke_in_same_tx_as_redeployment(). Adds test_program_sbf_invoke_in_same_tx_as_deployment() and test_program_sbf_invoke_in_same_tx_as_undeployment().
This commit is contained in:
parent
156454c980
commit
c5380d4699
|
@ -1745,7 +1745,7 @@ fn test_program_sbf_upgrade() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "sbf_rust")]
|
#[cfg(feature = "sbf_rust")]
|
||||||
fn test_program_sbf_upgrade_and_invoke_in_same_tx() {
|
fn test_program_sbf_invoke_in_same_tx_as_deployment() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
let GenesisConfigInfo {
|
let GenesisConfigInfo {
|
||||||
|
@ -1759,7 +1759,99 @@ fn test_program_sbf_upgrade_and_invoke_in_same_tx() {
|
||||||
let bank = Arc::new(bank);
|
let bank = Arc::new(bank);
|
||||||
let bank_client = BankClient::new_shared(&bank);
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
|
|
||||||
// Deploy upgrade program
|
// Deploy upgradeable program
|
||||||
|
let buffer_keypair = Keypair::new();
|
||||||
|
let program_keypair = Keypair::new();
|
||||||
|
let program_id = program_keypair.pubkey();
|
||||||
|
let authority_keypair = Keypair::new();
|
||||||
|
|
||||||
|
// Deploy indirect invocation program
|
||||||
|
let indirect_program_keypair = Keypair::new();
|
||||||
|
load_upgradeable_program(
|
||||||
|
&bank_client,
|
||||||
|
&mint_keypair,
|
||||||
|
&buffer_keypair,
|
||||||
|
&indirect_program_keypair,
|
||||||
|
&authority_keypair,
|
||||||
|
"solana_sbf_rust_invoke_and_return",
|
||||||
|
);
|
||||||
|
|
||||||
|
let invoke_instruction =
|
||||||
|
Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
|
||||||
|
let indirect_invoke_instruction = Instruction::new_with_bytes(
|
||||||
|
indirect_program_keypair.pubkey(),
|
||||||
|
&[0],
|
||||||
|
vec![
|
||||||
|
AccountMeta::new_readonly(program_id, false),
|
||||||
|
AccountMeta::new_readonly(clock::id(), false),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Prepare deployment
|
||||||
|
let program = load_upgradeable_buffer(
|
||||||
|
&bank_client,
|
||||||
|
&mint_keypair,
|
||||||
|
&buffer_keypair,
|
||||||
|
&authority_keypair,
|
||||||
|
"solana_sbf_rust_noop",
|
||||||
|
);
|
||||||
|
let deployment_instructions = bpf_loader_upgradeable::deploy_with_max_program_len(
|
||||||
|
&mint_keypair.pubkey(),
|
||||||
|
&program_keypair.pubkey(),
|
||||||
|
&buffer_keypair.pubkey(),
|
||||||
|
&authority_keypair.pubkey(),
|
||||||
|
1.max(
|
||||||
|
bank_client
|
||||||
|
.get_minimum_balance_for_rent_exemption(
|
||||||
|
bpf_loader_upgradeable::UpgradeableLoaderState::size_of_program(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
program.len() * 2,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Deployment is invisible to top-level-instructions but visible to CPI instructions
|
||||||
|
for (invoke_instruction, expected) in [
|
||||||
|
(
|
||||||
|
invoke_instruction,
|
||||||
|
Err(TransactionError::ProgramAccountNotFound),
|
||||||
|
),
|
||||||
|
(indirect_invoke_instruction, Ok(())),
|
||||||
|
] {
|
||||||
|
let mut instructions = deployment_instructions.clone();
|
||||||
|
instructions.push(invoke_instruction);
|
||||||
|
let tx = Transaction::new(
|
||||||
|
&[&mint_keypair, &program_keypair, &authority_keypair],
|
||||||
|
Message::new(&instructions, Some(&mint_keypair.pubkey())),
|
||||||
|
bank.last_blockhash(),
|
||||||
|
);
|
||||||
|
let results = execute_transactions(&bank, vec![tx]);
|
||||||
|
if let Err(err) = expected {
|
||||||
|
assert_eq!(results[0].as_ref().unwrap_err(), &err);
|
||||||
|
} else {
|
||||||
|
assert!(results[0].is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "sbf_rust")]
|
||||||
|
fn test_program_sbf_invoke_in_same_tx_as_redeployment() {
|
||||||
|
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_upgradeable_program!();
|
||||||
|
bank.add_builtin(&name, &id, entrypoint);
|
||||||
|
let bank = Arc::new(bank);
|
||||||
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
|
|
||||||
|
// Deploy upgradeable program
|
||||||
let buffer_keypair = Keypair::new();
|
let buffer_keypair = Keypair::new();
|
||||||
let program_keypair = Keypair::new();
|
let program_keypair = Keypair::new();
|
||||||
let program_id = program_keypair.pubkey();
|
let program_id = program_keypair.pubkey();
|
||||||
|
@ -1773,16 +1865,29 @@ fn test_program_sbf_upgrade_and_invoke_in_same_tx() {
|
||||||
"solana_sbf_rust_noop",
|
"solana_sbf_rust_noop",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Deploy indirect invocation program
|
||||||
|
let indirect_program_keypair = Keypair::new();
|
||||||
|
load_upgradeable_program(
|
||||||
|
&bank_client,
|
||||||
|
&mint_keypair,
|
||||||
|
&buffer_keypair,
|
||||||
|
&indirect_program_keypair,
|
||||||
|
&authority_keypair,
|
||||||
|
"solana_sbf_rust_invoke_and_return",
|
||||||
|
);
|
||||||
|
|
||||||
let invoke_instruction =
|
let invoke_instruction =
|
||||||
Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
|
Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
|
||||||
|
let indirect_invoke_instruction = Instruction::new_with_bytes(
|
||||||
|
indirect_program_keypair.pubkey(),
|
||||||
|
&[0],
|
||||||
|
vec![
|
||||||
|
AccountMeta::new_readonly(program_id, false),
|
||||||
|
AccountMeta::new_readonly(clock::id(), false),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
// Call upgradeable program
|
// Prepare redeployment
|
||||||
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(
|
load_upgradeable_buffer(
|
||||||
&bank_client,
|
&bank_client,
|
||||||
&mint_keypair,
|
&mint_keypair,
|
||||||
|
@ -1790,31 +1895,142 @@ fn test_program_sbf_upgrade_and_invoke_in_same_tx() {
|
||||||
&authority_keypair,
|
&authority_keypair,
|
||||||
"solana_sbf_rust_panic",
|
"solana_sbf_rust_panic",
|
||||||
);
|
);
|
||||||
|
let redeployment_instruction = bpf_loader_upgradeable::upgrade(
|
||||||
|
&program_id,
|
||||||
|
&buffer_keypair.pubkey(),
|
||||||
|
&authority_keypair.pubkey(),
|
||||||
|
&mint_keypair.pubkey(),
|
||||||
|
);
|
||||||
|
|
||||||
// Invoke, then upgrade the program, and then invoke again in same tx
|
// Redeployment is visible to both top-level-instructions and CPI instructions
|
||||||
let message = Message::new(
|
for invoke_instruction in [invoke_instruction, indirect_invoke_instruction] {
|
||||||
&[
|
// Call upgradeable program
|
||||||
invoke_instruction.clone(),
|
let result =
|
||||||
bpf_loader_upgradeable::upgrade(
|
bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone());
|
||||||
&program_id,
|
assert!(result.is_ok());
|
||||||
&buffer_keypair.pubkey(),
|
|
||||||
&authority_keypair.pubkey(),
|
// Upgrade the program and invoke in same tx
|
||||||
&mint_keypair.pubkey(),
|
let message = Message::new(
|
||||||
),
|
&[redeployment_instruction.clone(), invoke_instruction],
|
||||||
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(1, InstructionError::ProgramFailedToComplete),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "sbf_rust")]
|
||||||
|
fn test_program_sbf_invoke_in_same_tx_as_undeployment() {
|
||||||
|
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_upgradeable_program!();
|
||||||
|
bank.add_builtin(&name, &id, entrypoint);
|
||||||
|
let bank = Arc::new(bank);
|
||||||
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
|
|
||||||
|
// 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_program(
|
||||||
|
&bank_client,
|
||||||
|
&mint_keypair,
|
||||||
|
&buffer_keypair,
|
||||||
|
&program_keypair,
|
||||||
|
&authority_keypair,
|
||||||
|
"solana_sbf_rust_noop",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Deploy indirect invocation program
|
||||||
|
let indirect_program_keypair = Keypair::new();
|
||||||
|
load_upgradeable_program(
|
||||||
|
&bank_client,
|
||||||
|
&mint_keypair,
|
||||||
|
&buffer_keypair,
|
||||||
|
&indirect_program_keypair,
|
||||||
|
&authority_keypair,
|
||||||
|
"solana_sbf_rust_invoke_and_return",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Deploy panic program
|
||||||
|
let panic_program_keypair = Keypair::new();
|
||||||
|
load_upgradeable_program(
|
||||||
|
&bank_client,
|
||||||
|
&mint_keypair,
|
||||||
|
&buffer_keypair,
|
||||||
|
&panic_program_keypair,
|
||||||
|
&authority_keypair,
|
||||||
|
"solana_sbf_rust_panic",
|
||||||
|
);
|
||||||
|
|
||||||
|
let invoke_instruction =
|
||||||
|
Instruction::new_with_bytes(program_id, &[0], vec![AccountMeta::new(clock::id(), false)]);
|
||||||
|
let indirect_invoke_instruction = Instruction::new_with_bytes(
|
||||||
|
indirect_program_keypair.pubkey(),
|
||||||
|
&[0],
|
||||||
|
vec![
|
||||||
|
AccountMeta::new_readonly(program_id, false),
|
||||||
|
AccountMeta::new_readonly(clock::id(), false),
|
||||||
],
|
],
|
||||||
Some(&mint_keypair.pubkey()),
|
|
||||||
);
|
);
|
||||||
let tx = Transaction::new(
|
let panic_instruction =
|
||||||
&[&mint_keypair, &authority_keypair],
|
Instruction::new_with_bytes(panic_program_keypair.pubkey(), &[], vec![]);
|
||||||
message.clone(),
|
|
||||||
bank.last_blockhash(),
|
// Prepare undeployment
|
||||||
|
let (programdata_address, _) = Pubkey::find_program_address(
|
||||||
|
&[program_keypair.pubkey().as_ref()],
|
||||||
|
&bpf_loader_upgradeable::id(),
|
||||||
);
|
);
|
||||||
let (result, _, _) = process_transaction_and_record_inner(&bank, tx);
|
let undeployment_instruction = bpf_loader_upgradeable::close_any(
|
||||||
assert_eq!(
|
&programdata_address,
|
||||||
result.unwrap_err(),
|
&mint_keypair.pubkey(),
|
||||||
TransactionError::InstructionError(2, InstructionError::ProgramFailedToComplete)
|
Some(&authority_keypair.pubkey()),
|
||||||
|
Some(&program_id),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Undeployment is invisible to both top-level-instructions and CPI instructions
|
||||||
|
for invoke_instruction in [invoke_instruction, indirect_invoke_instruction] {
|
||||||
|
// Call upgradeable program
|
||||||
|
let result =
|
||||||
|
bank_client.send_and_confirm_instruction(&mint_keypair, invoke_instruction.clone());
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
// Upgrade the program and invoke in same tx
|
||||||
|
let message = Message::new(
|
||||||
|
&[
|
||||||
|
undeployment_instruction.clone(),
|
||||||
|
invoke_instruction,
|
||||||
|
panic_instruction.clone(), // Make sure the TX fails, so we don't have to deploy another program
|
||||||
|
],
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -2099,95 +2315,6 @@ fn test_program_sbf_upgrade_via_cpi() {
|
||||||
assert_ne!(programdata, original_programdata);
|
assert_ne!(programdata, original_programdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg(feature = "sbf_rust")]
|
|
||||||
fn test_program_sbf_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_program(
|
|
||||||
&bank_client,
|
|
||||||
&bpf_loader::id(),
|
|
||||||
&mint_keypair,
|
|
||||||
"solana_sbf_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_program(
|
|
||||||
&bank_client,
|
|
||||||
&mint_keypair,
|
|
||||||
&buffer_keypair,
|
|
||||||
&program_keypair,
|
|
||||||
&authority_keypair,
|
|
||||||
"solana_sbf_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(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_sbf_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)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "sbf_rust")]
|
#[cfg(feature = "sbf_rust")]
|
||||||
fn test_program_sbf_set_upgrade_authority_via_cpi() {
|
fn test_program_sbf_set_upgrade_authority_via_cpi() {
|
||||||
|
|
|
@ -167,9 +167,6 @@ pub fn load_upgradeable_program(
|
||||||
authority_keypair: &Keypair,
|
authority_keypair: &Keypair,
|
||||||
name: &str,
|
name: &str,
|
||||||
) {
|
) {
|
||||||
let program_pubkey = executable_keypair.pubkey();
|
|
||||||
let authority_pubkey = authority_keypair.pubkey();
|
|
||||||
|
|
||||||
let program = load_upgradeable_buffer(
|
let program = load_upgradeable_buffer(
|
||||||
bank_client,
|
bank_client,
|
||||||
from_keypair,
|
from_keypair,
|
||||||
|
@ -181,9 +178,9 @@ pub fn load_upgradeable_program(
|
||||||
let message = Message::new(
|
let message = Message::new(
|
||||||
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
||||||
&from_keypair.pubkey(),
|
&from_keypair.pubkey(),
|
||||||
&program_pubkey,
|
&executable_keypair.pubkey(),
|
||||||
&buffer_keypair.pubkey(),
|
&buffer_keypair.pubkey(),
|
||||||
&authority_pubkey,
|
&authority_keypair.pubkey(),
|
||||||
1.max(
|
1.max(
|
||||||
bank_client
|
bank_client
|
||||||
.get_minimum_balance_for_rent_exemption(
|
.get_minimum_balance_for_rent_exemption(
|
||||||
|
|
Loading…
Reference in New Issue