Skip to content

Commit ccc6a6b

Browse files
authored
Fix - test_feature_activation_loaded_programs_recompilation_phase() (solana-labs#35299)
* Fixes test_feature_activation_loaded_programs_recompilation_phase() to trigger the recompilation phase before the epoch boundary. * Adds a direct check of the cached entries around recompilation.
1 parent bd93285 commit ccc6a6b

File tree

2 files changed

+69
-27
lines changed

2 files changed

+69
-27
lines changed

program-runtime/src/loaded_programs.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,14 @@ impl<FG: ForkGraph> LoadedPrograms<FG> {
10791079
}
10801080
}
10811081

1082+
/// Returns the `slot_versions` of the second level for the given program id.
1083+
pub fn get_slot_versions_for_tests(&self, key: &Pubkey) -> &[Arc<LoadedProgram>] {
1084+
self.entries
1085+
.get(key)
1086+
.map(|second_level| second_level.slot_versions.as_ref())
1087+
.unwrap_or(&[])
1088+
}
1089+
10821090
/// This function removes the given entry for the given program from the cache.
10831091
/// The function expects that the program and entry exists in the cache. Otherwise it'll panic.
10841092
fn unload_program_entry(&mut self, program: &Pubkey, remove_entry: &Arc<LoadedProgram>) {

runtime/src/bank/tests.rs

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11884,12 +11884,6 @@ fn test_feature_activation_loaded_programs_recompilation_phase() {
1188411884
.remove(&feature_set::reject_callx_r10::id());
1188511885
let (root_bank, bank_forks) = Bank::new_with_bank_forks_for_tests(&genesis_config);
1188611886

11887-
// Test a basic transfer
11888-
let amount = genesis_config.rent.minimum_balance(0);
11889-
let pubkey = solana_sdk::pubkey::new_rand();
11890-
root_bank.transfer(amount, &mint_keypair, &pubkey).unwrap();
11891-
assert_eq!(root_bank.get_balance(&pubkey), amount);
11892-
1189311887
// Program Setup
1189411888
let program_keypair = Keypair::new();
1189511889
let program_data =
@@ -11903,26 +11897,19 @@ fn test_feature_activation_loaded_programs_recompilation_phase() {
1190311897
});
1190411898
root_bank.store_account(&program_keypair.pubkey(), &program_account);
1190511899

11906-
// Compose instruction using the desired program
11907-
let instruction1 = Instruction::new_with_bytes(program_keypair.pubkey(), &[], Vec::new());
11908-
let message1 = Message::new(&[instruction1], Some(&mint_keypair.pubkey()));
11909-
let binding1 = mint_keypair.insecure_clone();
11910-
let signers1 = vec![&binding1];
11911-
let transaction1 = Transaction::new(&signers1, message1, root_bank.last_blockhash());
11900+
// Compose message using the desired program.
11901+
let instruction = Instruction::new_with_bytes(program_keypair.pubkey(), &[], Vec::new());
11902+
let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
11903+
let binding = mint_keypair.insecure_clone();
11904+
let signers = vec![&binding];
1191211905

11913-
// Advance the bank so the next transaction can be submitted.
11906+
// Advance the bank so that the program becomes effective.
1191411907
goto_end_of_slot(root_bank.clone());
1191511908
let bank = new_from_parent_with_fork_next_slot(root_bank, bank_forks.as_ref());
1191611909

11917-
// Compose second instruction using the same program with a different block hash
11918-
let instruction2 = Instruction::new_with_bytes(program_keypair.pubkey(), &[], Vec::new());
11919-
let message2 = Message::new(&[instruction2], Some(&mint_keypair.pubkey()));
11920-
let binding2 = mint_keypair.insecure_clone();
11921-
let signers2 = vec![&binding2];
11922-
let transaction2 = Transaction::new(&signers2, message2, bank.last_blockhash());
11923-
11924-
// Execute before feature is enabled to get program into the cache.
11925-
let result_without_feature_enabled = bank.process_transaction(&transaction1);
11910+
// Load the program with the old environment.
11911+
let transaction = Transaction::new(&signers, message.clone(), bank.last_blockhash());
11912+
let result_without_feature_enabled = bank.process_transaction(&transaction);
1192611913
assert_eq!(
1192711914
result_without_feature_enabled,
1192811915
Err(TransactionError::InstructionError(
@@ -11931,20 +11918,67 @@ fn test_feature_activation_loaded_programs_recompilation_phase() {
1193111918
))
1193211919
);
1193311920

11934-
// Activate feature
11921+
// Schedule feature activation to trigger a change of environment at the epoch boundary.
1193511922
let feature_account_balance =
1193611923
std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1);
1193711924
bank.store_account(
1193811925
&feature_set::reject_callx_r10::id(),
1193911926
&feature::create_account(&Feature { activated_at: None }, feature_account_balance),
1194011927
);
1194111928

11929+
// Advance the bank to middle of epoch to start the recompilation phase.
11930+
goto_end_of_slot(bank.clone());
11931+
let bank = new_bank_from_parent_with_bank_forks(&bank_forks, bank, &Pubkey::default(), 16);
11932+
let current_env = bank
11933+
.loaded_programs_cache
11934+
.read()
11935+
.unwrap()
11936+
.get_environments_for_epoch(0)
11937+
.program_runtime_v1
11938+
.clone();
11939+
let upcoming_env = bank
11940+
.loaded_programs_cache
11941+
.read()
11942+
.unwrap()
11943+
.get_environments_for_epoch(1)
11944+
.program_runtime_v1
11945+
.clone();
11946+
11947+
// Advance the bank to recompile the program.
11948+
{
11949+
let loaded_programs_cache = bank.loaded_programs_cache.read().unwrap();
11950+
let slot_versions =
11951+
loaded_programs_cache.get_slot_versions_for_tests(&program_keypair.pubkey());
11952+
assert_eq!(slot_versions.len(), 1);
11953+
assert!(Arc::ptr_eq(
11954+
slot_versions[0].program.get_environment().unwrap(),
11955+
&current_env
11956+
));
11957+
}
11958+
goto_end_of_slot(bank.clone());
11959+
let bank = new_from_parent_with_fork_next_slot(bank, bank_forks.as_ref());
11960+
{
11961+
let loaded_programs_cache = bank.loaded_programs_cache.read().unwrap();
11962+
let slot_versions =
11963+
loaded_programs_cache.get_slot_versions_for_tests(&program_keypair.pubkey());
11964+
assert_eq!(slot_versions.len(), 2);
11965+
assert!(Arc::ptr_eq(
11966+
slot_versions[0].program.get_environment().unwrap(),
11967+
&current_env
11968+
));
11969+
assert!(Arc::ptr_eq(
11970+
slot_versions[1].program.get_environment().unwrap(),
11971+
&upcoming_env
11972+
));
11973+
}
11974+
11975+
// Advance the bank to cross the epoch boundary and activate the feature.
1194211976
goto_end_of_slot(bank.clone());
11943-
// Advance to next epoch, which starts the recompilation phase
11944-
let bank = new_from_parent_next_epoch(bank, bank_forks.as_ref(), 1);
11977+
let bank = new_bank_from_parent_with_bank_forks(&bank_forks, bank, &Pubkey::default(), 33);
1194511978

11946-
// Execute after feature is enabled to check it was filtered out and reverified.
11947-
let result_with_feature_enabled = bank.process_transaction(&transaction2);
11979+
// Load the program with the new environment.
11980+
let transaction = Transaction::new(&signers, message, bank.last_blockhash());
11981+
let result_with_feature_enabled = bank.process_transaction(&transaction);
1194811982
assert_eq!(
1194911983
result_with_feature_enabled,
1195011984
Err(TransactionError::InstructionError(

0 commit comments

Comments
 (0)