solana_builtins_default_costs/
lib.rs1#![cfg_attr(
2 not(feature = "agave-unstable-api"),
3 deprecated(
4 since = "3.1.0",
5 note = "This crate has been marked for formal inclusion in the Agave Unstable API. From \
6 v4.0.0 onward, the `agave-unstable-api` crate feature must be specified to \
7 acknowledge use of an interface that may break without warning."
8 )
9)]
10#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
11#![allow(clippy::arithmetic_side_effects)]
12
13#[cfg(feature = "dev-context-only-utils")]
14use qualifier_attr::field_qualifiers;
15use {
16 ahash::AHashMap,
17 solana_pubkey::Pubkey,
18 solana_sdk_ids::{
19 bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, compute_budget, ed25519_program,
20 loader_v4, secp256k1_program, system_program, vote,
21 },
22};
23
24#[derive(Clone)]
25#[cfg_attr(
26 feature = "dev-context-only-utils",
27 field_qualifiers(core_bpf_migration_feature(pub), position(pub))
28)]
29pub struct MigratingBuiltinCost {
30 core_bpf_migration_feature: Pubkey,
31 position: usize,
36}
37
38#[derive(Clone)]
45pub enum BuiltinCost {
46 Migrating(MigratingBuiltinCost),
47 NotMigrating,
48}
49
50impl BuiltinCost {
51 fn core_bpf_migration_feature(&self) -> Option<&Pubkey> {
52 match self {
53 BuiltinCost::Migrating(MigratingBuiltinCost {
54 core_bpf_migration_feature,
55 ..
56 }) => Some(core_bpf_migration_feature),
57 BuiltinCost::NotMigrating => None,
58 }
59 }
60
61 fn position(&self) -> Option<usize> {
62 match self {
63 BuiltinCost::Migrating(MigratingBuiltinCost { position, .. }) => Some(*position),
64 BuiltinCost::NotMigrating => None,
65 }
66 }
67}
68
69static BUILTIN_INSTRUCTION_COSTS: std::sync::LazyLock<AHashMap<Pubkey, BuiltinCost>> =
79 std::sync::LazyLock::new(|| {
80 MIGRATING_BUILTINS_COSTS
81 .iter()
82 .chain(NON_MIGRATING_BUILTINS_COSTS.iter())
83 .cloned()
84 .collect()
85 });
86#[allow(dead_code)]
95const TOTAL_COUNT_BUILTINS: usize = 9;
96#[cfg(test)]
97static_assertions::const_assert_eq!(
98 MIGRATING_BUILTINS_COSTS.len() + NON_MIGRATING_BUILTINS_COSTS.len(),
99 TOTAL_COUNT_BUILTINS
100);
101
102pub const MIGRATING_BUILTINS_COSTS: &[(Pubkey, BuiltinCost)] = &[];
105
106const NON_MIGRATING_BUILTINS_COSTS: &[(Pubkey, BuiltinCost)] = &[
107 (vote::id(), BuiltinCost::NotMigrating),
108 (system_program::id(), BuiltinCost::NotMigrating),
109 (compute_budget::id(), BuiltinCost::NotMigrating),
110 (bpf_loader_upgradeable::id(), BuiltinCost::NotMigrating),
111 (bpf_loader_deprecated::id(), BuiltinCost::NotMigrating),
112 (bpf_loader::id(), BuiltinCost::NotMigrating),
113 (loader_v4::id(), BuiltinCost::NotMigrating),
114 (secp256k1_program::id(), BuiltinCost::NotMigrating),
115 (ed25519_program::id(), BuiltinCost::NotMigrating),
116];
117
118pub static MAYBE_BUILTIN_KEY: std::sync::LazyLock<[bool; 256]> = std::sync::LazyLock::new(|| {
123 let mut temp_table: [bool; 256] = [false; 256];
124 BUILTIN_INSTRUCTION_COSTS
125 .keys()
126 .for_each(|key| temp_table[key.as_ref()[0] as usize] = true);
127 temp_table
128});
129
130pub enum BuiltinMigrationFeatureIndex {
131 NotBuiltin,
132 BuiltinNoMigrationFeature,
133 BuiltinWithMigrationFeature(usize),
134}
135
136pub fn get_builtin_migration_feature_index(program_id: &Pubkey) -> BuiltinMigrationFeatureIndex {
137 BUILTIN_INSTRUCTION_COSTS.get(program_id).map_or(
138 BuiltinMigrationFeatureIndex::NotBuiltin,
139 |builtin_cost| {
140 builtin_cost.position().map_or(
141 BuiltinMigrationFeatureIndex::BuiltinNoMigrationFeature,
142 BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature,
143 )
144 },
145 )
146}
147
148#[allow(dead_code)]
150const fn validate_position(migrating_builtins: &[(Pubkey, BuiltinCost)]) {
151 let mut index = 0;
152 while index < migrating_builtins.len() {
153 match migrating_builtins[index].1 {
154 BuiltinCost::Migrating(MigratingBuiltinCost { position, .. }) => assert!(
155 position == index,
156 "migration feture must exist and at correct position"
157 ),
158 BuiltinCost::NotMigrating => {
159 panic!("migration feture must exist and at correct position")
160 }
161 }
162 index += 1;
163 }
164}
165const _: () = validate_position(MIGRATING_BUILTINS_COSTS);
166
167pub fn get_migration_feature_id(index: usize) -> &'static Pubkey {
170 MIGRATING_BUILTINS_COSTS
171 .get(index)
172 .expect("valid index of MIGRATING_BUILTINS_COSTS")
173 .1
174 .core_bpf_migration_feature()
175 .expect("migrating builtin")
176}
177
178#[cfg(feature = "dev-context-only-utils")]
179pub fn get_migration_feature_position(feature_id: &Pubkey) -> usize {
180 MIGRATING_BUILTINS_COSTS
181 .iter()
182 .position(|(_, c)| c.core_bpf_migration_feature().expect("migrating builtin") == feature_id)
183 .unwrap()
184}
185
186#[cfg(test)]
187mod test {
188 use super::*;
189
190 #[test]
191 fn test_const_builtin_cost_arrays() {
192 assert!(MIGRATING_BUILTINS_COSTS
194 .iter()
195 .enumerate()
196 .all(|(index, (_, c))| {
197 c.core_bpf_migration_feature().is_some() && c.position() == Some(index)
198 }));
199 assert!(NON_MIGRATING_BUILTINS_COSTS
200 .iter()
201 .all(|(_, c)| c.core_bpf_migration_feature().is_none()));
202 }
203
204 #[test]
205 fn test_get_builtin_migration_feature_index() {
206 assert!(matches!(
207 get_builtin_migration_feature_index(&Pubkey::new_unique()),
208 BuiltinMigrationFeatureIndex::NotBuiltin
209 ));
210 assert!(matches!(
211 get_builtin_migration_feature_index(&compute_budget::id()),
212 BuiltinMigrationFeatureIndex::BuiltinNoMigrationFeature,
213 ));
214 for (program_id, migrating_builtin) in MIGRATING_BUILTINS_COSTS {
215 let feature_index = get_builtin_migration_feature_index(program_id);
216 assert!(matches!(
217 feature_index,
218 BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(_)
219 ));
220 let BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(feature_index) =
221 feature_index
222 else {
223 panic!("expect migrating builtin")
224 };
225 assert_eq!(
226 get_migration_feature_id(feature_index),
227 migrating_builtin.core_bpf_migration_feature().unwrap(),
228 );
229 }
230 }
231
232 #[test]
233 #[should_panic(expected = "valid index of MIGRATING_BUILTINS_COSTS")]
234 fn test_get_migration_feature_id_invalid_index() {
235 let _ = get_migration_feature_id(MIGRATING_BUILTINS_COSTS.len() + 1);
236 }
237}