From 3907ea2cc4fb3ded027310cfb1656a0d9c0a8c49 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Tue, 10 Dec 2024 21:04:27 +0900 Subject: [PATCH] builtins: port over cost modeling lookups --- Cargo.lock | 2 + builtins/Cargo.toml | 2 + builtins/src/cost_modeling.rs | 143 +++++++++++++++++++++++++++++++++- programs/sbf/Cargo.lock | 2 + svm/examples/Cargo.lock | 2 + 5 files changed, 149 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ffb1e84cb93d48..37d0f13ac3a801 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6276,6 +6276,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 9b783830faae32..d5d46ff6cbf9f2 100644 --- a/builtins/src/cost_modeling.rs +++ b/builtins/src/cost_modeling.rs @@ -1,6 +1,13 @@ //! Configurations for handling cost modeling of builtin programs. -use solana_pubkey::Pubkey; +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)] @@ -14,10 +21,142 @@ pub struct CostModelingConfig { } /// Configuration for updating the cost of a builtin program. -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] pub struct NewCostModelingConfig { /// The new cost of the builtin program. pub new_cost: u64, /// The feature gate to trigger the new cost. pub feature_id: Pubkey, } + +struct BuiltinCost { + default_cost: Option, + core_bpf_migration_feature: Option, + new_cost_config: Option, +} + +lazy_static! { + static ref BUILTIN_INSTRUCTION_COSTS: AHashMap = BUILTINS + .iter() + .map(|builtin| { + ( + builtin.program_id, + BuiltinCost { + default_cost: builtin.cost_modeling_config.default_cost, + core_bpf_migration_feature: builtin + .core_bpf_migration_config + .as_ref() + .map(|config| config.feature_id), + new_cost_config: builtin.cost_modeling_config.new_cost_config, + }, + ) + }) + .chain( + [ + ( + secp256k1_program::id(), + BuiltinCost { + default_cost: Some(0), + core_bpf_migration_feature: None, + new_cost_config: None, + }, + ), + ( + ed25519_program::id(), + BuiltinCost { + default_cost: Some(0), + core_bpf_migration_feature: None, + new_cost_config: 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; + } + // If the program has a new cost configuration and that feature is + // active, then return the new cost. + if builtin_cost + .new_cost_config + .is_some_and(|new_cost_config| feature_set.is_active(&new_cost_config.feature_id)) + { + return Some(builtin_cost.new_cost_config.unwrap().new_cost); + } + // Otherwise, return the default cost. + 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_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( + &solana_sdk_ids::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(&solana_sdk_ids::stake::id(), &FeatureSet::default()) + ); + + // 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()); + + // 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() + ); + } +} diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 4413415c55e15f..a2ab6f24415be6 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5161,6 +5161,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 e326abd8a08870..af0d3cdb49afc8 100644 --- a/svm/examples/Cargo.lock +++ b/svm/examples/Cargo.lock @@ -5012,6 +5012,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",