LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_prog_load.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 42 105 40.0 %
Date: 2025-12-06 04:45:29 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             : #include "../runtime/fd_acc_mgr.h"
       6             : #include "../accdb/fd_accdb_impl_v1.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             : fd_get_executable_program_content_for_v4_loader( fd_txn_account_t const * program_acc,
      17           0 :                                                  ulong *                  program_data_len ) {
      18           0 :   int err;
      19             : 
      20             :   /* Get the current loader v4 state. This implicitly also checks the dlen. */
      21           0 :   fd_loader_v4_state_t const * state = fd_loader_v4_get_state( program_acc, &err );
      22           0 :   if( FD_UNLIKELY( err ) ) {
      23           0 :     return NULL;
      24           0 :   }
      25             : 
      26             :   /* The program must be deployed or finalized. */
      27           0 :   if( FD_UNLIKELY( fd_loader_v4_status_is_retracted( state ) ) ) {
      28           0 :     return NULL;
      29           0 :   }
      30             : 
      31             :   /* This subtraction is safe because get_state() implicitly checks the
      32             :      dlen. */
      33           0 :   *program_data_len = fd_txn_account_get_data_len( program_acc )-LOADER_V4_PROGRAM_DATA_OFFSET;
      34           0 :   return fd_txn_account_get_data( program_acc )+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 uchar const *
      45             : fd_get_executable_program_content_for_upgradeable_loader( fd_funk_t const *         funk,
      46             :                                                           fd_funk_txn_xid_t const * xid,
      47             :                                                           fd_txn_account_t const *  program_acc,
      48             :                                                           ulong *                   program_data_len,
      49           0 :                                                           fd_funk_txn_xid_t *       out_xid ) {
      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_txn_account_get_data( program_acc ),
      55           0 :       fd_txn_account_get_data_len( program_acc ),
      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 :   fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
      66           0 :       funk, xid, programdata_address, NULL, NULL, out_xid );
      67           0 :   if( FD_UNLIKELY( !meta ) ) return NULL;
      68           0 :   fd_txn_account_t _rec[1];
      69           0 :   fd_txn_account_t * programdata_acc = fd_txn_account_join( fd_txn_account_new( _rec, programdata_address, (void *)meta, 0 ) );
      70           0 :   if( FD_UNLIKELY( !programdata_acc ) ) FD_LOG_CRIT(( "fd_txn_account_new failed" ));
      71             : 
      72             :   /* We don't actually need to decode here, just make sure that the account
      73             :      can be decoded successfully. */
      74           0 :   fd_bincode_decode_ctx_t ctx_programdata = {
      75           0 :     .data    = fd_txn_account_get_data( programdata_acc ),
      76           0 :     .dataend = fd_txn_account_get_data( programdata_acc ) + fd_txn_account_get_data_len( programdata_acc ),
      77           0 :   };
      78             : 
      79           0 :   ulong total_sz = 0UL;
      80           0 :   if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode_footprint( &ctx_programdata, &total_sz ) ) ) {
      81           0 :     return NULL;
      82           0 :   }
      83             : 
      84           0 :   if( FD_UNLIKELY( fd_txn_account_get_data_len( programdata_acc )<PROGRAMDATA_METADATA_SIZE ) ) {
      85           0 :     return NULL;
      86           0 :   }
      87             : 
      88           0 :   *program_data_len = fd_txn_account_get_data_len( programdata_acc ) - PROGRAMDATA_METADATA_SIZE;
      89           0 :   return fd_txn_account_get_data( programdata_acc ) + PROGRAMDATA_METADATA_SIZE;
      90           0 : }
      91             : 
      92             : /* Gets the programdata for a v1/v2 loader-owned account by returning a
      93             :    pointer to the account data. Returns a pointer to the programdata on
      94             :    success. Given the txn account API always returns a handle to the
      95             :    account data, this function should NEVER return NULL (since the
      96             :    programdata of v1 and v2 loader) accounts start at the beginning of
      97             :    the data. */
      98             : static uchar const *
      99             : fd_get_executable_program_content_for_v1_v2_loaders( fd_txn_account_t const * program_acc,
     100          45 :                                                      ulong *                  program_data_len ) {
     101          45 :   *program_data_len = fd_txn_account_get_data_len( program_acc );
     102          45 :   return fd_txn_account_get_data( program_acc );
     103          45 : }
     104             : 
     105             : uchar const *
     106             : fd_prog_load_elf( fd_accdb_user_t *         accdb,
     107             :                   fd_funk_txn_xid_t const * xid,
     108             :                   void const *              _prog_addr,
     109             :                   ulong *                   out_sz,
     110          51 :                   fd_funk_txn_xid_t *       out_xid ) {
     111          51 :   fd_pubkey_t prog_addr = FD_LOAD( fd_pubkey_t, _prog_addr );
     112             : 
     113          51 :   fd_funk_t * funk = fd_accdb_user_v1_funk( accdb );
     114          51 :   fd_funk_txn_xid_t _out_xid;
     115          51 :   if( !out_xid ) out_xid = &_out_xid;
     116          51 :   fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
     117          51 :       funk, xid, &prog_addr, NULL, NULL, out_xid );
     118          51 :   if( FD_UNLIKELY( !meta ) ) return NULL;
     119          48 :   fd_txn_account_t _rec[1];
     120          48 :   fd_txn_account_t * rec = fd_txn_account_join( fd_txn_account_new( _rec, &prog_addr, (void *)meta, 0 ) );
     121          48 :   if( FD_UNLIKELY( !rec ) ) FD_LOG_CRIT(( "fd_txn_account_new failed" ));
     122             : 
     123             :   /* v1/v2 loaders: Programdata is just the account data.
     124             :      v3 loader: Programdata lives in a separate account. Deserialize the
     125             :                 program account and lookup the programdata account.
     126             :                  Deserialize the programdata account.
     127             :      v4 loader: Programdata lives in the program account, offset by
     128             :                 LOADER_V4_PROGRAM_DATA_OFFSET. */
     129          48 :   fd_pubkey_t const * owner = fd_txn_account_get_owner( rec );
     130          48 :   uchar const * elf = NULL;
     131          48 :   if( !memcmp( owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) {
     132             :     /* When a loader v3 program is redeployed, the programdata account
     133             :        is always updated.  Therefore, use the programdata account's
     134             :        'last update XID' instead of the program account's. */
     135           0 :     elf = fd_get_executable_program_content_for_upgradeable_loader( funk, xid, rec, out_sz, out_xid );
     136          48 :   } else if( !memcmp( owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
     137           0 :     elf = fd_get_executable_program_content_for_v4_loader( rec, out_sz );
     138          48 :   } else if( !memcmp( owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ||
     139          48 :              !memcmp( owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) ) {
     140          45 :     elf = fd_get_executable_program_content_for_v1_v2_loaders( rec, out_sz );
     141          45 :   }
     142             : 
     143          48 :   if( FD_LIKELY( !elf ) ) {
     144           3 :     fd_funk_txn_xid_set_root( out_xid );
     145           3 :   }
     146             : 
     147          48 :   return elf;
     148          48 : }
     149             : 
     150             : FD_FN_PURE fd_prog_versions_t
     151             : fd_prog_versions( fd_features_t const * features,
     152          45 :                   ulong                 slot ) {
     153          45 :   int disable_v0  = FD_FEATURE_ACTIVE( slot, features, disable_sbpf_v0_execution );
     154          45 :   int reenable_v0 = FD_FEATURE_ACTIVE( slot, features, reenable_sbpf_v0_execution );
     155          45 :   int enable_v0   = !disable_v0 || reenable_v0;
     156          45 :   int enable_v1   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v1_deployment_and_execution );
     157          45 :   int enable_v2   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v2_deployment_and_execution );
     158          45 :   int enable_v3   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v3_deployment_and_execution );
     159             : 
     160          45 :   fd_prog_versions_t v = {0};
     161          45 :   v.min_sbpf_version = enable_v0 ? FD_SBPF_V0 : FD_SBPF_V3;
     162          45 :   if( enable_v3 ) {
     163          45 :     v.max_sbpf_version = FD_SBPF_V3;
     164          45 :   } else if( enable_v2 ) {
     165           0 :     v.max_sbpf_version = FD_SBPF_V2;
     166           0 :   } else if( enable_v1 ) {
     167           0 :     v.max_sbpf_version = FD_SBPF_V1;
     168           0 :   } else {
     169           0 :     v.max_sbpf_version = FD_SBPF_V0;
     170           0 :   }
     171          45 :   return v;
     172          45 : }
     173             : 
     174             : 
     175             : fd_prog_load_env_t *
     176             : fd_prog_load_env_from_bank( fd_prog_load_env_t * env,
     177           0 :                             fd_bank_t const *    bank ) {
     178           0 :   *env = (fd_prog_load_env_t) {
     179           0 :     .features      = fd_bank_features_query( bank ),
     180           0 :     .slot          = fd_bank_slot_get      ( bank ),
     181           0 :     .epoch         = fd_bank_epoch_get     ( bank ),
     182           0 :     .epoch_slot0   = fd_epoch_slot0( fd_bank_epoch_schedule_query( bank ), fd_bank_epoch_get( bank ) )
     183           0 :   };
     184           0 :   return env;
     185           0 : }

Generated by: LCOV version 1.14