Line data Source code
1 : #include "fd_builtin_programs.h"
2 : #include "fd_precompiles.h"
3 : #include "../fd_system_ids.h"
4 : #include "../fd_system_ids_pp.h"
5 : #include "../../accdb/fd_accdb_sync.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 : /* Core BPF migration configs */
30 : static const fd_core_bpf_migration_config_t BUILTIN_TO_CORE_BPF_STAKE_PROGRAM_CONFIG = {
31 : &fd_solana_stake_program_buffer_address,
32 : NULL,
33 : offsetof(fd_features_t, migrate_stake_program_to_core_bpf),
34 : FD_CORE_BPF_MIGRATION_TARGET_BUILTIN,
35 : &fd_solana_stake_program_id,
36 : NULL
37 : };
38 : static const fd_core_bpf_migration_config_t * const MIGRATE_BUILTIN_TO_CORE_BPF_STAKE_PROGRAM_CONFIG = &BUILTIN_TO_CORE_BPF_STAKE_PROGRAM_CONFIG;
39 :
40 : static const fd_core_bpf_migration_config_t BUILTIN_TO_CORE_BPF_CONFIG_PROGRAM_CONFIG = {
41 : &fd_solana_config_program_buffer_address,
42 : NULL,
43 : offsetof(fd_features_t, migrate_config_program_to_core_bpf),
44 : FD_CORE_BPF_MIGRATION_TARGET_BUILTIN,
45 : &fd_solana_config_program_id,
46 : NULL
47 : };
48 : static const fd_core_bpf_migration_config_t * const MIGRATE_BUILTIN_TO_CORE_BPF_CONFIG_PROGRAM_CONFIG = &BUILTIN_TO_CORE_BPF_CONFIG_PROGRAM_CONFIG;
49 :
50 : static const fd_core_bpf_migration_config_t BUILTIN_TO_CORE_BPF_ADDRESS_LOOKUP_TABLE_PROGRAM_CONFIG = {
51 : &fd_solana_address_lookup_table_program_buffer_address,
52 : NULL,
53 : offsetof(fd_features_t, migrate_address_lookup_table_program_to_core_bpf),
54 : FD_CORE_BPF_MIGRATION_TARGET_BUILTIN,
55 : &fd_solana_address_lookup_table_program_id,
56 : NULL
57 : };
58 : static const fd_core_bpf_migration_config_t * const MIGRATE_BUILTIN_TO_CORE_BPF_ADDRESS_LOOKUP_TABLE_PROGRAM_CONFIG = &BUILTIN_TO_CORE_BPF_ADDRESS_LOOKUP_TABLE_PROGRAM_CONFIG;
59 :
60 : static const fd_core_bpf_migration_config_t STATELESS_TO_CORE_BPF_FEATURE_GATE_PROGRAM_CONFIG = {
61 : &fd_solana_feature_program_buffer_address,
62 : NULL,
63 : offsetof(fd_features_t, migrate_feature_gate_program_to_core_bpf),
64 : FD_CORE_BPF_MIGRATION_TARGET_STATELESS,
65 : &fd_solana_feature_program_id,
66 : NULL
67 : };
68 : static const fd_core_bpf_migration_config_t * const MIGRATE_STATELESS_TO_CORE_BPF_FEATURE_GATE_PROGRAM_CONFIG = &STATELESS_TO_CORE_BPF_FEATURE_GATE_PROGRAM_CONFIG;
69 :
70 : /* 192ed727334abe822d5accba8b886e25f88b03c76973c2e7290cfb55b9e1115f */
71 : #define SLASHING_PROG_HASH_SIMD_204 0x19U,0x2eU,0xd7U,0x27U,0x33U,0x4aU,0xbeU,0x82U,0x2dU,0x5aU,0xccU,0xbaU,0x8bU,0x88U,0x6eU,0x25U, \
72 : 0xf8U,0x8bU,0x03U,0xc7U,0x69U,0x73U,0xc2U,0xe7U,0x29U,0x0cU,0xfbU,0x55U,0xb9U,0xe1U,0x11U,0x5fU
73 : const fd_hash_t fd_solana_slashing_program_verified_build_hash_simd_204 = { .uc = { SLASHING_PROG_HASH_SIMD_204 } };
74 : static const fd_core_bpf_migration_config_t STATELESS_TO_CORE_BPF_SLASHING_PROGRAM_CONFIG = {
75 : &fd_solana_slashing_program_buffer_address,
76 : NULL,
77 : offsetof(fd_features_t, enshrine_slashing_program),
78 : FD_CORE_BPF_MIGRATION_TARGET_STATELESS,
79 : &fd_solana_slashing_program_id,
80 : &fd_solana_slashing_program_verified_build_hash_simd_204
81 : };
82 : static const fd_core_bpf_migration_config_t * const MIGRATE_STATELESS_TO_CORE_BPF_SLASHING_PROGRAM_CONFIG = &STATELESS_TO_CORE_BPF_SLASHING_PROGRAM_CONFIG;
83 :
84 : #define SYSTEM_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_system_program_id, "system_program", NO_ENABLE_FEATURE_ID, NULL)
85 : #define VOTE_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_vote_program_id, "vote_program", NO_ENABLE_FEATURE_ID, NULL)
86 : #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)
87 : #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)
88 : #define LOADER_V4_BUILTIN BUILTIN_PROGRAM(&fd_solana_bpf_loader_v4_program_id, "loader_v4", offsetof(fd_features_t, enable_loader_v4), NULL)
89 : #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)
90 : #define BPF_LOADER_DEPRECATED_BUILTIN BUILTIN_PROGRAM(&fd_solana_bpf_loader_deprecated_program_id, "solana_bpf_loader_deprecated_program", NO_ENABLE_FEATURE_ID, NULL)
91 : #define BPF_LOADER_BUILTIN BUILTIN_PROGRAM(&fd_solana_bpf_loader_program_id, "solana_bpf_loader_program", NO_ENABLE_FEATURE_ID, NULL)
92 : #define BPF_LOADER_UPGRADEABLE_BUILTIN BUILTIN_PROGRAM(&fd_solana_bpf_loader_upgradeable_program_id, "solana_bpf_loader_upgradeable_program", NO_ENABLE_FEATURE_ID, NULL)
93 : #define COMPUTE_BUDGET_PROGRAM_BUILTIN BUILTIN_PROGRAM(&fd_solana_compute_budget_program_id, "compute_budget_program", NO_ENABLE_FEATURE_ID, NULL)
94 : #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), NULL)
95 : #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), NULL)
96 :
97 : #define FEATURE_PROGRAM_BUILTIN STATELESS_BUILTIN(&fd_solana_feature_program_id, MIGRATE_STATELESS_TO_CORE_BPF_FEATURE_GATE_PROGRAM_CONFIG)
98 : #define SLASHING_PROGRAM_BUILTIN STATELESS_BUILTIN(&fd_solana_slashing_program_id, MIGRATE_STATELESS_TO_CORE_BPF_SLASHING_PROGRAM_CONFIG)
99 :
100 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/mod.rs#L133-L143 */
101 : static const fd_stateless_builtin_program_t stateless_programs_builtins[] = {
102 : FEATURE_PROGRAM_BUILTIN,
103 : SLASHING_PROGRAM_BUILTIN
104 : };
105 126 : #define STATELESS_BUILTINS_COUNT (sizeof(stateless_programs_builtins) / sizeof(fd_stateless_builtin_program_t))
106 :
107 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/mod.rs#L34-L131 */
108 : static fd_builtin_program_t const builtin_programs[] = {
109 : SYSTEM_PROGRAM_BUILTIN,
110 : VOTE_PROGRAM_BUILTIN,
111 : STAKE_PROGRAM_BUILTIN,
112 : CONFIG_PROGRAM_BUILTIN,
113 : LOADER_V4_BUILTIN,
114 : ADDRESS_LOOKUP_TABLE_PROGRAM_BUILTIN,
115 : BPF_LOADER_DEPRECATED_BUILTIN,
116 : BPF_LOADER_BUILTIN,
117 : BPF_LOADER_UPGRADEABLE_BUILTIN,
118 : COMPUTE_BUDGET_PROGRAM_BUILTIN,
119 : ZK_TOKEN_PROOF_PROGRAM_BUILTIN,
120 : ZK_ELGAMAL_PROOF_PROGRAM_BUILTIN
121 : };
122 1170 : #define BUILTIN_PROGRAMS_COUNT (sizeof(builtin_programs) / sizeof(fd_builtin_program_t))
123 :
124 : /* Used by the compute budget program to determine how many CUs to deduct by default
125 : https://github.com/anza-xyz/agave/blob/v2.1.13/builtins-default-costs/src/lib.rs#L113-L139 */
126 : static fd_core_bpf_migration_config_t const * migrating_builtins[] = {
127 : MIGRATE_BUILTIN_TO_CORE_BPF_STAKE_PROGRAM_CONFIG,
128 : MIGRATE_BUILTIN_TO_CORE_BPF_CONFIG_PROGRAM_CONFIG,
129 : MIGRATE_BUILTIN_TO_CORE_BPF_ADDRESS_LOOKUP_TABLE_PROGRAM_CONFIG,
130 : };
131 348 : #define MIGRATING_BUILTINS_COUNT (sizeof(migrating_builtins) / sizeof(fd_core_bpf_migration_config_t const *))
132 :
133 : /* https://github.com/anza-xyz/agave/blob/v2.1.13/builtins-default-costs/src/lib.rs#L141-L193 */
134 : #define MAP_PERFECT_NAME fd_non_migrating_builtins_tbl
135 : #define MAP_PERFECT_LG_TBL_SZ 4
136 : #define MAP_PERFECT_T fd_pubkey_t
137 60 : #define MAP_PERFECT_HASH_C 146U
138 : #define MAP_PERFECT_KEY uc
139 : #define MAP_PERFECT_KEY_T fd_pubkey_t const *
140 : #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)
141 : #define MAP_PERFECT_COMPLEX_KEY 1
142 60 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
143 :
144 60 : #define PERFECT_HASH( u ) (((MAP_PERFECT_HASH_C*(u))>>28)&0x0FU)
145 :
146 : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
147 : a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
148 : PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) )
149 60 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr->uc + 8UL ) )
150 :
151 : #define MAP_PERFECT_0 ( VOTE_PROG_ID ),
152 : #define MAP_PERFECT_1 ( SYS_PROG_ID ),
153 : #define MAP_PERFECT_2 ( COMPUTE_BUDGET_PROG_ID ),
154 : #define MAP_PERFECT_3 ( BPF_UPGRADEABLE_PROG_ID ),
155 : #define MAP_PERFECT_4 ( BPF_LOADER_1_PROG_ID ),
156 : #define MAP_PERFECT_5 ( BPF_LOADER_2_PROG_ID ),
157 : #define MAP_PERFECT_6 ( LOADER_V4_PROG_ID ),
158 : #define MAP_PERFECT_7 ( KECCAK_SECP_PROG_ID ),
159 : #define MAP_PERFECT_8 ( ED25519_SV_PROG_ID ),
160 :
161 : #include "../../../util/tmpl/fd_map_perfect.c"
162 : #undef PERFECT_HASH
163 :
164 : // https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L4944
165 : static int
166 : fd_builtin_is_bpf( fd_accdb_user_t * accdb,
167 : fd_funk_txn_xid_t const * xid,
168 270 : fd_pubkey_t const * pubkey ) {
169 270 : fd_accdb_ro_t ro[1];
170 270 : if( !fd_accdb_open_ro( accdb, ro, xid, pubkey ) ) {
171 270 : return 0;
172 270 : }
173 0 : int is_bpf = memcmp( fd_accdb_ref_owner( ro ), &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_solana_bpf_loader_upgradeable_program_id) )==0;
174 0 : fd_accdb_close_ro( accdb, ro );
175 0 : return is_bpf;
176 270 : }
177 :
178 :
179 : /* BuiltIn programs need "bogus" executable accounts to exist.
180 : These are loaded and ignored during execution.
181 :
182 : Bogus accounts are marked as "executable", but their data is a
183 : hardcoded ASCII string. */
184 :
185 : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/src/native_loader.rs#L19 */
186 : void
187 : fd_write_builtin_account( fd_bank_t * bank,
188 : fd_accdb_user_t * accdb,
189 : fd_funk_txn_xid_t const * xid,
190 : fd_capture_ctx_t * capture_ctx,
191 : fd_pubkey_t const pubkey,
192 : void const * data,
193 642 : ulong sz ) {
194 :
195 642 : fd_accdb_rw_t rw[1];
196 642 : fd_accdb_open_rw( accdb, rw, xid, &pubkey, sz, FD_ACCDB_FLAG_CREATE );
197 :
198 642 : fd_lthash_value_t prev_hash[1];
199 642 : fd_hashes_account_lthash(
200 642 : &pubkey,
201 642 : rw->meta,
202 642 : fd_accdb_ref_data_const( rw->ro ),
203 642 : prev_hash );
204 :
205 642 : fd_accdb_ref_data_set( accdb, rw, data, sz );
206 642 : fd_accdb_ref_lamports_set( rw, 1UL );
207 642 : fd_accdb_ref_exec_bit_set( rw, 1 );
208 642 : fd_accdb_ref_owner_set( rw, &fd_solana_native_loader_id );
209 :
210 642 : fd_hashes_update_lthash( &pubkey, rw->meta, prev_hash, bank, capture_ctx );
211 642 : fd_bank_capitalization_set( bank, fd_bank_capitalization_get( bank ) + 1UL );
212 642 : fd_accdb_close_rw( accdb, rw );
213 642 : }
214 :
215 : void
216 : fd_builtin_programs_init( fd_bank_t * bank,
217 : fd_accdb_user_t * accdb,
218 : fd_funk_txn_xid_t const * xid,
219 48 : fd_capture_ctx_t * capture_ctx ) {
220 : /* https://github.com/anza-xyz/agave/blob/v2.3.7/builtins/src/lib.rs#L52 */
221 48 : fd_builtin_program_t const * builtins = fd_builtins();
222 :
223 624 : for( ulong i=0UL; i<fd_num_builtins(); i++ ) {
224 : /** https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L4949 */
225 576 : if( fd_bank_slot_get( bank )==0UL && builtins[i].enable_feature_offset==NO_ENABLE_FEATURE_ID && !fd_builtin_is_bpf( accdb, xid, builtins[i].pubkey ) ) {
226 270 : fd_write_builtin_account( bank, accdb, xid, capture_ctx, *builtins[i].pubkey, builtins[i].data, strlen( builtins[i].data ) );
227 306 : } else if( builtins[i].core_bpf_migration_config && FD_FEATURE_ACTIVE_OFFSET( fd_bank_slot_get( bank ), fd_bank_features_query( bank ), builtins[i].core_bpf_migration_config->enable_feature_offset ) ) {
228 36 : continue;
229 270 : } else if( builtins[i].enable_feature_offset!=NO_ENABLE_FEATURE_ID && !FD_FEATURE_ACTIVE_OFFSET( fd_bank_slot_get( bank ), fd_bank_features_query( bank ), builtins[i].enable_feature_offset ) ) {
230 30 : continue;
231 240 : } else {
232 240 : fd_write_builtin_account( bank, accdb, xid, capture_ctx, *builtins[i].pubkey, builtins[i].data, strlen(builtins[i].data) );
233 240 : }
234 576 : }
235 :
236 : /* Precompiles have empty account data */
237 48 : fd_write_builtin_account( bank, accdb, xid, capture_ctx, fd_solana_keccak_secp_256k_program_id, "", 0 );
238 48 : fd_write_builtin_account( bank, accdb, xid, capture_ctx, fd_solana_ed25519_sig_verify_program_id, "", 0 );
239 48 : if( FD_FEATURE_ACTIVE_BANK( bank, enable_secp256r1_precompile ) ) {
240 36 : fd_write_builtin_account( bank, accdb, xid, capture_ctx, fd_solana_secp256r1_program_id, "", 0 );
241 36 : }
242 48 : }
243 :
244 : fd_builtin_program_t const *
245 90 : fd_builtins( void ) {
246 90 : return builtin_programs;
247 90 : }
248 :
249 : ulong
250 1170 : fd_num_builtins( void ) {
251 1170 : return BUILTIN_PROGRAMS_COUNT;
252 1170 : }
253 :
254 : fd_stateless_builtin_program_t const *
255 42 : fd_stateless_builtins( void ) {
256 42 : return stateless_programs_builtins;
257 42 : }
258 :
259 : ulong
260 126 : fd_num_stateless_builtins( void ) {
261 126 : return STATELESS_BUILTINS_COUNT;
262 126 : }
263 :
264 : uchar
265 : fd_is_migrating_builtin_program( fd_bank_t const * bank,
266 : fd_pubkey_t const * pubkey,
267 87 : uchar * migrated_yet ) {
268 87 : *migrated_yet = 0;
269 :
270 348 : for( ulong i=0; i<MIGRATING_BUILTINS_COUNT; i++ ) {
271 261 : fd_core_bpf_migration_config_t const * config = migrating_builtins[i];
272 261 : if( !memcmp( pubkey->uc, config->builtin_program_id->key, sizeof(fd_pubkey_t) ) ) {
273 0 : if( config->enable_feature_offset!=NO_ENABLE_FEATURE_ID &&
274 0 : FD_FEATURE_ACTIVE_OFFSET( fd_bank_slot_get( bank ), fd_bank_features_query( bank ), config->enable_feature_offset ) ) {
275 : /* The program has been migrated to BPF. */
276 0 : *migrated_yet = 1;
277 0 : }
278 :
279 0 : return 1;
280 0 : }
281 261 : }
282 :
283 : /* No migration config exists for this program */
284 87 : return 0;
285 87 : }
286 :
287 : FD_FN_PURE uchar
288 60 : fd_is_non_migrating_builtin_program( fd_pubkey_t const * pubkey ) {
289 60 : return !!( fd_non_migrating_builtins_tbl_contains( pubkey ) );
290 60 : }
|