gemachain_runtime/
builtins.rs

1use crate::system_instruction_processor;
2use gemachain_sdk::{
3    feature_set,
4    instruction::InstructionError,
5    process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext},
6    pubkey::Pubkey,
7    stake, system_program,
8};
9use std::fmt;
10
11#[cfg(RUSTC_WITH_SPECIALIZATION)]
12use gemachain_frozen_abi::abi_example::AbiExample;
13
14fn process_instruction_with_program_logging(
15    process_instruction: ProcessInstructionWithContext,
16    program_id: &Pubkey,
17    instruction_data: &[u8],
18    invoke_context: &mut dyn InvokeContext,
19) -> Result<(), InstructionError> {
20    let logger = invoke_context.get_logger();
21    stable_log::program_invoke(&logger, program_id, invoke_context.invoke_depth());
22
23    let result = process_instruction(program_id, instruction_data, invoke_context);
24
25    match &result {
26        Ok(()) => stable_log::program_success(&logger, program_id),
27        Err(err) => stable_log::program_failure(&logger, program_id, err),
28    }
29    result
30}
31
32macro_rules! with_program_logging {
33    ($process_instruction:expr) => {
34        |program_id: &Pubkey, instruction_data: &[u8], invoke_context: &mut dyn InvokeContext| {
35            process_instruction_with_program_logging(
36                $process_instruction,
37                program_id,
38                instruction_data,
39                invoke_context,
40            )
41        }
42    };
43}
44
45#[derive(AbiExample, Debug, Clone)]
46pub enum ActivationType {
47    NewProgram,
48    NewVersion,
49}
50
51#[derive(Clone)]
52pub struct Builtin {
53    pub name: String,
54    pub id: Pubkey,
55    pub process_instruction_with_context: ProcessInstructionWithContext,
56}
57
58impl Builtin {
59    pub fn new(
60        name: &str,
61        id: Pubkey,
62        process_instruction_with_context: ProcessInstructionWithContext,
63    ) -> Self {
64        Self {
65            name: name.to_string(),
66            id,
67            process_instruction_with_context,
68        }
69    }
70}
71
72impl fmt::Debug for Builtin {
73    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74        write!(f, "Builtin [name={}, id={}]", self.name, self.id)
75    }
76}
77
78#[cfg(RUSTC_WITH_SPECIALIZATION)]
79impl AbiExample for Builtin {
80    fn example() -> Self {
81        Self {
82            name: String::default(),
83            id: Pubkey::default(),
84            process_instruction_with_context: |_, _, _| Ok(()),
85        }
86    }
87}
88
89#[derive(Clone, Debug)]
90pub struct Builtins {
91    /// Builtin programs that are always available
92    pub genesis_builtins: Vec<Builtin>,
93
94    /// Builtin programs activated dynamically by feature
95    pub feature_builtins: Vec<(Builtin, Pubkey, ActivationType)>,
96}
97
98/// Builtin programs that are always available
99fn genesis_builtins() -> Vec<Builtin> {
100    vec![
101        Builtin::new(
102            "system_program",
103            system_program::id(),
104            with_program_logging!(system_instruction_processor::process_instruction),
105        ),
106        Builtin::new(
107            "vote_program",
108            gemachain_vote_program::id(),
109            with_program_logging!(gemachain_vote_program::vote_instruction::process_instruction),
110        ),
111        Builtin::new(
112            "stake_program",
113            stake::program::id(),
114            with_program_logging!(gemachain_stake_program::stake_instruction::process_instruction),
115        ),
116        Builtin::new(
117            "config_program",
118            gemachain_config_program::id(),
119            with_program_logging!(gemachain_config_program::config_processor::process_instruction),
120        ),
121        Builtin::new(
122            "secp256k1_program",
123            gemachain_sdk::secp256k1_program::id(),
124            gemachain_secp256k1_program::process_instruction,
125        ),
126    ]
127}
128
129/// Builtin programs activated dynamically by feature
130///
131/// Note: If the feature_builtin is intended to replace another builtin program, it must have a new
132/// name.
133/// This is to enable the runtime to determine categorically whether the builtin update has
134/// occurred, and preserve idempotency in Bank::add_native_program across genesis, snapshot, and
135/// normal child Bank creation.
136/// https://github.com/gemacoin/gemachain/blob/84b139cc94b5be7c9e0c18c2ad91743231b85a0d/runtime/src/bank.rs#L1723
137fn feature_builtins() -> Vec<(Builtin, Pubkey, ActivationType)> {
138    vec![
139        (
140            Builtin::new(
141                "compute_budget_program",
142                gemachain_sdk::compute_budget::id(),
143                gemachain_compute_budget_program::process_instruction,
144            ),
145            feature_set::tx_wide_compute_cap::id(),
146            ActivationType::NewProgram,
147        ),
148        (
149            Builtin::new(
150                "ed25519_program",
151                gemachain_sdk::ed25519_program::id(),
152                gemachain_ed25519_program::process_instruction,
153            ),
154            feature_set::ed25519_program_enabled::id(),
155            ActivationType::NewProgram,
156        ),
157    ]
158}
159
160pub(crate) fn get() -> Builtins {
161    Builtins {
162        genesis_builtins: genesis_builtins(),
163        feature_builtins: feature_builtins(),
164    }
165}