Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Runtime: Bank: Prioritize additional builtins for init and feature activations #35267

Closed
Closed
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
1 change: 1 addition & 0 deletions core/tests/snapshots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ impl SnapshotTestConfig {
vec![accounts_dir.clone()],
AccountSecondaryIndexes::default(),
accounts_db::AccountShrinkThreshold::default(),
None,
);
bank0.freeze();
bank0.set_startup_verification_complete();
Expand Down
1 change: 1 addition & 0 deletions ledger/src/blockstore_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3894,6 +3894,7 @@ pub mod tests {
account_paths,
AccountSecondaryIndexes::default(),
AccountShrinkThreshold::default(),
None,
);
bank.epoch_schedule().clone()
}
Expand Down
37 changes: 32 additions & 5 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1488,7 +1488,11 @@ impl Bank {
);

let (_, apply_feature_activations_time) = measure!(
self.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false),
self.apply_feature_activations(
ApplyFeatureActivationsCaller::NewFromParent,
false,
None
),
"apply_feature_activation",
);

Expand Down Expand Up @@ -1716,7 +1720,7 @@ impl Bank {

let parent_timestamp = parent.clock().unix_timestamp;
let mut new = Bank::new_from_parent(parent, collector_id, slot);
new.apply_feature_activations(ApplyFeatureActivationsCaller::WarpFromParent, false);
new.apply_feature_activations(ApplyFeatureActivationsCaller::WarpFromParent, false, None);
new.update_epoch_stakes(new.epoch_schedule().get_epoch(slot));
new.tick_height.store(new.max_tick_height(), Relaxed);

Expand Down Expand Up @@ -5960,12 +5964,20 @@ impl Bank {
self.apply_feature_activations(
ApplyFeatureActivationsCaller::FinishInit,
debug_do_not_add_builtins,
additional_builtins,
);

if !debug_do_not_add_builtins {
let additional_builtins = additional_builtins.unwrap_or(&[]);
for builtin in BUILTINS
.iter()
.chain(additional_builtins.unwrap_or(&[]).iter())
.filter(|builtin| {
// Give priority to additional builtins.
!additional_builtins
.iter()
.any(|b| b.program_id == builtin.program_id)
})
.chain(additional_builtins.iter())
{
if builtin.feature_id.is_none() {
self.add_builtin(
Expand Down Expand Up @@ -7186,6 +7198,7 @@ impl Bank {
&mut self,
caller: ApplyFeatureActivationsCaller,
debug_do_not_add_builtins: bool,
additional_builtins: Option<&[BuiltinPrototype]>,
) {
use ApplyFeatureActivationsCaller as Caller;
let allow_new_activations = match caller {
Expand Down Expand Up @@ -7227,6 +7240,7 @@ impl Bank {
self.apply_builtin_program_feature_transitions(
allow_new_activations,
&new_feature_activations,
additional_builtins,
);
}

Expand Down Expand Up @@ -7311,8 +7325,19 @@ impl Bank {
&mut self,
only_apply_transitions_for_new_features: bool,
new_feature_activations: &HashSet<Pubkey>,
additional_builtins: Option<&[BuiltinPrototype]>,
) {
for builtin in BUILTINS.iter() {
let additional_builtins = additional_builtins.unwrap_or(&[]);
for builtin in BUILTINS
.iter()
.filter(|builtin| {
// Give priority to additional builtins.
!additional_builtins
.iter()
.any(|b| b.program_id == builtin.program_id)
})
.chain(additional_builtins.iter())
{
if let Some(feature_id) = builtin.feature_id {
let should_apply_action_for_feature_transition =
if only_apply_transitions_for_new_features {
Expand Down Expand Up @@ -7620,6 +7645,7 @@ impl Bank {
Vec::new(),
account_indexes,
shrink_ratio,
None,
)
}

Expand All @@ -7629,13 +7655,14 @@ impl Bank {
paths: Vec<PathBuf>,
account_indexes: AccountSecondaryIndexes,
shrink_ratio: AccountShrinkThreshold,
additional_builtins: Option<&[BuiltinPrototype]>,
) -> Self {
Self::new_with_paths(
genesis_config,
runtime_config,
paths,
None,
None,
additional_builtins,
account_indexes,
shrink_ratio,
false,
Expand Down
187 changes: 185 additions & 2 deletions runtime/src/bank/builtin_programs.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#[cfg(test)]
mod tests {
use {
crate::bank::*,
crate::{bank::*, builtins::BUILTINS},
solana_sdk::{
ed25519_program, feature_set::FeatureSet, genesis_config::create_genesis_config,
ed25519_program,
feature::{self, Feature},
feature_set::FeatureSet,
genesis_config::create_genesis_config,
},
};

Expand Down Expand Up @@ -39,6 +42,7 @@ mod tests {
bank.apply_builtin_program_feature_transitions(
only_apply_transitions_for_new_features,
&HashSet::new(),
None,
);
}

Expand All @@ -61,4 +65,183 @@ mod tests {
// Simulate starting up from snapshot finishing the initialization for a frozen bank
bank.finish_init(&genesis_config, None, false);
}

#[test]
fn test_override_builtins() {
let check_bank_builtins = |builtins: &[BuiltinPrototype], expected_len| {
let bank = Bank::new_with_paths_for_tests(
&GenesisConfig::default(),
Arc::<RuntimeConfig>::default(),
Vec::new(),
AccountSecondaryIndexes::default(),
AccountShrinkThreshold::default(),
Some(builtins),
);

// Assert the bank's builtins contain all additional builtins.
assert_eq!(bank.builtin_programs.len(), expected_len);
BUILTINS
.iter()
.filter(|b| b.feature_id.is_none())
.chain(builtins)
.for_each(|b| {
assert!(bank.builtin_programs.get(&b.program_id).is_some());
});
};

let builtins_len = BUILTINS.iter().filter(|b| b.feature_id.is_none()).count();

check_bank_builtins(&[], builtins_len);
check_bank_builtins(
&[BuiltinPrototype {
feature_id: None,
program_id: solana_system_program::id(),
name: "system_program",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
}],
// System program should be overriden.
builtins_len,
);
check_bank_builtins(
&[
BuiltinPrototype {
feature_id: None,
program_id: solana_system_program::id(),
name: "system_program",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: Pubkey::new_unique(),
name: "random_program",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
},
],
// System program should be overriden, and random program should be added.
builtins_len + 1,
);
check_bank_builtins(
&[
BuiltinPrototype {
feature_id: None,
program_id: solana_system_program::id(),
name: "system_program",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: solana_stake_program::id(),
name: "stake_program",
entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: Pubkey::new_unique(),
name: "random_program1",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: None,
program_id: Pubkey::new_unique(),
name: "stake_program2",
entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm,
},
],
// System & stake should be overriden, and random programs should be added.
builtins_len + 2,
);
}

#[test]
fn test_override_builtins_on_feature_activation() {
let check_bank_builtin_feature_activation = |builtins: &[BuiltinPrototype]| {
let mut bank = Bank::new_with_paths_for_tests(
&GenesisConfig::default(),
Arc::<RuntimeConfig>::default(),
Vec::new(),
AccountSecondaryIndexes::default(),
AccountShrinkThreshold::default(),
Some(builtins),
);

let mut feature_set = FeatureSet::default();
builtins
.iter()
.filter_map(|builtin| builtin.feature_id)
.for_each(|feature_id| {
feature_set.inactive.insert(feature_id);
bank.store_account(
&feature_id,
&feature::create_account(&Feature::default(), 42),
);
});
bank.feature_set = Arc::new(feature_set.clone());

// Assert the bank's builtins _do not_ contain the additional
// builtins, since they have not been enabled.
builtins.iter().for_each(|b| {
assert!(bank.builtin_programs.get(&b.program_id).is_none());
});

bank.apply_feature_activations(
ApplyFeatureActivationsCaller::NewFromParent,
false,
Some(builtins),
);

// Assert the bank's builtins contain the additional builtins,
// since they have now been enabled.
builtins.iter().for_each(|builtin| {
assert!(bank.builtin_programs.get(&builtin.program_id).is_some());
});
};

check_bank_builtin_feature_activation(&[]);
check_bank_builtin_feature_activation(&[BuiltinPrototype {
feature_id: Some(Pubkey::new_unique()),
program_id: solana_system_program::id(),
name: "system_program",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
}]);
check_bank_builtin_feature_activation(&[
BuiltinPrototype {
feature_id: Some(Pubkey::new_unique()),
program_id: solana_system_program::id(),
name: "system_program",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: Some(Pubkey::new_unique()),
program_id: Pubkey::new_unique(),
name: "random_program",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
},
]);
check_bank_builtin_feature_activation(&[
BuiltinPrototype {
feature_id: Some(Pubkey::new_unique()),
program_id: solana_system_program::id(),
name: "system_program",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: Some(Pubkey::new_unique()),
program_id: solana_stake_program::id(),
name: "stake_program",
entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: Some(Pubkey::new_unique()),
program_id: Pubkey::new_unique(),
name: "random_program1",
entrypoint: solana_system_program::system_processor::Entrypoint::vm,
},
BuiltinPrototype {
feature_id: Some(Pubkey::new_unique()),
program_id: Pubkey::new_unique(),
name: "stake_program2",
entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm,
},
]);
}
}
Loading
Loading