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 524 0.0 %
Date: 2025-10-13 04:42:14 Functions: 0 14 0.0 %

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

Generated by: LCOV version 1.14