diff --git a/ledger-tool/src/program.rs b/ledger-tool/src/program.rs index ace464561e65fa..f682a68e3c4a1f 100644 --- a/ledger-tool/src/program.rs +++ b/ledger-tool/src/program.rs @@ -548,7 +548,7 @@ pub fn program(ledger_path: &Path, matches: &ArgMatches<'_>) { .clone(), ); for key in cached_account_keys { - loaded_programs.replenish(key, bank.load_program(&key)); + loaded_programs.replenish(key, bank.load_program(&key, None)); debug!("Loaded program {}", key); } invoke_context.programs_loaded_for_tx_batch = &loaded_programs; diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 9d32bd6797467c..7deabe059f5616 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -1445,8 +1445,16 @@ impl Bank { new.update_epoch_stakes(leader_schedule_epoch); // Recompile loaded programs one at a time before the next epoch hits let (_epoch, slot_index) = new.get_epoch_and_slot_index(new.slot()); - let loaded_programs_cache = new.loaded_programs_cache.write().unwrap(); + let mut loaded_programs_cache = new.loaded_programs_cache.write().unwrap(); if !loaded_programs_cache.programs_to_recompile.is_empty() { + if let Some((key, program_to_recompile)) = + loaded_programs_cache.programs_to_recompile.pop() + { + drop(loaded_programs_cache); + let recompiled = new.load_program(&key, Some(program_to_recompile)); + let mut loaded_programs_cache = new.loaded_programs_cache.write().unwrap(); + loaded_programs_cache.replenish(key, recompiled); + } } else if slot_index.saturating_add( solana_program_runtime::loaded_programs::MAX_LOADED_ENTRY_COUNT .checked_div(2) @@ -4699,20 +4707,34 @@ impl Bank { ProgramAccountLoadResult::InvalidAccountData } - pub fn load_program(&self, pubkey: &Pubkey) -> Arc { + pub fn load_program( + &self, + pubkey: &Pubkey, + recompile: Option>, + ) -> Arc { let environments = self .loaded_programs_cache .read() .unwrap() .environments .clone(); + let program_runtime_environment_v1 = if recompile.is_some() { + environments.upcoming_program_runtime_v1.as_ref().unwrap() + } else { + &environments.program_runtime_v1 + }; + let program_runtime_environment_v2 = if recompile.is_some() { + environments.upcoming_program_runtime_v2.as_ref().unwrap() + } else { + &environments.program_runtime_v2 + }; let mut load_program_metrics = LoadProgramMetrics { program_id: pubkey.to_string(), ..LoadProgramMetrics::default() }; - let loaded_program = match self.load_program_accounts(pubkey) { + let mut loaded_program = match self.load_program_accounts(pubkey) { ProgramAccountLoadResult::AccountNotFound => Ok(LoadedProgram::new_tombstone( self.slot, LoadedProgramType::Closed, @@ -4732,7 +4754,7 @@ impl Bank { program_account.owner(), program_account.data().len(), 0, - environments.program_runtime_v1.clone(), + program_runtime_environment_v1.clone(), ) } @@ -4757,7 +4779,7 @@ impl Bank { .len() .saturating_add(programdata_account.data().len()), slot, - environments.program_runtime_v1.clone(), + program_runtime_environment_v1.clone(), ) }), @@ -4768,7 +4790,7 @@ impl Bank { .and_then(|elf_bytes| { LoadedProgram::new( &loader_v4::id(), - environments.program_runtime_v2.clone(), + program_runtime_environment_v2.clone(), slot, slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET), None, @@ -4780,25 +4802,36 @@ impl Bank { }) .unwrap_or(LoadedProgram::new_tombstone( self.slot, - LoadedProgramType::FailedVerification(environments.program_runtime_v2), + LoadedProgramType::FailedVerification( + program_runtime_environment_v2.clone(), + ), )); Ok(loaded_program) } ProgramAccountLoadResult::InvalidV4Program => Ok(LoadedProgram::new_tombstone( self.slot, - LoadedProgramType::FailedVerification(environments.program_runtime_v2), + LoadedProgramType::FailedVerification(program_runtime_environment_v2.clone()), )), } .unwrap_or_else(|_| { LoadedProgram::new_tombstone( self.slot, - LoadedProgramType::FailedVerification(environments.program_runtime_v1), + LoadedProgramType::FailedVerification(program_runtime_environment_v1.clone()), ) }); let mut timings = ExecuteDetailsTimings::default(); load_program_metrics.submit_datapoint(&mut timings); + if let Some(recompile) = recompile { + loaded_program.effective_slot = self + .epoch_schedule() + .get_first_slot_in_epoch(self.epoch.saturating_add(1)); + loaded_program.tx_usage_counter = + AtomicU64::new(recompile.tx_usage_counter.load(Ordering::Relaxed)); + loaded_program.ix_usage_counter = + AtomicU64::new(recompile.ix_usage_counter.load(Ordering::Relaxed)); + } Arc::new(loaded_program) } @@ -5042,7 +5075,7 @@ impl Bank { let missing_programs: Vec<(Pubkey, Arc)> = missing_programs .iter() .map(|(key, count)| { - let program = self.load_program(key); + let program = self.load_program(key, None); program.tx_usage_counter.store(*count, Ordering::Relaxed); (*key, program) }) diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index 6222ae1d42dba8..73604a030b6e11 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -7231,7 +7231,7 @@ fn test_bank_load_program() { programdata_account.set_rent_epoch(1); bank.store_account_and_update_capitalization(&key1, &program_account); bank.store_account_and_update_capitalization(&programdata_key, &programdata_account); - let program = bank.load_program(&key1); + let program = bank.load_program(&key1, None); assert!(matches!(program.program, LoadedProgramType::LegacyV1(_))); assert_eq!( program.account_size, @@ -7386,7 +7386,7 @@ fn test_bpf_loader_upgradeable_deploy_with_max_len() { assert_eq!(*elf.get(i).unwrap(), *byte); } - let loaded_program = bank.load_program(&program_keypair.pubkey()); + let loaded_program = bank.load_program(&program_keypair.pubkey(), None); // Invoke deployed program mock_process_instruction(