diff --git a/program-runtime/src/loaded_programs.rs b/program-runtime/src/loaded_programs.rs index ead152762da90f..4e5c1cdf50fd2f 100644 --- a/program-runtime/src/loaded_programs.rs +++ b/program-runtime/src/loaded_programs.rs @@ -483,6 +483,36 @@ impl LoadedPrograms { entry } + /// On the epoch boundary this removes all programs of the outdated feature set + pub fn prune_feature_set_transition(&mut self) { + for second_level in self.entries.values_mut() { + second_level.retain(|entry| { + let retain = match &entry.program { + LoadedProgramType::Builtin(_) | LoadedProgramType::Closed => true, + LoadedProgramType::LegacyV0(program) | LoadedProgramType::LegacyV1(program) + if Arc::ptr_eq( + program.get_loader(), + &self.program_runtime_environment_v1, + ) => + { + true + } + LoadedProgramType::Unloaded(environment) + if Arc::ptr_eq(environment, &self.program_runtime_environment_v1) => + { + true + } + _ => false, + }; + if !retain { + self.stats.prunes.fetch_add(1, Ordering::Relaxed); + } + retain + }); + } + self.remove_programs_with_no_entries(); + } + /// Before rerooting the blockstore this removes all programs of orphan forks pub fn prune(&mut self, fork_graph: &F, new_root: Slot) { let previous_root = self.latest_root; diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index 60db957d61877c..654d88114410b9 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -148,6 +148,8 @@ pub fn create_program_runtime_environment<'a>( debugging_features: bool, ) -> Result>, Error> { use rand::Rng; + // When adding new features for RBPF, + // also add them to `Bank::apply_builtin_program_feature_transitions()`. let config = Config { max_call_depth: compute_budget.max_call_depth, stack_frame_size: compute_budget.stack_frame_size, diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index df88a4255f9635..fb40449af36338 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -6286,17 +6286,6 @@ impl Bank { ); if !debug_do_not_add_builtins { - let program_runtime_environment_v1 = create_program_runtime_environment( - &self.feature_set, - &self.runtime_config.compute_budget.unwrap_or_default(), - false, /* deployment */ - false, /* debugging_features */ - ) - .unwrap(); - self.loaded_programs_cache - .write() - .unwrap() - .program_runtime_environment_v1 = Arc::new(program_runtime_environment_v1); for builtin in BUILTINS .iter() .chain(additional_builtins.unwrap_or(&[]).iter()) @@ -7577,6 +7566,33 @@ impl Bank { only_apply_transitions_for_new_features: bool, new_feature_activations: &HashSet, ) { + const FEATURES_AFFECTING_RBPF: &[Pubkey] = &[ + feature_set::error_on_syscall_bpf_function_hash_collisions::id(), + feature_set::reject_callx_r10::id(), + feature_set::switch_to_new_elf_parser::id(), + feature_set::bpf_account_data_direct_mapping::id(), + ]; + if !only_apply_transitions_for_new_features + || FEATURES_AFFECTING_RBPF + .iter() + .any(|key| new_feature_activations.contains(key)) + { + let program_runtime_environment_v1 = create_program_runtime_environment( + &self.feature_set, + &self.runtime_config.compute_budget.unwrap_or_default(), + false, /* deployment */ + false, /* debugging_features */ + ) + .unwrap(); + let mut loaded_programs_cache = self.loaded_programs_cache.write().unwrap(); + if *loaded_programs_cache.program_runtime_environment_v1 + != program_runtime_environment_v1 + { + loaded_programs_cache.program_runtime_environment_v1 = + Arc::new(program_runtime_environment_v1); + } + loaded_programs_cache.prune_feature_set_transition(); + } for builtin in BUILTINS.iter() { if let Some(feature_id) = builtin.feature_id { let should_apply_action_for_feature_transition = @@ -7598,7 +7614,6 @@ impl Bank { } } } - for precompile in get_precompiles() { #[allow(clippy::blocks_in_if_conditions)] if precompile.feature.map_or(false, |ref feature_id| {