|
@@ -12,15 +12,68 @@ use {
|
|
|
},
|
|
},
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+#[derive(Clone)]
|
|
|
|
|
+pub struct MigratingBuiltinCost {
|
|
|
|
|
+ native_cost: u64,
|
|
|
|
|
+ core_bpf_migration_feature: Pubkey,
|
|
|
|
|
+ // encoding positional information explicitly for migration feature item,
|
|
|
|
|
+ // its value must be correctly corresponding to this object's position
|
|
|
|
|
+ // in MIGRATING_BUILTINS_COSTS, otherwise a const validation
|
|
|
|
|
+ // `validate_position(MIGRATING_BUILTINS_COSTS)` will fail at compile time.
|
|
|
|
|
+ position: usize,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#[derive(Clone)]
|
|
|
|
|
+pub struct NotMigratingBuiltinCost {
|
|
|
|
|
+ native_cost: u64,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/// DEVELOPER: when a builtin is migrated to sbpf, please add its corresponding
|
|
/// DEVELOPER: when a builtin is migrated to sbpf, please add its corresponding
|
|
|
-/// migration feature ID to BUILTIN_INSTRUCTION_COSTS, so the builtin's default
|
|
|
|
|
-/// cost can be determined properly based on feature status.
|
|
|
|
|
|
|
+/// migration feature ID to BUILTIN_INSTRUCTION_COSTS, and move it from
|
|
|
|
|
+/// NON_MIGRATING_BUILTINS_COSTS to MIGRATING_BUILTINS_COSTS, so the builtin's
|
|
|
|
|
+/// default cost can be determined properly based on feature status.
|
|
|
/// When migration completed, eg the feature gate is enabled everywhere, please
|
|
/// When migration completed, eg the feature gate is enabled everywhere, please
|
|
|
-/// remove that builtin entry from BUILTIN_INSTRUCTION_COSTS.
|
|
|
|
|
|
|
+/// remove that builtin entry from MIGRATING_BUILTINS_COSTS.
|
|
|
#[derive(Clone)]
|
|
#[derive(Clone)]
|
|
|
-struct BuiltinCost {
|
|
|
|
|
- native_cost: u64,
|
|
|
|
|
- core_bpf_migration_feature: Option<Pubkey>,
|
|
|
|
|
|
|
+pub enum BuiltinCost {
|
|
|
|
|
+ Migrating(MigratingBuiltinCost),
|
|
|
|
|
+ NotMigrating(NotMigratingBuiltinCost),
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+impl BuiltinCost {
|
|
|
|
|
+ pub fn native_cost(&self) -> u64 {
|
|
|
|
|
+ match self {
|
|
|
|
|
+ BuiltinCost::Migrating(MigratingBuiltinCost { native_cost, .. }) => *native_cost,
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost { native_cost }) => *native_cost,
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pub fn core_bpf_migration_feature(&self) -> Option<&Pubkey> {
|
|
|
|
|
+ match self {
|
|
|
|
|
+ BuiltinCost::Migrating(MigratingBuiltinCost {
|
|
|
|
|
+ core_bpf_migration_feature,
|
|
|
|
|
+ ..
|
|
|
|
|
+ }) => Some(core_bpf_migration_feature),
|
|
|
|
|
+ BuiltinCost::NotMigrating(_) => None,
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pub fn position(&self) -> Option<usize> {
|
|
|
|
|
+ match self {
|
|
|
|
|
+ BuiltinCost::Migrating(MigratingBuiltinCost { position, .. }) => Some(*position),
|
|
|
|
|
+ BuiltinCost::NotMigrating(_) => None,
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn has_migrated(&self, feature_set: &FeatureSet) -> bool {
|
|
|
|
|
+ match self {
|
|
|
|
|
+ BuiltinCost::Migrating(MigratingBuiltinCost {
|
|
|
|
|
+ core_bpf_migration_feature,
|
|
|
|
|
+ ..
|
|
|
|
|
+ }) => feature_set.is_active(core_bpf_migration_feature),
|
|
|
|
|
+ BuiltinCost::NotMigrating(_) => false,
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
lazy_static! {
|
|
lazy_static! {
|
|
@@ -33,100 +86,110 @@ lazy_static! {
|
|
|
/// calculate the cost of a transaction which is used in replay to enforce
|
|
/// calculate the cost of a transaction which is used in replay to enforce
|
|
|
/// block cost limits as of
|
|
/// block cost limits as of
|
|
|
/// https://github.com/solana-labs/solana/issues/29595.
|
|
/// https://github.com/solana-labs/solana/issues/29595.
|
|
|
- static ref BUILTIN_INSTRUCTION_COSTS: AHashMap<Pubkey, BuiltinCost> = [
|
|
|
|
|
|
|
+ static ref BUILTIN_INSTRUCTION_COSTS: AHashMap<Pubkey, BuiltinCost> =
|
|
|
|
|
+ MIGRATING_BUILTINS_COSTS
|
|
|
|
|
+ .iter()
|
|
|
|
|
+ .chain(NON_MIGRATING_BUILTINS_COSTS.iter())
|
|
|
|
|
+ .cloned()
|
|
|
|
|
+ .collect();
|
|
|
|
|
+ // DO NOT ADD MORE ENTRIES TO THIS MAP
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/// DEVELOPER WARNING: please do not add new entry into MIGRATING_BUILTINS_COSTS or
|
|
|
|
|
+/// NON_MIGRATING_BUILTINS_COSTS, do so will modify BUILTIN_INSTRUCTION_COSTS therefore
|
|
|
|
|
+/// cause consensus failure. However, when a builtin started being migrated to core bpf,
|
|
|
|
|
+/// it MUST be moved from NON_MIGRATING_BUILTINS_COSTS to MIGRATING_BUILTINS_COSTS, then
|
|
|
|
|
+/// correctly furnishing `core_bpf_migration_feature`.
|
|
|
|
|
+///
|
|
|
|
|
+#[allow(dead_code)]
|
|
|
|
|
+const TOTAL_COUNT_BUILTS: usize = 12;
|
|
|
|
|
+#[cfg(test)]
|
|
|
|
|
+static_assertions::const_assert_eq!(
|
|
|
|
|
+ MIGRATING_BUILTINS_COSTS.len() + NON_MIGRATING_BUILTINS_COSTS.len(),
|
|
|
|
|
+ TOTAL_COUNT_BUILTS
|
|
|
|
|
+);
|
|
|
|
|
+
|
|
|
|
|
+pub const MIGRATING_BUILTINS_COSTS: &[(Pubkey, BuiltinCost)] = &[
|
|
|
(
|
|
(
|
|
|
stake::id(),
|
|
stake::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
|
|
+ BuiltinCost::Migrating(MigratingBuiltinCost {
|
|
|
native_cost: solana_stake_program::stake_instruction::DEFAULT_COMPUTE_UNITS,
|
|
native_cost: solana_stake_program::stake_instruction::DEFAULT_COMPUTE_UNITS,
|
|
|
- core_bpf_migration_feature: Some(feature_set::migrate_stake_program_to_core_bpf::id()),
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ core_bpf_migration_feature: feature_set::migrate_stake_program_to_core_bpf::id(),
|
|
|
|
|
+ position: 0,
|
|
|
|
|
+ }),
|
|
|
),
|
|
),
|
|
|
(
|
|
(
|
|
|
config::id(),
|
|
config::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
|
|
+ BuiltinCost::Migrating(MigratingBuiltinCost {
|
|
|
native_cost: solana_config_program::config_processor::DEFAULT_COMPUTE_UNITS,
|
|
native_cost: solana_config_program::config_processor::DEFAULT_COMPUTE_UNITS,
|
|
|
- core_bpf_migration_feature: Some(feature_set::migrate_config_program_to_core_bpf::id()),
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ core_bpf_migration_feature: feature_set::migrate_config_program_to_core_bpf::id(),
|
|
|
|
|
+ position: 1,
|
|
|
|
|
+ }),
|
|
|
),
|
|
),
|
|
|
|
|
+ (
|
|
|
|
|
+ address_lookup_table::id(),
|
|
|
|
|
+ BuiltinCost::Migrating(MigratingBuiltinCost {
|
|
|
|
|
+ native_cost: solana_address_lookup_table_program::processor::DEFAULT_COMPUTE_UNITS,
|
|
|
|
|
+ core_bpf_migration_feature:
|
|
|
|
|
+ feature_set::migrate_address_lookup_table_program_to_core_bpf::id(),
|
|
|
|
|
+ position: 2,
|
|
|
|
|
+ }),
|
|
|
|
|
+ ),
|
|
|
|
|
+];
|
|
|
|
|
+
|
|
|
|
|
+pub const NON_MIGRATING_BUILTINS_COSTS: &[(Pubkey, BuiltinCost)] = &[
|
|
|
(
|
|
(
|
|
|
vote::id(),
|
|
vote::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
|
|
|
native_cost: solana_vote_program::vote_processor::DEFAULT_COMPUTE_UNITS,
|
|
native_cost: solana_vote_program::vote_processor::DEFAULT_COMPUTE_UNITS,
|
|
|
- core_bpf_migration_feature: None,
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ }),
|
|
|
),
|
|
),
|
|
|
(
|
|
(
|
|
|
system_program::id(),
|
|
system_program::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
|
|
|
native_cost: solana_system_program::system_processor::DEFAULT_COMPUTE_UNITS,
|
|
native_cost: solana_system_program::system_processor::DEFAULT_COMPUTE_UNITS,
|
|
|
- core_bpf_migration_feature: None,
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ }),
|
|
|
),
|
|
),
|
|
|
(
|
|
(
|
|
|
compute_budget::id(),
|
|
compute_budget::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
|
|
|
native_cost: solana_compute_budget_program::DEFAULT_COMPUTE_UNITS,
|
|
native_cost: solana_compute_budget_program::DEFAULT_COMPUTE_UNITS,
|
|
|
- core_bpf_migration_feature: None,
|
|
|
|
|
- },
|
|
|
|
|
- ),
|
|
|
|
|
- (
|
|
|
|
|
- address_lookup_table::id(),
|
|
|
|
|
- BuiltinCost {
|
|
|
|
|
- native_cost: solana_address_lookup_table_program::processor::DEFAULT_COMPUTE_UNITS,
|
|
|
|
|
- core_bpf_migration_feature: Some(
|
|
|
|
|
- feature_set::migrate_address_lookup_table_program_to_core_bpf::id(),
|
|
|
|
|
- ),
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ }),
|
|
|
),
|
|
),
|
|
|
(
|
|
(
|
|
|
bpf_loader_upgradeable::id(),
|
|
bpf_loader_upgradeable::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
|
|
|
native_cost: solana_bpf_loader_program::UPGRADEABLE_LOADER_COMPUTE_UNITS,
|
|
native_cost: solana_bpf_loader_program::UPGRADEABLE_LOADER_COMPUTE_UNITS,
|
|
|
- core_bpf_migration_feature: None,
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ }),
|
|
|
),
|
|
),
|
|
|
(
|
|
(
|
|
|
bpf_loader_deprecated::id(),
|
|
bpf_loader_deprecated::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
|
|
|
native_cost: solana_bpf_loader_program::DEPRECATED_LOADER_COMPUTE_UNITS,
|
|
native_cost: solana_bpf_loader_program::DEPRECATED_LOADER_COMPUTE_UNITS,
|
|
|
- core_bpf_migration_feature: None,
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ }),
|
|
|
),
|
|
),
|
|
|
(
|
|
(
|
|
|
bpf_loader::id(),
|
|
bpf_loader::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
|
|
|
native_cost: solana_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS,
|
|
native_cost: solana_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS,
|
|
|
- core_bpf_migration_feature: None,
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ }),
|
|
|
),
|
|
),
|
|
|
(
|
|
(
|
|
|
loader_v4::id(),
|
|
loader_v4::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
|
|
|
native_cost: solana_loader_v4_program::DEFAULT_COMPUTE_UNITS,
|
|
native_cost: solana_loader_v4_program::DEFAULT_COMPUTE_UNITS,
|
|
|
- core_bpf_migration_feature: None,
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ }),
|
|
|
),
|
|
),
|
|
|
// Note: These are precompile, run directly in bank during sanitizing;
|
|
// Note: These are precompile, run directly in bank during sanitizing;
|
|
|
(
|
|
(
|
|
|
secp256k1_program::id(),
|
|
secp256k1_program::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
- native_cost: 0,
|
|
|
|
|
- core_bpf_migration_feature: None,
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost { native_cost: 0 }),
|
|
|
),
|
|
),
|
|
|
(
|
|
(
|
|
|
ed25519_program::id(),
|
|
ed25519_program::id(),
|
|
|
- BuiltinCost {
|
|
|
|
|
- native_cost: 0,
|
|
|
|
|
- core_bpf_migration_feature: None,
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ BuiltinCost::NotMigrating(NotMigratingBuiltinCost { native_cost: 0 }),
|
|
|
),
|
|
),
|
|
|
- // DO NOT ADD MORE ENTRIES TO THIS MAP
|
|
|
|
|
- ]
|
|
|
|
|
- .iter()
|
|
|
|
|
- .cloned()
|
|
|
|
|
- .collect();
|
|
|
|
|
-}
|
|
|
|
|
|
|
+];
|
|
|
|
|
|
|
|
lazy_static! {
|
|
lazy_static! {
|
|
|
/// A table of 256 booleans indicates whether the first `u8` of a Pubkey exists in
|
|
/// A table of 256 booleans indicates whether the first `u8` of a Pubkey exists in
|
|
@@ -148,28 +211,84 @@ pub fn get_builtin_instruction_cost<'a>(
|
|
|
) -> Option<u64> {
|
|
) -> Option<u64> {
|
|
|
BUILTIN_INSTRUCTION_COSTS
|
|
BUILTIN_INSTRUCTION_COSTS
|
|
|
.get(program_id)
|
|
.get(program_id)
|
|
|
- .filter(
|
|
|
|
|
- // Returns true if builtin program id has no core_bpf_migration_feature or feature is not activated;
|
|
|
|
|
- // otherwise returns false because it's not considered as builtin
|
|
|
|
|
- |builtin_cost| -> bool {
|
|
|
|
|
- builtin_cost
|
|
|
|
|
- .core_bpf_migration_feature
|
|
|
|
|
- .map(|feature_id| !feature_set.is_active(&feature_id))
|
|
|
|
|
- .unwrap_or(true)
|
|
|
|
|
- },
|
|
|
|
|
- )
|
|
|
|
|
- .map(|builtin_cost| builtin_cost.native_cost)
|
|
|
|
|
|
|
+ .filter(|builtin_cost| !builtin_cost.has_migrated(feature_set))
|
|
|
|
|
+ .map(|builtin_cost| builtin_cost.native_cost())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-#[inline]
|
|
|
|
|
-pub fn is_builtin_program(program_id: &Pubkey) -> bool {
|
|
|
|
|
- BUILTIN_INSTRUCTION_COSTS.contains_key(program_id)
|
|
|
|
|
|
|
+pub enum BuiltinMigrationFeatureIndex {
|
|
|
|
|
+ NotBuiltin,
|
|
|
|
|
+ BuiltinNoMigrationFeature,
|
|
|
|
|
+ BuiltinWithMigrationFeature(usize),
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+pub fn get_builtin_migration_feature_index(program_id: &Pubkey) -> BuiltinMigrationFeatureIndex {
|
|
|
|
|
+ BUILTIN_INSTRUCTION_COSTS.get(program_id).map_or(
|
|
|
|
|
+ BuiltinMigrationFeatureIndex::NotBuiltin,
|
|
|
|
|
+ |builtin_cost| {
|
|
|
|
|
+ builtin_cost.position().map_or(
|
|
|
|
|
+ BuiltinMigrationFeatureIndex::BuiltinNoMigrationFeature,
|
|
|
|
|
+ BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature,
|
|
|
|
|
+ )
|
|
|
|
|
+ },
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/// const function validates `position` correctness at compile time.
|
|
|
|
|
+#[allow(dead_code)]
|
|
|
|
|
+const fn validate_position(migrating_builtins: &[(Pubkey, BuiltinCost)]) {
|
|
|
|
|
+ let mut index = 0;
|
|
|
|
|
+ while index < migrating_builtins.len() {
|
|
|
|
|
+ match migrating_builtins[index].1 {
|
|
|
|
|
+ BuiltinCost::Migrating(MigratingBuiltinCost { position, .. }) => assert!(
|
|
|
|
|
+ position == index,
|
|
|
|
|
+ "migration feture must exist and at correct position"
|
|
|
|
|
+ ),
|
|
|
|
|
+ BuiltinCost::NotMigrating(_) => {
|
|
|
|
|
+ panic!("migration feture must exist and at correct position")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ index += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+const _: () = validate_position(MIGRATING_BUILTINS_COSTS);
|
|
|
|
|
+
|
|
|
|
|
+/// Helper function to return ref of migration feature Pubkey at position `index`
|
|
|
|
|
+/// from MIGRATING_BUILTINS_COSTS
|
|
|
|
|
+pub fn get_migration_feature_id(index: usize) -> &'static Pubkey {
|
|
|
|
|
+ MIGRATING_BUILTINS_COSTS
|
|
|
|
|
+ .get(index)
|
|
|
|
|
+ .expect("valid index of MIGRATING_BUILTINS_COSTS")
|
|
|
|
|
+ .1
|
|
|
|
|
+ .core_bpf_migration_feature()
|
|
|
|
|
+ .expect("migrating builtin")
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#[cfg(feature = "dev-context-only-utils")]
|
|
|
|
|
+pub fn get_migration_feature_position(feature_id: &Pubkey) -> usize {
|
|
|
|
|
+ MIGRATING_BUILTINS_COSTS
|
|
|
|
|
+ .iter()
|
|
|
|
|
+ .position(|(_, c)| c.core_bpf_migration_feature().expect("migrating builtin") == feature_id)
|
|
|
|
|
+ .unwrap()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
#[cfg(test)]
|
|
|
mod test {
|
|
mod test {
|
|
|
use super::*;
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ fn test_const_builtin_cost_arrays() {
|
|
|
|
|
+ // sanity check to make sure built-ins are declared in the correct array
|
|
|
|
|
+ assert!(MIGRATING_BUILTINS_COSTS
|
|
|
|
|
+ .iter()
|
|
|
|
|
+ .enumerate()
|
|
|
|
|
+ .all(|(index, (_, c))| {
|
|
|
|
|
+ c.core_bpf_migration_feature().is_some() && c.position() == Some(index)
|
|
|
|
|
+ }));
|
|
|
|
|
+ assert!(NON_MIGRATING_BUILTINS_COSTS
|
|
|
|
|
+ .iter()
|
|
|
|
|
+ .all(|(_, c)| c.core_bpf_migration_feature().is_none()));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
#[test]
|
|
#[test]
|
|
|
fn test_get_builtin_instruction_cost() {
|
|
fn test_get_builtin_instruction_cost() {
|
|
|
// use native cost if no migration planned
|
|
// use native cost if no migration planned
|
|
@@ -181,15 +300,11 @@ mod test {
|
|
|
// use native cost if migration is planned but not activated
|
|
// use native cost if migration is planned but not activated
|
|
|
assert_eq!(
|
|
assert_eq!(
|
|
|
Some(solana_stake_program::stake_instruction::DEFAULT_COMPUTE_UNITS),
|
|
Some(solana_stake_program::stake_instruction::DEFAULT_COMPUTE_UNITS),
|
|
|
- get_builtin_instruction_cost(&solana_stake_program::id(), &FeatureSet::default())
|
|
|
|
|
|
|
+ get_builtin_instruction_cost(&stake::id(), &FeatureSet::default())
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
// None if migration is planned and activated, in which case, it's no longer builtin
|
|
// None if migration is planned and activated, in which case, it's no longer builtin
|
|
|
- assert!(get_builtin_instruction_cost(
|
|
|
|
|
- &solana_stake_program::id(),
|
|
|
|
|
- &FeatureSet::all_enabled()
|
|
|
|
|
- )
|
|
|
|
|
- .is_none());
|
|
|
|
|
|
|
+ assert!(get_builtin_instruction_cost(&stake::id(), &FeatureSet::all_enabled()).is_none());
|
|
|
|
|
|
|
|
// None if not builtin
|
|
// None if not builtin
|
|
|
assert!(
|
|
assert!(
|
|
@@ -200,4 +315,64 @@ mod test {
|
|
|
.is_none()
|
|
.is_none()
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ fn test_get_builtin_migration_feature_index() {
|
|
|
|
|
+ assert!(matches!(
|
|
|
|
|
+ get_builtin_migration_feature_index(&Pubkey::new_unique()),
|
|
|
|
|
+ BuiltinMigrationFeatureIndex::NotBuiltin
|
|
|
|
|
+ ));
|
|
|
|
|
+ assert!(matches!(
|
|
|
|
|
+ get_builtin_migration_feature_index(&compute_budget::id()),
|
|
|
|
|
+ BuiltinMigrationFeatureIndex::BuiltinNoMigrationFeature,
|
|
|
|
|
+ ));
|
|
|
|
|
+ let feature_index = get_builtin_migration_feature_index(&stake::id());
|
|
|
|
|
+ assert!(matches!(
|
|
|
|
|
+ feature_index,
|
|
|
|
|
+ BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(_)
|
|
|
|
|
+ ));
|
|
|
|
|
+ let BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(feature_index) =
|
|
|
|
|
+ feature_index
|
|
|
|
|
+ else {
|
|
|
|
|
+ panic!("expect migrating builtin")
|
|
|
|
|
+ };
|
|
|
|
|
+ assert_eq!(
|
|
|
|
|
+ get_migration_feature_id(feature_index),
|
|
|
|
|
+ &feature_set::migrate_stake_program_to_core_bpf::id()
|
|
|
|
|
+ );
|
|
|
|
|
+ let feature_index = get_builtin_migration_feature_index(&config::id());
|
|
|
|
|
+ assert!(matches!(
|
|
|
|
|
+ feature_index,
|
|
|
|
|
+ BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(_)
|
|
|
|
|
+ ));
|
|
|
|
|
+ let BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(feature_index) =
|
|
|
|
|
+ feature_index
|
|
|
|
|
+ else {
|
|
|
|
|
+ panic!("expect migrating builtin")
|
|
|
|
|
+ };
|
|
|
|
|
+ assert_eq!(
|
|
|
|
|
+ get_migration_feature_id(feature_index),
|
|
|
|
|
+ &feature_set::migrate_config_program_to_core_bpf::id()
|
|
|
|
|
+ );
|
|
|
|
|
+ let feature_index = get_builtin_migration_feature_index(&address_lookup_table::id());
|
|
|
|
|
+ assert!(matches!(
|
|
|
|
|
+ feature_index,
|
|
|
|
|
+ BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(_)
|
|
|
|
|
+ ));
|
|
|
|
|
+ let BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(feature_index) =
|
|
|
|
|
+ feature_index
|
|
|
|
|
+ else {
|
|
|
|
|
+ panic!("expect migrating builtin")
|
|
|
|
|
+ };
|
|
|
|
|
+ assert_eq!(
|
|
|
|
|
+ get_migration_feature_id(feature_index),
|
|
|
|
|
+ &feature_set::migrate_address_lookup_table_program_to_core_bpf::id()
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ #[should_panic(expected = "valid index of MIGRATING_BUILTINS_COSTS")]
|
|
|
|
|
+ fn test_get_migration_feature_id_invalid_index() {
|
|
|
|
|
+ let _ = get_migration_feature_id(MIGRATING_BUILTINS_COSTS.len() + 1);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|