Line data Source code
1 : #include "fd_builtin_programs.h"
2 : #include "../fd_runtime.h"
3 : #include "../fd_acc_mgr.h"
4 : #include "../fd_system_ids.h"
5 : #include "../fd_system_ids_pp.h"
6 :
7 : #define BUILTIN_PROGRAM(program_id, name, feature_offset, migration_config) \
8 : { \
9 : program_id, \
10 : name, \
11 : feature_offset, \
12 : migration_config \
13 : }
14 :
15 : #define STATELESS_BUILTIN(program_id, migration_config) \
16 : { \
17 : program_id, \
18 : migration_config \
19 : }
20 :
21 : #define CORE_BPF_MIGRATION_CONFIG(source_buffer_address, upgrade_authority_address, enable_feature_offset, builtin_program_id) \
22 : { \
23 : source_buffer_address, \
24 : upgrade_authority_address, \
25 : enable_feature_offset, \
26 : builtin_program_id \
27 : }
28 :
29 : #define NO_CORE_BPF_MIGRATION_CONFIG NULL
30 :
31 : #define DEFINE_CORE_BPF_MIGRATION_CONFIG(name, buffer_address, feature_offset, program_id) \
32 : static const fd_core_bpf_migration_config_t name = { \
33 : buffer_address, \
34 : NULL, \
35 : offsetof(fd_features_t, feature_offset), \
36 : program_id \
37 : }; \
38 : static const fd_core_bpf_migration_config_t * const MIGRATE_##name = &name
39 :
40 : DEFINE_CORE_BPF_MIGRATION_CONFIG(BUILTIN_TO_CORE_BPF_STAKE_PROGRAM_CONFIG, &fd_solana_stake_program_buffer_address, migrate_stake_program_to_core_bpf, &fd_solana_stake_program_id);
41 : DEFINE_CORE_BPF_MIGRATION_CONFIG(BUILTIN_TO_CORE_BPF_CONFIG_PROGRAM_CONFIG, &fd_solana_config_program_buffer_address, migrate_config_program_to_core_bpf, &fd_solana_config_program_id);
42 : DEFINE_CORE_BPF_MIGRATION_CONFIG(BUILTIN_TO_CORE_BPF_ADDRESS_LOOKUP_TABLE_PROGRAM_CONFIG, &fd_solana_address_lookup_table_program_buffer_address, migrate_address_lookup_table_program_to_core_bpf, &fd_solana_address_lookup_table_program_id);
43 : DEFINE_CORE_BPF_MIGRATION_CONFIG(STATELESS_TO_CORE_BPF_FEATURE_GATE_PROGRAM_CONFIG, &fd_solana_feature_program_buffer_address, migrate_feature_gate_program_to_core_bpf, &fd_solana_feature_program_id);
44 :
45 : #define SYSTEM_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_system_program_id, "system_program", NO_ENABLE_FEATURE_ID, NO_CORE_BPF_MIGRATION_CONFIG)
46 : #define VOTE_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_vote_program_id, "vote_program", NO_ENABLE_FEATURE_ID, NO_CORE_BPF_MIGRATION_CONFIG)
47 : #define STAKE_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_stake_program_id, "stake_program", NO_ENABLE_FEATURE_ID, MIGRATE_BUILTIN_TO_CORE_BPF_STAKE_PROGRAM_CONFIG)
48 : #define CONFIG_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_config_program_id, "config_program", NO_ENABLE_FEATURE_ID, MIGRATE_BUILTIN_TO_CORE_BPF_CONFIG_PROGRAM_CONFIG)
49 : #define LOADER_V4_BUILTIN BUILTIN_PROGRAM(&fd_solana_bpf_loader_v4_program_id, "loader_v4", offsetof(fd_features_t, enable_program_runtime_v2_and_loader_v4), NO_CORE_BPF_MIGRATION_CONFIG)
50 : #define ADDRESS_LOOKUP_TABLE_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_address_lookup_table_program_id, "address_lookup_table_program", NO_ENABLE_FEATURE_ID, MIGRATE_BUILTIN_TO_CORE_BPF_ADDRESS_LOOKUP_TABLE_PROGRAM_CONFIG)
51 : #define BPF_LOADER_DEPRECATED_BUILTIN BUILTIN_PROGRAM(&fd_solana_bpf_loader_deprecated_program_id, "solana_bpf_loader_deprecated_program", NO_ENABLE_FEATURE_ID, NO_CORE_BPF_MIGRATION_CONFIG)
52 : #define BPF_LOADER_BUILTIN BUILTIN_PROGRAM(&fd_solana_bpf_loader_program_id, "solana_bpf_loader_program", NO_ENABLE_FEATURE_ID, NO_CORE_BPF_MIGRATION_CONFIG)
53 : #define BPF_LOADER_UPGRADEABLE_BUILTIN BUILTIN_PROGRAM(&fd_solana_bpf_loader_upgradeable_program_id, "solana_bpf_loader_upgradeable_program", NO_ENABLE_FEATURE_ID, NO_CORE_BPF_MIGRATION_CONFIG)
54 : #define COMPUTE_BUDGET_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_compute_budget_program_id, "compute_budget_program", NO_ENABLE_FEATURE_ID, NO_CORE_BPF_MIGRATION_CONFIG)
55 : #define ZK_TOKEN_PROOF_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_zk_token_proof_program_id, "zk_token_proof_program", offsetof(fd_features_t, zk_token_sdk_enabled), NO_CORE_BPF_MIGRATION_CONFIG)
56 : #define ZK_ELGAMAL_PROOF_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_zk_elgamal_proof_program_id, "zk_elgamal_proof_program", offsetof(fd_features_t, zk_elgamal_proof_program_enabled), NO_CORE_BPF_MIGRATION_CONFIG)
57 :
58 : #define FEATURE_PROGRAM_BUILTIN STATELESS_BUILTIN(&fd_solana_feature_program_id, MIGRATE_STATELESS_TO_CORE_BPF_FEATURE_GATE_PROGRAM_CONFIG)
59 :
60 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/mod.rs#L133-L143 */
61 : static const fd_stateless_builtin_program_t stateless_programs_builtins[] = {
62 : FEATURE_PROGRAM_BUILTIN
63 : };
64 0 : #define STATELESS_BUILTINS_COUNT (sizeof(stateless_programs_builtins) / sizeof(fd_stateless_builtin_program_t))
65 :
66 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/mod.rs#L34-L131 */
67 : fd_builtin_program_t const builtin_programs[] = {
68 : SYSTEM_PROGRAM_BUILTIN,
69 : VOTE_PROGRAM_BUILTIN,
70 : STAKE_PROGRAM_BUILTIN,
71 : CONFIG_PROGRAM_BUILTIN,
72 : LOADER_V4_BUILTIN,
73 : ADDRESS_LOOKUP_TABLE_PROGRAM_BUILTIN,
74 : BPF_LOADER_DEPRECATED_BUILTIN,
75 : BPF_LOADER_BUILTIN,
76 : BPF_LOADER_UPGRADEABLE_BUILTIN,
77 : COMPUTE_BUDGET_PROGRAM_BUILTIN,
78 : ZK_TOKEN_PROOF_PROGRAM_BUILTIN,
79 : ZK_ELGAMAL_PROOF_PROGRAM_BUILTIN
80 : };
81 0 : #define BUILTIN_PROGRAMS_COUNT (sizeof(builtin_programs) / sizeof(fd_builtin_program_t))
82 :
83 : /* Used by the compute budget program to determine how many CUs to deduct by default
84 : https://github.com/anza-xyz/agave/blob/v2.1.13/builtins-default-costs/src/lib.rs#L113-L139 */
85 : fd_core_bpf_migration_config_t const * migrating_builtins[] = {
86 : MIGRATE_BUILTIN_TO_CORE_BPF_STAKE_PROGRAM_CONFIG,
87 : MIGRATE_BUILTIN_TO_CORE_BPF_CONFIG_PROGRAM_CONFIG,
88 : MIGRATE_BUILTIN_TO_CORE_BPF_ADDRESS_LOOKUP_TABLE_PROGRAM_CONFIG,
89 : };
90 0 : #define MIGRATING_BUILTINS_COUNT (sizeof(migrating_builtins) / sizeof(fd_core_bpf_migration_config_t const *))
91 :
92 : /* Using MAP_PERFECT instead of a list for optimization
93 : https://github.com/anza-xyz/agave/blob/v2.1.13/builtins-default-costs/src/lib.rs#L141-L193 */
94 : #define MAP_PERFECT_NAME fd_non_migrating_builtins_tbl
95 : #define MAP_PERFECT_LG_TBL_SZ 4
96 : #define MAP_PERFECT_T fd_pubkey_t
97 0 : #define MAP_PERFECT_HASH_C 146U
98 : #define MAP_PERFECT_KEY uc
99 : #define MAP_PERFECT_KEY_T fd_pubkey_t const *
100 : #define MAP_PERFECT_ZERO_KEY (0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0)
101 : #define MAP_PERFECT_COMPLEX_KEY 1
102 0 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
103 :
104 0 : #define PERFECT_HASH( u ) (((MAP_PERFECT_HASH_C*(u))>>28)&0x0FU)
105 :
106 : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
107 : a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
108 : PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) )
109 0 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr->uc + 8UL ) )
110 :
111 : #define MAP_PERFECT_0 ( VOTE_PROG_ID ),
112 : #define MAP_PERFECT_1 ( SYS_PROG_ID ),
113 : #define MAP_PERFECT_2 ( COMPUTE_BUDGET_PROG_ID ),
114 : #define MAP_PERFECT_3 ( BPF_UPGRADEABLE_PROG_ID ),
115 : #define MAP_PERFECT_4 ( BPF_LOADER_1_PROG_ID ),
116 : #define MAP_PERFECT_5 ( BPF_LOADER_2_PROG_ID ),
117 : #define MAP_PERFECT_6 ( LOADER_V4_PROG_ID ),
118 : #define MAP_PERFECT_7 ( KECCAK_SECP_PROG_ID ),
119 : #define MAP_PERFECT_8 ( ED25519_SV_PROG_ID ),
120 :
121 : #include "../../../util/tmpl/fd_map_perfect.c"
122 : #undef PERFECT_HASH
123 :
124 :
125 : /* BuiltIn programs need "bogus" executable accounts to exist.
126 : These are loaded and ignored during execution.
127 :
128 : Bogus accounts are marked as "executable", but their data is a
129 : hardcoded ASCII string. */
130 :
131 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/src/native_loader.rs#L19 */
132 : void
133 : fd_write_builtin_account( fd_exec_slot_ctx_t * slot_ctx,
134 : fd_pubkey_t const pubkey,
135 : char const * data,
136 0 : ulong sz ) {
137 :
138 0 : fd_acc_mgr_t * acc_mgr = slot_ctx->acc_mgr;
139 0 : fd_funk_txn_t * txn = slot_ctx->funk_txn;
140 0 : FD_TXN_ACCOUNT_DECL( rec );
141 :
142 0 : int err = fd_acc_mgr_modify( acc_mgr, txn, &pubkey, 1, sz, rec);
143 0 : FD_TEST( !err );
144 :
145 0 : rec->meta->dlen = sz;
146 0 : rec->meta->info.lamports = 1UL;
147 0 : rec->meta->info.rent_epoch = 0UL;
148 0 : rec->meta->info.executable = 1;
149 0 : fd_memcpy( rec->meta->info.owner, fd_solana_native_loader_id.key, 32 );
150 0 : memcpy( rec->data, data, sz );
151 :
152 0 : slot_ctx->slot_bank.capitalization++;
153 :
154 : // err = fd_acc_mgr_commit( acc_mgr, rec, slot_ctx );
155 0 : FD_TEST( !err );
156 0 : }
157 :
158 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/inline_spl_token.rs#L74 */
159 : /* TODO: move this somewhere more appropiate */
160 : static void
161 0 : write_inline_spl_native_mint_program_account( fd_exec_slot_ctx_t * slot_ctx ) {
162 : // really?! really!?
163 0 : fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
164 0 : if( epoch_bank->cluster_type != 3)
165 0 : return;
166 :
167 0 : fd_acc_mgr_t * acc_mgr = slot_ctx->acc_mgr;
168 0 : fd_funk_txn_t * txn = slot_ctx->funk_txn;
169 0 : fd_pubkey_t const * key = (fd_pubkey_t const *)&fd_solana_spl_native_mint_id;
170 0 : FD_TXN_ACCOUNT_DECL( rec );
171 :
172 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/inline_spl_token.rs#L86-L90 */
173 0 : static uchar const data[] = {
174 0 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
175 0 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
176 0 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
177 :
178 0 : int err = fd_acc_mgr_modify( acc_mgr, txn, key, 1, sizeof(data), rec );
179 0 : FD_TEST( !err );
180 :
181 0 : rec->meta->dlen = sizeof(data);
182 0 : rec->meta->info.lamports = 1000000000UL;
183 0 : rec->meta->info.rent_epoch = 1UL;
184 0 : rec->meta->info.executable = 0;
185 0 : fd_memcpy( rec->meta->info.owner, fd_solana_spl_token_id.key, 32 );
186 0 : memcpy( rec->data, data, sizeof(data) );
187 :
188 0 : FD_TEST( !err );
189 0 : }
190 :
191 0 : void fd_builtin_programs_init( fd_exec_slot_ctx_t * slot_ctx ) {
192 : // https://github.com/anza-xyz/agave/blob/v2.0.1/runtime/src/bank/builtins/mod.rs#L33
193 0 : fd_builtin_program_t const * builtins = fd_builtins();
194 0 : for( ulong i=0UL; i<fd_num_builtins(); i++ ) {
195 0 : if( builtins[i].core_bpf_migration_config && FD_FEATURE_ACTIVE_OFFSET( slot_ctx->slot_bank.slot, slot_ctx->epoch_ctx->features, builtins[i].core_bpf_migration_config->enable_feature_offset ) ) {
196 0 : continue;
197 0 : } else if( builtins[i].enable_feature_offset!=NO_ENABLE_FEATURE_ID && !FD_FEATURE_ACTIVE_OFFSET( slot_ctx->slot_bank.slot, slot_ctx->epoch_ctx->features, builtins[i].enable_feature_offset ) ) {
198 0 : continue;
199 0 : } else {
200 0 : fd_write_builtin_account( slot_ctx, *builtins[i].pubkey, builtins[i].data, strlen(builtins[i].data) );
201 0 : }
202 0 : }
203 :
204 : //TODO: remove when no longer necessary
205 0 : if( FD_FEATURE_ACTIVE( slot_ctx->slot_bank.slot, slot_ctx->epoch_ctx->features, zk_token_sdk_enabled ) ) {
206 0 : fd_write_builtin_account( slot_ctx, fd_solana_zk_token_proof_program_id, "zk_token_proof_program", 22UL );
207 0 : }
208 :
209 0 : if( FD_FEATURE_ACTIVE( slot_ctx->slot_bank.slot, slot_ctx->epoch_ctx->features, zk_elgamal_proof_program_enabled ) ) {
210 0 : fd_write_builtin_account( slot_ctx, fd_solana_zk_elgamal_proof_program_id, "zk_elgamal_proof_program", 24UL );
211 0 : }
212 :
213 : /* Precompiles have empty account data */
214 0 : if( slot_ctx->epoch_ctx->epoch_bank.cluster_version[0]<2 ) {
215 0 : char data[1] = {1};
216 0 : fd_write_builtin_account( slot_ctx, fd_solana_keccak_secp_256k_program_id, data, 1 );
217 0 : fd_write_builtin_account( slot_ctx, fd_solana_ed25519_sig_verify_program_id, data, 1 );
218 0 : if( FD_FEATURE_ACTIVE( slot_ctx->slot_bank.slot, slot_ctx->epoch_ctx->features, enable_secp256r1_precompile ) )
219 0 : fd_write_builtin_account( slot_ctx, fd_solana_secp256r1_program_id, data, 1 );
220 0 : } else {
221 0 : fd_write_builtin_account( slot_ctx, fd_solana_keccak_secp_256k_program_id, "", 0 );
222 0 : fd_write_builtin_account( slot_ctx, fd_solana_ed25519_sig_verify_program_id, "", 0 );
223 0 : if( FD_FEATURE_ACTIVE( slot_ctx->slot_bank.slot, slot_ctx->epoch_ctx->features, enable_secp256r1_precompile ) )
224 0 : fd_write_builtin_account( slot_ctx, fd_solana_secp256r1_program_id, "", 0 );
225 0 : }
226 :
227 : /* Inline SPL token mint program ("inlined to avoid an external dependency on the spl-token crate") */
228 0 : write_inline_spl_native_mint_program_account( slot_ctx );
229 0 : }
230 :
231 : fd_builtin_program_t const *
232 0 : fd_builtins( void ) {
233 0 : return builtin_programs;
234 0 : }
235 :
236 : ulong
237 0 : fd_num_builtins( void ) {
238 0 : return BUILTIN_PROGRAMS_COUNT;
239 0 : }
240 :
241 : fd_stateless_builtin_program_t const *
242 0 : fd_stateless_builtins( void ) {
243 0 : return stateless_programs_builtins;
244 0 : }
245 :
246 : ulong
247 0 : fd_num_stateless_builtins( void ) {
248 0 : return STATELESS_BUILTINS_COUNT;
249 0 : }
250 :
251 : uchar
252 : fd_is_migrating_builtin_program( fd_exec_txn_ctx_t const * txn_ctx,
253 : fd_pubkey_t const * pubkey,
254 0 : uchar * migrated_yet ) {
255 0 : *migrated_yet = 0;
256 :
257 0 : for( ulong i=0; i<MIGRATING_BUILTINS_COUNT; i++ ) {
258 0 : fd_core_bpf_migration_config_t const * config = migrating_builtins[i];
259 0 : if( !memcmp( pubkey->uc, config->builtin_program_id->key, sizeof(fd_pubkey_t) ) ) {
260 0 : if( config->enable_feature_offset!=NO_ENABLE_FEATURE_ID &&
261 0 : FD_FEATURE_ACTIVE_OFFSET( txn_ctx->slot, txn_ctx->features, config->enable_feature_offset ) ) {
262 : /* The program has been migrated to BPF. */
263 0 : *migrated_yet = 1;
264 0 : }
265 :
266 0 : return 1;
267 0 : }
268 0 : }
269 :
270 : /* No migration config exists for this program */
271 0 : return 0;
272 0 : }
273 :
274 : FD_FN_PURE uchar
275 0 : fd_is_non_migrating_builtin_program( fd_pubkey_t const * pubkey ) {
276 0 : return !!( fd_non_migrating_builtins_tbl_contains( pubkey ) );
277 0 : }
|