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: 11 446 2.5 %
Date: 2025-01-08 12:08:44 Functions: 2 13 15.4 %

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

Generated by: LCOV version 1.14