Skip to content

Commit

Permalink
Adds test_loader_v3_to_v4_migration.
Browse files Browse the repository at this point in the history
  • Loading branch information
Lichtso committed Feb 7, 2025
1 parent af0e909 commit 66974b0
Showing 1 changed file with 306 additions and 0 deletions.
306 changes: 306 additions & 0 deletions runtime/src/bank/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13385,6 +13385,312 @@ fn test_deploy_last_epoch_slot() {
assert_eq!(result_with_feature_enabled, Ok(()));
}

#[test]
fn test_loader_v3_to_v4_migration() {
solana_logger::setup();

// Bank Setup
let (mut genesis_config, mint_keypair) = create_genesis_config(1_000_000 * LAMPORTS_PER_SOL);
activate_feature(
&mut genesis_config,
solana_feature_set::enable_loader_v4::id(),
);
let mut bank = Bank::new_for_tests(&genesis_config);
bank.activate_feature(&feature_set::remove_accounts_executable_flag_checks::id());
let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
let fee_calculator = genesis_config.fee_rate_governor.create_fee_calculator();
let mut next_slot = 1;

// deploy a program
let mut file = File::open("../programs/bpf_loader/test_elfs/out/noop_aligned.so").unwrap();
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();

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

let min_program_balance =
bank.get_minimum_balance_for_rent_exemption(UpgradeableLoaderState::size_of_program());
let mut program_account = AccountSharedData::new(
min_program_balance,
UpgradeableLoaderState::size_of_program(),
&bpf_loader_upgradeable::id(),
);
program_account
.set_state(&UpgradeableLoaderState::Program {
programdata_address,
})
.unwrap();
bank.store_account(&program_keypair.pubkey(), &program_account);

let closed_programdata_account = AccountSharedData::new(0, 0, &bpf_loader_upgradeable::id());

let mut uninitialized_programdata_account = AccountSharedData::new(
0,
UpgradeableLoaderState::size_of_programdata_metadata(),
&bpf_loader_upgradeable::id(),
);
uninitialized_programdata_account
.set_state(&UpgradeableLoaderState::Uninitialized)
.unwrap();

let mut finalized_programdata_account = AccountSharedData::new(
0,
UpgradeableLoaderState::size_of_programdata(elf.len()),
&bpf_loader_upgradeable::id(),
);
finalized_programdata_account
.set_state(&UpgradeableLoaderState::ProgramData {
slot: 0,
upgrade_authority_address: None,
})
.unwrap();
finalized_programdata_account
.data_as_mut_slice()
.get_mut(UpgradeableLoaderState::size_of_programdata_metadata()..)
.unwrap()
.copy_from_slice(&elf);
let message = Message::new(
&[bpf_loader_upgradeable::migrate_program(
&programdata_address,
&program_keypair.pubkey(),
&program_keypair.pubkey(),
)],
Some(&payer_keypair.pubkey()),
);
let signers = &[&payer_keypair, &program_keypair];
let finalized_migration_transaction =
Transaction::new(signers, message.clone(), bank.last_blockhash());

let mut upgradeable_programdata_account = AccountSharedData::new(
0,
UpgradeableLoaderState::size_of_programdata(elf.len()),
&bpf_loader_upgradeable::id(),
);
let min_programdata_balance =
bank.get_minimum_balance_for_rent_exemption(upgradeable_programdata_account.data().len());
upgradeable_programdata_account.set_lamports(min_programdata_balance);
upgradeable_programdata_account
.set_state(&UpgradeableLoaderState::ProgramData {
slot: 0,
upgrade_authority_address: Some(upgrade_authority_keypair.pubkey()),
})
.unwrap();
upgradeable_programdata_account
.data_as_mut_slice()
.get_mut(UpgradeableLoaderState::size_of_programdata_metadata()..)
.unwrap()
.copy_from_slice(&elf);
let message = Message::new(
&[bpf_loader_upgradeable::migrate_program(
&programdata_address,
&program_keypair.pubkey(),
&upgrade_authority_keypair.pubkey(),
)],
Some(&payer_keypair.pubkey()),
);
let signers = &[&payer_keypair, &upgrade_authority_keypair];
let upgradeable_migration_transaction =
Transaction::new(signers, message.clone(), bank.last_blockhash());

let payer_account = AccountSharedData::new(LAMPORTS_PER_SOL, 0, &system_program::id());
bank.store_account(
&programdata_address,
&upgradeable_programdata_account.clone(),
);
bank.store_account(&payer_keypair.pubkey(), &payer_account);

// Error case: Program was deployed in this block already
let case_redeployment_cooldown = vec![
AccountMeta::new(programdata_address, false),
AccountMeta::new(programdata_address, false),
AccountMeta::new(programdata_address, false),
];
let message = Message::new(
&[Instruction::new_with_bincode(
bpf_loader_upgradeable::id(),
&UpgradeableLoaderInstruction::Migrate,
case_redeployment_cooldown,
)],
Some(&payer_keypair.pubkey()),
);
let signers = &[&payer_keypair];
let transaction = Transaction::new(signers, message.clone(), bank.last_blockhash());
let error = bank.process_transaction(&transaction).unwrap_err();
assert_eq!(
error,
TransactionError::InstructionError(0, InstructionError::InvalidArgument)
);

let bank = new_bank_from_parent_with_bank_forks(
&bank_forks,
bank.clone(),
&Pubkey::default(),
next_slot,
);
next_slot += 1;

// All other error cases
let case_too_few_accounts = vec![
AccountMeta::new(programdata_address, false),
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true),
];
let case_readonly_programdata = vec![
AccountMeta::new_readonly(programdata_address, false),
AccountMeta::new(program_keypair.pubkey(), false),
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true),
];
let case_incorrect_authority = vec![
AccountMeta::new(programdata_address, false),
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true),
AccountMeta::new(program_keypair.pubkey(), false),
];
let case_missing_signature = vec![
AccountMeta::new(programdata_address, false),
AccountMeta::new(program_keypair.pubkey(), false),
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), false),
];
let case_readonly_program = vec![
AccountMeta::new(programdata_address, false),
AccountMeta::new_readonly(program_keypair.pubkey(), false),
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true),
];
let case_program_has_wrong_owner = vec![
AccountMeta::new(programdata_address, false),
AccountMeta::new(upgrade_authority_keypair.pubkey(), false),
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true),
];
let case_incorrect_programdata_address = vec![
AccountMeta::new(program_keypair.pubkey(), false),
AccountMeta::new(program_keypair.pubkey(), false),
AccountMeta::new_readonly(program_keypair.pubkey(), true),
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true),
];
let case_invalid_program_account = vec![
AccountMeta::new(programdata_address, false),
AccountMeta::new(programdata_address, false),
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true),
];
let case_missing_loader_v4 = vec![
AccountMeta::new(programdata_address, false),
AccountMeta::new(program_keypair.pubkey(), false),
AccountMeta::new_readonly(upgrade_authority_keypair.pubkey(), true),
];
for (instruction_accounts, expected_error) in [
(
case_too_few_accounts,
InstructionError::NotEnoughAccountKeys,
),
(case_readonly_programdata, InstructionError::InvalidArgument),
(
case_incorrect_authority,
InstructionError::IncorrectAuthority,
),
(
case_missing_signature,
InstructionError::MissingRequiredSignature,
),
(case_readonly_program, InstructionError::InvalidArgument),
(
case_program_has_wrong_owner,
InstructionError::IncorrectProgramId,
),
(
case_incorrect_programdata_address,
InstructionError::InvalidArgument,
),
(
case_invalid_program_account,
InstructionError::InvalidAccountData,
),
(case_missing_loader_v4, InstructionError::MissingAccount),
] {
let message = Message::new(
&[Instruction::new_with_bincode(
bpf_loader_upgradeable::id(),
&UpgradeableLoaderInstruction::Migrate,
instruction_accounts,
)],
Some(&payer_keypair.pubkey()),
);
let signers = &[&payer_keypair, &upgrade_authority_keypair, &program_keypair];
let transaction = Transaction::new(
&signers[..message.header.num_required_signatures as usize],
message.clone(),
bank.last_blockhash(),
);
let error = bank.process_transaction(&transaction).unwrap_err();
assert_eq!(error, TransactionError::InstructionError(0, expected_error));
}

for (mut programdata_account, transaction, expected_execution_result) in [
(
closed_programdata_account,
finalized_migration_transaction.clone(),
Err(TransactionError::InstructionError(
0,
InstructionError::InvalidInstructionData,
)),
),
(
uninitialized_programdata_account,
finalized_migration_transaction.clone(),
Err(TransactionError::InstructionError(
0,
InstructionError::InvalidInstructionData,
)),
),
(
finalized_programdata_account,
finalized_migration_transaction,
Ok(()),
),
(
upgradeable_programdata_account,
upgradeable_migration_transaction,
Ok(()),
),
] {
let bank = new_bank_from_parent_with_bank_forks(
&bank_forks,
bank.clone(),
&Pubkey::default(),
next_slot,
);
next_slot += 1;

let min_programdata_balance =
bank.get_minimum_balance_for_rent_exemption(programdata_account.data().len());
programdata_account.set_lamports(min_programdata_balance);
let payer_balance = min_program_balance
.saturating_add(min_programdata_balance)
.saturating_add(LAMPORTS_PER_SOL)
.saturating_add(fee_calculator.lamports_per_signature);
let payer_account = AccountSharedData::new(payer_balance, 0, &system_program::id());
bank.store_account(&programdata_address, &programdata_account);
bank.store_account(&payer_keypair.pubkey(), &payer_account);
let result = bank.process_transaction(&transaction);
assert!(result.is_ok(), "result: {:?}", result);

goto_end_of_slot(bank.clone());
let bank =
new_bank_from_parent_with_bank_forks(&bank_forks, bank, &Pubkey::default(), next_slot);
next_slot += 1;

let instruction = Instruction::new_with_bytes(program_keypair.pubkey(), &[], Vec::new());
let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
let binding = mint_keypair.insecure_clone();
let transaction = Transaction::new(&[&binding], message, bank.last_blockhash());
let execution_result = bank.process_transaction(&transaction);
assert_eq!(execution_result, expected_execution_result);
}
}

#[test]
fn test_blockhash_last_valid_block_height() {
let genesis_config = GenesisConfig::default();
Expand Down

0 comments on commit 66974b0

Please sign in to comment.