LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_prog_load.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 41 104 39.4 %
Date: 2025-10-27 04:40:00 Functions: 3 6 50.0 %

          Line data    Source code
       1             : #include "fd_prog_load.h"
       2             : #include "../runtime/program/fd_bpf_loader_program.h"
       3             : #include "../runtime/program/fd_loader_v4_program.h"
       4             : #include "../runtime/sysvar/fd_sysvar_epoch_schedule.h"
       5             : 
       6             : /* Similar to the below function, but gets the executable program content for the v4 loader.
       7             :    Unlike the v3 loader, the programdata is stored in a single program account. The program must
       8             :    NOT be retracted to be added to the cache. Returns a pointer to the programdata on success,
       9             :    and NULL on failure.
      10             : 
      11             :    Reasons for failure include:
      12             :    - The program state cannot be read from the account data or is in the `retracted` state. */
      13             : static uchar const *
      14             : fd_get_executable_program_content_for_v4_loader( fd_txn_account_t const * program_acc,
      15           0 :                                                  ulong *                  program_data_len ) {
      16           0 :   int err;
      17             : 
      18             :   /* Get the current loader v4 state. This implicitly also checks the dlen. */
      19           0 :   fd_loader_v4_state_t const * state = fd_loader_v4_get_state( program_acc, &err );
      20           0 :   if( FD_UNLIKELY( err ) ) {
      21           0 :     return NULL;
      22           0 :   }
      23             : 
      24             :   /* The program must be deployed or finalized. */
      25           0 :   if( FD_UNLIKELY( fd_loader_v4_status_is_retracted( state ) ) ) {
      26           0 :     return NULL;
      27           0 :   }
      28             : 
      29             :   /* This subtraction is safe because get_state() implicitly checks the
      30             :      dlen. */
      31           0 :   *program_data_len = fd_txn_account_get_data_len( program_acc )-LOADER_V4_PROGRAM_DATA_OFFSET;
      32           0 :   return fd_txn_account_get_data( program_acc )+LOADER_V4_PROGRAM_DATA_OFFSET;
      33           0 : }
      34             : 
      35             : /* Gets the programdata for a v3 loader-owned account by decoding the account data
      36             :    as well as the programdata account. Returns a pointer to the programdata on success,
      37             :    and NULL on failure.
      38             : 
      39             :    Reasons for failure include:
      40             :    - The program account data cannot be decoded or is not in the `program` state.
      41             :    - The programdata account is not large enough to hold at least `PROGRAMDATA_METADATA_SIZE` bytes. */
      42             : static uchar const *
      43             : fd_get_executable_program_content_for_upgradeable_loader( fd_funk_t const *         funk,
      44             :                                                           fd_funk_txn_xid_t const * xid,
      45             :                                                           fd_txn_account_t const *  program_acc,
      46             :                                                           ulong *                   program_data_len,
      47           0 :                                                           fd_funk_txn_xid_t *       out_xid ) {
      48           0 :   fd_bpf_upgradeable_loader_state_t program_account_state[1];
      49           0 :   if( FD_UNLIKELY( !fd_bincode_decode_static(
      50           0 :       bpf_upgradeable_loader_state,
      51           0 :       program_account_state,
      52           0 :       fd_txn_account_get_data( program_acc ),
      53           0 :       fd_txn_account_get_data_len( program_acc ),
      54           0 :       NULL ) ) ) {
      55           0 :     return NULL;
      56           0 :   }
      57           0 :   if( !fd_bpf_upgradeable_loader_state_is_program( program_account_state ) ) {
      58           0 :     return NULL;
      59           0 :   }
      60             : 
      61           0 :   fd_pubkey_t * programdata_address = &program_account_state->inner.program.programdata_address;
      62             : 
      63           0 :   fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
      64           0 :       funk, xid, programdata_address, NULL, NULL, out_xid );
      65           0 :   if( FD_UNLIKELY( !meta ) ) return NULL;
      66           0 :   fd_txn_account_t _rec[1];
      67           0 :   fd_txn_account_t * programdata_acc = fd_txn_account_join( fd_txn_account_new( _rec, programdata_address, (void *)meta, 0 ), funk->wksp );
      68           0 :   if( FD_UNLIKELY( !programdata_acc ) ) FD_LOG_CRIT(( "fd_txn_account_new failed" ));
      69             : 
      70             :   /* We don't actually need to decode here, just make sure that the account
      71             :      can be decoded successfully. */
      72           0 :   fd_bincode_decode_ctx_t ctx_programdata = {
      73           0 :     .data    = fd_txn_account_get_data( programdata_acc ),
      74           0 :     .dataend = fd_txn_account_get_data( programdata_acc ) + fd_txn_account_get_data_len( programdata_acc ),
      75           0 :   };
      76             : 
      77           0 :   ulong total_sz = 0UL;
      78           0 :   if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode_footprint( &ctx_programdata, &total_sz ) ) ) {
      79           0 :     return NULL;
      80           0 :   }
      81             : 
      82           0 :   if( FD_UNLIKELY( fd_txn_account_get_data_len( programdata_acc )<PROGRAMDATA_METADATA_SIZE ) ) {
      83           0 :     return NULL;
      84           0 :   }
      85             : 
      86           0 :   *program_data_len = fd_txn_account_get_data_len( programdata_acc ) - PROGRAMDATA_METADATA_SIZE;
      87           0 :   return fd_txn_account_get_data( programdata_acc ) + PROGRAMDATA_METADATA_SIZE;
      88           0 : }
      89             : 
      90             : /* Gets the programdata for a v1/v2 loader-owned account by returning a
      91             :    pointer to the account data. Returns a pointer to the programdata on
      92             :    success. Given the txn account API always returns a handle to the
      93             :    account data, this function should NEVER return NULL (since the
      94             :    programdata of v1 and v2 loader) accounts start at the beginning of
      95             :    the data. */
      96             : static uchar const *
      97             : fd_get_executable_program_content_for_v1_v2_loaders( fd_txn_account_t const * program_acc,
      98          39 :                                                      ulong *                  program_data_len ) {
      99          39 :   *program_data_len = fd_txn_account_get_data_len( program_acc );
     100          39 :   return fd_txn_account_get_data( program_acc );
     101          39 : }
     102             : 
     103             : uchar const *
     104             : fd_prog_load_elf( fd_funk_t const *         accdb,
     105             :                   fd_funk_txn_xid_t const * xid,
     106             :                   void const *              _prog_addr,
     107             :                   ulong *                   out_sz,
     108          45 :                   fd_funk_txn_xid_t *       out_xid ) {
     109          45 :   fd_pubkey_t prog_addr = FD_LOAD( fd_pubkey_t, _prog_addr );
     110             : 
     111          45 :   fd_funk_txn_xid_t _out_xid;
     112          45 :   if( !out_xid ) out_xid = &_out_xid;
     113          45 :   fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
     114          45 :       accdb, xid, &prog_addr, NULL, NULL, out_xid );
     115          45 :   if( FD_UNLIKELY( !meta ) ) return NULL;
     116          42 :   fd_txn_account_t _rec[1];
     117          42 :   fd_txn_account_t * rec = fd_txn_account_join( fd_txn_account_new( _rec, &prog_addr, (void *)meta, 0 ), accdb->wksp );
     118          42 :   if( FD_UNLIKELY( !rec ) ) FD_LOG_CRIT(( "fd_txn_account_new failed" ));
     119             : 
     120             :   /* v1/v2 loaders: Programdata is just the account data.
     121             :      v3 loader: Programdata lives in a separate account. Deserialize the
     122             :                 program account and lookup the programdata account.
     123             :                  Deserialize the programdata account.
     124             :      v4 loader: Programdata lives in the program account, offset by
     125             :                 LOADER_V4_PROGRAM_DATA_OFFSET. */
     126          42 :   fd_pubkey_t const * owner = fd_txn_account_get_owner( rec );
     127          42 :   uchar const * elf = NULL;
     128          42 :   if( !memcmp( owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) {
     129             :     /* When a loader v3 program is redeployed, the programdata account
     130             :        is always updated.  Therefore, use the programdata account's
     131             :        'last update XID' instead of the program account's. */
     132           0 :     elf = fd_get_executable_program_content_for_upgradeable_loader( accdb, xid, rec, out_sz, out_xid );
     133          42 :   } else if( !memcmp( owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
     134           0 :     elf = fd_get_executable_program_content_for_v4_loader( rec, out_sz );
     135          42 :   } else if( !memcmp( owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ||
     136          42 :              !memcmp( owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) ) {
     137          39 :     elf = fd_get_executable_program_content_for_v1_v2_loaders( rec, out_sz );
     138          39 :   }
     139             : 
     140          42 :   if( FD_LIKELY( !elf ) ) {
     141           3 :     fd_funk_txn_xid_set_root( out_xid );
     142           3 :   }
     143             : 
     144          42 :   return elf;
     145          42 : }
     146             : 
     147             : FD_FN_PURE fd_prog_versions_t
     148             : fd_prog_versions( fd_features_t const * features,
     149          39 :                   ulong                 slot ) {
     150          39 :   int disable_v0  = FD_FEATURE_ACTIVE( slot, features, disable_sbpf_v0_execution );
     151          39 :   int reenable_v0 = FD_FEATURE_ACTIVE( slot, features, reenable_sbpf_v0_execution );
     152          39 :   int enable_v0   = !disable_v0 || reenable_v0;
     153          39 :   int enable_v1   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v1_deployment_and_execution );
     154          39 :   int enable_v2   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v2_deployment_and_execution );
     155          39 :   int enable_v3   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v3_deployment_and_execution );
     156             : 
     157          39 :   fd_prog_versions_t v = {0};
     158          39 :   v.min_sbpf_version = enable_v0 ? FD_SBPF_V0 : FD_SBPF_V3;
     159          39 :   if( enable_v3 ) {
     160          39 :     v.max_sbpf_version = FD_SBPF_V3;
     161          39 :   } else if( enable_v2 ) {
     162           0 :     v.max_sbpf_version = FD_SBPF_V2;
     163           0 :   } else if( enable_v1 ) {
     164           0 :     v.max_sbpf_version = FD_SBPF_V1;
     165           0 :   } else {
     166           0 :     v.max_sbpf_version = FD_SBPF_V0;
     167           0 :   }
     168          39 :   return v;
     169          39 : }
     170             : 
     171             : 
     172             : fd_prog_load_env_t *
     173             : fd_prog_load_env_from_bank( fd_prog_load_env_t * env,
     174           0 :                             fd_bank_t const *    bank ) {
     175           0 :   *env = (fd_prog_load_env_t) {
     176           0 :     .features      = fd_bank_features_query( bank ),
     177           0 :     .slot          = fd_bank_slot_get      ( bank ),
     178           0 :     .epoch         = fd_bank_epoch_get     ( bank ),
     179           0 :     .epoch_slot0   = fd_epoch_slot0( fd_bank_epoch_schedule_query( bank ), fd_bank_epoch_get( bank ) )
     180           0 :   };
     181           0 :   return env;
     182           0 : }

Generated by: LCOV version 1.14