From 7c625131825b47fd67008932bf9c4ac94b3f5f06 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Tue, 10 Dec 2024 19:59:51 +0900 Subject: [PATCH 1/9] builtins: reorder field names --- builtins/src/lib.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/builtins/src/lib.rs b/builtins/src/lib.rs index 5ba11fbf1cd937..98dfa8c4304d7e 100644 --- a/builtins/src/lib.rs +++ b/builtins/src/lib.rs @@ -23,11 +23,12 @@ use { macro_rules! testable_prototype { ($prototype:ident { - core_bpf_migration_config: $core_bpf_migration_config:expr, name: $name:ident, + core_bpf_migration_config: $core_bpf_migration_config:expr, $($field:ident : $value:expr),* $(,)? }) => { $prototype { + name: stringify!($name), core_bpf_migration_config: { #[cfg(not(feature = "dev-context-only-utils"))] { @@ -38,7 +39,6 @@ macro_rules! testable_prototype { Some( test_only::$name::CONFIG ) } }, - name: stringify!($name), $($field: $value),* } }; @@ -51,20 +51,21 @@ macro_rules! testable_prototype { /// remove that builtin entry from solana-builtin-default-costs::BUILTIN_INSTRUCTION_COSTS. pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { - core_bpf_migration_config: None, name: system_program, + core_bpf_migration_config: None, enable_feature_id: None, program_id: solana_system_program::id(), entrypoint: solana_system_program::system_processor::Entrypoint::vm, }), testable_prototype!(BuiltinPrototype { - core_bpf_migration_config: None, name: vote_program, + core_bpf_migration_config: None, enable_feature_id: None, program_id: solana_vote_program::id(), entrypoint: solana_vote_program::vote_processor::Entrypoint::vm, }), BuiltinPrototype { + name: "stake_program", core_bpf_migration_config: Some(CoreBpfMigrationConfig { source_buffer_address: buffer_accounts::stake_program::id(), upgrade_authority_address: None, @@ -72,12 +73,12 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ migration_target: CoreBpfMigrationTargetType::Builtin, datapoint_name: "migrate_builtin_to_core_bpf_stake_program", }), - name: "stake_program", enable_feature_id: None, program_id: solana_stake_program::id(), entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm, }, BuiltinPrototype { + name: "config_program", core_bpf_migration_config: Some(CoreBpfMigrationConfig { source_buffer_address: buffer_accounts::config_program::id(), upgrade_authority_address: None, @@ -85,40 +86,40 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ migration_target: CoreBpfMigrationTargetType::Builtin, datapoint_name: "migrate_builtin_to_core_bpf_config_program", }), - name: "config_program", enable_feature_id: None, program_id: solana_config_program::id(), entrypoint: solana_config_program::config_processor::Entrypoint::vm, }, testable_prototype!(BuiltinPrototype { - core_bpf_migration_config: None, name: solana_bpf_loader_deprecated_program, + core_bpf_migration_config: None, enable_feature_id: None, program_id: bpf_loader_deprecated::id(), entrypoint: solana_bpf_loader_program::Entrypoint::vm, }), testable_prototype!(BuiltinPrototype { - core_bpf_migration_config: None, name: solana_bpf_loader_program, + core_bpf_migration_config: None, enable_feature_id: None, program_id: bpf_loader::id(), entrypoint: solana_bpf_loader_program::Entrypoint::vm, }), testable_prototype!(BuiltinPrototype { - core_bpf_migration_config: None, name: solana_bpf_loader_upgradeable_program, + core_bpf_migration_config: None, enable_feature_id: None, program_id: bpf_loader_upgradeable::id(), entrypoint: solana_bpf_loader_program::Entrypoint::vm, }), testable_prototype!(BuiltinPrototype { - core_bpf_migration_config: None, name: compute_budget_program, + core_bpf_migration_config: None, enable_feature_id: None, program_id: solana_sdk_ids::compute_budget::id(), entrypoint: solana_compute_budget_program::Entrypoint::vm, }), BuiltinPrototype { + name: "address_lookup_table_program", core_bpf_migration_config: Some(CoreBpfMigrationConfig { source_buffer_address: buffer_accounts::address_lookup_table_program::id(), upgrade_authority_address: None, @@ -126,28 +127,27 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ migration_target: CoreBpfMigrationTargetType::Builtin, datapoint_name: "migrate_builtin_to_core_bpf_address_lookup_table_program", }), - name: "address_lookup_table_program", enable_feature_id: None, program_id: solana_sdk_ids::address_lookup_table::id(), entrypoint: solana_address_lookup_table_program::processor::Entrypoint::vm, }, testable_prototype!(BuiltinPrototype { - core_bpf_migration_config: None, name: zk_token_proof_program, + core_bpf_migration_config: None, enable_feature_id: Some(feature_set::zk_token_sdk_enabled::id()), program_id: solana_sdk_ids::zk_token_proof_program::id(), entrypoint: solana_zk_token_proof_program::Entrypoint::vm, }), testable_prototype!(BuiltinPrototype { - core_bpf_migration_config: None, name: loader_v4, + core_bpf_migration_config: None, enable_feature_id: Some(feature_set::enable_program_runtime_v2_and_loader_v4::id()), program_id: solana_sdk_ids::loader_v4::id(), entrypoint: solana_loader_v4_program::Entrypoint::vm, }), testable_prototype!(BuiltinPrototype { - core_bpf_migration_config: None, name: zk_elgamal_proof_program, + core_bpf_migration_config: None, enable_feature_id: Some(feature_set::zk_elgamal_proof_program_enabled::id()), program_id: solana_sdk_ids::zk_elgamal_proof_program::id(), entrypoint: solana_zk_elgamal_proof_program::Entrypoint::vm, From d0fc2f8a78b15b668552859db9c3d8c7e449a167 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Tue, 10 Dec 2024 20:12:23 +0900 Subject: [PATCH 2/9] builtins: add cost modeling config --- builtins/src/cost_modeling.rs | 13 +++++++++++++ builtins/src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ builtins/src/prototype.rs | 8 ++++++-- 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 builtins/src/cost_modeling.rs diff --git a/builtins/src/cost_modeling.rs b/builtins/src/cost_modeling.rs new file mode 100644 index 00000000000000..4cab7d41127d3b --- /dev/null +++ b/builtins/src/cost_modeling.rs @@ -0,0 +1,13 @@ +//! Configurations for handling cost modeling of builtin programs. + +/// Configuration for cost modeling of a builtin program. +#[derive(Debug)] +pub enum CostModelingConfig { + /// The builtin program is cost modeled. + CostModeled { + /// The default cost of the builtin program. + default_cost: u64, + }, + /// The builtin program is not cost modeled. + NotCostModeled, +} diff --git a/builtins/src/lib.rs b/builtins/src/lib.rs index 98dfa8c4304d7e..954167ffcb7477 100644 --- a/builtins/src/lib.rs +++ b/builtins/src/lib.rs @@ -10,11 +10,13 @@ //! Core BPF, as well as whether or not that feature gate has been activated. pub mod core_bpf_migration; +pub mod cost_modeling; pub mod prototype; use { crate::{ core_bpf_migration::{CoreBpfMigrationConfig, CoreBpfMigrationTargetType}, + cost_modeling::CostModelingConfig, prototype::{BuiltinPrototype, StatelessBuiltinPrototype}, }, solana_feature_set as feature_set, @@ -53,6 +55,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: system_program, core_bpf_migration_config: None, + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_system_program::system_processor::DEFAULT_COMPUTE_UNITS, + }, enable_feature_id: None, program_id: solana_system_program::id(), entrypoint: solana_system_program::system_processor::Entrypoint::vm, @@ -60,6 +65,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: vote_program, core_bpf_migration_config: None, + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_vote_program::vote_processor::DEFAULT_COMPUTE_UNITS, + }, enable_feature_id: None, program_id: solana_vote_program::id(), entrypoint: solana_vote_program::vote_processor::Entrypoint::vm, @@ -73,6 +81,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ migration_target: CoreBpfMigrationTargetType::Builtin, datapoint_name: "migrate_builtin_to_core_bpf_stake_program", }), + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_stake_program::stake_instruction::DEFAULT_COMPUTE_UNITS, + }, enable_feature_id: None, program_id: solana_stake_program::id(), entrypoint: solana_stake_program::stake_instruction::Entrypoint::vm, @@ -86,6 +97,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ migration_target: CoreBpfMigrationTargetType::Builtin, datapoint_name: "migrate_builtin_to_core_bpf_config_program", }), + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_config_program::config_processor::DEFAULT_COMPUTE_UNITS, + }, enable_feature_id: None, program_id: solana_config_program::id(), entrypoint: solana_config_program::config_processor::Entrypoint::vm, @@ -93,6 +107,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: solana_bpf_loader_deprecated_program, core_bpf_migration_config: None, + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_bpf_loader_program::DEPRECATED_LOADER_COMPUTE_UNITS, + }, enable_feature_id: None, program_id: bpf_loader_deprecated::id(), entrypoint: solana_bpf_loader_program::Entrypoint::vm, @@ -100,6 +117,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: solana_bpf_loader_program, core_bpf_migration_config: None, + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS, + }, enable_feature_id: None, program_id: bpf_loader::id(), entrypoint: solana_bpf_loader_program::Entrypoint::vm, @@ -107,6 +127,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: solana_bpf_loader_upgradeable_program, core_bpf_migration_config: None, + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_bpf_loader_program::UPGRADEABLE_LOADER_COMPUTE_UNITS, + }, enable_feature_id: None, program_id: bpf_loader_upgradeable::id(), entrypoint: solana_bpf_loader_program::Entrypoint::vm, @@ -114,6 +137,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: compute_budget_program, core_bpf_migration_config: None, + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_compute_budget_program::DEFAULT_COMPUTE_UNITS, + }, enable_feature_id: None, program_id: solana_sdk_ids::compute_budget::id(), entrypoint: solana_compute_budget_program::Entrypoint::vm, @@ -127,6 +153,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ migration_target: CoreBpfMigrationTargetType::Builtin, datapoint_name: "migrate_builtin_to_core_bpf_address_lookup_table_program", }), + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_address_lookup_table_program::processor::DEFAULT_COMPUTE_UNITS, + }, enable_feature_id: None, program_id: solana_sdk_ids::address_lookup_table::id(), entrypoint: solana_address_lookup_table_program::processor::Entrypoint::vm, @@ -134,6 +163,7 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: zk_token_proof_program, core_bpf_migration_config: None, + cost_modeling_config: CostModelingConfig::NotCostModeled, // WARNING: DO NOT CHANGE WITHOUT FEATURE GATE!! enable_feature_id: Some(feature_set::zk_token_sdk_enabled::id()), program_id: solana_sdk_ids::zk_token_proof_program::id(), entrypoint: solana_zk_token_proof_program::Entrypoint::vm, @@ -141,6 +171,9 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: loader_v4, core_bpf_migration_config: None, + cost_modeling_config: CostModelingConfig::CostModeled { + default_cost: solana_loader_v4_program::DEFAULT_COMPUTE_UNITS, + }, enable_feature_id: Some(feature_set::enable_program_runtime_v2_and_loader_v4::id()), program_id: solana_sdk_ids::loader_v4::id(), entrypoint: solana_loader_v4_program::Entrypoint::vm, @@ -148,6 +181,7 @@ pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: zk_elgamal_proof_program, core_bpf_migration_config: None, + cost_modeling_config: CostModelingConfig::NotCostModeled, // WARNING: DO NOT CHANGE WITHOUT FEATURE GATE!! enable_feature_id: Some(feature_set::zk_elgamal_proof_program_enabled::id()), program_id: solana_sdk_ids::zk_elgamal_proof_program::id(), entrypoint: solana_zk_elgamal_proof_program::Entrypoint::vm, diff --git a/builtins/src/prototype.rs b/builtins/src/prototype.rs index 2b76dd5c353fec..b9147dd07a5ff5 100644 --- a/builtins/src/prototype.rs +++ b/builtins/src/prototype.rs @@ -1,14 +1,17 @@ //! Prototype layouts for builtins. use { - crate::core_bpf_migration::CoreBpfMigrationConfig, - solana_program_runtime::invoke_context::BuiltinFunctionWithContext, solana_pubkey::Pubkey, + crate::{core_bpf_migration::CoreBpfMigrationConfig, cost_modeling::CostModelingConfig}, + solana_program_runtime::invoke_context::BuiltinFunctionWithContext, + solana_pubkey::Pubkey, }; /// Transitions of built-in programs at epoch boundaries when features are activated. pub struct BuiltinPrototype { /// Configurations for migrating the builtin to Core BPF. pub core_bpf_migration_config: Option, + /// Configurations for cost modeling. + pub cost_modeling_config: CostModelingConfig, /// Feature ID that enables the builtin program. /// If None, the built-in program is always enabled. pub enable_feature_id: Option, @@ -27,6 +30,7 @@ impl std::fmt::Debug for BuiltinPrototype { builder.field("name", &self.name); builder.field("enable_feature_id", &self.enable_feature_id); builder.field("core_bpf_migration_config", &self.core_bpf_migration_config); + builder.field("cost_modeling_config", &self.cost_modeling_config); builder.finish() } } From 7ebab93bfcc563b43ee8d07c0bb51e6c5e8304a5 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Tue, 10 Dec 2024 21:04:27 +0900 Subject: [PATCH 3/9] builtins: port over cost modeling lookups --- Cargo.lock | 2 + builtins/Cargo.toml | 2 + builtins/src/cost_modeling.rs | 218 ++++++++++++++++++++++++++++++++++ programs/sbf/Cargo.lock | 2 + svm/examples/Cargo.lock | 2 + 5 files changed, 226 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 23c429edd446de..41f54c6d9d2d65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6286,6 +6286,8 @@ dependencies = [ name = "solana-builtins" version = "2.2.0" dependencies = [ + "ahash 0.8.11", + "lazy_static", "solana-address-lookup-table-program", "solana-bpf-loader-program", "solana-compute-budget-program", diff --git a/builtins/Cargo.toml b/builtins/Cargo.toml index 3cdf7f63e64136..637a4af083012c 100644 --- a/builtins/Cargo.toml +++ b/builtins/Cargo.toml @@ -13,6 +13,8 @@ edition = { workspace = true } dev-context-only-utils = [] [dependencies] +ahash = { workspace = true } +lazy_static = { workspace = true } solana-address-lookup-table-program = { workspace = true } solana-bpf-loader-program = { workspace = true } solana-compute-budget-program = { workspace = true } diff --git a/builtins/src/cost_modeling.rs b/builtins/src/cost_modeling.rs index 4cab7d41127d3b..a23161d056861e 100644 --- a/builtins/src/cost_modeling.rs +++ b/builtins/src/cost_modeling.rs @@ -1,5 +1,14 @@ //! Configurations for handling cost modeling of builtin programs. +use { + crate::BUILTINS, + ahash::AHashMap, + lazy_static::lazy_static, + solana_feature_set::FeatureSet, + solana_pubkey::Pubkey, + solana_sdk_ids::{ed25519_program, secp256k1_program}, +}; + /// Configuration for cost modeling of a builtin program. #[derive(Debug)] pub enum CostModelingConfig { @@ -11,3 +20,212 @@ pub enum CostModelingConfig { /// The builtin program is not cost modeled. NotCostModeled, } + +struct BuiltinCost { + default_cost: u64, + core_bpf_migration_feature: Option, +} + +lazy_static! { + static ref BUILTIN_INSTRUCTION_COSTS: AHashMap = BUILTINS + .iter() + .filter_map(|builtin| { + match builtin.cost_modeling_config { + CostModelingConfig::CostModeled { default_cost } => Some(( + builtin.program_id, + BuiltinCost { + default_cost, + core_bpf_migration_feature: builtin + .core_bpf_migration_config + .as_ref() + .map(|config| config.feature_id), + }, + )), + CostModelingConfig::NotCostModeled => { + None + } + } + }) + .chain( + [ + ( + secp256k1_program::id(), + BuiltinCost { + default_cost: 0, // Hard-coded to zero. + core_bpf_migration_feature: None, + }, + ), + ( + ed25519_program::id(), + BuiltinCost { + default_cost: 0, // Hard-coded to zero. + core_bpf_migration_feature: None, + }, + ), + ] + .into_iter() + ) + .collect(); +} + +lazy_static! { + /// A table of 256 booleans indicates whether the first `u8` of a Pubkey exists in + /// BUILTIN_INSTRUCTION_COSTS. If the value is true, the Pubkey might be a builtin key; + /// if false, it cannot be a builtin key. This table allows for quick filtering of + /// builtin program IDs without the need for hashing. + pub static ref MAYBE_BUILTIN_KEY: [bool; 256] = { + let mut temp_table: [bool; 256] = [false; 256]; + BUILTIN_INSTRUCTION_COSTS + .keys() + .for_each(|key| temp_table[key.as_ref()[0] as usize] = true); + temp_table + }; +} + +pub fn get_builtin_instruction_cost<'a>( + program_id: &'a Pubkey, + feature_set: &'a FeatureSet, +) -> Option { + BUILTIN_INSTRUCTION_COSTS + .get(program_id) + .and_then(|builtin_cost| { + // If the program has a Core BPF Migration feature and that feature + // is active, then the program is not considered a builtin. + if builtin_cost + .core_bpf_migration_feature + .is_some_and(|feature_id| feature_set.is_active(&feature_id)) + { + return None; + } + // Otherwise, return the default cost. + Some(builtin_cost.default_cost) + }) +} + +#[inline] +pub fn is_builtin_program(program_id: &Pubkey) -> bool { + BUILTIN_INSTRUCTION_COSTS.contains_key(program_id) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_maybe_builtin_key() { + let check = |key: &Pubkey, expected: bool| { + assert_eq!(MAYBE_BUILTIN_KEY[key.as_ref()[0] as usize], expected); + assert_eq!(is_builtin_program(key), expected); + }; + + check(&solana_sdk_ids::system_program::id(), true); + check(&solana_sdk_ids::vote::id(), true); + check(&solana_sdk_ids::stake::id(), true); + check(&solana_sdk_ids::config::id(), true); + check(&solana_sdk_ids::bpf_loader_deprecated::id(), true); + check(&solana_sdk_ids::bpf_loader::id(), true); + check(&solana_sdk_ids::bpf_loader_upgradeable::id(), true); + check(&solana_sdk_ids::compute_budget::id(), true); + check(&solana_sdk_ids::address_lookup_table::id(), true); + check(&solana_sdk_ids::loader_v4::id(), true); + check(&solana_sdk_ids::ed25519_program::id(), true); + check(&solana_sdk_ids::secp256k1_program::id(), true); + + // Not cost modeled. + check(&solana_sdk_ids::zk_elgamal_proof_program::id(), false); + check(&solana_sdk_ids::zk_token_proof_program::id(), false); + + // Not builtins. + check(&Pubkey::new_from_array([1; 32]), false); + check(&Pubkey::new_from_array([9; 32]), false); + } + + #[test] + fn test_get_builtin_instruction_cost() { + let feature_set = FeatureSet::all_enabled(); + + // Default cost defined, no migration. + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::system_program::id(), &feature_set), + Some(solana_system_program::system_processor::DEFAULT_COMPUTE_UNITS), + ); + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::vote::id(), &feature_set), + Some(solana_vote_program::vote_processor::DEFAULT_COMPUTE_UNITS), + ); + assert_eq!( + get_builtin_instruction_cost( + &solana_sdk_ids::bpf_loader_deprecated::id(), + &feature_set + ), + Some(solana_bpf_loader_program::DEPRECATED_LOADER_COMPUTE_UNITS), + ); + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::bpf_loader::id(), &feature_set), + Some(solana_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS), + ); + assert_eq!( + get_builtin_instruction_cost( + &solana_sdk_ids::bpf_loader_upgradeable::id(), + &feature_set + ), + Some(solana_bpf_loader_program::UPGRADEABLE_LOADER_COMPUTE_UNITS), + ); + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::compute_budget::id(), &feature_set), + Some(solana_compute_budget_program::DEFAULT_COMPUTE_UNITS), + ); + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::loader_v4::id(), &feature_set), + Some(solana_loader_v4_program::DEFAULT_COMPUTE_UNITS), + ); + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::ed25519_program::id(), &feature_set), + Some(0), + ); + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::secp256k1_program::id(), &feature_set), + Some(0), + ); + + // Default cost defined, migration active. + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::stake::id(), &feature_set), + None, + ); + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::config::id(), &feature_set), + None, + ); + assert_eq!( + get_builtin_instruction_cost(&solana_sdk_ids::address_lookup_table::id(), &feature_set), + None, + ); + + // Not cost modeled. + assert_eq!( + get_builtin_instruction_cost( + &solana_sdk_ids::zk_elgamal_proof_program::id(), + &feature_set + ), + None, + ); + assert_eq!( + get_builtin_instruction_cost( + &solana_sdk_ids::zk_token_proof_program::id(), + &feature_set + ), + None, + ); + + // Not a builtin from the list. + assert_eq!( + get_builtin_instruction_cost(&Pubkey::new_unique(), &feature_set), + None, + ); + assert_eq!( + get_builtin_instruction_cost(&Pubkey::new_unique(), &feature_set), + None, + ); + } +} diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index b5ae6a5cfd16b9..334a6198c5b651 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5155,6 +5155,8 @@ dependencies = [ name = "solana-builtins" version = "2.2.0" dependencies = [ + "ahash 0.8.11", + "lazy_static", "solana-address-lookup-table-program", "solana-bpf-loader-program", "solana-compute-budget-program", diff --git a/svm/examples/Cargo.lock b/svm/examples/Cargo.lock index 10e72b4ec732ff..3d31dfb2a230f2 100644 --- a/svm/examples/Cargo.lock +++ b/svm/examples/Cargo.lock @@ -5006,6 +5006,8 @@ dependencies = [ name = "solana-builtins" version = "2.2.0" dependencies = [ + "ahash 0.8.11", + "lazy_static", "solana-address-lookup-table-program", "solana-bpf-loader-program", "solana-compute-budget-program", From c99f3b1985b230c06e7a518faabfe21ac9a194c7 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Wed, 18 Dec 2024 13:27:29 +0800 Subject: [PATCH 4/9] builtins: add core bpf migration cost modeling --- builtins/src/cost_modeling.rs | 72 +++++++++++++++++++++++++++++++++++ builtins/src/lib.rs | 1 + 2 files changed, 73 insertions(+) diff --git a/builtins/src/cost_modeling.rs b/builtins/src/cost_modeling.rs index a23161d056861e..1b89f5c73e2e42 100644 --- a/builtins/src/cost_modeling.rs +++ b/builtins/src/cost_modeling.rs @@ -9,6 +9,11 @@ use { solana_sdk_ids::{ed25519_program, secp256k1_program}, }; +/// CONTRIBUTOR: If you change any builtin Core BPF migration confiurations +/// in this crate's `BUILTINS` list, you must update this constant to reflect +/// the number of builtin programs that have Core BPF migration configurations. +pub const NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS: usize = 3; + /// Configuration for cost modeling of a builtin program. #[derive(Debug)] pub enum CostModelingConfig { @@ -21,11 +26,24 @@ pub enum CostModelingConfig { NotCostModeled, } +impl CostModelingConfig { + /// Returns `true` if the builtin program is cost modeled. + pub fn is_cost_modeled(&self) -> bool { + matches!(self, Self::CostModeled { .. }) + } +} + struct BuiltinCost { default_cost: u64, core_bpf_migration_feature: Option, } +#[derive(Copy, Clone, Default)] +struct BuiltinWithMigration { + program_id: Pubkey, + migration_feature_id: Pubkey, +} + lazy_static! { static ref BUILTIN_INSTRUCTION_COSTS: AHashMap = BUILTINS .iter() @@ -82,6 +100,27 @@ lazy_static! { }; } +lazy_static! { + // This lazy-static list is designed to panic if any builtin migrations + // are changed without updating `NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS`. + static ref COST_MODELED_BUILTINS_WITH_MIGRATIONS: [BuiltinWithMigration; NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS] = { + let mut temp = [BuiltinWithMigration::default(); NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS]; + let mut i: usize = 0; + for builtin in BUILTINS.iter() { + if builtin.cost_modeling_config.is_cost_modeled() { + if let Some(migration_config) = &builtin.core_bpf_migration_config { + temp[i] = BuiltinWithMigration { + program_id: builtin.program_id, + migration_feature_id: migration_config.feature_id, + }; + i = i.saturating_add(1); + } + } + } + temp + }; +} + pub fn get_builtin_instruction_cost<'a>( program_id: &'a Pubkey, feature_set: &'a FeatureSet, @@ -107,10 +146,43 @@ pub fn is_builtin_program(program_id: &Pubkey) -> bool { BUILTIN_INSTRUCTION_COSTS.contains_key(program_id) } +/// Returns the index of a builtin in `COST_MODELED_BUILTINS_WITH_MIGRATIONS`, +/// if it exists in the list. +pub fn get_builtin_migration_feature_index(program_id: &Pubkey) -> Option { + COST_MODELED_BUILTINS_WITH_MIGRATIONS + .iter() + .position(|builtin| builtin.program_id == *program_id) +} + +/// Returns the feature ID of a builtin in `COST_MODELED_BUILTINS_WITH_MIGRATIONS` +/// by index. Panics if the index is out of bounds. +pub fn get_builtin_migration_feature_id(index: usize) -> &'static Pubkey { + &COST_MODELED_BUILTINS_WITH_MIGRATIONS[index].migration_feature_id +} + +/// Returns the index of a builtin in `COST_MODELED_BUILTINS_WITH_MIGRATIONS` +/// by feature ID. If the feature ID is not found, returns `None`. +pub fn get_builtin_migration_feature_index_from_feature_id(feature_id: &Pubkey) -> Option { + COST_MODELED_BUILTINS_WITH_MIGRATIONS + .iter() + .position(|builtin| builtin.migration_feature_id == *feature_id) +} + #[cfg(test)] mod test { use super::*; + #[cfg(not(feature = "dev-context-only-utils"))] + #[test] + fn test_cost_modeled_builtins_with_migrations_compiles() { + // This test is a compile-time check to ensure that the number of + // cost-modeled builtins with migration features matches the constant. + assert_eq!( + COST_MODELED_BUILTINS_WITH_MIGRATIONS.len(), + NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS + ); + } + #[test] fn test_maybe_builtin_key() { let check = |key: &Pubkey, expected: bool| { diff --git a/builtins/src/lib.rs b/builtins/src/lib.rs index 954167ffcb7477..dc6b17825d9857 100644 --- a/builtins/src/lib.rs +++ b/builtins/src/lib.rs @@ -403,6 +403,7 @@ mod tests { // Since a macro is used to initialize the test IDs from the `test_only` // module, best to ensure the lists have the expected values within a test // context. + #[cfg(feature = "dev-context-only-utils")] #[test] fn test_testable_prototypes() { assert_eq!( From 257727a1c3725efc370ee4bec85fcdf130b64030 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Wed, 18 Dec 2024 13:37:56 +0800 Subject: [PATCH 5/9] compute-budget-instruction: integrate builtins --- Cargo.lock | 6 ++-- compute-budget-instruction/Cargo.toml | 3 +- .../src/builtin_programs_filter.rs | 31 ++++++++++--------- .../src/compute_budget_instruction_details.rs | 24 ++++++++------ .../src/compute_budget_program_id_filter.rs | 2 +- core/Cargo.toml | 2 +- core/src/banking_stage/packet_filter.rs | 2 +- cost-model/Cargo.toml | 2 +- cost-model/src/cost_model.rs | 2 +- programs/sbf/Cargo.lock | 26 ++-------------- svm/examples/Cargo.lock | 26 ++-------------- 11 files changed, 47 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41f54c6d9d2d65..92d296a8a280c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6666,7 +6666,7 @@ dependencies = [ "criterion", "log", "rand 0.8.5", - "solana-builtins-default-costs", + "solana-builtins", "solana-compute-budget", "solana-program", "solana-pubkey", @@ -6793,7 +6793,7 @@ dependencies = [ "solana-accounts-db", "solana-address-lookup-table-program", "solana-bloom", - "solana-builtins-default-costs", + "solana-builtins", "solana-client", "solana-compute-budget", "solana-compute-budget-instruction", @@ -6866,7 +6866,7 @@ dependencies = [ "lazy_static", "log", "rand 0.8.5", - "solana-builtins-default-costs", + "solana-builtins", "solana-compute-budget", "solana-compute-budget-instruction", "solana-compute-budget-program", diff --git a/compute-budget-instruction/Cargo.toml b/compute-budget-instruction/Cargo.toml index 8e5bdd0b1c9bf7..9e505487c1c16d 100644 --- a/compute-budget-instruction/Cargo.toml +++ b/compute-budget-instruction/Cargo.toml @@ -11,7 +11,7 @@ edition = { workspace = true } [dependencies] log = { workspace = true } -solana-builtins-default-costs = { workspace = true } +solana-builtins = { workspace = true } solana-compute-budget = { workspace = true } solana-pubkey = { workspace = true } solana-sdk = { workspace = true } @@ -26,7 +26,6 @@ name = "solana_compute_budget_instruction" bincode = { workspace = true } criterion = { workspace = true } rand = { workspace = true } -solana-builtins-default-costs = { workspace = true, features = ["dev-context-only-utils"] } solana-program = { workspace = true } [package.metadata.docs.rs] diff --git a/compute-budget-instruction/src/builtin_programs_filter.rs b/compute-budget-instruction/src/builtin_programs_filter.rs index 1525dd1f2cfc61..7d1ba3aff91b24 100644 --- a/compute-budget-instruction/src/builtin_programs_filter.rs +++ b/compute-budget-instruction/src/builtin_programs_filter.rs @@ -1,6 +1,6 @@ use { - solana_builtins_default_costs::{ - get_builtin_migration_feature_index, BuiltinMigrationFeatureIndex, MAYBE_BUILTIN_KEY, + solana_builtins::cost_modeling::{ + get_builtin_migration_feature_index, is_builtin_program, MAYBE_BUILTIN_KEY, }, solana_sdk::{packet::PACKET_DATA_SIZE, pubkey::Pubkey}, }; @@ -48,14 +48,16 @@ impl BuiltinProgramsFilter { return ProgramKind::NotBuiltin; } - match get_builtin_migration_feature_index(program_id) { - BuiltinMigrationFeatureIndex::NotBuiltin => ProgramKind::NotBuiltin, - BuiltinMigrationFeatureIndex::BuiltinNoMigrationFeature => ProgramKind::Builtin, - BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature( - core_bpf_migration_feature_index, - ) => ProgramKind::MigratingBuiltin { - core_bpf_migration_feature_index, - }, + if is_builtin_program(program_id) { + if let Some(index) = get_builtin_migration_feature_index(program_id) { + ProgramKind::MigratingBuiltin { + core_bpf_migration_feature_index: index, + } + } else { + ProgramKind::Builtin + } + } else { + ProgramKind::NotBuiltin } } } @@ -63,7 +65,8 @@ impl BuiltinProgramsFilter { #[cfg(test)] mod test { use { - super::*, solana_builtins_default_costs::get_migration_feature_position, + super::*, + solana_builtins::cost_modeling::get_builtin_migration_feature_index_from_feature_id, solana_sdk::feature_set, }; @@ -127,9 +130,9 @@ mod test { assert_eq!( test_store.get_program_kind(index, &migrating_builtin_pubkey), ProgramKind::MigratingBuiltin { - core_bpf_migration_feature_index: get_migration_feature_position( - &migration_feature_id - ), + core_bpf_migration_feature_index: + get_builtin_migration_feature_index_from_feature_id(&migration_feature_id) + .unwrap(), } ); } diff --git a/compute-budget-instruction/src/compute_budget_instruction_details.rs b/compute-budget-instruction/src/compute_budget_instruction_details.rs index e0ef6341694167..45ee08654ec13e 100644 --- a/compute-budget-instruction/src/compute_budget_instruction_details.rs +++ b/compute-budget-instruction/src/compute_budget_instruction_details.rs @@ -3,7 +3,9 @@ use { builtin_programs_filter::{BuiltinProgramsFilter, ProgramKind}, compute_budget_program_id_filter::ComputeBudgetProgramIdFilter, }, - solana_builtins_default_costs::{get_migration_feature_id, MIGRATING_BUILTINS_COSTS}, + solana_builtins::cost_modeling::{ + get_builtin_migration_feature_id, NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS, + }, solana_compute_budget::compute_budget_limits::*, solana_sdk::{ borsh1::try_from_slice_unchecked, @@ -22,16 +24,17 @@ use { #[cfg_attr(feature = "dev-context-only-utils", derive(Clone))] #[derive(Debug)] struct MigrationBuiltinFeatureCounter { - // The vector of counters, matching the size of the static vector MIGRATION_FEATURE_IDS, - // each counter representing the number of times its corresponding feature ID is + // The vector of counters, matching the size of the + // `NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS` constant, each counter + // representing the number of times its corresponding feature ID is // referenced in this transaction. - migrating_builtin: [u16; MIGRATING_BUILTINS_COSTS.len()], + migrating_builtin: [u16; NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS], } impl Default for MigrationBuiltinFeatureCounter { fn default() -> Self { Self { - migrating_builtin: [0; MIGRATING_BUILTINS_COSTS.len()], + migrating_builtin: [0; NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS], } } } @@ -217,7 +220,8 @@ impl ComputeBudgetInstructionDetails { .iter() .enumerate() .fold((0, 0), |(migrated, not_migrated), (index, count)| { - if *count > 0 && feature_set.is_active(get_migration_feature_id(index)) { + if *count > 0 && feature_set.is_active(get_builtin_migration_feature_id(index)) + { (migrated + count, not_migrated) } else { (migrated, not_migrated + count) @@ -243,7 +247,7 @@ impl ComputeBudgetInstructionDetails { mod test { use { super::*, - solana_builtins_default_costs::get_migration_feature_position, + solana_builtins::cost_modeling::get_builtin_migration_feature_index_from_feature_id, solana_sdk::{ instruction::Instruction, message::Message, @@ -585,8 +589,10 @@ mod test { &Pubkey::new_unique(), ), ]); - let feature_id_index = - get_migration_feature_position(&feature_set::migrate_stake_program_to_core_bpf::id()); + let feature_id_index = get_builtin_migration_feature_index_from_feature_id( + &feature_set::migrate_stake_program_to_core_bpf::id(), + ) + .unwrap(); let mut expected_details = ComputeBudgetInstructionDetails { num_non_compute_budget_instructions: 2, num_non_builtin_instructions: 1, diff --git a/compute-budget-instruction/src/compute_budget_program_id_filter.rs b/compute-budget-instruction/src/compute_budget_program_id_filter.rs index 62ec47b7209ef0..b606626635e8fc 100644 --- a/compute-budget-instruction/src/compute_budget_program_id_filter.rs +++ b/compute-budget-instruction/src/compute_budget_program_id_filter.rs @@ -1,6 +1,6 @@ // static account keys has max use { - crate::builtin_programs_filter::FILTER_SIZE, solana_builtins_default_costs::MAYBE_BUILTIN_KEY, + crate::builtin_programs_filter::FILTER_SIZE, solana_builtins::cost_modeling::MAYBE_BUILTIN_KEY, solana_sdk::pubkey::Pubkey, }; diff --git a/core/Cargo.toml b/core/Cargo.toml index 0143180ced5b4d..4ae5405d0ece67 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -47,7 +47,7 @@ serde_derive = { workspace = true } slab = { workspace = true } solana-accounts-db = { workspace = true } solana-bloom = { workspace = true } -solana-builtins-default-costs = { workspace = true } +solana-builtins = { workspace = true } solana-client = { workspace = true } solana-compute-budget = { workspace = true } solana-compute-budget-instruction = { workspace = true } diff --git a/core/src/banking_stage/packet_filter.rs b/core/src/banking_stage/packet_filter.rs index b9176c9b8ac91d..b87624d8abd86f 100644 --- a/core/src/banking_stage/packet_filter.rs +++ b/core/src/banking_stage/packet_filter.rs @@ -1,7 +1,7 @@ use { super::immutable_deserialized_packet::ImmutableDeserializedPacket, lazy_static::lazy_static, - solana_builtins_default_costs::get_builtin_instruction_cost, + solana_builtins::cost_modeling::get_builtin_instruction_cost, solana_sdk::{ ed25519_program, feature_set::FeatureSet, saturating_add_assign, secp256k1_program, }, diff --git a/cost-model/Cargo.toml b/cost-model/Cargo.toml index 1e0593daedeeaa..b80a29b857047e 100644 --- a/cost-model/Cargo.toml +++ b/cost-model/Cargo.toml @@ -13,7 +13,7 @@ edition = { workspace = true } ahash = { workspace = true } lazy_static = { workspace = true } log = { workspace = true } -solana-builtins-default-costs = { workspace = true } +solana-builtins = { workspace = true } solana-compute-budget = { workspace = true } solana-compute-budget-instruction = { workspace = true } solana-feature-set = { workspace = true } diff --git a/cost-model/src/cost_model.rs b/cost-model/src/cost_model.rs index f958ce6cb4eed1..6588a8baffe233 100644 --- a/cost-model/src/cost_model.rs +++ b/cost-model/src/cost_model.rs @@ -7,7 +7,7 @@ use { crate::{block_cost_limits::*, transaction_cost::*}, - solana_builtins_default_costs::get_builtin_instruction_cost, + solana_builtins::cost_modeling::get_builtin_instruction_cost, solana_compute_budget::compute_budget_limits::{ DEFAULT_HEAP_COST, DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT, MAX_COMPUTE_UNIT_LIMIT, }, diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 334a6198c5b651..84c89c9d38f6b8 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5173,26 +5173,6 @@ dependencies = [ "solana-zk-token-proof-program", ] -[[package]] -name = "solana-builtins-default-costs" -version = "2.2.0" -dependencies = [ - "ahash 0.8.11", - "lazy_static", - "log", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-compute-budget-program", - "solana-config-program", - "solana-feature-set", - "solana-loader-v4-program", - "solana-pubkey", - "solana-sdk-ids", - "solana-stake-program", - "solana-system-program", - "solana-vote-program", -] - [[package]] name = "solana-clap-utils" version = "2.2.0" @@ -5363,7 +5343,7 @@ name = "solana-compute-budget-instruction" version = "2.2.0" dependencies = [ "log", - "solana-builtins-default-costs", + "solana-builtins", "solana-compute-budget", "solana-pubkey", "solana-sdk", @@ -5462,7 +5442,7 @@ dependencies = [ "slab", "solana-accounts-db", "solana-bloom", - "solana-builtins-default-costs", + "solana-builtins", "solana-client", "solana-compute-budget", "solana-compute-budget-instruction", @@ -5520,7 +5500,7 @@ dependencies = [ "ahash 0.8.11", "lazy_static", "log", - "solana-builtins-default-costs", + "solana-builtins", "solana-compute-budget", "solana-compute-budget-instruction", "solana-feature-set", diff --git a/svm/examples/Cargo.lock b/svm/examples/Cargo.lock index 3d31dfb2a230f2..e5e06d6c1d623f 100644 --- a/svm/examples/Cargo.lock +++ b/svm/examples/Cargo.lock @@ -5024,26 +5024,6 @@ dependencies = [ "solana-zk-token-proof-program", ] -[[package]] -name = "solana-builtins-default-costs" -version = "2.2.0" -dependencies = [ - "ahash 0.8.11", - "lazy_static", - "log", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-compute-budget-program", - "solana-config-program", - "solana-feature-set", - "solana-loader-v4-program", - "solana-pubkey", - "solana-sdk-ids", - "solana-stake-program", - "solana-system-program", - "solana-vote-program", -] - [[package]] name = "solana-clap-utils" version = "2.2.0" @@ -5214,7 +5194,7 @@ name = "solana-compute-budget-instruction" version = "2.2.0" dependencies = [ "log", - "solana-builtins-default-costs", + "solana-builtins", "solana-compute-budget", "solana-pubkey", "solana-sdk", @@ -5313,7 +5293,7 @@ dependencies = [ "slab", "solana-accounts-db", "solana-bloom", - "solana-builtins-default-costs", + "solana-builtins", "solana-client", "solana-compute-budget", "solana-compute-budget-instruction", @@ -5371,7 +5351,7 @@ dependencies = [ "ahash 0.8.11", "lazy_static", "log", - "solana-builtins-default-costs", + "solana-builtins", "solana-compute-budget", "solana-compute-budget-instruction", "solana-feature-set", From 8f0c37a3bda608f27490766e28fe96c1e99d0d0e Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Wed, 18 Dec 2024 13:42:19 +0800 Subject: [PATCH 6/9] drop builtins-default-costs crate --- Cargo.lock | 23 -- Cargo.toml | 2 - builtins-default-costs/Cargo.toml | 51 --- .../benches/builtin_instruction_costs.rs | 74 ---- builtins-default-costs/src/lib.rs | 378 ------------------ scripts/patch-crates.sh | 2 - 6 files changed, 530 deletions(-) delete mode 100644 builtins-default-costs/Cargo.toml delete mode 100644 builtins-default-costs/benches/builtin_instruction_costs.rs delete mode 100644 builtins-default-costs/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 92d296a8a280c7..9b8dda61c6cb02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6304,29 +6304,6 @@ dependencies = [ "solana-zk-token-proof-program", ] -[[package]] -name = "solana-builtins-default-costs" -version = "2.2.0" -dependencies = [ - "ahash 0.8.11", - "lazy_static", - "log", - "rand 0.8.5", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-compute-budget-program", - "solana-config-program", - "solana-feature-set", - "solana-frozen-abi", - "solana-loader-v4-program", - "solana-pubkey", - "solana-sdk-ids", - "solana-stake-program", - "solana-system-program", - "solana-vote-program", - "static_assertions", -] - [[package]] name = "solana-cargo-build-sbf" version = "2.2.0" diff --git a/Cargo.toml b/Cargo.toml index ac186c11930cf3..31209454ec5d74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,6 @@ members = [ "bloom", "bucket_map", "builtins", - "builtins-default-costs", "cargo-registry", "clap-utils", "clap-v3-utils", @@ -452,7 +451,6 @@ solana-borsh = { path = "sdk/borsh", version = "=2.2.0" } solana-bpf-loader-program = { path = "programs/bpf_loader", version = "=2.2.0" } solana-bucket-map = { path = "bucket_map", version = "=2.2.0" } solana-builtins = { path = "builtins", version = "=2.2.0" } -solana-builtins-default-costs = { path = "builtins-default-costs", version = "=2.2.0" } agave-cargo-registry = { path = "cargo-registry", version = "=2.2.0" } solana-clap-utils = { path = "clap-utils", version = "=2.2.0" } solana-clap-v3-utils = { path = "clap-v3-utils", version = "=2.2.0" } diff --git a/builtins-default-costs/Cargo.toml b/builtins-default-costs/Cargo.toml deleted file mode 100644 index 986ef59c9fcc7d..00000000000000 --- a/builtins-default-costs/Cargo.toml +++ /dev/null @@ -1,51 +0,0 @@ -[package] -name = "solana-builtins-default-costs" -description = "Solana builtins default costs" -documentation = "https://docs.rs/solana-builtins-default-costs" -version = { workspace = true } -authors = { workspace = true } -repository = { workspace = true } -homepage = { workspace = true } -license = { workspace = true } -edition = { workspace = true } - -[dependencies] -ahash = { workspace = true } -lazy_static = { workspace = true } -log = { workspace = true } -solana-address-lookup-table-program = { workspace = true } -solana-bpf-loader-program = { workspace = true } -solana-compute-budget-program = { workspace = true } -solana-config-program = { workspace = true } -solana-feature-set = { workspace = true } -solana-frozen-abi = { workspace = true, optional = true, features = [ - "frozen-abi", -] } -solana-loader-v4-program = { workspace = true } -solana-pubkey = { workspace = true } -solana-sdk-ids = { workspace = true } -solana-stake-program = { workspace = true } -solana-system-program = { workspace = true } -solana-vote-program = { workspace = true } -# Add additional builtin programs here - -[lib] -crate-type = ["lib"] -name = "solana_builtins_default_costs" - -[dev-dependencies] -rand = "0.8.5" -static_assertions = { workspace = true } - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[features] -frozen-abi = [ - "dep:solana-frozen-abi", - "solana-vote-program/frozen-abi", -] -dev-context-only-utils = [] - -[lints] -workspace = true diff --git a/builtins-default-costs/benches/builtin_instruction_costs.rs b/builtins-default-costs/benches/builtin_instruction_costs.rs deleted file mode 100644 index 71618852be5ef5..00000000000000 --- a/builtins-default-costs/benches/builtin_instruction_costs.rs +++ /dev/null @@ -1,74 +0,0 @@ -#![feature(test)] -extern crate test; -use { - rand::Rng, - solana_builtins_default_costs::get_builtin_instruction_cost, - solana_feature_set::FeatureSet, - solana_pubkey::Pubkey, - solana_sdk_ids::{ - address_lookup_table, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, - compute_budget, config, ed25519_program, loader_v4, secp256k1_program, stake, - system_program, vote, - }, - test::Bencher, -}; - -struct BenchSetup { - pubkeys: [Pubkey; 12], - feature_set: FeatureSet, -} - -const NUM_TRANSACTIONS_PER_ITER: usize = 1024; - -fn setup(all_features_enabled: bool) -> BenchSetup { - let pubkeys: [Pubkey; 12] = [ - stake::id(), - config::id(), - vote::id(), - system_program::id(), - compute_budget::id(), - address_lookup_table::id(), - bpf_loader_upgradeable::id(), - bpf_loader_deprecated::id(), - bpf_loader::id(), - loader_v4::id(), - secp256k1_program::id(), - ed25519_program::id(), - ]; - - let feature_set = if all_features_enabled { - FeatureSet::all_enabled() - } else { - FeatureSet::default() - }; - - BenchSetup { - pubkeys, - feature_set, - } -} - -fn do_hash_find(setup: &BenchSetup) { - for _t in 0..NUM_TRANSACTIONS_PER_ITER { - let idx = rand::thread_rng().gen_range(0..setup.pubkeys.len()); - get_builtin_instruction_cost(&setup.pubkeys[idx], &setup.feature_set); - } -} - -#[bench] -fn bench_hash_find_builtins_not_migrated(bencher: &mut Bencher) { - let bench_setup = setup(false); - - bencher.iter(|| { - do_hash_find(&bench_setup); - }); -} - -#[bench] -fn bench_hash_find_builtins_migrated(bencher: &mut Bencher) { - let bench_setup = setup(true); - - bencher.iter(|| { - do_hash_find(&bench_setup); - }); -} diff --git a/builtins-default-costs/src/lib.rs b/builtins-default-costs/src/lib.rs deleted file mode 100644 index a1c4000a75499d..00000000000000 --- a/builtins-default-costs/src/lib.rs +++ /dev/null @@ -1,378 +0,0 @@ -#![cfg_attr(feature = "frozen-abi", feature(min_specialization))] -#![allow(clippy::arithmetic_side_effects)] -use { - ahash::AHashMap, - lazy_static::lazy_static, - solana_feature_set::{self as feature_set, FeatureSet}, - solana_pubkey::Pubkey, - solana_sdk_ids::{ - address_lookup_table, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, - compute_budget, config, ed25519_program, loader_v4, secp256k1_program, stake, - system_program, vote, - }, -}; - -#[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 -/// 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 -/// remove that builtin entry from MIGRATING_BUILTINS_COSTS. -#[derive(Clone)] -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 { - 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! { - /// Number of compute units for each built-in programs - /// - /// DEVELOPER WARNING: This map CANNOT be modified without causing a - /// consensus failure because this map is used to calculate the compute - /// limit for transactions that don't specify a compute limit themselves as - /// of https://github.com/anza-xyz/agave/issues/2212. It's also used to - /// calculate the cost of a transaction which is used in replay to enforce - /// block cost limits as of - /// https://github.com/solana-labs/solana/issues/29595. - static ref BUILTIN_INSTRUCTION_COSTS: AHashMap = - 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(), - BuiltinCost::Migrating(MigratingBuiltinCost { - native_cost: solana_stake_program::stake_instruction::DEFAULT_COMPUTE_UNITS, - core_bpf_migration_feature: feature_set::migrate_stake_program_to_core_bpf::id(), - position: 0, - }), - ), - ( - config::id(), - BuiltinCost::Migrating(MigratingBuiltinCost { - native_cost: solana_config_program::config_processor::DEFAULT_COMPUTE_UNITS, - 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(), - BuiltinCost::NotMigrating(NotMigratingBuiltinCost { - native_cost: solana_vote_program::vote_processor::DEFAULT_COMPUTE_UNITS, - }), - ), - ( - system_program::id(), - BuiltinCost::NotMigrating(NotMigratingBuiltinCost { - native_cost: solana_system_program::system_processor::DEFAULT_COMPUTE_UNITS, - }), - ), - ( - compute_budget::id(), - BuiltinCost::NotMigrating(NotMigratingBuiltinCost { - native_cost: solana_compute_budget_program::DEFAULT_COMPUTE_UNITS, - }), - ), - ( - bpf_loader_upgradeable::id(), - BuiltinCost::NotMigrating(NotMigratingBuiltinCost { - native_cost: solana_bpf_loader_program::UPGRADEABLE_LOADER_COMPUTE_UNITS, - }), - ), - ( - bpf_loader_deprecated::id(), - BuiltinCost::NotMigrating(NotMigratingBuiltinCost { - native_cost: solana_bpf_loader_program::DEPRECATED_LOADER_COMPUTE_UNITS, - }), - ), - ( - bpf_loader::id(), - BuiltinCost::NotMigrating(NotMigratingBuiltinCost { - native_cost: solana_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS, - }), - ), - ( - loader_v4::id(), - BuiltinCost::NotMigrating(NotMigratingBuiltinCost { - native_cost: solana_loader_v4_program::DEFAULT_COMPUTE_UNITS, - }), - ), - // Note: These are precompile, run directly in bank during sanitizing; - ( - secp256k1_program::id(), - BuiltinCost::NotMigrating(NotMigratingBuiltinCost { native_cost: 0 }), - ), - ( - ed25519_program::id(), - BuiltinCost::NotMigrating(NotMigratingBuiltinCost { native_cost: 0 }), - ), -]; - -lazy_static! { - /// A table of 256 booleans indicates whether the first `u8` of a Pubkey exists in - /// BUILTIN_INSTRUCTION_COSTS. If the value is true, the Pubkey might be a builtin key; - /// if false, it cannot be a builtin key. This table allows for quick filtering of - /// builtin program IDs without the need for hashing. - pub static ref MAYBE_BUILTIN_KEY: [bool; 256] = { - let mut temp_table: [bool; 256] = [false; 256]; - BUILTIN_INSTRUCTION_COSTS - .keys() - .for_each(|key| temp_table[key.as_ref()[0] as usize] = true); - temp_table - }; -} - -pub fn get_builtin_instruction_cost<'a>( - program_id: &'a Pubkey, - feature_set: &'a FeatureSet, -) -> Option { - BUILTIN_INSTRUCTION_COSTS - .get(program_id) - .filter(|builtin_cost| !builtin_cost.has_migrated(feature_set)) - .map(|builtin_cost| builtin_cost.native_cost()) -} - -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)] -mod test { - 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] - fn test_get_builtin_instruction_cost() { - // use native cost if no migration planned - assert_eq!( - Some(solana_compute_budget_program::DEFAULT_COMPUTE_UNITS), - get_builtin_instruction_cost(&compute_budget::id(), &FeatureSet::all_enabled()) - ); - - // use native cost if migration is planned but not activated - assert_eq!( - Some(solana_stake_program::stake_instruction::DEFAULT_COMPUTE_UNITS), - get_builtin_instruction_cost(&stake::id(), &FeatureSet::default()) - ); - - // None if migration is planned and activated, in which case, it's no longer builtin - assert!(get_builtin_instruction_cost(&stake::id(), &FeatureSet::all_enabled()).is_none()); - - // None if not builtin - assert!( - get_builtin_instruction_cost(&Pubkey::new_unique(), &FeatureSet::default()).is_none() - ); - assert!( - get_builtin_instruction_cost(&Pubkey::new_unique(), &FeatureSet::all_enabled()) - .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); - } -} diff --git a/scripts/patch-crates.sh b/scripts/patch-crates.sh index 45a2d67caf7f9b..1af7e7ca0b8eeb 100644 --- a/scripts/patch-crates.sh +++ b/scripts/patch-crates.sh @@ -14,7 +14,6 @@ update_solana_dependencies() { solana-banks-server solana-bloom solana-bucket-map - solana-builtins-default-costs solana-clap-utils solana-clap-v3-utils solana-cli-config @@ -151,7 +150,6 @@ patch_crates_io_solana_no_header() { crates_map+=("solana-banks-server banks-server") crates_map+=("solana-bloom bloom") crates_map+=("solana-bucket-map bucket_map") - crates_map+=("solana-builtins-default-costs builtins-default-costs") crates_map+=("solana-clap-utils clap-utils") crates_map+=("solana-clap-v3-utils clap-v3-utils") crates_map+=("solana-cli-config cli-config") From 20ebc30d46b111f69a40148b657fad4bbf7c2978 Mon Sep 17 00:00:00 2001 From: Joe C Date: Thu, 19 Dec 2024 16:05:52 +0800 Subject: [PATCH 7/9] Update builtins/src/cost_modeling.rs Co-authored-by: Tao Zhu <82401714+tao-stones@users.noreply.github.com> --- builtins/src/cost_modeling.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtins/src/cost_modeling.rs b/builtins/src/cost_modeling.rs index 1b89f5c73e2e42..8049db142192da 100644 --- a/builtins/src/cost_modeling.rs +++ b/builtins/src/cost_modeling.rs @@ -9,7 +9,7 @@ use { solana_sdk_ids::{ed25519_program, secp256k1_program}, }; -/// CONTRIBUTOR: If you change any builtin Core BPF migration confiurations +/// CONTRIBUTOR: If you change any builtin Core BPF migration configurations /// in this crate's `BUILTINS` list, you must update this constant to reflect /// the number of builtin programs that have Core BPF migration configurations. pub const NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS: usize = 3; From d7e816c12bc78d2b46396e7ec24be5493c505f94 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Thu, 19 Dec 2024 17:53:40 +0800 Subject: [PATCH 8/9] use special feature for mock builtin migrations --- builtins/Cargo.toml | 2 +- builtins/src/cost_modeling.rs | 6 +++++- builtins/src/lib.rs | 8 ++++---- runtime/Cargo.toml | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/builtins/Cargo.toml b/builtins/Cargo.toml index 637a4af083012c..7c416c4a36fc43 100644 --- a/builtins/Cargo.toml +++ b/builtins/Cargo.toml @@ -10,7 +10,7 @@ license = { workspace = true } edition = { workspace = true } [features] -dev-context-only-utils = [] +mock-builtin-migrations = [] [dependencies] ahash = { workspace = true } diff --git a/builtins/src/cost_modeling.rs b/builtins/src/cost_modeling.rs index 8049db142192da..942773e2b3fd3a 100644 --- a/builtins/src/cost_modeling.rs +++ b/builtins/src/cost_modeling.rs @@ -9,10 +9,15 @@ use { solana_sdk_ids::{ed25519_program, secp256k1_program}, }; +#[cfg(not(feature = "mock-builtin-migrations"))] /// CONTRIBUTOR: If you change any builtin Core BPF migration configurations /// in this crate's `BUILTINS` list, you must update this constant to reflect /// the number of builtin programs that have Core BPF migration configurations. pub const NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS: usize = 3; +#[cfg(feature = "mock-builtin-migrations")] +/// CONTRIBUTOR: Under the `mock-builtin-migrations` feature, this value is +/// `BUILTINS.len()`. If a new builtin is added, this should be updated. +pub const NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS: usize = 11; /// Configuration for cost modeling of a builtin program. #[derive(Debug)] @@ -172,7 +177,6 @@ pub fn get_builtin_migration_feature_index_from_feature_id(feature_id: &Pubkey) mod test { use super::*; - #[cfg(not(feature = "dev-context-only-utils"))] #[test] fn test_cost_modeled_builtins_with_migrations_compiles() { // This test is a compile-time check to ensure that the number of diff --git a/builtins/src/lib.rs b/builtins/src/lib.rs index dc6b17825d9857..05a4cf36515703 100644 --- a/builtins/src/lib.rs +++ b/builtins/src/lib.rs @@ -32,11 +32,11 @@ macro_rules! testable_prototype { $prototype { name: stringify!($name), core_bpf_migration_config: { - #[cfg(not(feature = "dev-context-only-utils"))] + #[cfg(not(feature = "mock-builtin-migrations"))] { $core_bpf_migration_config } - #[cfg(feature = "dev-context-only-utils")] + #[cfg(feature = "mock-builtin-migrations")] { Some( test_only::$name::CONFIG ) } @@ -223,7 +223,7 @@ mod buffer_accounts { // into the builtins list for both the feature ID and the source program ID. // These arbitrary IDs can then be used to configure feature-activation runtime // tests. -#[cfg(any(test, feature = "dev-context-only-utils"))] +#[cfg(any(test, feature = "mock-builtin-migrations"))] pub mod test_only { use crate::core_bpf_migration::{CoreBpfMigrationConfig, CoreBpfMigrationTargetType}; pub mod system_program { @@ -403,7 +403,7 @@ mod tests { // Since a macro is used to initialize the test IDs from the `test_only` // module, best to ensure the lists have the expected values within a test // context. - #[cfg(feature = "dev-context-only-utils")] + #[cfg(feature = "mock-builtin-migrations")] #[test] fn test_testable_prototypes() { assert_eq!( diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 0bec4f1ea64660..3f0e57830791e1 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -106,7 +106,7 @@ memoffset = { workspace = true } rand0-7 = { package = "rand", version = "0.7" } rand_chacha = { workspace = true } solana-accounts-db = { workspace = true, features = ["dev-context-only-utils"] } -solana-builtins = { workspace = true, features = ["dev-context-only-utils"] } +solana-builtins = { workspace = true, features = ["mock-builtin-migrations"] } solana-logger = { workspace = true } # See order-crates-for-publishing.py for using this unusual `path = "."` solana-runtime = { path = ".", features = ["dev-context-only-utils"] } From 73825e3f8d2e3a680ca959717f70c36d0cefe231 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Thu, 19 Dec 2024 18:08:11 +0800 Subject: [PATCH 9/9] builtins: update contributor comments --- builtins/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/builtins/src/lib.rs b/builtins/src/lib.rs index 05a4cf36515703..02a437db70cf01 100644 --- a/builtins/src/lib.rs +++ b/builtins/src/lib.rs @@ -46,11 +46,11 @@ macro_rules! testable_prototype { }; } -/// DEVELOPER: when a builtin is migrated to sbpf, please add its corresponding -/// migration feature ID to solana-builtin-default-costs::BUILTIN_INSTRUCTION_COSTS, -/// so the builtin's default cost can be determined properly based on feature status. -/// When migration completed, and the feature gate is enabled everywhere, please -/// remove that builtin entry from solana-builtin-default-costs::BUILTIN_INSTRUCTION_COSTS. +/// CONTRIBUTOR: When a builtin is scheduled to be migrated to Core BPF, add +/// the `CoreBpfMigrationConfig` to the builtin prototype here, and adjust the +/// length value in `cost_modeling::NUM_COST_MODELED_BUILTINS_WITH_MIGRATIONS`. +/// When the migration is completed and the feature is cleaned up, remove the +/// builtin from this list and update the length value again. pub static BUILTINS: &[BuiltinPrototype] = &[ testable_prototype!(BuiltinPrototype { name: system_program,