LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_prog_load.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 31 103 30.1 %
Date: 2026-01-23 05:02:40 Functions: 2 5 40.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           0 : fd_get_executable_program_content_for_v4_loader( fd_accdb_ro_t const * ro ) {
      17           0 :   int err;
      18             : 
      19             :   /* Get the current loader v4 state. This implicitly also checks the dlen. */
      20           0 :   void const * data    = fd_accdb_ref_data_const( ro );
      21           0 :   ulong        data_sz = fd_accdb_ref_data_sz( ro );
      22           0 :   fd_loader_v4_state_t const * state = fd_loader_v4_get_state( data, data_sz, &err );
      23           0 :   if( FD_UNLIKELY( err ) ) {
      24           0 :     return NULL;
      25           0 :   }
      26             : 
      27             :   /* The program must be deployed or finalized. */
      28           0 :   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           0 :   return (uchar const *)data+LOADER_V4_PROGRAM_DATA_OFFSET;
      35           0 : }
      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           0 :                  ulong *                   out_offset ) {
      50           0 :   fd_bpf_upgradeable_loader_state_t program_account_state[1];
      51           0 :   if( FD_UNLIKELY( !fd_bincode_decode_static(
      52           0 :       bpf_upgradeable_loader_state,
      53           0 :       program_account_state,
      54           0 :       fd_accdb_ref_data_const( prog ),
      55           0 :       fd_accdb_ref_data_sz   ( prog ),
      56           0 :       NULL ) ) ) {
      57           0 :     return NULL;
      58           0 :   }
      59           0 :   if( !fd_bpf_upgradeable_loader_state_is_program( program_account_state ) ) {
      60           0 :     return NULL;
      61           0 :   }
      62             : 
      63           0 :   fd_pubkey_t * programdata_address = &program_account_state->inner.program.programdata_address;
      64             : 
      65           0 :   if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, progdata, xid, programdata_address ) ) ) {
      66           0 :     return NULL;
      67           0 :   }
      68             : 
      69             :   /* We don't actually need to decode here, just make sure that the account
      70             :      can be decoded successfully. */
      71           0 :   fd_bincode_decode_ctx_t ctx_programdata = {
      72           0 :     .data    = fd_accdb_ref_data_const( progdata ),
      73           0 :     .dataend = (uchar const *)fd_accdb_ref_data_const( progdata ) + fd_accdb_ref_data_sz( progdata ),
      74           0 :   };
      75             : 
      76           0 :   ulong total_sz = 0UL;
      77           0 :   if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode_footprint( &ctx_programdata, &total_sz ) ) ) {
      78           0 :     fd_accdb_close_ro( accdb, progdata );
      79           0 :     return NULL;
      80           0 :   }
      81             : 
      82           0 :   if( FD_UNLIKELY( fd_accdb_ref_data_sz( progdata )<PROGRAMDATA_METADATA_SIZE ) ) {
      83           0 :     fd_accdb_close_ro( accdb, progdata );
      84           0 :     return NULL;
      85           0 :   }
      86             : 
      87           0 :   *out_offset = PROGRAMDATA_METADATA_SIZE;
      88           0 :   return progdata;
      89           0 : }
      90             : 
      91             : fd_accdb_ro_t *
      92             : fd_prog_load_elf( fd_accdb_user_t *         accdb,
      93             :                   fd_funk_txn_xid_t const * xid,
      94             :                   fd_accdb_ro_t *           out,
      95             :                   void const *              prog_addr,
      96          51 :                   ulong *                   out_offset ) {
      97          51 :   fd_accdb_ro_t prog[1];
      98          51 :   if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, prog, xid, prog_addr ) ) ) {
      99           3 :     return NULL;
     100           3 :   }
     101             : 
     102             :   /* v1/v2 loaders: Programdata is just the account data.
     103             :      v3 loader: Programdata lives in a separate account. Deserialize the
     104             :                 program account and lookup the programdata account.
     105             :                  Deserialize the programdata account.
     106             :      v4 loader: Programdata lives in the program account, offset by
     107             :                 LOADER_V4_PROGRAM_DATA_OFFSET. */
     108          48 :   void const * owner = fd_accdb_ref_owner( prog );
     109          48 :   if( !memcmp( owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) {
     110             : 
     111             :     /* When a loader v3 program is redeployed, the programdata account
     112             :        is always updated.  Therefore, use the programdata account's
     113             :        'last update XID' instead of the program account's. */
     114           0 :     fd_accdb_ro_t progdata_[1];
     115           0 :     fd_accdb_ro_t * progdata = fd_prog_load_v3( accdb, xid, progdata_, prog, out_offset );
     116           0 :     fd_accdb_close_ro( accdb, prog );
     117           0 :     if( !progdata ) return NULL;
     118           0 :     *out = *progdata;
     119             : 
     120          48 :   } else if( !memcmp( owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
     121             : 
     122           0 :     if( !fd_get_executable_program_content_for_v4_loader( prog ) ) {
     123           0 :       fd_accdb_close_ro( accdb, prog );
     124           0 :       return NULL;
     125           0 :     }
     126           0 :     *out        = *prog;
     127           0 :     *out_offset = LOADER_V4_PROGRAM_DATA_OFFSET;
     128             : 
     129          48 :   } else if( !memcmp( owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ||
     130          48 :              !memcmp( owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) ) {
     131             : 
     132          45 :     *out        = *prog;
     133          45 :     *out_offset = 0UL;
     134             : 
     135          45 :   } else {
     136           3 :     return NULL;
     137           3 :   }
     138             : 
     139          45 :   return out;
     140          48 : }
     141             : 
     142             : FD_FN_PURE fd_prog_versions_t
     143             : fd_prog_versions( fd_features_t const * features,
     144          45 :                   ulong                 slot ) {
     145          45 :   int disable_v0  = FD_FEATURE_ACTIVE( slot, features, disable_sbpf_v0_execution );
     146          45 :   int reenable_v0 = FD_FEATURE_ACTIVE( slot, features, reenable_sbpf_v0_execution );
     147          45 :   int enable_v0   = !disable_v0 || reenable_v0;
     148          45 :   int enable_v1   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v1_deployment_and_execution );
     149          45 :   int enable_v2   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v2_deployment_and_execution );
     150          45 :   int enable_v3   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v3_deployment_and_execution );
     151             : 
     152          45 :   fd_prog_versions_t v = {0};
     153          45 :   v.min_sbpf_version = enable_v0 ? FD_SBPF_V0 : FD_SBPF_V3;
     154          45 :   if( enable_v3 ) {
     155          45 :     v.max_sbpf_version = FD_SBPF_V3;
     156          45 :   } else if( enable_v2 ) {
     157           0 :     v.max_sbpf_version = FD_SBPF_V2;
     158           0 :   } else if( enable_v1 ) {
     159           0 :     v.max_sbpf_version = FD_SBPF_V1;
     160           0 :   } else {
     161           0 :     v.max_sbpf_version = FD_SBPF_V0;
     162           0 :   }
     163          45 :   return v;
     164          45 : }
     165             : 
     166             : 
     167             : fd_prog_load_env_t *
     168             : fd_prog_load_env_from_bank( fd_prog_load_env_t * env,
     169           0 :                             fd_bank_t const *    bank ) {
     170           0 :   *env = (fd_prog_load_env_t) {
     171           0 :     .features      = fd_bank_features_query( bank ),
     172           0 :     .slot          = fd_bank_slot_get      ( bank ),
     173           0 :     .epoch         = fd_bank_epoch_get     ( bank ),
     174           0 :     .epoch_slot0   = fd_epoch_slot0( fd_bank_epoch_schedule_query( bank ), fd_bank_epoch_get( bank ) )
     175           0 :   };
     176           0 :   return env;
     177           0 : }

Generated by: LCOV version 1.14