LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_prog_load.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 76 100 76.0 %
Date: 2026-03-19 18:19:27 Functions: 5 5 100.0 %

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

Generated by: LCOV version 1.14