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 452 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 13 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 set the state of a writable program account. Similar to `get_state()`,
      20             :    `set_state()` will do a simple transmute operation, which is quicker. */
      21             : static int
      22             : fd_loader_v4_set_state( fd_borrowed_account_t * borrowed_acct,
      23           0 :                         fd_loader_v4_state_t * state ) {
      24           0 :   int err;
      25             : 
      26           0 :   uchar * data = NULL;
      27           0 :   ulong   dlen = 0UL;
      28             : 
      29           0 :   err = fd_borrowed_account_get_data_mut( borrowed_acct, &data, &dlen );
      30           0 :   if( FD_UNLIKELY( err ) ) {
      31           0 :     return err;
      32           0 :   }
      33             : 
      34           0 :   if( FD_UNLIKELY( dlen<LOADER_V4_PROGRAM_DATA_OFFSET ) ) {
      35           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
      36           0 :   }
      37             : 
      38           0 :   fd_loader_v4_state_t * out_state = fd_type_pun( data );
      39           0 :   *out_state = *state;
      40           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
      41           0 : }
      42             : 
      43             : /* `loader_v4::get_state()` performs a `transmute` operation which bypasses any decoding and directly
      44             :     reinterprets the data as a loader v4 state. The key difference between the transmute and standard
      45             :     decoding logic is that `get_state()` won't fail if `state.status` is not a valid discriminant, i.e.
      46             :     `state.status` can be any value within a ulong range that's not {Deployed, Retracted, Finalized}.
      47             : 
      48             :    https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L28-L40 */
      49             : int
      50             : fd_loader_v4_get_state( fd_txn_account_t const * program,
      51           0 :                         fd_loader_v4_state_t *   state ) {
      52             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L32 */
      53           0 :   if( FD_UNLIKELY( program->const_meta->dlen<LOADER_V4_PROGRAM_DATA_OFFSET ) ) {
      54           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
      55           0 :   }
      56             : 
      57           0 :   fd_loader_v4_state_t const * in_state = fd_type_pun_const( program->const_data );
      58           0 :   *state = *in_state;
      59           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
      60           0 : }
      61             : 
      62             : /* `check_program_account()` validates the program account's state from its data.
      63             :    Returns an instruction error if any of the checks fail. Writes the decoded
      64             :    state into `state`. */
      65             : static int
      66             : check_program_account( fd_exec_instr_ctx_t *         instr_ctx,
      67             :                        fd_borrowed_account_t const * program,
      68             :                        fd_pubkey_t const *           authority_address,
      69           0 :                        fd_loader_v4_state_t *        state ) {
      70           0 :   int err;
      71             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L62-L65 */
      72           0 :   if( FD_UNLIKELY( memcmp( program->acct->const_meta->info.owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
      73           0 :     fd_log_collector_msg_literal( instr_ctx, "Program not owned by loader" );
      74           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
      75           0 :   }
      76             : 
      77             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L66 */
      78           0 :   err = fd_loader_v4_get_state( program->acct, state );
      79           0 :   if( FD_UNLIKELY( err ) ) {
      80           0 :     return err;
      81           0 :   }
      82             : 
      83             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L67-L70 */
      84           0 :   if( FD_UNLIKELY( !fd_borrowed_account_is_writable( program ) ) ) {
      85           0 :     fd_log_collector_msg_literal( instr_ctx, "Program is not writeable" );
      86           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
      87           0 :   }
      88             : 
      89             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L71-L74 */
      90           0 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL ) ) ) {
      91           0 :     fd_log_collector_msg_literal( instr_ctx, "Authority did not sign" );
      92           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
      93           0 :   }
      94             : 
      95             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L75-L78 */
      96           0 :   if( FD_UNLIKELY( memcmp( &state->authority_address_or_next_version, authority_address, sizeof(fd_pubkey_t) ) ) ) {
      97           0 :     fd_log_collector_msg_literal( instr_ctx, "Incorrect authority provided" );
      98           0 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
      99           0 :   }
     100             : 
     101             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L79-L82 */
     102           0 :   if( FD_UNLIKELY( fd_loader_v4_status_is_finalized( state ) ) ) {
     103           0 :     fd_log_collector_msg_literal( instr_ctx, "Program is finalized" );
     104           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     105           0 :   }
     106             : 
     107             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L83 */
     108           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     109           0 : }
     110             : 
     111             : /* `process_instruction_write()` writes ELF data into an undeployed program account.
     112             :    This could either be a program which was already deployed and then retracted, or
     113             :    a new program which is uninitialized with enough space allocated from a call to `truncate`.
     114             : 
     115             :    Accounts:
     116             :     0. Program account (writable)
     117             :     1. Authority account (signer)
     118             : 
     119             :    https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L86-L121 */
     120             : static int
     121             : fd_loader_v4_program_instruction_write( fd_exec_instr_ctx_t *                            instr_ctx,
     122           0 :                                         fd_loader_v4_program_instruction_write_t const * write ) {
     123           0 :   int           err;
     124           0 :   uint          offset    = write->offset;
     125           0 :   uchar const * bytes     = write->bytes;
     126           0 :   ulong         bytes_len = write->bytes_len;
     127             : 
     128             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L94 */
     129           0 :   fd_guarded_borrowed_account_t program;
     130           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     131             : 
     132             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L95-L97 */
     133           0 :   fd_pubkey_t const * authority_address = &instr_ctx->instr->acct_pubkeys[ 1UL ];
     134             : 
     135             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L98-L103 */
     136           0 :   fd_loader_v4_state_t state = {0};
     137           0 :   err = check_program_account( instr_ctx, &program, authority_address, &state );
     138           0 :   if( FD_UNLIKELY( err ) ) {
     139           0 :     return err;
     140           0 :   }
     141             : 
     142             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L104-L107 */
     143           0 :   if( FD_UNLIKELY( !fd_loader_v4_status_is_retracted( &state ) ) ) {
     144           0 :     fd_log_collector_msg_literal( instr_ctx, "Program is not retracted" );
     145           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     146           0 :   }
     147             : 
     148             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L108 */
     149           0 :   ulong end_offset = fd_ulong_sat_add( offset, bytes_len );
     150             : 
     151             :   /* Break up the chained operations into separate lines...
     152             :       https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L109-L110 */
     153           0 :   uchar * data = NULL;
     154           0 :   ulong dlen = 0UL;
     155           0 :   err = fd_borrowed_account_get_data_mut( &program, &data, &dlen );
     156           0 :   if( FD_UNLIKELY( err ) ) {
     157           0 :     return err;
     158           0 :   }
     159             : 
     160             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L111-L114 */
     161           0 :   if( FD_UNLIKELY( fd_ulong_sat_add( LOADER_V4_PROGRAM_DATA_OFFSET, end_offset )>dlen ) ) {
     162           0 :     fd_log_collector_msg_literal( instr_ctx, "Write out of bounds" );
     163           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     164           0 :   }
     165             : 
     166           0 :   if( FD_LIKELY( bytes_len>0 ) ) {
     167           0 :     fd_memcpy( data+LOADER_V4_PROGRAM_DATA_OFFSET+offset, bytes, bytes_len );
     168           0 :   }
     169             : 
     170           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     171           0 : }
     172             : 
     173             : /* `process_instruction_truncate()` resizes an undeployed program account to the specified size.
     174             :    Initialization is taken care of when the program account size is first increased. Decreasing the size
     175             :    to 0 will close the program account.
     176             : 
     177             :    Other notes:
     178             :    - The executable status is set to true here on initialization.
     179             : 
     180             :    Accounts:
     181             :       0. Program account (writable + signer)
     182             :       1. Authority account (signer)
     183             :       2. Recipient account to receive excess lamports from rent when decreasing account size (writable)
     184             :          - This account is only required when the program account size is being decreased (new_size < program dlen).
     185             : 
     186             :    https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L123-L208 */
     187             : static int
     188             : fd_loader_v4_program_instruction_truncate( fd_exec_instr_ctx_t *                               instr_ctx,
     189           0 :                                            fd_loader_v4_program_instruction_truncate_t const * truncate ) {
     190           0 :   int  err;
     191           0 :   uint new_size = truncate->new_size;
     192             : 
     193             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L130 */
     194           0 :   fd_guarded_borrowed_account_t program;
     195           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     196             : 
     197             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L131-L133 */
     198           0 :   fd_pubkey_t const * authority_address = &instr_ctx->instr->acct_pubkeys[ 1UL ];
     199             : 
     200             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L134C9-L135 */
     201           0 :   uchar is_initialization = !!( new_size>0UL && program.acct->const_meta->dlen<LOADER_V4_PROGRAM_DATA_OFFSET );
     202             : 
     203             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L136-L164 */
     204           0 :   if( is_initialization ) {
     205             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L137-L140 */
     206           0 :     if( FD_UNLIKELY( memcmp( program.acct->const_meta->info.owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     207           0 :       fd_log_collector_msg_literal( instr_ctx, "Program not owned by loader" );
     208           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     209           0 :     }
     210             : 
     211             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L141-L144 */
     212           0 :     if( FD_UNLIKELY( !fd_borrowed_account_is_writable( &program ) ) ) {
     213           0 :       fd_log_collector_msg_literal( instr_ctx, "Program is not writeable" );
     214           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     215           0 :     }
     216             : 
     217             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L145-L148 */
     218           0 :     if( FD_UNLIKELY( !fd_borrowed_account_is_signer( &program ) ) ) {
     219           0 :       fd_log_collector_msg_literal( instr_ctx, "Program did not sign" );
     220           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     221           0 :     }
     222             : 
     223             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L149-L152 */
     224           0 :     if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL ) ) ) {
     225           0 :       fd_log_collector_msg_literal( instr_ctx, "Authority did not sign" );
     226           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     227           0 :     }
     228           0 :   } else {
     229             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L154-L159 */
     230           0 :     fd_loader_v4_state_t state = {0};
     231           0 :     err = check_program_account( instr_ctx, &program, authority_address, &state );
     232           0 :     if( FD_UNLIKELY( err ) ) {
     233           0 :       return err;
     234           0 :     }
     235             : 
     236             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L160-L163 */
     237           0 :     if(  FD_UNLIKELY( !fd_loader_v4_status_is_retracted( &state ) ) ) {
     238           0 :       fd_log_collector_msg_literal( instr_ctx, "Program is not retracted" );
     239           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     240           0 :     }
     241           0 :   }
     242             : 
     243             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L165-L171 */
     244           0 :   fd_rent_t const * rent = (fd_rent_t const *)fd_sysvar_cache_rent( instr_ctx->txn_ctx->sysvar_cache );
     245           0 :   if( FD_UNLIKELY( rent==NULL ) ) {
     246           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     247           0 :   }
     248             : 
     249             :   /* Note that this new_program_dlen is only relevant when new_size > 0 */
     250           0 :   ulong new_program_dlen = fd_ulong_sat_add( LOADER_V4_PROGRAM_DATA_OFFSET, new_size );
     251           0 :   ulong required_lamports = ( new_size==0UL ) ?
     252           0 :                               0UL :
     253           0 :                               fd_ulong_max( fd_rent_exempt_minimum_balance( rent, new_program_dlen ),
     254           0 :                                             1UL );
     255             : 
     256             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L172-L193 */
     257           0 :   if( FD_UNLIKELY( program.acct->const_meta->info.lamports<required_lamports ) ) {
     258             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L174-L179 */
     259           0 :     fd_log_collector_printf_dangerous_max_127( instr_ctx,
     260           0 :       "Insufficient lamports, %lu are required", required_lamports );
     261           0 :     return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
     262           0 :   } else if( program.acct->const_meta->info.lamports>required_lamports ) {
     263             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L182-L183 */
     264           0 :     fd_guarded_borrowed_account_t recipient;
     265           0 :     FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 2UL, &recipient );
     266             : 
     267             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L184-L187 */
     268           0 :     if( FD_UNLIKELY( !fd_borrowed_account_is_writable( &recipient ) ) ) {
     269           0 :       fd_log_collector_msg_literal( instr_ctx, "Recipient is not writeable" );
     270           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     271           0 :     }
     272             : 
     273             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L190 */
     274           0 :     ulong lamports_to_receive = fd_ulong_sat_sub( program.acct->const_meta->info.lamports,
     275           0 :                                                   required_lamports );
     276           0 :     err = fd_borrowed_account_checked_sub_lamports( &program, lamports_to_receive );
     277           0 :     if( FD_UNLIKELY( err ) ) {
     278           0 :       return err;
     279           0 :     }
     280           0 :     err = fd_borrowed_account_checked_add_lamports( &recipient, lamports_to_receive );
     281           0 :     if( FD_UNLIKELY( err ) ) {
     282           0 :       return err;
     283           0 :     }
     284             : 
     285             :     /* recipient is dropped when it goes out of scope */
     286           0 :   } /* no-op for program lamports == required lamports */
     287             : 
     288             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L194-L206 */
     289           0 :   if( new_size==0UL ) {
     290             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L195 */
     291           0 :     err = fd_borrowed_account_set_data_length( &program, 0UL );
     292           0 :     if( FD_UNLIKELY( err ) ) {
     293           0 :       return err;
     294           0 :     }
     295           0 :   } else {
     296             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L197-L199 */
     297           0 :     err = fd_borrowed_account_set_data_length( &program, new_program_dlen );
     298           0 :     if( FD_UNLIKELY( err ) ) {
     299           0 :       return err;
     300           0 :     }
     301             : 
     302             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L200-L205 */
     303           0 :     if( is_initialization ) {
     304             :       /* https://github.com/anza-xyz/agave/blob/09ef71223b24e30e59eaeaf5eb95e85f222c7de1/programs/loader-v4/src/lib.rs#L197 */
     305           0 :       program.acct->meta->info.executable = true;
     306             : 
     307             :       /* Serialize into the program account directly. Note that an error is impossible
     308             :           because `new_program_dlen` > `LOADER_V4_PROGRAM_DATA_OFFSET`.
     309             :           https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L201-L204 */
     310           0 :       fd_loader_v4_state_t state = {
     311           0 :         .slot = 0UL,
     312           0 :         .status = FD_LOADER_V4_STATUS_ENUM_RETRACTED,
     313           0 :         .authority_address_or_next_version = *authority_address,
     314           0 :       };
     315           0 :       err = fd_loader_v4_set_state( &program, &state );
     316           0 :       if( FD_UNLIKELY( err ) ) {
     317           0 :         return err;
     318           0 :       }
     319           0 :     }
     320           0 :   }
     321             : 
     322             :   /* program is dropped when it goes out of scope */
     323           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     324           0 : }
     325             : 
     326             : /* `process_instruction_deploy()` will verify the ELF bytes of a program account in a `Retracted`
     327             :    state and deploy it if successful, making it ready for use. Optionally, a source buffer account
     328             :    may be provided to copy the ELF bytes from. In this case, the program data is overwritten by the
     329             :    data in the buffer account, and the buffer account is closed with some of its lamports transferred
     330             :    to the program account if needed to meet the minimum rent exemption balance.
     331             : 
     332             :    Other notes:
     333             :    - Newly deployed programs may not be retracted/redeployed within `LOADER_V4_DEPLOYMENT_COOLDOWN_IN_SLOTS` (750) slots.
     334             : 
     335             :   Accounts:
     336             :     0. Program account (writable)
     337             :     1. Authority account (signer)
     338             :     2. (OPTIONAL) Source buffer account (writable)
     339             : 
     340             :    https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L210-L325 */
     341             : static int
     342           0 : fd_loader_v4_program_instruction_deploy( fd_exec_instr_ctx_t * instr_ctx ) {
     343           0 :   int err;
     344             : 
     345             :   /* These variables should exist outside of borrowed account scopes. */
     346           0 :   uchar                         source_program_present = !!( instr_ctx->instr->acct_cnt>2 );
     347           0 :   fd_loader_v4_state_t          program_state          = {0};
     348           0 :   fd_sol_sysvar_clock_t const * clock                  = (fd_sol_sysvar_clock_t const *)fd_sysvar_cache_clock( instr_ctx->txn_ctx->sysvar_cache );
     349             : 
     350             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L217-L219 */
     351           0 :   fd_pubkey_t const * authority_address = &instr_ctx->instr->acct_pubkeys[ 1UL ];
     352             : 
     353             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L216 */
     354           0 :   fd_guarded_borrowed_account_t program;
     355           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     356             : 
     357             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L220 */
     358           0 :   fd_guarded_borrowed_account_t source_program;
     359           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 2UL, &source_program );
     360             : 
     361             :   /* Here Agave tries to acquire the source buffer account but does not fail if it is not present.
     362             :       We will only try to borrow the account when we need it.
     363             : 
     364             :       https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L220-L222
     365             : 
     366             :       No-op for us... */
     367             : 
     368             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L223-L228 */
     369           0 :   err = check_program_account( instr_ctx, &program, authority_address, &program_state );
     370           0 :   if( FD_UNLIKELY( err ) ) {
     371           0 :     return err;
     372           0 :   }
     373             : 
     374             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L229 */
     375           0 :   if( FD_UNLIKELY( clock==NULL ) ) {
     376           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     377           0 :   }
     378           0 :   ulong current_slot = clock->slot;
     379             : 
     380             :   /* `current_slot == 0` indicates that the program hasn't been deployed yet, so a cooldown check
     381             :       is not needed. Otherwise, a cooldown of 750 slots is applied before being able to
     382             :       redeploy or retract the program.
     383             : 
     384             :       https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L231-L240 */
     385           0 :   if( FD_UNLIKELY( current_slot>0UL && fd_ulong_sat_add( program_state.slot, LOADER_V4_DEPLOYMENT_COOLDOWN_IN_SLOTS )>current_slot ) ) {
     386           0 :     fd_log_collector_msg_literal( instr_ctx, "Program was deployed recently, cooldown still in effect" );
     387           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     388           0 :   }
     389             : 
     390             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L241-L244 */
     391           0 :   if(  FD_UNLIKELY( !fd_loader_v4_status_is_retracted( &program_state ) ) ) {
     392           0 :     fd_log_collector_msg_literal( instr_ctx, "Destination program is not retracted" );
     393           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     394           0 :   }
     395             : 
     396           0 :   fd_borrowed_account_t * buffer = ( source_program_present ) ? &source_program : &program;
     397             : 
     398             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L245-L259 */
     399           0 :   if( source_program_present ) {
     400             :     /* buffer == source_program here
     401             :         https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L246-L251 */
     402           0 :     fd_loader_v4_state_t source_state = {0};
     403           0 :     err = check_program_account( instr_ctx, buffer, authority_address, &source_state );
     404           0 :     if( FD_UNLIKELY( err ) ) {
     405           0 :       return err;
     406           0 :     }
     407             : 
     408             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L252-L255 */
     409           0 :     if( FD_UNLIKELY( !fd_loader_v4_status_is_retracted( &source_state ) ) ) {
     410           0 :       fd_log_collector_msg_literal( instr_ctx, "Source program is not retracted" );
     411           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     412           0 :     }
     413           0 :   }
     414             : 
     415             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L261-L264 */
     416           0 :   if( FD_UNLIKELY( buffer->acct->const_meta->dlen<LOADER_V4_PROGRAM_DATA_OFFSET ) ) {
     417           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     418           0 :   }
     419           0 :   uchar const * programdata = buffer->acct->const_data + LOADER_V4_PROGRAM_DATA_OFFSET;
     420             : 
     421             :   /* Our program cache is fundamentally different from Agave's. Here, they would perform verifications and
     422             :       add the program to their cache, but we only perform verifications now and defer cache population to the
     423             :       end of the slot. Since programs cannot be invoked until the next slot anyways, doing this is okay.
     424             : 
     425             :       https://github.com/anza-xyz/agave/blob/09ef71223b24e30e59eaeaf5eb95e85f222c7de1/programs/loader-v4/src/lib.rs#L262-L269 */
     426           0 :   err = fd_deploy_program( instr_ctx, programdata, buffer->acct->const_meta->dlen - LOADER_V4_PROGRAM_DATA_OFFSET, instr_ctx->txn_ctx->spad );
     427           0 :   if( FD_UNLIKELY( err ) ) {
     428           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     429           0 :   }
     430             : 
     431             :   /* Transfer enough lamports from the source program, if exists, to the program account to cover
     432             :       the rent exempt minimum balance amount. Then, close the source program account.
     433             : 
     434             :       https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L295-L303 */
     435           0 :   if( source_program_present ) {
     436             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L296 */
     437           0 :       fd_rent_t const * rent = (fd_rent_t const *)fd_sysvar_cache_rent( instr_ctx->txn_ctx->sysvar_cache );
     438           0 :       if( FD_UNLIKELY( rent==NULL ) ) {
     439           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     440           0 :       }
     441             : 
     442             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L297 */
     443           0 :       ulong required_lamports = fd_rent_exempt_minimum_balance( rent, buffer->acct->const_meta->dlen );
     444             : 
     445             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L298 */
     446           0 :       ulong transfer_lamports = fd_ulong_sat_sub( required_lamports, program.acct->const_meta->info.lamports );
     447             : 
     448             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L299 */
     449           0 :       err = fd_borrowed_account_set_data_from_slice( &program, buffer->acct->const_data, buffer->acct->const_meta->dlen );
     450           0 :       if( FD_UNLIKELY( err ) ) {
     451           0 :         return err;
     452           0 :       }
     453             : 
     454             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L300 */
     455           0 :       err = fd_borrowed_account_set_data_length( &source_program, 0UL );
     456           0 :       if( FD_UNLIKELY( err ) ) {
     457           0 :         return err;
     458           0 :       }
     459             : 
     460             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L301 */
     461           0 :       err = fd_borrowed_account_checked_sub_lamports( &source_program, transfer_lamports );
     462           0 :       if( FD_UNLIKELY( err ) ) {
     463           0 :         return err;
     464           0 :       }
     465             : 
     466             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L302 */
     467           0 :       err = fd_borrowed_account_checked_add_lamports( &program, transfer_lamports );
     468           0 :       if( FD_UNLIKELY( err ) ) {
     469           0 :         return err;
     470           0 :       }
     471           0 :   }
     472             : 
     473             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L304-L306 */
     474           0 :   program_state.slot                = clock->slot;
     475           0 :   program_state.status              = FD_LOADER_V4_STATUS_ENUM_DELOYED;
     476           0 :   err = fd_loader_v4_set_state( &program, &program_state );
     477           0 :   if( FD_UNLIKELY( err ) ) {
     478           0 :     return err;
     479           0 :   }
     480             : 
     481           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     482           0 : }
     483             : 
     484             : /* `process_instruction_retract()` retracts a currently deployed program, making it writable
     485             :    and uninvokable. After a program is retracted, users can write and truncate data freely,
     486             :    allowing them to upgrade or close the program account.
     487             : 
     488             :    Other notes:
     489             :    - Newly deployed programs may not be retracted/redeployed within `LOADER_V4_DEPLOYMENT_COOLDOWN_IN_SLOTS` (750) slots.
     490             :    - When a program is retracted, the executable flag is NOT changed.
     491             : 
     492             :    Accounts:
     493             :     0. Program account (writable)
     494             :     1. Authority account (signer)
     495             : 
     496             :     https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L327-L369 */
     497             : static int
     498           0 : fd_loader_v4_program_instruction_retract( fd_exec_instr_ctx_t * instr_ctx ) {
     499           0 :   int err;
     500             : 
     501             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L333 */
     502           0 :   fd_guarded_borrowed_account_t program;
     503           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     504             : 
     505             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L335-L337 */
     506           0 :   fd_pubkey_t const * authority_address = &instr_ctx->instr->acct_pubkeys[ 1UL ];
     507             : 
     508             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L338-L343 */
     509           0 :   fd_loader_v4_state_t state = {0};
     510           0 :   err = check_program_account( instr_ctx, &program, authority_address, &state );
     511           0 :   if( FD_UNLIKELY( err ) ) {
     512           0 :     return err;
     513           0 :   }
     514             : 
     515             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L344 */
     516           0 :   fd_sol_sysvar_clock_t const * clock = (fd_sol_sysvar_clock_t const *)fd_sysvar_cache_clock( instr_ctx->txn_ctx->sysvar_cache );
     517           0 :   if( FD_UNLIKELY( clock==NULL ) ) {
     518           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     519           0 :   }
     520           0 :   ulong current_slot = clock->slot;
     521             : 
     522             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L345-L351 */
     523           0 :   if( FD_UNLIKELY( fd_ulong_sat_add( state.slot, LOADER_V4_DEPLOYMENT_COOLDOWN_IN_SLOTS )>current_slot ) ) {
     524           0 :     fd_log_collector_msg_literal( instr_ctx, "Program was deployed recently, cooldown still in effect" );
     525           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     526           0 :   }
     527             : 
     528             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L352-L355 */
     529           0 :   if( FD_UNLIKELY( !fd_loader_v4_status_is_deployed( &state ) ) ) {
     530           0 :     fd_log_collector_msg_literal( instr_ctx, "Program is not deployed" );
     531           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     532           0 :   }
     533             : 
     534             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L356 */
     535           0 :   state.status = FD_LOADER_V4_STATUS_ENUM_RETRACTED;
     536           0 :   err = fd_loader_v4_set_state( &program, &state );
     537           0 :   if( FD_UNLIKELY( err ) ) {
     538           0 :     return err;
     539           0 :   }
     540             : 
     541             :   /* No need to update program cache - see note in `deploy` processor. */
     542             : 
     543           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     544           0 : }
     545             : 
     546             : /* `process_instruction_transfer_authority()` transfers the authority of a program account.
     547             : 
     548             :    Accounts:
     549             :    0. Program account (writable)
     550             :    1. Current authority (signer)
     551             :    2. New authority (signer
     552             : 
     553             :    https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L371-L401 */
     554             : static int
     555           0 : fd_loader_v4_program_instruction_transfer_authority( fd_exec_instr_ctx_t * instr_ctx ) {
     556           0 :   int err;
     557             : 
     558             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L377 */
     559           0 :   fd_guarded_borrowed_account_t program;
     560           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     561             : 
     562             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L378-L380 */
     563           0 :   fd_pubkey_t const * authority_address = &instr_ctx->instr->acct_pubkeys[ 1UL ];
     564             : 
     565             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L381-L383 */
     566           0 :   fd_pubkey_t const * new_authority_address = &instr_ctx->instr->acct_pubkeys[ 2UL ];
     567             : 
     568             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L384-L389 */
     569           0 :   fd_loader_v4_state_t state = {0};
     570           0 :   err = check_program_account( instr_ctx, &program, authority_address, &state );
     571           0 :   if( FD_UNLIKELY( err ) ) {
     572           0 :     return err;
     573           0 :   }
     574             : 
     575             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L390-L393 */
     576           0 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 2UL ) ) ) {
     577           0 :     fd_log_collector_msg_literal( instr_ctx, "New authority did not sign" );
     578           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     579           0 :   }
     580             : 
     581             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L394-L397 */
     582           0 :   if( FD_UNLIKELY( !memcmp( state.authority_address_or_next_version.key, new_authority_address, sizeof(fd_pubkey_t) ) ) ) {
     583           0 :     fd_log_collector_msg_literal( instr_ctx, "No change" );
     584           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     585           0 :   }
     586             : 
     587             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L398-L399 */
     588           0 :   state.authority_address_or_next_version = *new_authority_address;
     589           0 :   err = fd_loader_v4_set_state( &program, &state );
     590           0 :   if( FD_UNLIKELY( err ) ) {
     591           0 :     return err;
     592           0 :   }
     593             : 
     594           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     595           0 : }
     596             : 
     597             : /* `process_instruction_finalize()` finalizes the program account, rendering it immutable.
     598             : 
     599             :    Other notes:
     600             :    - Users must specify a "next version" which, from my inspection, serves no functional purpose besides showing up
     601             :      as extra information on a block explorer. The next version can be itself.
     602             :    - The next version must be a program that...
     603             :     - Is not finalized
     604             :     - Has the same authority as the current program
     605             : 
     606             :    Accounts:
     607             :    0. Program account (writable)
     608             :    1. Authority account (signer)
     609             :    2. Next version of the program
     610             : 
     611             :    https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L403-L446 */
     612             : static int
     613           0 : fd_loader_v4_program_instruction_finalize( fd_exec_instr_ctx_t * instr_ctx ) {
     614           0 :   int err;
     615             : 
     616             :   /* Contains variables that need to be accessed in multiple borrowed account scopes.
     617             :      https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L410-L412 */
     618           0 :   fd_pubkey_t const *  authority_address       = &instr_ctx->instr->acct_pubkeys[ 1UL ];
     619           0 :   fd_pubkey_t const *  address_of_next_version = &instr_ctx->instr->acct_pubkeys[ 2UL ];
     620           0 :   fd_loader_v4_state_t state                   = {0};
     621             : 
     622             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L409 */
     623           0 :   fd_guarded_borrowed_account_t program;
     624           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     625             : 
     626             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L413-L418 */
     627             : 
     628           0 :   err = check_program_account( instr_ctx, &program, authority_address, &state );
     629           0 :   if( FD_UNLIKELY( err ) ) {
     630           0 :     return err;
     631           0 :   }
     632             : 
     633             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L419-L422 */
     634           0 :   if( FD_UNLIKELY( !fd_loader_v4_status_is_deployed( &state ) ) ) {
     635           0 :     fd_log_collector_msg_literal( instr_ctx, "Program must be deployed to be finalized" );
     636           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     637           0 :   }
     638             : 
     639             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L423 */
     640           0 :   fd_borrowed_account_drop( &program );
     641             : 
     642             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L424-L425 */
     643           0 :   fd_guarded_borrowed_account_t next_version;
     644           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK(instr_ctx, 2UL, &next_version );
     645             : 
     646             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L426-L429 */
     647           0 :   if( FD_UNLIKELY( memcmp( next_version.acct->const_meta->info.owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     648           0 :     fd_log_collector_msg_literal( instr_ctx, "Next version is not owned by loader" );
     649           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     650           0 :   }
     651             : 
     652             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L430 */
     653           0 :   fd_loader_v4_state_t state_of_next_version = {0};
     654           0 :   err = fd_loader_v4_get_state( next_version.acct, &state_of_next_version );
     655           0 :   if( FD_UNLIKELY( err ) ) {
     656           0 :     return err;
     657           0 :   }
     658             : 
     659             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L431-L434 */
     660           0 :   if( FD_UNLIKELY( memcmp( state_of_next_version.authority_address_or_next_version.key, authority_address, sizeof(fd_pubkey_t) ) ) ) {
     661           0 :     fd_log_collector_msg_literal( instr_ctx, "Next version has different authority" );
     662           0 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     663           0 :   }
     664             : 
     665             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L435-L438 */
     666           0 :   if( FD_UNLIKELY( fd_loader_v4_status_is_finalized( &state_of_next_version ) ) ) {
     667           0 :     fd_log_collector_msg_literal( instr_ctx, "Next version is finalized" );
     668           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     669           0 :   }
     670             : 
     671             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L440 */
     672           0 :   fd_borrowed_account_drop( &next_version );
     673             : 
     674             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L441 */
     675           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &program );
     676             : 
     677             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L442-L444 */
     678           0 :   state.authority_address_or_next_version = *address_of_next_version;
     679           0 :   state.status                            = FD_LOADER_V4_STATUS_ENUM_FINALIZED;
     680           0 :   err = fd_loader_v4_set_state( &program, &state );
     681           0 :   if( FD_UNLIKELY( err ) ) {
     682           0 :     return err;
     683           0 :   }
     684             : 
     685           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     686           0 : }
     687             : 
     688             : /* `process_instruction_inner()`, the entrypoint for all loader v4 instruction invocations +
     689             :    any loader v4-owned programs.
     690             : 
     691             :    https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L463-L526 */
     692             : int
     693           0 : fd_loader_v4_program_execute( fd_exec_instr_ctx_t * instr_ctx ) {
     694           0 :   if( FD_UNLIKELY( !FD_FEATURE_ACTIVE( instr_ctx->txn_ctx->slot, instr_ctx->txn_ctx->features, enable_program_runtime_v2_and_loader_v4 ) ) ) {
     695           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     696           0 :   }
     697             : 
     698           0 :   FD_SPAD_FRAME_BEGIN( instr_ctx->txn_ctx->spad ) {
     699             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L470 */
     700           0 :     fd_pubkey_t const * program_id = &instr_ctx->instr->program_id_pubkey;
     701             : 
     702             :     /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L471-L488 */
     703           0 :     int rc = FD_EXECUTOR_INSTR_SUCCESS;
     704           0 :     if( !memcmp( program_id, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
     705             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L472 */
     706           0 :       FD_EXEC_CU_UPDATE( instr_ctx, LOADER_V4_DEFAULT_COMPUTE_UNITS );
     707             : 
     708             :       /* Note the dataend is capped at a 1232 bytes offset to mirror the semantics of `limited_deserialize`.
     709             :          https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L473 */
     710           0 :       uchar const * data = instr_ctx->instr->data;
     711             : 
     712           0 :       fd_bincode_decode_ctx_t decode_ctx = {
     713           0 :         .data    = data,
     714           0 :         .dataend = &data[ instr_ctx->instr->data_sz > FD_TXN_MTU ? FD_TXN_MTU : instr_ctx->instr->data_sz ]
     715           0 :       };
     716             : 
     717           0 :       ulong total_sz = 0UL;
     718           0 :       if( FD_UNLIKELY( fd_loader_v4_program_instruction_decode_footprint( &decode_ctx, &total_sz ) ) ) {
     719           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     720           0 :       }
     721             : 
     722           0 :       uchar * mem = fd_spad_alloc( instr_ctx->txn_ctx->spad,
     723           0 :                                    fd_loader_v4_program_instruction_align(),
     724           0 :                                    total_sz );
     725           0 :       if( FD_UNLIKELY( !mem ) ) {
     726           0 :         FD_LOG_ERR(( "Unable to allocate memory for loader v4 instruction" ));
     727           0 :       }
     728             : 
     729           0 :       fd_loader_v4_program_instruction_t * instruction = fd_loader_v4_program_instruction_decode( mem, &decode_ctx );
     730             : 
     731             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L473-L486 */
     732           0 :       switch( instruction->discriminant ) {
     733           0 :         case fd_loader_v4_program_instruction_enum_write: {
     734           0 :           fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 2U );
     735             : 
     736             :           /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L474-L476 */
     737           0 :           rc = fd_loader_v4_program_instruction_write( instr_ctx, &instruction->inner.write );
     738           0 :           break;
     739           0 :         }
     740           0 :         case fd_loader_v4_program_instruction_enum_truncate: {
     741           0 :           fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 2U );
     742             : 
     743             :           /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L477-L479 */
     744           0 :           rc = fd_loader_v4_program_instruction_truncate( instr_ctx, &instruction->inner.truncate );
     745           0 :           break;
     746           0 :         }
     747           0 :         case fd_loader_v4_program_instruction_enum_deploy: {
     748           0 :           fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 2U );
     749             : 
     750             :           /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L480 */
     751           0 :           rc = fd_loader_v4_program_instruction_deploy( instr_ctx );
     752           0 :           break;
     753           0 :         }
     754           0 :         case fd_loader_v4_program_instruction_enum_retract: {
     755           0 :           fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 2U );
     756             : 
     757             :           /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L481 */
     758           0 :           rc = fd_loader_v4_program_instruction_retract( instr_ctx );
     759           0 :           break;
     760           0 :         }
     761           0 :         case fd_loader_v4_program_instruction_enum_transfer_authority: {
     762           0 :           fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 3U );
     763             : 
     764             :           /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L482-L484 */
     765           0 :           rc = fd_loader_v4_program_instruction_transfer_authority( instr_ctx );
     766           0 :           break;
     767           0 :         }
     768           0 :         case fd_loader_v4_program_instruction_enum_finalize: {
     769           0 :           fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 3U );
     770             : 
     771             :           /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L485 */
     772           0 :           rc = fd_loader_v4_program_instruction_finalize( instr_ctx );
     773           0 :           break;
     774           0 :         }
     775           0 :       }
     776           0 :     } else {
     777             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L489 */
     778           0 :       fd_txn_account_t * program = NULL;
     779           0 :       rc = fd_exec_txn_ctx_get_account_view_idx( instr_ctx->txn_ctx, instr_ctx->instr->program_id, &program );
     780           0 :       if( FD_UNLIKELY( rc ) ) {
     781           0 :         return rc;
     782           0 :       }
     783             : 
     784             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L490 */
     785           0 :       fd_loader_v4_state_t state = {0};
     786           0 :       rc = fd_loader_v4_get_state( program, &state );
     787           0 :       if( FD_UNLIKELY( rc ) ) {
     788           0 :         return rc;
     789           0 :       }
     790             : 
     791             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L491-L494 */
     792           0 :       if( FD_UNLIKELY( fd_loader_v4_status_is_retracted( &state ) ) ) {
     793           0 :         fd_log_collector_msg_literal( instr_ctx, "Program is retracted" );
     794           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     795           0 :       }
     796             : 
     797             :       /* Handle `DelayedVisibility` case */
     798           0 :       if( FD_UNLIKELY( state.slot>=instr_ctx->txn_ctx->slot ) ) {
     799           0 :         fd_log_collector_msg_literal( instr_ctx, "Program is not deployed" );
     800           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     801           0 :       }
     802             : 
     803             :       /* See note in `fd_bpf_loader_program_execute()` as to why we must tie the cache into consensus :(
     804             :          https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L496-L502 */
     805           0 :       fd_sbpf_validated_program_t * prog = NULL;
     806           0 :       if( FD_UNLIKELY( fd_bpf_load_cache_entry( instr_ctx->txn_ctx->acc_mgr->funk,
     807           0 :                                                 instr_ctx->txn_ctx->funk_txn,
     808           0 :                                                 &instr_ctx->instr->program_id_pubkey,
     809           0 :                                                 &prog )!=0 ) ) {
     810           0 :         fd_log_collector_msg_literal( instr_ctx, "Program is not cached" );
     811           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     812           0 :       }
     813             : 
     814             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/loader-v4/src/lib.rs#L519 */
     815           0 :       rc = fd_bpf_execute( instr_ctx, prog, 0 );
     816           0 :     }
     817             : 
     818           0 :     return rc;
     819           0 :   } FD_SPAD_FRAME_END;
     820           0 : }

Generated by: LCOV version 1.14