rialo_s_builtins_default_costs/
lib.rs1#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
6#![allow(clippy::arithmetic_side_effects)]
7use std::sync::LazyLock;
8
9use ahash::AHashMap;
10#[cfg(feature = "svm-internal")]
11use qualifier_attr::qualifiers;
12use rialo_s_feature_set::{self as feature_set, FeatureSet};
13use rialo_s_pubkey::Pubkey;
14use rialo_s_sdk_ids::{
15 bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, compute_budget, config,
16 ed25519_program, loader_v4, secp256k1_program, system_program,
17};
18
19#[derive(Clone)]
20#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
21struct MigratingBuiltinCost {
22 native_cost: u64,
23 core_bpf_migration_feature: Pubkey,
24 position: usize,
29}
30
31#[derive(Clone)]
32#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
33struct NotMigratingBuiltinCost {
34 native_cost: u64,
35}
36
37#[derive(Clone)]
44#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
45enum BuiltinCost {
46 Migrating(MigratingBuiltinCost),
47 NotMigrating(NotMigratingBuiltinCost),
48}
49
50impl BuiltinCost {
51 fn native_cost(&self) -> u64 {
52 match self {
53 BuiltinCost::Migrating(MigratingBuiltinCost { native_cost, .. }) => *native_cost,
54 BuiltinCost::NotMigrating(NotMigratingBuiltinCost { native_cost }) => *native_cost,
55 }
56 }
57
58 #[cfg(feature = "svm-internal")]
59 fn core_bpf_migration_feature(&self) -> Option<&Pubkey> {
60 match self {
61 BuiltinCost::Migrating(MigratingBuiltinCost {
62 core_bpf_migration_feature,
63 ..
64 }) => Some(core_bpf_migration_feature),
65 BuiltinCost::NotMigrating(_) => None,
66 }
67 }
68
69 #[cfg(feature = "svm-internal")]
70 fn position(&self) -> Option<usize> {
71 match self {
72 BuiltinCost::Migrating(MigratingBuiltinCost { position, .. }) => Some(*position),
73 BuiltinCost::NotMigrating(_) => None,
74 }
75 }
76
77 fn has_migrated(&self, feature_set: &FeatureSet) -> bool {
78 match self {
79 BuiltinCost::Migrating(MigratingBuiltinCost {
80 core_bpf_migration_feature,
81 ..
82 }) => feature_set.is_active(core_bpf_migration_feature),
83 BuiltinCost::NotMigrating(_) => false,
84 }
85 }
86}
87
88static BUILTIN_INSTRUCTION_COSTS: LazyLock<AHashMap<Pubkey, BuiltinCost>> = LazyLock::new(|| {
99 MIGRATING_BUILTINS_COSTS
100 .iter()
101 .chain(NON_MIGRATING_BUILTINS_COSTS.iter())
102 .cloned()
103 .collect()
104});
105
106#[allow(dead_code)]
113const TOTAL_COUNT_BUILTINS: usize = 9;
114#[cfg(test)]
115static_assertions::const_assert_eq!(
116 MIGRATING_BUILTINS_COSTS.len() + NON_MIGRATING_BUILTINS_COSTS.len(),
117 TOTAL_COUNT_BUILTINS
118);
119
120#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
121const MIGRATING_BUILTINS_COSTS: &[(Pubkey, BuiltinCost)] = &[(
122 config::id(),
123 BuiltinCost::Migrating(MigratingBuiltinCost {
124 native_cost: rialo_s_config_program::config_processor::DEFAULT_COMPUTE_UNITS,
125 core_bpf_migration_feature: feature_set::migrate_config_program_to_core_bpf::id(),
126 position: 0,
127 }),
128)];
129
130const NON_MIGRATING_BUILTINS_COSTS: &[(Pubkey, BuiltinCost)] = &[
131 (
132 system_program::id(),
133 BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
134 native_cost: rialo_s_system_program::system_processor::DEFAULT_COMPUTE_UNITS,
135 }),
136 ),
137 (
138 compute_budget::id(),
139 BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
140 native_cost: rialo_s_compute_budget_program::DEFAULT_COMPUTE_UNITS,
141 }),
142 ),
143 (
144 bpf_loader_upgradeable::id(),
145 BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
146 native_cost: rialo_s_bpf_loader_program::UPGRADEABLE_LOADER_COMPUTE_UNITS,
147 }),
148 ),
149 (
150 bpf_loader_deprecated::id(),
151 BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
152 native_cost: rialo_s_bpf_loader_program::DEPRECATED_LOADER_COMPUTE_UNITS,
153 }),
154 ),
155 (
156 bpf_loader::id(),
157 BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
158 native_cost: rialo_s_bpf_loader_program::DEFAULT_LOADER_COMPUTE_UNITS,
159 }),
160 ),
161 (
162 loader_v4::id(),
163 BuiltinCost::NotMigrating(NotMigratingBuiltinCost {
164 native_cost: rialo_s_loader_v4_program::DEFAULT_COMPUTE_UNITS,
165 }),
166 ),
167 (
169 secp256k1_program::id(),
170 BuiltinCost::NotMigrating(NotMigratingBuiltinCost { native_cost: 0 }),
171 ),
172 (
173 ed25519_program::id(),
174 BuiltinCost::NotMigrating(NotMigratingBuiltinCost { native_cost: 0 }),
175 ),
176];
177
178pub static MAYBE_BUILTIN_KEY: LazyLock<[bool; 256]> = LazyLock::new(|| {
183 let mut temp_table: [bool; 256] = [false; 256];
184 BUILTIN_INSTRUCTION_COSTS
185 .keys()
186 .for_each(|key| temp_table[key.as_ref()[0] as usize] = true);
187 temp_table
188});
189
190pub fn get_builtin_instruction_cost<'a>(
191 program_id: &'a Pubkey,
192 feature_set: &'a FeatureSet,
193) -> Option<u64> {
194 BUILTIN_INSTRUCTION_COSTS
195 .get(program_id)
196 .filter(|builtin_cost| !builtin_cost.has_migrated(feature_set))
197 .map(|builtin_cost| builtin_cost.native_cost())
198}
199
200#[cfg(feature = "svm-internal")]
201#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
202enum BuiltinMigrationFeatureIndex {
203 NotBuiltin,
204 BuiltinNoMigrationFeature,
205 BuiltinWithMigrationFeature(usize),
206}
207
208#[cfg(feature = "svm-internal")]
209#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
210fn get_builtin_migration_feature_index(program_id: &Pubkey) -> BuiltinMigrationFeatureIndex {
211 BUILTIN_INSTRUCTION_COSTS.get(program_id).map_or(
212 BuiltinMigrationFeatureIndex::NotBuiltin,
213 |builtin_cost| {
214 builtin_cost.position().map_or(
215 BuiltinMigrationFeatureIndex::BuiltinNoMigrationFeature,
216 BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature,
217 )
218 },
219 )
220}
221
222#[allow(dead_code)]
224const fn validate_position(migrating_builtins: &[(Pubkey, BuiltinCost)]) {
225 let mut index = 0;
226 while index < migrating_builtins.len() {
227 match migrating_builtins[index].1 {
228 BuiltinCost::Migrating(MigratingBuiltinCost { position, .. }) => assert!(
229 position == index,
230 "migration feture must exist and at correct position"
231 ),
232 BuiltinCost::NotMigrating(_) => {
233 panic!("migration feture must exist and at correct position")
234 }
235 }
236 index += 1;
237 }
238}
239const _: () = validate_position(MIGRATING_BUILTINS_COSTS);
240
241#[cfg(feature = "svm-internal")]
244#[cfg_attr(feature = "svm-internal", qualifiers(pub))]
245pub(crate) fn get_migration_feature_id(index: usize) -> &'static Pubkey {
246 MIGRATING_BUILTINS_COSTS
247 .get(index)
248 .expect("valid index of MIGRATING_BUILTINS_COSTS")
249 .1
250 .core_bpf_migration_feature()
251 .expect("migrating builtin")
252}
253
254#[cfg(feature = "dev-context-only-utils")]
255pub fn get_migration_feature_position(feature_id: &Pubkey) -> usize {
256 MIGRATING_BUILTINS_COSTS
257 .iter()
258 .position(|(_, c)| c.core_bpf_migration_feature().expect("migrating builtin") == feature_id)
259 .unwrap()
260}
261
262#[cfg(test)]
263mod test {
264 use super::*;
265
266 #[test]
267 fn test_const_builtin_cost_arrays() {
268 assert!(MIGRATING_BUILTINS_COSTS
270 .iter()
271 .enumerate()
272 .all(|(index, (_, c))| {
273 c.core_bpf_migration_feature().is_some() && c.position() == Some(index)
274 }));
275 assert!(NON_MIGRATING_BUILTINS_COSTS
276 .iter()
277 .all(|(_, c)| c.core_bpf_migration_feature().is_none()));
278 }
279
280 #[test]
281 fn test_get_builtin_instruction_cost() {
282 assert_eq!(
284 Some(rialo_s_compute_budget_program::DEFAULT_COMPUTE_UNITS),
285 get_builtin_instruction_cost(&compute_budget::id(), &FeatureSet::all_enabled())
286 );
287
288 assert!(
290 get_builtin_instruction_cost(&Pubkey::new_unique(), &FeatureSet::default()).is_none()
291 );
292 assert!(
293 get_builtin_instruction_cost(&Pubkey::new_unique(), &FeatureSet::all_enabled())
294 .is_none()
295 );
296 }
297
298 #[test]
299 fn test_get_builtin_migration_feature_index() {
300 assert!(matches!(
301 get_builtin_migration_feature_index(&Pubkey::new_unique()),
302 BuiltinMigrationFeatureIndex::NotBuiltin
303 ));
304 assert!(matches!(
305 get_builtin_migration_feature_index(&compute_budget::id()),
306 BuiltinMigrationFeatureIndex::BuiltinNoMigrationFeature,
307 ));
308 let feature_index = get_builtin_migration_feature_index(&config::id());
309 assert!(matches!(
310 feature_index,
311 BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(_)
312 ));
313 let BuiltinMigrationFeatureIndex::BuiltinWithMigrationFeature(feature_index) =
314 feature_index
315 else {
316 panic!("expect migrating builtin")
317 };
318 assert_eq!(
319 get_migration_feature_id(feature_index),
320 &feature_set::migrate_config_program_to_core_bpf::id()
321 );
322 }
323
324 #[test]
325 #[should_panic(expected = "valid index of MIGRATING_BUILTINS_COSTS")]
326 fn test_get_migration_feature_id_invalid_index() {
327 let _ = get_migration_feature_id(MIGRATING_BUILTINS_COSTS.len() + 1);
328 }
329}