1#[cfg(RUSTC_WITH_SPECIALIZATION)]
2use safecoin_frozen_abi::abi_example::AbiExample;
3use {
4 crate::system_instruction_processor,
5 solana_program_runtime::invoke_context::{InvokeContext, ProcessInstructionWithContext},
6 solana_sdk::{
7 feature_set, instruction::InstructionError, pubkey::Pubkey, stake, system_program,
8 },
9 std::fmt,
10};
11
12#[derive(Clone)]
13pub struct Builtin {
14 pub name: String,
15 pub id: Pubkey,
16 pub process_instruction_with_context: ProcessInstructionWithContext,
17}
18
19impl Builtin {
20 pub fn new(
21 name: &str,
22 id: Pubkey,
23 process_instruction_with_context: ProcessInstructionWithContext,
24 ) -> Self {
25 Self {
26 name: name.to_string(),
27 id,
28 process_instruction_with_context,
29 }
30 }
31}
32
33impl fmt::Debug for Builtin {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 write!(f, "Builtin [name={}, id={}]", self.name, self.id)
36 }
37}
38
39#[cfg(RUSTC_WITH_SPECIALIZATION)]
40impl AbiExample for Builtin {
41 fn example() -> Self {
42 Self {
43 name: String::default(),
44 id: Pubkey::default(),
45 process_instruction_with_context: |_, _| Ok(()),
46 }
47 }
48}
49
50#[derive(Clone, Debug)]
51pub struct Builtins {
52 pub genesis_builtins: Vec<Builtin>,
54
55 pub feature_transitions: Vec<BuiltinFeatureTransition>,
57}
58
59#[derive(Debug, Clone)]
61pub enum BuiltinAction {
62 Add(Builtin),
63 Remove(Pubkey),
64}
65
66#[derive(Debug, Clone, AbiExample)]
69pub enum BuiltinFeatureTransition {
70 Add {
72 builtin: Builtin,
73 feature_id: Pubkey,
74 },
75 RemoveOrRetain {
78 previously_added_builtin: Builtin,
79 addition_feature_id: Pubkey,
80 removal_feature_id: Pubkey,
81 },
82}
83
84impl BuiltinFeatureTransition {
85 pub fn to_action(
86 &self,
87 should_apply_action_for_feature: &impl Fn(&Pubkey) -> bool,
88 ) -> Option<BuiltinAction> {
89 match self {
90 Self::Add {
91 builtin,
92 feature_id,
93 } => {
94 if should_apply_action_for_feature(feature_id) {
95 Some(BuiltinAction::Add(builtin.clone()))
96 } else {
97 None
98 }
99 }
100 Self::RemoveOrRetain {
101 previously_added_builtin,
102 addition_feature_id,
103 removal_feature_id,
104 } => {
105 if should_apply_action_for_feature(removal_feature_id) {
106 Some(BuiltinAction::Remove(previously_added_builtin.id))
107 } else if should_apply_action_for_feature(addition_feature_id) {
108 Some(BuiltinAction::Add(previously_added_builtin.clone()))
110 } else {
111 None
112 }
113 }
114 }
115 }
116}
117
118fn genesis_builtins() -> Vec<Builtin> {
120 vec![
121 Builtin::new(
122 "system_program",
123 system_program::id(),
124 system_instruction_processor::process_instruction,
125 ),
126 Builtin::new(
127 "vote_program",
128 solana_vote_program::id(),
129 solana_vote_program::vote_processor::process_instruction,
130 ),
131 Builtin::new(
132 "stake_program",
133 stake::program::id(),
134 solana_stake_program::stake_instruction::process_instruction,
135 ),
136 Builtin::new(
137 "config_program",
138 solana_config_program::id(),
139 solana_config_program::config_processor::process_instruction,
140 ),
141 ]
142}
143
144fn dummy_process_instruction(
146 _first_instruction_account: usize,
147 _invoke_context: &mut InvokeContext,
148) -> Result<(), InstructionError> {
149 Ok(())
150}
151
152fn builtin_feature_transitions() -> Vec<BuiltinFeatureTransition> {
154 vec![
155 BuiltinFeatureTransition::Add {
156 builtin: Builtin::new(
157 "compute_budget_program",
158 solana_sdk::compute_budget::id(),
159 solana_compute_budget_program::process_instruction,
160 ),
161 feature_id: feature_set::add_compute_budget_program::id(),
162 },
163 BuiltinFeatureTransition::RemoveOrRetain {
164 previously_added_builtin: Builtin::new(
165 "secp256k1_program",
166 solana_sdk::secp256k1_program::id(),
167 dummy_process_instruction,
168 ),
169 addition_feature_id: feature_set::secp256k1_program_enabled::id(),
170 removal_feature_id: feature_set::prevent_calling_precompiles_as_programs::id(),
171 },
172 BuiltinFeatureTransition::RemoveOrRetain {
173 previously_added_builtin: Builtin::new(
174 "ed25519_program",
175 solana_sdk::ed25519_program::id(),
176 dummy_process_instruction,
177 ),
178 addition_feature_id: feature_set::ed25519_program_enabled::id(),
179 removal_feature_id: feature_set::prevent_calling_precompiles_as_programs::id(),
180 },
181 BuiltinFeatureTransition::Add {
182 builtin: Builtin::new(
183 "address_lookup_table_program",
184 solana_address_lookup_table_program::id(),
185 solana_address_lookup_table_program::processor::process_instruction,
186 ),
187 feature_id: feature_set::versioned_tx_message_enabled::id(),
188 },
189 BuiltinFeatureTransition::Add {
190 builtin: Builtin::new(
191 "zk_token_proof_program",
192 safe_zk_token_sdk::zk_token_proof_program::id(),
193 safe_zk_token_proof_program::process_instruction,
194 ),
195 feature_id: feature_set::zk_token_sdk_enabled::id(),
196 },
197 ]
198}
199
200pub(crate) fn get() -> Builtins {
201 Builtins {
202 genesis_builtins: genesis_builtins(),
203 feature_transitions: builtin_feature_transitions(),
204 }
205}
206
207pub fn get_pubkeys() -> Vec<Pubkey> {
209 let builtins = get();
210
211 let mut pubkeys = Vec::new();
212 pubkeys.extend(builtins.genesis_builtins.iter().map(|b| b.id));
213 pubkeys.extend(builtins.feature_transitions.iter().filter_map(|f| match f {
214 BuiltinFeatureTransition::Add { builtin, .. } => Some(builtin.id),
215 BuiltinFeatureTransition::RemoveOrRetain { .. } => None,
216 }));
217 pubkeys
218}