solana_runtime/
builtins.rs

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    /// Builtin programs that are always available
53    pub genesis_builtins: Vec<Builtin>,
54
55    /// Dynamic feature transitions for builtin programs
56    pub feature_transitions: Vec<BuiltinFeatureTransition>,
57}
58
59/// Actions taken by a bank when managing the list of active builtin programs.
60#[derive(Debug, Clone)]
61pub enum BuiltinAction {
62    Add(Builtin),
63    Remove(Pubkey),
64}
65
66/// State transition enum used for adding and removing builtin programs through
67/// feature activations.
68#[derive(Debug, Clone, AbiExample)]
69pub enum BuiltinFeatureTransition {
70    /// Add a builtin program if a feature is activated.
71    Add {
72        builtin: Builtin,
73        feature_id: Pubkey,
74    },
75    /// Remove a builtin program if a feature is activated or
76    /// retain a previously added builtin.
77    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                    // Retaining is no different from adding a new builtin.
109                    Some(BuiltinAction::Add(previously_added_builtin.clone()))
110                } else {
111                    None
112                }
113            }
114        }
115    }
116}
117
118/// Builtin programs that are always available
119fn 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
144/// place holder for precompile programs, remove when the precompile program is deactivated via feature activation
145fn dummy_process_instruction(
146    _first_instruction_account: usize,
147    _invoke_context: &mut InvokeContext,
148) -> Result<(), InstructionError> {
149    Ok(())
150}
151
152/// Dynamic feature transitions for builtin programs
153fn 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
207/// Returns the addresses of all builtin programs.
208pub 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}