Line data Source code
1 : #include "fd_bpf_program_util.h"
2 : #include "fd_bpf_loader_program.h"
3 : #include "fd_loader_v4_program.h"
4 : #include "../fd_acc_mgr.h"
5 : #include "../context/fd_exec_slot_ctx.h"
6 : #include "../../vm/syscall/fd_vm_syscall.h"
7 :
8 : #include <assert.h>
9 :
10 : fd_sbpf_validated_program_t *
11 0 : fd_sbpf_validated_program_new( void * mem, fd_sbpf_elf_info_t const * elf_info ) {
12 0 : fd_sbpf_validated_program_t * validated_prog = (fd_sbpf_validated_program_t *)mem;
13 :
14 0 : ulong l = FD_LAYOUT_INIT;
15 :
16 : /* calldests backing memory */
17 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_sbpf_validated_program_t), sizeof(fd_sbpf_validated_program_t) );
18 0 : validated_prog->calldests_shmem = (uchar *)mem + l;
19 :
20 : /* rodata backing memory */
21 0 : l = FD_LAYOUT_APPEND( l, fd_sbpf_calldests_align(), fd_sbpf_calldests_footprint(elf_info->rodata_sz/8UL) );
22 0 : validated_prog->rodata = (uchar *)mem + l;
23 :
24 : /* SBPF version */
25 0 : validated_prog->sbpf_version = elf_info->sbpf_version;
26 :
27 0 : return (fd_sbpf_validated_program_t *)mem;
28 0 : }
29 :
30 : ulong
31 0 : fd_sbpf_validated_program_align( void ) {
32 0 : return alignof(fd_sbpf_validated_program_t);
33 0 : }
34 :
35 : ulong
36 0 : fd_sbpf_validated_program_footprint( fd_sbpf_elf_info_t const * elf_info ) {
37 0 : ulong l = FD_LAYOUT_INIT;
38 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_sbpf_validated_program_t), sizeof(fd_sbpf_validated_program_t) );
39 0 : l = FD_LAYOUT_APPEND( l, fd_sbpf_calldests_align(), fd_sbpf_calldests_footprint(elf_info->rodata_sz/8UL) );
40 0 : l = FD_LAYOUT_APPEND( l, 8UL, elf_info->rodata_footprint );
41 0 : l = FD_LAYOUT_FINI( l, 128UL );
42 0 : return l;
43 0 : }
44 :
45 : static inline fd_funk_rec_key_t
46 0 : fd_acc_mgr_cache_key( fd_pubkey_t const * pubkey ) {
47 0 : fd_funk_rec_key_t id;
48 0 : memcpy( id.uc, pubkey, sizeof(fd_pubkey_t) );
49 0 : memset( id.uc + sizeof(fd_pubkey_t), 0, sizeof(fd_funk_rec_key_t) - sizeof(fd_pubkey_t) );
50 :
51 0 : id.c[ FD_FUNK_REC_KEY_FOOTPRINT - 1 ] = FD_FUNK_KEY_TYPE_ELF_CACHE;
52 :
53 0 : return id;
54 0 : }
55 :
56 : /* Similar to the below function, but gets the executable program content for the v4 loader.
57 : Unlike the v3 loader, the programdata is stored in a single program account. The program must
58 : NOT be retracted to be added to the cache. */
59 : static int
60 : fd_bpf_get_executable_program_content_for_v4_loader( fd_txn_account_t * program_acc,
61 : uchar const ** program_data,
62 0 : ulong * program_data_len ) {
63 0 : int err;
64 0 : fd_loader_v4_state_t state = {0};
65 :
66 : /* Get the current loader v4 state. This implicitly also checks the dlen. */
67 0 : err = fd_loader_v4_get_state( program_acc, &state );
68 0 : if( FD_UNLIKELY( err ) ) {
69 0 : return -1;
70 0 : }
71 :
72 : /* The program must be deployed or finalized. */
73 0 : if( FD_UNLIKELY( fd_loader_v4_status_is_retracted( &state ) ) ) {
74 0 : return -1;
75 0 : }
76 :
77 0 : *program_data = program_acc->const_data + LOADER_V4_PROGRAM_DATA_OFFSET;
78 0 : *program_data_len = program_acc->const_meta->dlen - LOADER_V4_PROGRAM_DATA_OFFSET;
79 0 : return 0;
80 0 : }
81 :
82 : static int
83 : fd_bpf_get_executable_program_content_for_upgradeable_loader( fd_exec_slot_ctx_t * slot_ctx,
84 : fd_txn_account_t * program_acc,
85 : uchar const ** program_data,
86 : ulong * program_data_len,
87 0 : fd_spad_t * runtime_spad ) {
88 0 : FD_TXN_ACCOUNT_DECL( programdata_acc );
89 :
90 0 : fd_bincode_decode_ctx_t ctx = {
91 0 : .data = program_acc->const_data,
92 0 : .dataend = program_acc->const_data + program_acc->const_meta->dlen,
93 0 : };
94 :
95 0 : ulong total_sz = 0UL;
96 0 : if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode_footprint( &ctx, &total_sz ) ) ) {
97 0 : return -1;
98 0 : }
99 :
100 0 : uchar * mem = fd_spad_alloc( runtime_spad, fd_bpf_upgradeable_loader_state_align(), total_sz );
101 0 : if( FD_UNLIKELY( !mem ) ) {
102 0 : FD_LOG_ERR(( "Unable to allocate memory for bpf upgradeable loader state" ));
103 0 : }
104 :
105 0 : fd_bpf_upgradeable_loader_state_t * program_account_state =
106 0 : fd_bpf_upgradeable_loader_state_decode( mem, &ctx );
107 :
108 0 : if( !fd_bpf_upgradeable_loader_state_is_program( program_account_state ) ) {
109 0 : return -1;
110 0 : }
111 :
112 0 : fd_pubkey_t * programdata_address = &program_account_state->inner.program.programdata_address;
113 :
114 0 : if( fd_acc_mgr_view( slot_ctx->acc_mgr,
115 0 : slot_ctx->funk_txn,
116 0 : programdata_address,
117 0 : programdata_acc ) != FD_ACC_MGR_SUCCESS ) {
118 0 : return -1;
119 0 : }
120 :
121 : /* We don't actually need to decode here, just make sure that the account
122 : can be decoded successfully. */
123 0 : fd_bincode_decode_ctx_t ctx_programdata = {
124 0 : .data = programdata_acc->const_data,
125 0 : .dataend = programdata_acc->const_data + programdata_acc->const_meta->dlen,
126 0 : };
127 :
128 0 : if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode_footprint( &ctx_programdata, &total_sz ) ) ) {
129 0 : return -1;
130 0 : }
131 :
132 0 : *program_data = programdata_acc->const_data + PROGRAMDATA_METADATA_SIZE;
133 0 : *program_data_len = programdata_acc->const_meta->dlen - PROGRAMDATA_METADATA_SIZE;
134 0 : return 0;
135 0 : }
136 :
137 : static int
138 : fd_bpf_get_executable_program_content_for_v1_v2_loaders( fd_txn_account_t * program_acc,
139 : uchar const ** program_data,
140 0 : ulong * program_data_len ) {
141 0 : *program_data = program_acc->const_data;
142 0 : *program_data_len = program_acc->const_meta->dlen;
143 0 : return 0;
144 0 : }
145 :
146 : void
147 : fd_bpf_get_sbpf_versions( uint * sbpf_min_version,
148 : uint * sbpf_max_version,
149 : ulong slot,
150 0 : fd_features_t const * features ) {
151 0 : int disable_v0 = FD_FEATURE_ACTIVE( slot, *features, disable_sbpf_v0_execution );
152 0 : int reenable_v0 = FD_FEATURE_ACTIVE( slot, *features, reenable_sbpf_v0_execution );
153 0 : int enable_v0 = !disable_v0 || reenable_v0;
154 0 : int enable_v1 = FD_FEATURE_ACTIVE( slot, *features, enable_sbpf_v1_deployment_and_execution );
155 0 : int enable_v2 = FD_FEATURE_ACTIVE( slot, *features, enable_sbpf_v2_deployment_and_execution );
156 0 : int enable_v3 = FD_FEATURE_ACTIVE( slot, *features, enable_sbpf_v3_deployment_and_execution );
157 :
158 0 : *sbpf_min_version = enable_v0 ? FD_SBPF_V0 : FD_SBPF_V3;
159 0 : if( enable_v3 ) {
160 0 : *sbpf_max_version = FD_SBPF_V3;
161 0 : } else if( enable_v2 ) {
162 0 : *sbpf_max_version = FD_SBPF_V2;
163 0 : } else if( enable_v1 ) {
164 0 : *sbpf_max_version = FD_SBPF_V1;
165 0 : } else {
166 0 : *sbpf_max_version = FD_SBPF_V0;
167 0 : }
168 0 : }
169 :
170 : static int
171 : fd_bpf_create_bpf_program_cache_entry( fd_exec_slot_ctx_t * slot_ctx,
172 : fd_txn_account_t * program_acc,
173 0 : fd_spad_t * runtime_spad ) {
174 0 : FD_SPAD_FRAME_BEGIN( runtime_spad ) {
175 :
176 0 : fd_pubkey_t * program_pubkey = program_acc->pubkey;
177 :
178 0 : fd_funk_t * funk = slot_ctx->acc_mgr->funk;
179 0 : fd_funk_txn_t * funk_txn = slot_ctx->funk_txn;
180 0 : fd_funk_rec_key_t id = fd_acc_mgr_cache_key( program_pubkey );
181 :
182 0 : uchar const * program_data = NULL;
183 0 : ulong program_data_len = 0UL;
184 :
185 : /* For v3 loaders, deserialize the program account and lookup the
186 : programdata account. Deserialize the programdata account. */
187 :
188 0 : int res;
189 0 : if( !memcmp( program_acc->const_meta->info.owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) {
190 0 : res = fd_bpf_get_executable_program_content_for_upgradeable_loader( slot_ctx, program_acc, &program_data, &program_data_len, runtime_spad );
191 0 : } else if( !memcmp( program_acc->const_meta->info.owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
192 0 : res = fd_bpf_get_executable_program_content_for_v4_loader( program_acc, &program_data, &program_data_len );
193 0 : } else {
194 0 : res = fd_bpf_get_executable_program_content_for_v1_v2_loaders( program_acc, &program_data, &program_data_len );
195 0 : }
196 :
197 0 : if( res ) {
198 0 : return -1;
199 0 : }
200 :
201 0 : fd_sbpf_elf_info_t elf_info = {0};
202 0 : uint min_sbpf_version, max_sbpf_version;
203 0 : fd_bpf_get_sbpf_versions( &min_sbpf_version,
204 0 : &max_sbpf_version,
205 0 : slot_ctx->slot_bank.slot,
206 0 : &slot_ctx->epoch_ctx->features );
207 0 : if( fd_sbpf_elf_peek( &elf_info, program_data, program_data_len, /* deploy checks */ 0, min_sbpf_version, max_sbpf_version ) == NULL ) {
208 0 : FD_LOG_DEBUG(( "fd_sbpf_elf_peek() failed: %s", fd_sbpf_strerror() ));
209 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
210 0 : }
211 :
212 0 : int funk_err = FD_FUNK_SUCCESS;
213 0 : fd_funk_rec_t const * existing_rec = fd_funk_rec_query_global( funk, funk_txn, &id, NULL );
214 0 : fd_funk_rec_t * rec = fd_funk_rec_write_prepare( funk, funk_txn, &id, fd_sbpf_validated_program_footprint( &elf_info ), 1, existing_rec, &funk_err );
215 0 : if( rec == NULL || funk_err != FD_FUNK_SUCCESS ) {
216 0 : return -1;
217 0 : }
218 :
219 0 : void * val = fd_funk_val( rec, fd_funk_wksp( funk ) );
220 0 : fd_sbpf_validated_program_t * validated_prog = fd_sbpf_validated_program_new( val, &elf_info );
221 :
222 0 : ulong prog_align = fd_sbpf_program_align();
223 0 : ulong prog_footprint = fd_sbpf_program_footprint( &elf_info );
224 0 : fd_sbpf_program_t * prog = fd_sbpf_program_new( fd_spad_alloc( runtime_spad, prog_align, prog_footprint ), &elf_info, validated_prog->rodata );
225 0 : if( FD_UNLIKELY( !prog ) ) {
226 0 : return -1;
227 0 : }
228 :
229 : /* Allocate syscalls */
230 :
231 0 : fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_new( fd_spad_alloc( runtime_spad, fd_sbpf_syscalls_align(), fd_sbpf_syscalls_footprint() ) );
232 0 : if( FD_UNLIKELY( !syscalls ) ) {
233 0 : FD_LOG_ERR(( "Call to fd_sbpf_syscalls_new() failed" ));
234 0 : }
235 :
236 0 : fd_vm_syscall_register_slot( syscalls,
237 0 : slot_ctx->slot_bank.slot,
238 0 : &slot_ctx->epoch_ctx->features,
239 0 : 0 );
240 :
241 : /* Load program. */
242 :
243 0 : if( FD_UNLIKELY( 0!=fd_sbpf_program_load( prog, program_data, program_data_len, syscalls, false ) ) ) {
244 : /* Remove pending funk record */
245 0 : FD_LOG_DEBUG(( "fd_sbpf_program_load() failed: %s", fd_sbpf_strerror() ));
246 0 : fd_funk_rec_remove( funk, rec, funk_txn->xid.ul[0] );
247 0 : return -1;
248 0 : }
249 :
250 : /* Validate the program. */
251 :
252 0 : fd_vm_t _vm[ 1UL ];
253 0 : fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
254 0 : if( FD_UNLIKELY( !vm ) ) {
255 0 : FD_LOG_ERR(( "fd_vm_new() or fd_vm_join() failed" ));
256 0 : }
257 0 : fd_exec_instr_ctx_t dummy_instr_ctx = {0};
258 0 : fd_exec_txn_ctx_t dummy_txn_ctx = {0};
259 0 : dummy_txn_ctx.slot = slot_ctx->slot_bank.slot;
260 0 : dummy_txn_ctx.features = slot_ctx->epoch_ctx->features;
261 0 : dummy_instr_ctx.txn_ctx = &dummy_txn_ctx;
262 0 : vm = fd_vm_init( vm,
263 0 : &dummy_instr_ctx,
264 0 : 0UL,
265 0 : 0UL,
266 0 : prog->rodata,
267 0 : prog->rodata_sz,
268 0 : prog->text,
269 0 : prog->text_cnt,
270 0 : prog->text_off,
271 0 : prog->text_sz,
272 0 : prog->entry_pc,
273 0 : prog->calldests,
274 0 : elf_info.sbpf_version,
275 0 : NULL,
276 0 : NULL,
277 0 : NULL,
278 0 : NULL,
279 0 : 0U,
280 0 : NULL,
281 0 : 0,
282 0 : FD_FEATURE_ACTIVE( slot_ctx->slot_bank.slot, slot_ctx->epoch_ctx->features, bpf_account_data_direct_mapping ) );
283 :
284 0 : if( FD_UNLIKELY( !vm ) ) {
285 0 : FD_LOG_ERR(( "fd_vm_init() failed" ));
286 0 : }
287 :
288 0 : res = fd_vm_validate( vm );
289 0 : if( FD_UNLIKELY( res ) ) {
290 : /* Remove pending funk record */
291 0 : FD_LOG_DEBUG(( "fd_vm_validate() failed" ));
292 0 : fd_funk_rec_remove( funk, rec, 0UL );
293 0 : return -1;
294 0 : }
295 :
296 0 : fd_memcpy( validated_prog->calldests_shmem, prog->calldests_shmem, fd_sbpf_calldests_footprint( prog->rodata_sz/8UL ) );
297 0 : validated_prog->calldests = fd_sbpf_calldests_join( validated_prog->calldests_shmem );
298 :
299 0 : validated_prog->entry_pc = prog->entry_pc;
300 0 : validated_prog->last_updated_slot = slot_ctx->slot_bank.slot;
301 0 : validated_prog->text_off = prog->text_off;
302 0 : validated_prog->text_cnt = prog->text_cnt;
303 0 : validated_prog->text_sz = prog->text_sz;
304 0 : validated_prog->rodata_sz = prog->rodata_sz;
305 :
306 0 : return 0;
307 0 : } FD_SPAD_FRAME_END;
308 0 : }
309 :
310 : static void FD_FN_UNUSED
311 : fd_bpf_scan_task( void * tpool,
312 : ulong t0 FD_PARAM_UNUSED, ulong t1 FD_PARAM_UNUSED,
313 : void * args,
314 : void * reduce , ulong stride FD_PARAM_UNUSED,
315 : ulong l0 FD_PARAM_UNUSED, ulong l1 FD_PARAM_UNUSED,
316 : ulong m0, ulong m1 FD_PARAM_UNUSED,
317 0 : ulong n0 FD_PARAM_UNUSED, ulong n1 FD_PARAM_UNUSED ) {
318 0 : fd_funk_rec_t const * recs = ((fd_funk_rec_t const **)tpool)[m0];
319 0 : fd_exec_slot_ctx_t * slot_ctx = (fd_exec_slot_ctx_t *)args;
320 0 : uchar * is_bpf_program = (uchar *)reduce + m0;
321 :
322 0 : if( !fd_funk_key_is_acc( recs->pair.key ) ) {
323 0 : *is_bpf_program = 0;
324 0 : return;
325 0 : }
326 :
327 0 : fd_pubkey_t const * pubkey = fd_type_pun_const( recs->pair.key[0].uc );
328 :
329 0 : FD_TXN_ACCOUNT_DECL( exec_rec );
330 0 : if( fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, pubkey, exec_rec ) != FD_ACC_MGR_SUCCESS ) {
331 0 : return;
332 0 : }
333 :
334 0 : if( memcmp( exec_rec->const_meta->info.owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) &&
335 0 : memcmp( exec_rec->const_meta->info.owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) &&
336 0 : memcmp( exec_rec->const_meta->info.owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) &&
337 0 : memcmp( exec_rec->const_meta->info.owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
338 0 : *is_bpf_program = 0;
339 0 : } else {
340 0 : *is_bpf_program = 1;
341 0 : }
342 0 : }
343 :
344 : int
345 : fd_bpf_scan_and_create_bpf_program_cache_entry_tpool( fd_exec_slot_ctx_t * slot_ctx,
346 : fd_funk_txn_t * funk_txn,
347 : fd_tpool_t * tpool,
348 0 : fd_spad_t * runtime_spad ) {
349 0 : long elapsed_ns = -fd_log_wallclock();
350 0 : fd_funk_t * funk = slot_ctx->acc_mgr->funk;
351 0 : ulong cached_cnt = 0UL;
352 :
353 : /* Use random-ish xid to avoid concurrency issues */
354 0 : fd_funk_txn_xid_t cache_xid = fd_funk_generate_xid();
355 :
356 0 : fd_funk_txn_t * cache_txn = fd_funk_txn_prepare( funk, slot_ctx->funk_txn, &cache_xid, 1 );
357 0 : if( !cache_txn ) {
358 0 : FD_LOG_ERR(( "fd_funk_txn_prepare() failed" ));
359 0 : return -1;
360 0 : }
361 :
362 0 : fd_funk_txn_t * parent_txn = slot_ctx->funk_txn;
363 0 : slot_ctx->funk_txn = cache_txn;
364 :
365 0 : fd_funk_rec_t const * rec = fd_funk_txn_first_rec( funk, funk_txn );
366 0 : while( rec!=NULL ) {
367 0 : FD_SPAD_FRAME_BEGIN( runtime_spad ) {
368 0 : fd_funk_rec_t const * * recs = fd_spad_alloc( runtime_spad, alignof(fd_funk_rec_t*), 65536UL * sizeof(fd_funk_rec_t const *) );
369 0 : uchar * is_bpf_program = fd_spad_alloc( runtime_spad, 8UL, 65536UL * sizeof(uchar) );
370 :
371 : /* Make a list of rec ptrs to process */
372 0 : ulong rec_cnt = 0UL;
373 0 : for( ; NULL != rec; rec = fd_funk_txn_next_rec( funk, rec ) ) {
374 0 : if( rec->flags & FD_FUNK_REC_FLAG_ERASE ) continue;
375 0 : recs[ rec_cnt ] = rec;
376 :
377 0 : if( rec_cnt==65536UL ) {
378 0 : break;
379 0 : }
380 :
381 0 : rec_cnt++;
382 0 : }
383 :
384 0 : fd_tpool_exec_all_block( tpool, 0, fd_tpool_worker_cnt( tpool ), fd_bpf_scan_task,
385 0 : recs, slot_ctx, is_bpf_program, 1, 0, rec_cnt );
386 :
387 0 : for( ulong i = 0; i<rec_cnt; i++ ) {
388 0 : if( !is_bpf_program[ i ] ) {
389 0 : continue;
390 0 : }
391 :
392 0 : fd_pubkey_t const * pubkey = fd_type_pun_const( recs[i]->pair.key[0].uc );
393 0 : int res = fd_bpf_check_and_create_bpf_program_cache_entry( slot_ctx, funk_txn, pubkey, runtime_spad );
394 0 : if( res==0 ) {
395 0 : cached_cnt++;
396 0 : }
397 0 : }
398 :
399 0 : } FD_SPAD_FRAME_END;
400 0 : }
401 :
402 0 : if( fd_funk_txn_publish_into_parent( funk, cache_txn, 1 ) != FD_FUNK_SUCCESS ) {
403 0 : FD_LOG_ERR(( "fd_funk_txn_publish_into_parent() failed" ));
404 0 : return -1;
405 0 : }
406 :
407 0 : slot_ctx->funk_txn = parent_txn;
408 :
409 0 : elapsed_ns += fd_log_wallclock();
410 :
411 0 : FD_LOG_NOTICE(( "loaded program cache - entries: %lu, elapsed_seconds: %ld", cached_cnt, elapsed_ns/(long)1e9 ));
412 :
413 0 : return 0;
414 0 : }
415 :
416 : int
417 : fd_bpf_scan_and_create_bpf_program_cache_entry( fd_exec_slot_ctx_t * slot_ctx,
418 : fd_funk_txn_t * funk_txn,
419 0 : fd_spad_t * runtime_spad ) {
420 0 : fd_funk_t * funk = slot_ctx->acc_mgr->funk;
421 0 : ulong cnt = 0UL;
422 :
423 : /* Use random-ish xid to avoid concurrency issues */
424 0 : fd_funk_txn_xid_t cache_xid = fd_funk_generate_xid();
425 :
426 0 : fd_funk_txn_t * cache_txn = fd_funk_txn_prepare( funk, slot_ctx->funk_txn, &cache_xid, 1 );
427 0 : if( !cache_txn ) {
428 0 : FD_LOG_ERR(( "fd_funk_txn_prepare() failed" ));
429 0 : return -1;
430 0 : }
431 :
432 0 : fd_funk_txn_t * parent_txn = slot_ctx->funk_txn;
433 0 : slot_ctx->funk_txn = cache_txn;
434 :
435 0 : for (fd_funk_rec_t const *rec = fd_funk_txn_first_rec( funk, funk_txn );
436 0 : NULL != rec;
437 0 : rec = fd_funk_txn_next_rec( funk, rec )) {
438 0 : if( !fd_funk_key_is_acc( rec->pair.key ) || ( rec->flags & FD_FUNK_REC_FLAG_ERASE ) ) {
439 0 : continue;
440 0 : }
441 :
442 0 : fd_pubkey_t const * program_pubkey = fd_type_pun_const( rec->pair.key[0].uc );
443 :
444 0 : int res = fd_bpf_check_and_create_bpf_program_cache_entry( slot_ctx,
445 0 : funk_txn,
446 0 : program_pubkey,
447 0 : runtime_spad );
448 :
449 0 : if( res==0 ) {
450 0 : cnt++;
451 0 : }
452 0 : }
453 :
454 0 : FD_LOG_DEBUG(( "loaded program cache: %lu", cnt));
455 :
456 0 : if( fd_funk_txn_publish_into_parent( funk, cache_txn, 1 ) != FD_FUNK_SUCCESS ) {
457 0 : FD_LOG_ERR(( "fd_funk_txn_publish_into_parent() failed" ));
458 0 : return -1;
459 0 : }
460 :
461 0 : slot_ctx->funk_txn = parent_txn;
462 0 : return 0;
463 0 : }
464 :
465 : int
466 : fd_bpf_check_and_create_bpf_program_cache_entry( fd_exec_slot_ctx_t * slot_ctx,
467 : fd_funk_txn_t * funk_txn,
468 : fd_pubkey_t const * pubkey,
469 0 : fd_spad_t * runtime_spad ) {
470 0 : FD_TXN_ACCOUNT_DECL( exec_rec );
471 0 : if( fd_acc_mgr_view( slot_ctx->acc_mgr, funk_txn, pubkey, exec_rec ) != FD_ACC_MGR_SUCCESS ) {
472 0 : return -1;
473 0 : }
474 :
475 0 : if( memcmp( exec_rec->const_meta->info.owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) &&
476 0 : memcmp( exec_rec->const_meta->info.owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) &&
477 0 : memcmp( exec_rec->const_meta->info.owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) &&
478 0 : memcmp( exec_rec->const_meta->info.owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
479 0 : return -1;
480 0 : }
481 :
482 0 : if( fd_bpf_create_bpf_program_cache_entry( slot_ctx, exec_rec, runtime_spad ) != 0 ) {
483 0 : return -1;
484 0 : }
485 :
486 0 : return 0;
487 0 : }
488 :
489 : int
490 : fd_bpf_load_cache_entry( fd_funk_t * funk,
491 : fd_funk_txn_t * funk_txn,
492 : fd_pubkey_t const * program_pubkey,
493 0 : fd_sbpf_validated_program_t ** valid_prog ) {
494 0 : fd_funk_rec_key_t id = fd_acc_mgr_cache_key( program_pubkey );
495 :
496 0 : fd_funk_rec_t const * rec = fd_funk_rec_query_global( funk, funk_txn, &id, NULL );
497 :
498 0 : if( FD_UNLIKELY( !rec || !!( rec->flags & FD_FUNK_REC_FLAG_ERASE ) ) ) {
499 0 : return -1;
500 0 : }
501 :
502 0 : void const * data = fd_funk_val_const( rec, fd_funk_wksp( funk ) );
503 :
504 : /* TODO: magic check */
505 :
506 0 : *valid_prog = (fd_sbpf_validated_program_t *)data;
507 :
508 0 : return 0;
509 0 : }
|