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: 0 340 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 14 0.0 %

          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 : }

Generated by: LCOV version 1.14