LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_loader_v4_program.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 532 0.0 %
Date: 2026-01-23 05:02:40 Functions: 0 14 0.0 %

          Line data    Source code
       1             : #include "fd_loader_v4_program.h"
       2             : #include "../../progcache/fd_progcache_user.h"
       3             : #include "../../log_collector/fd_log_collector.h"
       4             : #include "../fd_borrowed_account.h"
       5             : #include "../fd_system_ids.h"
       6             : 
       7             : /* The loader v4 program instruction can correspond to one of three
       8             :    instruction types: write, copy, set_program_length.  Only the write
       9             :    instruction is dynamically sized.  We can derive a reasonably tight
      10             :    bound for the decoded footprint of the worst case loader v4
      11             :    instruction based off of the transaction MTU (1232) bytes.  Let's
      12             :    assume the entire MTU is used to repesent the char vector for the
      13             :    write instruction: then we can have a vector of length 1232.  So,
      14             :    the worst case footprint for the loader v4 program instruction is
      15             :    the size of the instruction struct and the size of the worst case
      16             :    char vector.*/
      17             : 
      18             : #define FD_LOADER_V4_PROGRAM_INSTRUCTION_FOOTPRINT (sizeof(fd_loader_v4_program_instruction_t) + FD_TXN_MTU)
      19             : 
      20             : /* Helper functions that would normally be provided by fd_types. */
      21             : FD_FN_PURE uchar
      22           0 : fd_loader_v4_status_is_deployed( fd_loader_v4_state_t const * state ) {
      23           0 :   return state->status==FD_LOADER_V4_STATUS_ENUM_DELOYED;
      24           0 : }
      25             : 
      26             : FD_FN_PURE uchar
      27           0 : fd_loader_v4_status_is_retracted( fd_loader_v4_state_t const * state ) {
      28           0 :   return state->status==FD_LOADER_V4_STATUS_ENUM_RETRACTED;
      29           0 : }
      30             : 
      31             : FD_FN_PURE uchar
      32           0 : fd_loader_v4_status_is_finalized( fd_loader_v4_state_t const * state ) {
      33           0 :   return state->status==FD_LOADER_V4_STATUS_ENUM_FINALIZED;
      34           0 : }
      35             : 
      36             : /* Convenience method to get the state of a writable program account as a mutable reference.
      37             :    `get_state_mut()` takes a mutable pointer to a borrowed account's writable data and transmutes
      38             :    it into a loader v4 state. It is safe to write to the returned loader v4 state. The function
      39             :    returns 0 on success or an error code if the account data is too small. Assumes `data` is a
      40             :    non-null, writable pointer into an account's data.
      41             : 
      42             :    https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L46-L58 */
      43             : static fd_loader_v4_state_t *
      44             : fd_loader_v4_get_state_mut( uchar * data,
      45             :                             ulong   dlen,
      46           0 :                             int   * err ) {
      47           0 :   *err = FD_EXECUTOR_INSTR_SUCCESS;
      48             : 
      49             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L48-L52 */
      50           0 :   if( FD_UNLIKELY( dlen<LOADER_V4_PROGRAM_DATA_OFFSET ) ) {
      51           0 :     *err = FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
      52           0 :     return NULL;
      53           0 :   }
      54             : 
      55           0 :   return fd_type_pun( data );
      56           0 : }
      57             : 
      58             : /* `loader_v4::get_state()` performs a `transmute` operation which bypasses any decoding and directly
      59             :    reinterprets the data as a loader v4 state. The key difference between the transmute and standard
      60             :    decoding logic is that `get_state()` won't fail if `state.status` is not a valid discriminant, i.e.
      61             :    `state.status` can be any value within a ulong range that's not {Deployed, Retracted, Finalized}.
      62             :    Returns a casted pointer to the account data, interpreted as a loader v4 state type, or NULL if the
      63             :    account data is too small. The returned state is const and thus is NOT safe to modify.
      64             : 
      65             :    https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L32-L44 */
      66             : fd_loader_v4_state_t const *
      67             : fd_loader_v4_get_state( void const * data,
      68             :                         ulong        data_sz,
      69           0 :                         int *        err ) {
      70           0 :   *err = FD_EXECUTOR_INSTR_SUCCESS;
      71             : 
      72             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L35-L36 */
      73           0 :   if( FD_UNLIKELY( data_sz<LOADER_V4_PROGRAM_DATA_OFFSET ) ) {
      74           0 :     *err = FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
      75           0 :     return NULL;
      76           0 :   }
      77             : 
      78           0 :   return fd_type_pun_const( data );
      79           0 : }
      80             : 
      81             : /* `check_program_account()` validates the program account's state from its data.
      82             :    Sets `err` to an instruction error if any of the checks fail. Otherwise, returns a
      83             :    const pointer to the program account data, transmuted as a loader v4 state.
      84             :    https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L60-L88 */
      85             : static fd_loader_v4_state_t const *
      86             : check_program_account( fd_exec_instr_ctx_t *         instr_ctx,
      87             :                        fd_borrowed_account_t const * program,
      88             :                        fd_pubkey_t const *           authority_address,
      89           0 :                        int *                         err ) {
      90           0 :   *err = FD_EXECUTOR_INSTR_SUCCESS;
      91             : 
      92             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L66-L69 */
      93           0 :   if( FD_UNLIKELY( memcmp( fd_borrowed_account_get_owner( program ), fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
      94           0 :     fd_log_collector_msg_literal( instr_ctx, "Program not owned by loader" );
      95           0 :     *err = FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
      96           0 :     return NULL;
      97           0 :   }
      98             : 
      99             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L70 */
     100           0 :   void const * data    = fd_borrowed_account_get_data    ( program );
     101           0 :   ulong        data_sz = fd_borrowed_account_get_data_len( program );
     102           0 :   fd_loader_v4_state_t const * state = fd_loader_v4_get_state( data, data_sz, err );
     103           0 :   if( FD_UNLIKELY( *err ) ) {
     104           0 :     return NULL;
     105           0 :   }
     106             : 
     107             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L71-L73 */
     108           0 :   if( FD_UNLIKELY( !fd_borrowed_account_is_writable( program ) ) ) {
     109           0 :     fd_log_collector_msg_literal( instr_ctx, "Program is not writeable" );
     110           0 :     *err = FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     111           0 :     return NULL;
     112           0 :   }
     113             : 
     114             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L75-L78 */
     115           0 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL, err ) ) ) {
     116             :     /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
     117           0 :     if( FD_UNLIKELY( !!(*err) ) ) {
     118           0 :       return NULL;
     119           0 :     }
     120           0 :     fd_log_collector_msg_literal( instr_ctx, "Authority did not sign" );
     121           0 :     *err = FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     122           0 :     return NULL;
     123           0 :   }
     124             : 
     125             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L79-L82 */
     126           0 :   if( FD_UNLIKELY( memcmp( &state->authority_address_or_next_version, authority_address, sizeof(fd_pubkey_t) ) ) ) {
     127           0 :     fd_log_collector_msg_literal( instr_ctx, "Incorrect authority provided" );
     128           0 :     *err = FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     129           0 :     return NULL;
     130           0 :   }
     131             : 
     132             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L83-L86 */
     133           0 :   if( FD_UNLIKELY( fd_loader_v4_status_is_finalized( state ) ) ) {
     134           0 :     fd_log_collector_msg_literal( instr_ctx, "Program is finalized" );
     135           0 :     *err = FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     136           0 :     return NULL;
     137           0 :   }
     138             : 
     139             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L87 */
     140           0 :   return state;
     141           0 : }
     142             : 
     143             : /* `process_instruction_write()` writes ELF data into an undeployed program account.
     144             :    This could either be a program which was already deployed and then retracted, or
     145             :    a new program which is uninitialized with enough space allocated from a call to `set_program_length`.
     146             : 
     147             :    Accounts:
     148             :     0. Program account (writable)
     149             :     1. Authority account (signer)
     150             : 
     151             :    https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L90-L122 */
     152             : static int
     153             : fd_loader_v4_program_instruction_write( fd_exec_instr_ctx_t *                            instr_ctx,
     154           0 :                                         fd_loader_v4_program_instruction_write_t const * write ) {
     155           0 :   int           err;
     156           0 :   uint          offset    = write->offset;
     157           0 :   uchar const * bytes     = write->bytes;
     158           0 :   ulong         bytes_len = write->bytes_len;
     159             : 
     160             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L98 */
     161           0 :   fd_guarded_borrowed_account_t program = {0};
     162           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     163             : 
     164             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L99-L101 */
     165           0 :   fd_pubkey_t const * authority_address = NULL;
     166           0 :   err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &authority_address );
     167           0 :   if( FD_UNLIKELY( err ) ) {
     168           0 :     return err;
     169           0 :   }
     170             : 
     171             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L102-L107 */
     172           0 :   fd_loader_v4_state_t const * state = check_program_account( instr_ctx, &program, authority_address, &err );
     173           0 :   if( FD_UNLIKELY( err ) ) {
     174           0 :     return err;
     175           0 :   }
     176             : 
     177             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L108-L111 */
     178           0 :   if( FD_UNLIKELY( !fd_loader_v4_status_is_retracted( state ) ) ) {
     179           0 :     fd_log_collector_msg_literal( instr_ctx, "Program is not retracted" );
     180           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     181           0 :   }
     182             : 
     183             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L112 */
     184           0 :   ulong destination_offset = fd_ulong_sat_add( offset, LOADER_V4_PROGRAM_DATA_OFFSET );
     185             : 
     186             :   /* Break up the chained operations into separate lines...
     187             :      https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L113-L114 */
     188           0 :   uchar * data = NULL;
     189           0 :   ulong dlen = 0UL;
     190           0 :   err = fd_borrowed_account_get_data_mut( &program, &data, &dlen );
     191           0 :   if( FD_UNLIKELY( err ) ) {
     192           0 :     return err;
     193           0 :   }
     194             : 
     195             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L115-L118 */
     196           0 :   if( FD_UNLIKELY( fd_ulong_sat_add( destination_offset, bytes_len )>dlen ) ) {
     197           0 :     fd_log_collector_msg_literal( instr_ctx, "Write out of bounds" );
     198           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     199           0 :   }
     200             : 
     201           0 :   if( FD_LIKELY( bytes_len>0 ) ) {
     202           0 :     fd_memcpy( data+destination_offset, bytes, bytes_len );
     203           0 :   }
     204             : 
     205           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     206           0 : }
     207             : 
     208             : /* `fd_loader_v4_program_instruction_copy()` is similar to `fd_loader_v4_program_instruction_write()`, except
     209             :    it copies ELF data from a source program account instead of from instruction data. This is useful
     210             :    for migrating existing v1/v2/v3 programs to v4.
     211             : 
     212             :    Accounts:
     213             :     0. Program account (writable)
     214             :     1. Authority account (signer)
     215             :     2. Source program account
     216             : 
     217             :    https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L124-L181
     218             : */
     219             : static int
     220             : fd_loader_v4_program_instruction_copy( fd_exec_instr_ctx_t *                           instr_ctx,
     221           0 :                                        fd_loader_v4_program_instruction_copy_t const * copy ) {
     222           0 :   int  err;
     223           0 :   uint destination_offset = copy->destination_offset;
     224           0 :   uint source_offset      = copy->source_offset;
     225           0 :   uint length             = copy->length;
     226             : 
     227             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L133 */
     228           0 :   fd_guarded_borrowed_account_t program = {0};
     229           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     230             : 
     231             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L134-L136 */
     232           0 :   fd_pubkey_t const * authority_address = NULL;
     233           0 :   err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &authority_address );
     234           0 :   if( FD_UNLIKELY( err ) ) {
     235           0 :     return err;
     236           0 :   }
     237             : 
     238             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L137-L138 */
     239           0 :   fd_guarded_borrowed_account_t source_program = {0};
     240           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 2UL, &source_program );
     241             : 
     242             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L139-L144 */
     243           0 :   fd_loader_v4_state_t const * state = check_program_account( instr_ctx, &program, authority_address, &err );
     244           0 :   if( FD_UNLIKELY( err ) ) {
     245           0 :     return err;
     246           0 :   }
     247             : 
     248             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L145-L148 */
     249           0 :   if( FD_UNLIKELY( !fd_loader_v4_status_is_retracted( state ) ) ) {
     250           0 :     fd_log_collector_msg_literal( instr_ctx, "Program is not retracted" );
     251           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     252           0 :   }
     253             : 
     254             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L149-L162 */
     255           0 :   fd_pubkey_t const * source_owner = fd_borrowed_account_get_owner( &source_program );
     256           0 :   if( !memcmp( source_owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
     257           0 :     source_offset = fd_uint_sat_add( source_offset, (uint)LOADER_V4_PROGRAM_DATA_OFFSET );
     258           0 :   } else if( !memcmp( source_owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) {
     259           0 :     source_offset = fd_uint_sat_add( source_offset, (uint)PROGRAMDATA_METADATA_SIZE );
     260           0 :   } else if( FD_UNLIKELY( memcmp( source_owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) &&
     261           0 :                           memcmp( source_owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     262           0 :     fd_log_collector_msg_literal( instr_ctx, "Source is not a program" );
     263           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     264           0 :   }
     265             : 
     266             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L163-L169 */
     267           0 :   uchar const * data = fd_borrowed_account_get_data( &source_program );
     268           0 :   if( FD_UNLIKELY( fd_uint_sat_add( source_offset, length )>(uint)fd_borrowed_account_get_data_len( &source_program ) ) ) {
     269           0 :     fd_log_collector_msg_literal( instr_ctx, "Read out of bounds" );
     270           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     271           0 :   }
     272             : 
     273             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L170-L179 */
     274           0 :   uchar * data_mut = NULL;
     275           0 :   ulong   dlen     = 0UL;
     276           0 :   err = fd_borrowed_account_get_data_mut( &program, &data_mut, &dlen );
     277           0 :   if( FD_UNLIKELY( err ) ) {
     278           0 :     return err;
     279           0 :   }
     280             : 
     281           0 :   destination_offset = fd_uint_sat_add( destination_offset, LOADER_V4_PROGRAM_DATA_OFFSET );
     282           0 :   if( FD_UNLIKELY( fd_uint_sat_add( destination_offset, length )>(uint)dlen ) ) {
     283           0 :     fd_log_collector_msg_literal( instr_ctx, "Write out of bounds" );
     284           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     285           0 :   }
     286             : 
     287           0 :   fd_memcpy( data_mut+destination_offset, data+source_offset, length );
     288           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     289           0 : }
     290             : 
     291             : /* `fd_loader_v4_program_instruction_set_program_length()` resizes an undeployed program account to the specified size.
     292             :    Initialization is taken care of when the program account size is first increased. Decreasing the size
     293             :    to 0 will close the program account. This instruction does NOT require a native CPI into the system program
     294             :    to resize the account.
     295             : 
     296             :    Other notes:
     297             :    - The executable status is set to true here on initialization.
     298             : 
     299             :    Accounts:
     300             :       0. Program account (writable)
     301             :       1. Authority account (signer)
     302             :       2. Recipient account to receive excess lamports from rent when decreasing account size (writable)
     303             :          - This account is only required when the program account size is being decreased (new_size < program dlen).
     304             : 
     305             :    https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L183-L274 */
     306             : static int
     307             : fd_loader_v4_program_instruction_set_program_length( fd_exec_instr_ctx_t *                                         instr_ctx,
     308           0 :                                                      fd_loader_v4_program_instruction_set_program_length_t const * set_program_length ) {
     309           0 :   int  err;
     310           0 :   uint new_size = set_program_length->new_size;
     311             : 
     312             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L190 */
     313           0 :   fd_guarded_borrowed_account_t program = {0};
     314           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     315             : 
     316             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L191-L193 */
     317           0 :   fd_pubkey_t const * authority_address = NULL;
     318           0 :   err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &authority_address );
     319           0 :   if( FD_UNLIKELY( err ) ) {
     320           0 :     return err;
     321           0 :   }
     322             : 
     323             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L194-L195 */
     324           0 :   uchar is_initialization = !!( fd_borrowed_account_get_data_len( &program )<LOADER_V4_PROGRAM_DATA_OFFSET );
     325             : 
     326             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L196-L220 */
     327           0 :   if( is_initialization ) {
     328             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L197-L200 */
     329           0 :     if( FD_UNLIKELY( memcmp( fd_borrowed_account_get_owner( &program ), fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     330           0 :       fd_log_collector_msg_literal( instr_ctx, "Program not owned by loader" );
     331           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     332           0 :     }
     333             : 
     334             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L201-L204 */
     335           0 :     if( FD_UNLIKELY( !fd_borrowed_account_is_writable( &program ) ) ) {
     336           0 :       fd_log_collector_msg_literal( instr_ctx, "Program is not writeable" );
     337           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     338           0 :     }
     339             : 
     340             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L205-L208 */
     341           0 :     if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL, &err ) ) ) {
     342             :       /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
     343           0 :       if( FD_UNLIKELY( !!err ) ) return err;
     344           0 :       fd_log_collector_msg_literal( instr_ctx, "Authority did not sign" );
     345           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     346           0 :     }
     347           0 :   } else {
     348             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L210-L215 */
     349           0 :     fd_loader_v4_state_t const * state = check_program_account( instr_ctx, &program, authority_address, &err );
     350           0 :     if( FD_UNLIKELY( err ) ) {
     351           0 :       return err;
     352           0 :     }
     353             : 
     354             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L216-L219 */
     355           0 :     if(  FD_UNLIKELY( !fd_loader_v4_status_is_retracted( state ) ) ) {
     356           0 :       fd_log_collector_msg_literal( instr_ctx, "Program is not retracted" );
     357           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     358           0 :     }
     359           0 :   }
     360             : 
     361             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L221-L227 */
     362           0 :   fd_rent_t rent_;
     363           0 :   fd_rent_t const * rent = fd_sysvar_cache_rent_read( instr_ctx->sysvar_cache, &rent_ );
     364           0 :   if( FD_UNLIKELY( !rent ) ) {
     365           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     366           0 :   }
     367             : 
     368           0 :   ulong new_program_dlen  = fd_ulong_sat_add( LOADER_V4_PROGRAM_DATA_OFFSET, new_size );
     369           0 :   ulong required_lamports = ( new_size==0UL ) ?
     370           0 :                               0UL :
     371           0 :                               fd_ulong_max( fd_rent_exempt_minimum_balance( rent, new_program_dlen ),
     372           0 :                                             1UL );
     373             : 
     374             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L228-L258 */
     375           0 :   ulong program_lamports = fd_borrowed_account_get_lamports( &program );
     376           0 :   if( FD_UNLIKELY( program_lamports<required_lamports ) ) {
     377             : 
     378             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L229-L236 */
     379           0 :     fd_log_collector_printf_dangerous_max_127( instr_ctx,
     380           0 :       "Insufficient lamports, %lu are required", required_lamports );
     381           0 :     return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
     382             : 
     383           0 :   } else if( FD_LIKELY( program_lamports>required_lamports ) ) {
     384             : 
     385             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L238-L240 */
     386           0 :     fd_guarded_borrowed_account_t recipient = {0};
     387           0 :     int err = fd_exec_instr_ctx_try_borrow_instr_account( instr_ctx, 2UL, &recipient );
     388             : 
     389             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L241-L245 */
     390           0 :     if( FD_LIKELY( !err ) ) {
     391           0 :       if( FD_UNLIKELY( !instr_ctx->instr->accounts[ 2UL ].is_writable ) ) {
     392           0 :         fd_log_collector_msg_literal( instr_ctx, "Recipient is not writeable" );
     393           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     394           0 :       }
     395             : 
     396             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L246-L248 */
     397           0 :       ulong lamports_to_receive = fd_ulong_sat_sub( program_lamports, required_lamports );
     398           0 :       err = fd_borrowed_account_checked_sub_lamports( &program, lamports_to_receive );
     399           0 :       if( FD_UNLIKELY( err ) ) {
     400           0 :         return err;
     401           0 :       }
     402           0 :       err = fd_borrowed_account_checked_add_lamports( &recipient, lamports_to_receive );
     403           0 :       if( FD_UNLIKELY( err ) ) {
     404           0 :         return err;
     405           0 :       }
     406           0 :     } else if( FD_UNLIKELY( new_size==0U ) ) {
     407           0 :       fd_log_collector_msg_literal( instr_ctx, "Closing a program requires a recipient account" );
     408           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     409           0 :     }
     410             : 
     411             :     /* recipient is dropped when it goes out of scope */
     412           0 :   } /* no-op for program lamports == required lamports */
     413             : 
     414             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L259-L272 */
     415           0 :   if( new_size==0UL ) {
     416             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L260 */
     417           0 :     err = fd_borrowed_account_set_data_length( &program, 0UL );
     418           0 :     if( FD_UNLIKELY( err ) ) {
     419           0 :       return err;
     420           0 :     }
     421           0 :   } else {
     422             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L262-L264 */
     423           0 :     err = fd_borrowed_account_set_data_length( &program, new_program_dlen );
     424           0 :     if( FD_UNLIKELY( err ) ) {
     425           0 :       return err;
     426           0 :     }
     427             : 
     428             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L265-L271 */
     429           0 :     if( is_initialization ) {
     430             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L266 */
     431           0 :       err = fd_borrowed_account_set_executable( &program, 1 );
     432           0 :       if( FD_UNLIKELY( err ) ) {
     433           0 :         return err;
     434           0 :       }
     435             : 
     436             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L267 */
     437           0 :       uchar * data = NULL;
     438           0 :       ulong   dlen = 0UL;
     439           0 :       err = fd_borrowed_account_get_data_mut( &program, &data, &dlen );
     440           0 :       if( FD_UNLIKELY( err ) ) {
     441           0 :         return err;
     442           0 :       }
     443             : 
     444           0 :       fd_loader_v4_state_t * state = fd_loader_v4_get_state_mut( data, dlen, &err );
     445           0 :       if( FD_UNLIKELY( err ) ) {
     446           0 :         return err;
     447           0 :       }
     448             : 
     449             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L268-L270 */
     450           0 :       state->slot                              = 0UL;
     451           0 :       state->status                            = FD_LOADER_V4_STATUS_ENUM_RETRACTED;
     452           0 :       state->authority_address_or_next_version = *authority_address;
     453           0 :     }
     454           0 :   }
     455             : 
     456             :   /* program is dropped when it goes out of scope */
     457           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     458           0 : }
     459             : 
     460             : /* `process_instruction_deploy()` will verify the ELF bytes of a program account in a `Retracted`
     461             :    state and deploy it if successful, making it ready for use. Optionally, a source buffer account
     462             :    may be provided to copy the ELF bytes from. In this case, the program data is overwritten by the
     463             :    data in the buffer account, and the buffer account is closed with some of its lamports transferred
     464             :    to the program account if needed to meet the minimum rent exemption balance. If a source program
     465             :    is provided, the source program's programdata is copied into the target program, and the source
     466             :    program is closed afterwards.
     467             : 
     468             :    Other notes:
     469             :    - Newly deployed programs may not be retracted/redeployed within `LOADER_V4_DEPLOYMENT_COOLDOWN_IN_SLOTS` (750) slots.
     470             : 
     471             :   Accounts:
     472             :     0. Program account (writable)
     473             :     1. Authority account (signer)
     474             : 
     475             :    https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L274-L322 */
     476             : static int
     477           0 : fd_loader_v4_program_instruction_deploy( fd_exec_instr_ctx_t * instr_ctx ) {
     478           0 :   int err;
     479             : 
     480             :   /* https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L278 */
     481           0 :   fd_guarded_borrowed_account_t program = {0};
     482           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     483             : 
     484             :   /* https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L279-L281 */
     485           0 :   fd_pubkey_t const * authority_address = NULL;
     486           0 :   err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &authority_address );
     487           0 :   if( FD_UNLIKELY( err ) ) {
     488           0 :     return err;
     489           0 :   }
     490             : 
     491             :   /* https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L282-L287 */
     492           0 :   fd_loader_v4_state_t const * state = check_program_account( instr_ctx, &program, authority_address, &err );
     493           0 :   if( FD_UNLIKELY( err ) ) {
     494           0 :     return err;
     495           0 :   }
     496             : 
     497             :   /* https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L288 */
     498           0 :   fd_sol_sysvar_clock_t clock_;
     499           0 :   fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( instr_ctx->sysvar_cache, &clock_ );
     500           0 :   if( FD_UNLIKELY( !clock ) ) {
     501           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     502           0 :   }
     503           0 :   ulong current_slot = clock->slot;
     504             : 
     505             :   /* `state->slot == 0` indicates that the program hasn't been deployed
     506             :      yet, so a cooldown check is not needed. Otherwise, a cooldown of 1
     507             :      slot is applied before being able to redeploy or retract the
     508             :      program.
     509             : 
     510             :       https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L293-L299 */
     511           0 :   if( FD_UNLIKELY( state->slot!=0UL && fd_ulong_sat_add( state->slot, LOADER_V4_DEPLOYMENT_COOLDOWN_IN_SLOTS )>current_slot ) ) {
     512           0 :     fd_log_collector_msg_literal( instr_ctx, "Program was deployed recently, cooldown still in effect" );
     513           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     514           0 :   }
     515             : 
     516             :   /* https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L300-L303 */
     517           0 :   if( FD_UNLIKELY( !fd_loader_v4_status_is_retracted( state ) ) ) {
     518           0 :     fd_log_collector_msg_literal( instr_ctx, "Destination program is not retracted" );
     519           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     520           0 :   }
     521             : 
     522             :   /* https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L305-L308 */
     523           0 :   ulong buffer_dlen = fd_borrowed_account_get_data_len( &program );
     524           0 :   if( FD_UNLIKELY( buffer_dlen<LOADER_V4_PROGRAM_DATA_OFFSET ) ) {
     525           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     526           0 :   }
     527           0 :   uchar const * programdata = fd_borrowed_account_get_data( &program ) + LOADER_V4_PROGRAM_DATA_OFFSET;
     528             : 
     529             :   /* Our program cache is fundamentally different from Agave's.  Here,
     530             :      they would perform verifications and add the program to their
     531             :      cache, but we only perform verifications now and defer cache
     532             :      population to the end of the slot.  Since programs cannot be
     533             :      invoked until the next slot anyways, doing this is okay.
     534             : 
     535             :      https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L309-L316 */
     536           0 :   err = fd_deploy_program( instr_ctx, program.pubkey, programdata, buffer_dlen - LOADER_V4_PROGRAM_DATA_OFFSET );
     537           0 :   if( FD_UNLIKELY( err ) ) {
     538           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     539           0 :   }
     540             : 
     541             :   /* https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L318-L321 */
     542           0 :   uchar * data = NULL;
     543           0 :   ulong   dlen = 0UL;
     544           0 :   err = fd_borrowed_account_get_data_mut( &program, &data, &dlen );
     545           0 :   if( FD_UNLIKELY( err ) ) {
     546           0 :     return err;
     547           0 :   }
     548             : 
     549           0 :   fd_loader_v4_state_t * mut_state = fd_loader_v4_get_state_mut( data, dlen, &err );
     550           0 :   if( FD_UNLIKELY( err ) ) {
     551           0 :     return err;
     552           0 :   }
     553             : 
     554           0 :   mut_state->slot   = current_slot;
     555           0 :   mut_state->status = FD_LOADER_V4_STATUS_ENUM_DELOYED;
     556             : 
     557           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     558           0 : }
     559             : 
     560             : /* `process_instruction_retract()` retracts a currently deployed program, making it writable
     561             :    and uninvokable. After a program is retracted, users can write and truncate data freely,
     562             :    allowing them to upgrade or close the program account.
     563             : 
     564             :    Other notes:
     565             :    - Newly deployed programs may not be retracted/redeployed within 1 slot.
     566             :    - When a program is retracted, the executable flag is NOT changed.
     567             : 
     568             :    Accounts:
     569             :     0. Program account (writable)
     570             :     1. Authority account (signer)
     571             : 
     572             :     https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L353-L393 */
     573             : static int
     574           0 : fd_loader_v4_program_instruction_retract( fd_exec_instr_ctx_t * instr_ctx ) {
     575           0 :   int err;
     576             : 
     577             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L357 */
     578           0 :   fd_guarded_borrowed_account_t program = {0};
     579           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     580             : 
     581             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L359-L361 */
     582           0 :   fd_pubkey_t const * authority_address = NULL;
     583           0 :   err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &authority_address );
     584           0 :   if( FD_UNLIKELY( err ) ) {
     585           0 :     return err;
     586           0 :   }
     587             : 
     588             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L362-L367 */
     589           0 :   fd_loader_v4_state_t const * state = check_program_account( instr_ctx, &program, authority_address, &err );
     590           0 :   if( FD_UNLIKELY( err ) ) {
     591           0 :     return err;
     592           0 :   }
     593             : 
     594             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L368 */
     595           0 :   fd_sol_sysvar_clock_t clock_;
     596           0 :   fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( instr_ctx->sysvar_cache, &clock_ );
     597           0 :   if( FD_UNLIKELY( !clock ) ) {
     598           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     599           0 :   }
     600           0 :   ulong current_slot = clock->slot;
     601             : 
     602             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L369-L375 */
     603           0 :   if( FD_UNLIKELY( fd_ulong_sat_add( state->slot, LOADER_V4_DEPLOYMENT_COOLDOWN_IN_SLOTS )>current_slot ) ) {
     604           0 :     fd_log_collector_msg_literal( instr_ctx, "Program was deployed recently, cooldown still in effect" );
     605           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     606           0 :   }
     607             : 
     608             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L376-L379 */
     609           0 :   if( FD_UNLIKELY( !fd_loader_v4_status_is_deployed( state ) ) ) {
     610           0 :     fd_log_collector_msg_literal( instr_ctx, "Program is not deployed" );
     611           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     612           0 :   }
     613             : 
     614             :   /* No need to update program cache - see note in `deploy` processor.
     615             :      https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L380-L391 */
     616           0 :   uchar * data = NULL;
     617           0 :   ulong   dlen = 0UL;
     618           0 :   err = fd_borrowed_account_get_data_mut( &program, &data, &dlen );
     619           0 :   if( FD_UNLIKELY( err ) ) {
     620           0 :     return err;
     621           0 :   }
     622             : 
     623           0 :   fd_loader_v4_state_t * mut_state = fd_loader_v4_get_state_mut( data, dlen, &err );
     624           0 :   if( FD_UNLIKELY( err ) ) {
     625           0 :     return err;
     626           0 :   }
     627             : 
     628           0 :   mut_state->status = FD_LOADER_V4_STATUS_ENUM_RETRACTED;
     629             : 
     630           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     631           0 : }
     632             : 
     633             : /* `process_instruction_transfer_authority()` transfers the authority of a program account.
     634             : 
     635             :    Accounts:
     636             :    0. Program account (writable)
     637             :    1. Current authority (signer)
     638             :    2. New authority (signer)
     639             : 
     640             :    https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L395-L425 */
     641             : static int
     642           0 : fd_loader_v4_program_instruction_transfer_authority( fd_exec_instr_ctx_t * instr_ctx ) {
     643           0 :   int err;
     644             : 
     645             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L401 */
     646           0 :   fd_guarded_borrowed_account_t program = {0};
     647           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     648             : 
     649             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L402-L404 */
     650           0 :   fd_pubkey_t const * authority_address = NULL;
     651           0 :   err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &authority_address );
     652           0 :   if( FD_UNLIKELY( err ) ) {
     653           0 :     return err;
     654           0 :   }
     655             : 
     656             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L405-L407 */
     657           0 :   fd_pubkey_t const * new_authority_address = NULL;
     658           0 :   err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 2UL, &new_authority_address );
     659           0 :   if( FD_UNLIKELY( err ) ) {
     660           0 :     return err;
     661           0 :   }
     662             : 
     663             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L408-L413 */
     664           0 :   fd_loader_v4_state_t const * state = check_program_account( instr_ctx, &program, authority_address, &err );
     665           0 :   if( FD_UNLIKELY( err ) ) {
     666           0 :     return err;
     667           0 :   }
     668             : 
     669             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L414-L417 */
     670           0 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 2UL, &err ) ) ) {
     671             :     /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
     672           0 :     if( FD_UNLIKELY( !!err ) ) return err;
     673           0 :     fd_log_collector_msg_literal( instr_ctx, "New authority did not sign" );
     674           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     675           0 :   }
     676             : 
     677             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L418-L421 */
     678           0 :   if( FD_UNLIKELY( !memcmp( state->authority_address_or_next_version.key, new_authority_address, sizeof(fd_pubkey_t) ) ) ) {
     679           0 :     fd_log_collector_msg_literal( instr_ctx, "No change" );
     680           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     681           0 :   }
     682             : 
     683             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L422-L424 */
     684           0 :   uchar * data = NULL;
     685           0 :   ulong   dlen = 0UL;
     686           0 :   err = fd_borrowed_account_get_data_mut( &program, &data, &dlen );
     687           0 :   if( FD_UNLIKELY( err ) ) {
     688           0 :     return err;
     689           0 :   }
     690             : 
     691           0 :   fd_loader_v4_state_t * mut_state = fd_loader_v4_get_state_mut( data, dlen, &err );
     692           0 :   if( FD_UNLIKELY( err ) ) {
     693           0 :     return err;
     694           0 :   }
     695             : 
     696           0 :   mut_state->authority_address_or_next_version = *new_authority_address;
     697             : 
     698           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     699           0 : }
     700             : 
     701             : /* `process_instruction_finalize()` finalizes the program account,
     702             :    rendering it immutable.
     703             : 
     704             :    Other notes:
     705             :    - Users must specify a "next version" which, from my inspection,
     706             :      serves no functional purpose besides showing up
     707             :      as extra information on a block explorer. The next version can be
     708             :      itself.
     709             :    - The next version must be a program that...
     710             :     - Is not finalized
     711             :     - Has the same authority as the current program
     712             : 
     713             :    Accounts:
     714             :    0. Program account (writable)
     715             :    1. Authority account (signer)
     716             :    2. Next version of the program
     717             : 
     718             :    https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L427-L470 */
     719             : static int
     720           0 : fd_loader_v4_program_instruction_finalize( fd_exec_instr_ctx_t * instr_ctx ) {
     721           0 :   int err;
     722             : 
     723             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L433 */
     724           0 :   fd_guarded_borrowed_account_t program = {0};
     725           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     726             : 
     727             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L434-L436 */
     728           0 :   fd_pubkey_t const * authority_address = NULL;
     729           0 :   err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &authority_address );
     730           0 :   if( FD_UNLIKELY( err ) ) {
     731           0 :     return err;
     732           0 :   }
     733             : 
     734             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L437-L442 */
     735           0 :   fd_loader_v4_state_t const * state = check_program_account( instr_ctx, &program, authority_address, &err );
     736           0 :   if( FD_UNLIKELY( err ) ) {
     737           0 :     return err;
     738           0 :   }
     739             : 
     740             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L443-L446 */
     741           0 :   if( FD_UNLIKELY( !fd_loader_v4_status_is_deployed( state ) ) ) {
     742           0 :     fd_log_collector_msg_literal( instr_ctx, "Program must be deployed to be finalized" );
     743           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     744           0 :   }
     745             : 
     746             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L447 */
     747           0 :   fd_borrowed_account_drop( &program );
     748             : 
     749             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L448-L449 */
     750           0 :   fd_guarded_borrowed_account_t next_version = {0};
     751           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK(instr_ctx, 2UL, &next_version );
     752             : 
     753             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L450-L453 */
     754           0 :   if( FD_UNLIKELY( memcmp( fd_borrowed_account_get_owner( &next_version ), fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     755           0 :     fd_log_collector_msg_literal( instr_ctx, "Next version is not owned by loader" );
     756           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     757           0 :   }
     758             : 
     759             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L454 */
     760           0 :   void const * next_data    = fd_borrowed_account_get_data    ( &next_version );
     761           0 :   ulong        next_data_sz = fd_borrowed_account_get_data_len( &next_version );
     762           0 :   fd_loader_v4_state_t const * state_of_next_version = fd_loader_v4_get_state( next_data, next_data_sz, &err );
     763           0 :   if( FD_UNLIKELY( err ) ) {
     764           0 :     return err;
     765           0 :   }
     766             : 
     767             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L455-L458 */
     768           0 :   if( FD_UNLIKELY( memcmp( state_of_next_version->authority_address_or_next_version.key, authority_address, sizeof(fd_pubkey_t) ) ) ) {
     769           0 :     fd_log_collector_msg_literal( instr_ctx, "Next version has a different authority" );
     770           0 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     771           0 :   }
     772             : 
     773             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L459-L462 */
     774           0 :   if( FD_UNLIKELY( fd_loader_v4_status_is_finalized( state_of_next_version ) ) ) {
     775           0 :     fd_log_collector_msg_literal( instr_ctx, "Next version is finalized" );
     776           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     777           0 :   }
     778             : 
     779             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L463 */
     780           0 :   fd_pubkey_t const * address_of_next_version = next_version.pubkey;
     781             : 
     782             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L464 */
     783           0 :   fd_borrowed_account_drop( &next_version );
     784             : 
     785             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L465 */
     786           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     787             : 
     788             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L466-L469 */
     789           0 :   uchar * data = NULL;
     790           0 :   ulong   dlen = 0UL;
     791           0 :   err = fd_borrowed_account_get_data_mut( &program, &data, &dlen );
     792           0 :   if( FD_UNLIKELY( err ) ) {
     793           0 :     return err;
     794           0 :   }
     795             : 
     796           0 :   fd_loader_v4_state_t * mut_state = fd_loader_v4_get_state_mut( data, dlen, &err );
     797           0 :   if( FD_UNLIKELY( err ) ) {
     798           0 :     return err;
     799           0 :   }
     800             : 
     801           0 :   mut_state->authority_address_or_next_version = *address_of_next_version;
     802           0 :   mut_state->status                            = FD_LOADER_V4_STATUS_ENUM_FINALIZED;
     803             : 
     804           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     805           0 : }
     806             : 
     807             : /* `process_instruction_inner()`, the entrypoint for all loader v4 instruction invocations +
     808             :    any loader v4-owned programs.
     809             : 
     810             :    https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L487-L549 */
     811             : int
     812           0 : fd_loader_v4_program_execute( fd_exec_instr_ctx_t * instr_ctx ) {
     813           0 :   FD_TEST( FD_FEATURE_ACTIVE_BANK( instr_ctx->bank, enable_loader_v4 ) );
     814             : 
     815           0 :   int rc = FD_EXECUTOR_INSTR_SUCCESS;
     816             : 
     817             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L494 */
     818           0 :   fd_pubkey_t const * program_id = NULL;
     819           0 :   rc = fd_exec_instr_ctx_get_last_program_key( instr_ctx, &program_id );
     820           0 :   if( FD_UNLIKELY( rc ) ) {
     821           0 :     return rc;
     822           0 :   }
     823             : 
     824             :   /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L495-L519 */
     825           0 :   if( !memcmp( program_id, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
     826             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L496 */
     827           0 :     FD_EXEC_CU_UPDATE( instr_ctx, LOADER_V4_DEFAULT_COMPUTE_UNITS );
     828             : 
     829             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L497 */
     830           0 :     uchar __attribute__((aligned(FD_BPF_UPGRADEABLE_LOADER_PROGRAM_INSTRUCTION_ALIGN))) instruction_mem[ FD_LOADER_V4_PROGRAM_INSTRUCTION_FOOTPRINT ] = {0};
     831           0 :     rc = 0;
     832           0 :     fd_loader_v4_program_instruction_t * instruction = fd_bincode_decode_static_limited_deserialize(
     833           0 :         loader_v4_program_instruction,
     834           0 :         instruction_mem,
     835           0 :         instr_ctx->instr->data,
     836           0 :         instr_ctx->instr->data_sz,
     837           0 :         FD_TXN_MTU,
     838           0 :         &rc );
     839           0 :     if( FD_UNLIKELY( rc ) ) {
     840           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     841           0 :     }
     842             : 
     843             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L497-L518 */
     844           0 :     switch( instruction->discriminant ) {
     845           0 :       case fd_loader_v4_program_instruction_enum_write: {
     846             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L498-L500 */
     847           0 :         rc = fd_loader_v4_program_instruction_write( instr_ctx, &instruction->inner.write );
     848           0 :         break;
     849           0 :       }
     850           0 :       case fd_loader_v4_program_instruction_enum_copy: {
     851             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L501-L507 */
     852           0 :         rc = fd_loader_v4_program_instruction_copy( instr_ctx, &instruction->inner.copy );
     853           0 :         break;
     854           0 :       }
     855           0 :       case fd_loader_v4_program_instruction_enum_set_program_length: {
     856             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L508-L510 */
     857           0 :         rc = fd_loader_v4_program_instruction_set_program_length( instr_ctx, &instruction->inner.set_program_length );
     858           0 :         break;
     859           0 :       }
     860           0 :       case fd_loader_v4_program_instruction_enum_deploy: {
     861             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L511 */
     862           0 :         rc = fd_loader_v4_program_instruction_deploy( instr_ctx );
     863           0 :         break;
     864           0 :       }
     865           0 :       case fd_loader_v4_program_instruction_enum_retract: {
     866             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L512 */
     867           0 :         rc = fd_loader_v4_program_instruction_retract( instr_ctx );
     868           0 :         break;
     869           0 :       }
     870           0 :       case fd_loader_v4_program_instruction_enum_transfer_authority: {
     871             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L513-L515 */
     872           0 :         rc = fd_loader_v4_program_instruction_transfer_authority( instr_ctx );
     873           0 :         break;
     874           0 :       }
     875           0 :       case fd_loader_v4_program_instruction_enum_finalize: {
     876             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L516 */
     877           0 :         rc = fd_loader_v4_program_instruction_finalize( instr_ctx );
     878           0 :         break;
     879           0 :       }
     880           0 :     }
     881           0 :   } else {
     882             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L520 */
     883           0 :     fd_guarded_borrowed_account_t program = {0};
     884           0 :     rc = fd_exec_instr_ctx_try_borrow_last_program_account( instr_ctx, &program );
     885           0 :     if( FD_UNLIKELY( rc ) ) {
     886           0 :       return rc;
     887           0 :     }
     888             : 
     889             :     /* Work around differences in program caching behavior between
     890             :        Fireadncer and Agave here.
     891             : 
     892             :        Agave includes load failures due to program metadata (e.g.
     893             :        "DelayVisibility", "Closed") in their cache.  Firedancer
     894             :        does not create cache entries for these states, instead only
     895             :        including load results ("FailedVerification", "Loaded").
     896             : 
     897             :        Therefore, Firedancer recovers the DelayVisibility and Closed
     898             :        states on-the-fly before querying cahce. */
     899             : 
     900           0 :     void const * prog_data    = fd_borrowed_account_get_data    ( &program );
     901           0 :     ulong        prog_data_sz = fd_borrowed_account_get_data_len( &program );
     902           0 :     fd_loader_v4_state_t const * state = fd_loader_v4_get_state( prog_data, prog_data_sz, &rc );
     903           0 :     if( FD_UNLIKELY( rc ) ) {
     904           0 :       fd_log_collector_msg_literal( instr_ctx, "Program is not deployed" );
     905           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     906           0 :     }
     907             : 
     908           0 :     if( FD_UNLIKELY( fd_loader_v4_status_is_retracted( state ) ) ) {
     909           0 :       fd_log_collector_msg_literal( instr_ctx, "Program is not deployed" );
     910           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     911           0 :     }
     912             : 
     913             :     /* Handle `DelayedVisibility` case */
     914           0 :     if( FD_UNLIKELY( state->slot>=fd_bank_slot_get( instr_ctx->bank ) ) ) {
     915           0 :       fd_log_collector_msg_literal( instr_ctx, "Program is not deployed" );
     916           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     917           0 :     }
     918             : 
     919             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L522-L528 */
     920           0 :     fd_funk_txn_xid_t xid = { .ul = { fd_bank_slot_get( instr_ctx->bank ), instr_ctx->bank->data->idx } };
     921           0 :     fd_prog_load_env_t load_env[1]; fd_prog_load_env_from_bank( load_env, instr_ctx->bank );
     922           0 :     fd_progcache_rec_t const * cache_entry = fd_progcache_pull( instr_ctx->runtime->progcache,
     923           0 :                                                                 instr_ctx->runtime->accdb,
     924           0 :                                                                 &xid,
     925           0 :                                                                 program_id,
     926           0 :                                                                 load_env );
     927           0 :     if( FD_UNLIKELY( !cache_entry ) ) {
     928           0 :       fd_log_collector_msg_literal( instr_ctx, "Program is not cached" );
     929           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     930           0 :     }
     931             : 
     932             :     /* The program may be in the cache but could have failed
     933             :        verification in the current epoch. */
     934           0 :     if( FD_UNLIKELY( cache_entry->executable==0 ) ) {
     935           0 :       fd_log_collector_msg_literal( instr_ctx, "Program is not deployed" );
     936           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     937           0 :     }
     938             : 
     939             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L531 */
     940           0 :     fd_borrowed_account_drop( &program );
     941             : 
     942             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L542 */
     943           0 :     rc = fd_bpf_execute( instr_ctx, cache_entry, 0 );
     944           0 :   }
     945             : 
     946           0 :   return rc;
     947           0 : }

Generated by: LCOV version 1.14