LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_bpf_program_util.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 231 325 71.1 %
Date: 2025-01-08 12:08:44 Functions: 11 14 78.6 %

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

Generated by: LCOV version 1.14