Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip adding builtins if they will be removed #23233

Merged
merged 6 commits into from
Feb 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions ledger/src/builtins.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use {
solana_runtime::builtins::{ActivationType, Builtin, Builtins},
solana_sdk::pubkey::Pubkey,
};
use solana_runtime::builtins::{Builtin, BuiltinFeatureTransition, Builtins};

macro_rules! to_builtin {
($b:expr) => {
Expand Down Expand Up @@ -37,14 +34,14 @@ fn genesis_builtins(bpf_jit: bool) -> Vec<Builtin> {
]
}

/// Builtin programs activated dynamically by feature
fn feature_builtins() -> Vec<(Builtin, Pubkey, ActivationType)> {
/// Dynamic feature transitions for builtin programs
fn builtin_feature_transitions() -> Vec<BuiltinFeatureTransition> {
vec![]
}

pub(crate) fn get(bpf_jit: bool) -> Builtins {
Builtins {
genesis_builtins: genesis_builtins(bpf_jit),
feature_builtins: feature_builtins(),
feature_transitions: builtin_feature_transitions(),
}
}
96 changes: 36 additions & 60 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use {
accounts_update_notifier_interface::AccountsUpdateNotifier,
ancestors::{Ancestors, AncestorsForSerialization},
blockhash_queue::BlockhashQueue,
builtins::{self, ActivationType, Builtin, Builtins},
builtins::{self, BuiltinAction, BuiltinFeatureTransition, Builtins},
cost_tracker::CostTracker,
epoch_stakes::{EpochStakes, NodeVoteAccounts},
inline_spl_associated_token_account, inline_spl_token,
Expand Down Expand Up @@ -157,6 +157,7 @@ use {
};

mod address_lookup_table;
mod builtin_programs;
mod sysvar_cache;
mod transaction_account_state_info;

Expand Down Expand Up @@ -1196,9 +1197,9 @@ pub struct Bank {

compute_budget: Option<ComputeBudget>,

/// Builtin programs activated dynamically by feature
/// Dynamic feature transitions for builtin programs
#[allow(clippy::rc_buffer)]
feature_builtins: Arc<Vec<(Builtin, Pubkey, ActivationType)>>,
builtin_feature_transitions: Arc<Vec<BuiltinFeatureTransition>>,

/// Protocol-level rewards that were distributed by this bank
pub rewards: RwLock<Vec<(Pubkey, RewardInfo)>>,
Expand Down Expand Up @@ -1367,7 +1368,7 @@ impl Bank {
is_delta: AtomicBool::default(),
builtin_programs: BuiltinPrograms::default(),
compute_budget: Option::<ComputeBudget>::default(),
feature_builtins: Arc::<Vec<(Builtin, Pubkey, ActivationType)>>::default(),
builtin_feature_transitions: Arc::<Vec<BuiltinFeatureTransition>>::default(),
rewards: RwLock::<Vec<(Pubkey, RewardInfo)>>::default(),
cluster_type: Option::<ClusterType>::default(),
lazy_rent_collection: AtomicBool::default(),
Expand Down Expand Up @@ -1703,7 +1704,7 @@ impl Bank {
signature_count: AtomicU64::new(0),
builtin_programs,
compute_budget: parent.compute_budget,
feature_builtins: parent.feature_builtins.clone(),
builtin_feature_transitions: parent.builtin_feature_transitions.clone(),
hard_forks: parent.hard_forks.clone(),
rewards: RwLock::new(vec![]),
cluster_type: parent.cluster_type,
Expand Down Expand Up @@ -1989,7 +1990,7 @@ impl Bank {
is_delta: AtomicBool::new(fields.is_delta),
builtin_programs: new(),
compute_budget: None,
feature_builtins: new(),
builtin_feature_transitions: new(),
rewards: new(),
cluster_type: Some(genesis_config.cluster_type),
lazy_rent_collection: new(),
Expand Down Expand Up @@ -5514,8 +5515,8 @@ impl Bank {
.genesis_builtins
.extend_from_slice(&additional_builtins.genesis_builtins);
builtins
.feature_builtins
.extend_from_slice(&additional_builtins.feature_builtins);
.feature_transitions
.extend_from_slice(&additional_builtins.feature_transitions);
}
if !debug_do_not_add_builtins {
for builtin in builtins.genesis_builtins {
Expand All @@ -5531,7 +5532,7 @@ impl Bank {
}
}
}
self.feature_builtins = Arc::new(builtins.feature_builtins);
self.builtin_feature_transitions = Arc::new(builtins.feature_transitions);

self.apply_feature_activations(true, debug_do_not_add_builtins);
}
Expand Down Expand Up @@ -6238,29 +6239,9 @@ impl Bank {
debug!("Added program {} under {:?}", name, program_id);
}

/// Replace a builtin instruction processor if it already exists
pub fn replace_builtin(
&mut self,
name: &str,
program_id: &Pubkey,
process_instruction: ProcessInstructionWithContext,
) {
debug!("Replacing program {} under {:?}", name, program_id);
self.add_builtin_account(name, program_id, true);
if let Some(entry) = self
.builtin_programs
.vec
.iter_mut()
.find(|entry| entry.program_id == *program_id)
{
entry.process_instruction = process_instruction;
}
debug!("Replaced program {} under {:?}", name, program_id);
}

/// Remove a builtin instruction processor if it already exists
pub fn remove_builtin(&mut self, name: &str, program_id: &Pubkey) {
debug!("Removing program {} under {:?}", name, program_id);
pub fn remove_builtin(&mut self, program_id: &Pubkey) {
debug!("Removing program {}", program_id);
// Don't remove the account since the bank expects the account state to
// be idempotent
if let Some(position) = self
Expand All @@ -6271,7 +6252,7 @@ impl Bank {
{
self.builtin_programs.vec.remove(position);
}
debug!("Removed program {} under {:?}", name, program_id);
debug!("Removed program {}", program_id);
}

pub fn add_precompile(&mut self, program_id: &Pubkey) {
Expand Down Expand Up @@ -6451,7 +6432,11 @@ impl Bank {
}

if !debug_do_not_add_builtins {
self.ensure_feature_builtins(init_finish_or_warp, &new_feature_activations);
let apply_transitions_for_new_features = !init_finish_or_warp;
self.apply_builtin_program_feature_transitions(
apply_transitions_for_new_features,
&new_feature_activations,
);
self.reconfigure_token2_native_mint();
}
self.ensure_no_storage_rewards_pool();
Expand Down Expand Up @@ -6508,33 +6493,34 @@ impl Bank {
newly_activated
}

fn ensure_feature_builtins(
fn apply_builtin_program_feature_transitions(
&mut self,
init_or_warp: bool,
apply_transitions_for_new_features: bool,
new_feature_activations: &HashSet<Pubkey>,
) {
let feature_builtins = self.feature_builtins.clone();
for (builtin, feature, activation_type) in feature_builtins.iter() {
let should_populate = init_or_warp && self.feature_set.is_active(feature)
|| !init_or_warp && new_feature_activations.contains(feature);
if should_populate {
match activation_type {
ActivationType::NewProgram => self.add_builtin(
&builtin.name,
&builtin.id,
builtin.process_instruction_with_context,
),
ActivationType::NewVersion => self.replace_builtin(
let feature_set = self.feature_set.clone();
let should_apply_action_for_feature = |feature_id: &Pubkey| -> bool {
if apply_transitions_for_new_features {
new_feature_activations.contains(feature_id)
} else {
feature_set.is_active(feature_id)
}
};

let builtin_feature_transitions = self.builtin_feature_transitions.clone();
for transition in builtin_feature_transitions.iter() {
if let Some(builtin_action) = transition.to_action(&should_apply_action_for_feature) {
match builtin_action {
BuiltinAction::Add(builtin) => self.add_builtin(
&builtin.name,
&builtin.id,
builtin.process_instruction_with_context,
),
ActivationType::RemoveProgram => {
self.remove_builtin(&builtin.name, &builtin.id)
}
BuiltinAction::Remove(program_id) => self.remove_builtin(&program_id),
}
}
}

for precompile in get_precompiles() {
#[allow(clippy::blocks_in_if_conditions)]
if precompile.feature.map_or(false, |ref feature_id| {
Expand Down Expand Up @@ -13350,16 +13336,6 @@ pub(crate) mod tests {
mock_ix_processor,
);
assert_eq!(bank.get_account_modified_slot(&program_id).unwrap().1, slot);

Arc::get_mut(&mut bank).unwrap().replace_builtin(
"mock_program v2",
&program_id,
mock_ix_processor,
);
assert_eq!(
bank.get_account_modified_slot(&program_id).unwrap().1,
bank.slot()
);
}

#[test]
Expand Down
27 changes: 27 additions & 0 deletions runtime/src/bank/builtin_programs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#[cfg(test)]
mod tests {
use {
crate::bank::*,
solana_sdk::{feature_set::FeatureSet, genesis_config::create_genesis_config},
};

#[test]
fn test_startup_from_snapshot_after_precompile_transition() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for writing this. yeah, feature activation needs more test coverage...

let (genesis_config, _mint_keypair) = create_genesis_config(100_000);

let mut bank = Bank::new_for_tests(&genesis_config);
bank.feature_set = Arc::new(FeatureSet::all_enabled());
bank.finish_init(&genesis_config, None, false);

// Overwrite precompile accounts to simulate a cluster which already added precompiles.
for precompile in get_precompiles() {
bank.store_account(&precompile.program_id, &AccountSharedData::default());
bank.add_precompiled_account(&precompile.program_id);
}

bank.freeze();

// Simulate starting up from snapshot finishing the initialization for a frozen bank
bank.finish_init(&genesis_config, None, false);
}
}
Loading