diff --git a/ledger-tool/src/program.rs b/ledger-tool/src/program.rs index 66d18f126ad099..149335aea1372f 100644 --- a/ledger-tool/src/program.rs +++ b/ledger-tool/src/program.rs @@ -551,7 +551,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 8c5e06ac556dc6..fdde130ce752d4 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) @@ -4715,20 +4723,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, @@ -4748,7 +4770,7 @@ impl Bank { program_account.owner(), program_account.data().len(), 0, - environments.program_runtime_v1.clone(), + program_runtime_environment_v1.clone(), ) } @@ -4773,7 +4795,7 @@ impl Bank { .len() .saturating_add(programdata_account.data().len()), slot, - environments.program_runtime_v1.clone(), + program_runtime_environment_v1.clone(), ) }), @@ -4784,7 +4806,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, @@ -4796,25 +4818,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) } @@ -5058,7 +5091,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 b0f758a25f82c1..a04d2700f28313 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -7230,7 +7230,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, @@ -7385,7 +7385,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(