LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_bpf_loader_program.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 12 1820 0.7 %
Date: 2025-10-13 04:42:14 Functions: 1 13 7.7 %

          Line data    Source code
       1             : #include "fd_bpf_loader_program.h"
       2             : 
       3             : /* For additional context see https://solana.com/docs/programs/deploying#state-accounts */
       4             : 
       5             : #include "../fd_pubkey_utils.h"
       6             : #include "../../../ballet/sbpf/fd_sbpf_loader.h"
       7             : #include "../sysvar/fd_sysvar.h"
       8             : #include "fd_bpf_loader_serialization.h"
       9             : #include "fd_builtin_programs.h"
      10             : #include "fd_native_cpi.h"
      11             : #include "../fd_borrowed_account.h"
      12             : 
      13             : /* https://github.com/anza-xyz/agave/blob/ced98f1ebe73f7e9691308afa757323003ff744f/sdk/program/src/program_error.rs#L290-L335 */
      14             : static inline int
      15             : program_error_to_instr_error( ulong  err,
      16           0 :                               uint * custom_err ) {
      17           0 :   switch( err ) {
      18           0 :     case CUSTOM_ZERO:
      19           0 :       *custom_err = 0;
      20           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
      21           0 :     case INVALID_ARGUMENT:
      22           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
      23           0 :     case INVALID_INSTRUCTION_DATA:
      24           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
      25           0 :     case INVALID_ACCOUNT_DATA:
      26           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      27           0 :     case ACCOUNT_DATA_TOO_SMALL:
      28           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
      29           0 :     case INSUFFICIENT_FUNDS:
      30           0 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
      31           0 :     case INCORRECT_PROGRAM_ID:
      32           0 :       return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
      33           0 :     case MISSING_REQUIRED_SIGNATURES:
      34           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
      35           0 :     case ACCOUNT_ALREADY_INITIALIZED:
      36           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
      37           0 :     case UNINITIALIZED_ACCOUNT:
      38           0 :       return FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT;
      39           0 :     case NOT_ENOUGH_ACCOUNT_KEYS:
      40           0 :       return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
      41           0 :     case ACCOUNT_BORROW_FAILED:
      42           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED;
      43           0 :     case MAX_SEED_LENGTH_EXCEEDED:
      44           0 :       return FD_EXECUTOR_INSTR_ERR_MAX_SEED_LENGTH_EXCEEDED;
      45           0 :     case INVALID_SEEDS:
      46           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_SEEDS;
      47           0 :     case BORSH_IO_ERROR:
      48           0 :       return FD_EXECUTOR_INSTR_ERR_BORSH_IO_ERROR;
      49           0 :     case ACCOUNT_NOT_RENT_EXEMPT:
      50           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_NOT_RENT_EXEMPT;
      51           0 :     case UNSUPPORTED_SYSVAR:
      52           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
      53           0 :     case ILLEGAL_OWNER:
      54           0 :       return FD_EXECUTOR_INSTR_ERR_ILLEGAL_OWNER;
      55           0 :     case MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED:
      56           0 :       return FD_EXECUTOR_INSTR_ERR_MAX_ACCS_DATA_ALLOCS_EXCEEDED;
      57           0 :     case INVALID_ACCOUNT_DATA_REALLOC:
      58           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC;
      59           0 :     case MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED:
      60           0 :       return FD_EXECUTOR_INSTR_ERR_MAX_INSN_TRACE_LENS_EXCEEDED;
      61           0 :     case BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS:
      62           0 :       return FD_EXECUTOR_INSTR_ERR_BUILTINS_MUST_CONSUME_CUS;
      63           0 :     case INVALID_ACCOUNT_OWNER:
      64           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
      65           0 :     case ARITHMETIC_OVERFLOW:
      66           0 :       return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
      67           0 :     case IMMUTABLE:
      68           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
      69           0 :     case INCORRECT_AUTHORITY:
      70           0 :       return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
      71           0 :     default:
      72           0 :       if( err>>BUILTIN_BIT_SHIFT == 0 ) {
      73           0 :         *custom_err = (uint)err;
      74           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
      75           0 :       }
      76           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ERR;
      77           0 :   }
      78           0 : }
      79             : 
      80             : /* https://github.com/anza-xyz/agave/blob/9b22f28104ec5fd606e4bb39442a7600b38bb671/programs/bpf_loader/src/lib.rs#L216-L229 */
      81             : static ulong
      82           0 : calculate_heap_cost( ulong heap_size, ulong heap_cost ) {
      83           0 :   #define KIBIBYTE_MUL_PAGES       (1024UL * 32UL)
      84           0 :   #define KIBIBYTE_MUL_PAGES_SUB_1 (KIBIBYTE_MUL_PAGES - 1UL)
      85             : 
      86           0 :   heap_size = fd_ulong_sat_add( heap_size, KIBIBYTE_MUL_PAGES_SUB_1 );
      87             : 
      88           0 :   heap_size = fd_ulong_sat_mul( fd_ulong_sat_sub( heap_size / KIBIBYTE_MUL_PAGES, 1UL ), heap_cost );
      89           0 :   return heap_size;
      90             : 
      91           0 :   #undef KIBIBYTE_MUL_PAGES
      92           0 :   #undef KIBIBYTE_MUL_PAGES_SUB_1
      93           0 : }
      94             : 
      95             : void
      96             : fd_bpf_get_sbpf_versions( uint *                sbpf_min_version,
      97             :                           uint *                sbpf_max_version,
      98             :                           ulong                 slot,
      99          45 :                           fd_features_t const * features ) {
     100          45 :   int disable_v0  = FD_FEATURE_ACTIVE( slot, features, disable_sbpf_v0_execution );
     101          45 :   int reenable_v0 = FD_FEATURE_ACTIVE( slot, features, reenable_sbpf_v0_execution );
     102          45 :   int enable_v0   = !disable_v0 || reenable_v0;
     103          45 :   int enable_v1   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v1_deployment_and_execution );
     104          45 :   int enable_v2   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v2_deployment_and_execution );
     105          45 :   int enable_v3   = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v3_deployment_and_execution );
     106             : 
     107          45 :   *sbpf_min_version = enable_v0 ? FD_SBPF_V0 : FD_SBPF_V3;
     108          45 :   if( enable_v3 ) {
     109          45 :     *sbpf_max_version = FD_SBPF_V3;
     110          45 :   } else if( enable_v2 ) {
     111           0 :     *sbpf_max_version = FD_SBPF_V2;
     112           0 :   } else if( enable_v1 ) {
     113           0 :     *sbpf_max_version = FD_SBPF_V1;
     114           0 :   } else {
     115           0 :     *sbpf_max_version = FD_SBPF_V0;
     116           0 :   }
     117          45 : }
     118             : 
     119             : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L105-L171
     120             : 
     121             :    Our arguments to deploy_program are different from the Agave version because
     122             :    we handle the caching of deployed programs differently. In Firedancer we
     123             :    lack the concept of ProgramCacheEntryType entirely.
     124             :    https://github.com/anza-xyz/agave/blob/114d94a25e9631f9bf6349c4b833d7900ef1fb1c/program-runtime/src/loaded_programs.rs#L158
     125             : 
     126             :    In Agave there is a separate caching structure that is used to store the
     127             :    deployed programs. In Firedancer the deployed, validated program is stored as
     128             :   metadata for the account in the funk record.
     129             : 
     130             :    See https://github.com/firedancer-io/firedancer/blob/9c1df680b3f38bebb0597e089766ec58f3b41e85/src/flamenco/runtime/program/fd_bpf_loader_v3_program.c#L1640
     131             :    for how we handle the concept of 'LoadedProgramType::DelayVisibility' in Firedancer.
     132             : 
     133             :    As a concrete example, our version of deploy_program does not have the
     134             :    'account_size' argument because we do not update the funk record here.
     135             : 
     136             :    The spad used for allocations can be either scoped to the executor or the
     137             :    runtime depending on where it is called from. If a program is deployed from
     138             :    the v3 contract, then the executor spad should be used. */
     139             : int
     140             : fd_deploy_program( fd_exec_instr_ctx_t * instr_ctx,
     141             :                    fd_pubkey_t const *   program_key,
     142             :                    uchar const *         programdata,
     143             :                    ulong                 programdata_size,
     144           0 :                    fd_spad_t *           spad ) {
     145           0 :   int deploy_mode    = 1;
     146           0 :   int direct_mapping = FD_FEATURE_ACTIVE_BANK( instr_ctx->txn_ctx->bank, bpf_account_data_direct_mapping );
     147           0 :   fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_new( fd_spad_alloc( spad,
     148           0 :                                                                        fd_sbpf_syscalls_align(),
     149           0 :                                                                        fd_sbpf_syscalls_footprint() ) );
     150           0 :   if( FD_UNLIKELY( !syscalls ) ) {
     151             :     //TODO: full log including err
     152           0 :     fd_log_collector_msg_literal( instr_ctx, "Failed to register syscalls" );
     153           0 :     return FD_EXECUTOR_INSTR_ERR_PROGRAM_ENVIRONMENT_SETUP_FAILURE;
     154           0 :   }
     155             : 
     156           0 :   fd_vm_syscall_register_slot( syscalls,
     157           0 :                                instr_ctx->txn_ctx->slot,
     158           0 :                                &instr_ctx->txn_ctx->features,
     159           0 :                                1 );
     160             : 
     161             :   /* Load executable */
     162           0 :   fd_sbpf_elf_info_t elf_info[ 1UL ];
     163           0 :   uint min_sbpf_version, max_sbpf_version;
     164           0 :   fd_bpf_get_sbpf_versions( &min_sbpf_version,
     165           0 :                             &max_sbpf_version,
     166           0 :                             instr_ctx->txn_ctx->slot,
     167           0 :                             &instr_ctx->txn_ctx->features );
     168             : 
     169           0 :   fd_sbpf_loader_config_t config = { 0 };
     170           0 :   config.elf_deploy_checks = deploy_mode;
     171           0 :   config.sbpf_min_version = min_sbpf_version;
     172           0 :   config.sbpf_max_version = max_sbpf_version;
     173             : 
     174           0 :   if( FD_UNLIKELY( fd_sbpf_elf_peek( elf_info, programdata, programdata_size, &config )<0 ) ) {
     175             :     //TODO: actual log, this is a custom Firedancer msg
     176           0 :     fd_log_collector_msg_literal( instr_ctx, "Failed to load or verify Elf" );
     177           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     178           0 :   }
     179             : 
     180             :   /* Allocate rodata segment */
     181           0 :   void * rodata = fd_spad_alloc( spad, FD_SBPF_PROG_RODATA_ALIGN, elf_info->bin_sz );
     182           0 :   if( FD_UNLIKELY( !rodata ) ) {
     183           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     184           0 :   }
     185             : 
     186             :   /* Allocate program buffer */
     187           0 :   ulong  prog_align        = fd_sbpf_program_align();
     188           0 :   ulong  prog_footprint    = fd_sbpf_program_footprint( elf_info );
     189           0 :   fd_sbpf_program_t * prog = fd_sbpf_program_new( fd_spad_alloc( spad, prog_align, prog_footprint ), elf_info, rodata );
     190           0 :   if( FD_UNLIKELY( !prog ) ) {
     191           0 :     FD_LOG_ERR(( "fd_sbpf_program_new() failed" ));
     192           0 :   }
     193             : 
     194             :   /* Load program */
     195           0 :   int err = fd_sbpf_program_load( prog, programdata, programdata_size, syscalls, &config );
     196           0 :   if( FD_UNLIKELY( err ) ) {
     197           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     198           0 :   }
     199             : 
     200             :   /* Validate the program */
     201           0 :   fd_vm_t _vm[ 1UL ];
     202           0 :   fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
     203             : 
     204           0 :   vm = fd_vm_init(
     205           0 :     /* vm                 */ vm,
     206           0 :     /* instr_ctx          */ instr_ctx,
     207           0 :     /* heap_max           */ instr_ctx->txn_ctx->compute_budget_details.heap_size,
     208           0 :     /* entry_cu           */ instr_ctx->txn_ctx->compute_budget_details.compute_meter,
     209           0 :     /* rodata             */ prog->rodata,
     210           0 :     /* rodata_sz          */ prog->rodata_sz,
     211           0 :     /* text               */ prog->text,
     212           0 :     /* text_cnt           */ prog->info.text_cnt,
     213           0 :     /* text_off           */ prog->info.text_off, /* FIXME: What if text_off is not multiple of 8 */
     214           0 :     /* text_sz            */ prog->info.text_sz,
     215           0 :     /* entry_pc           */ prog->entry_pc,
     216           0 :     /* calldests          */ prog->calldests,
     217           0 :     /* sbpf_version       */ elf_info->sbpf_version,
     218           0 :     /* syscalls           */ syscalls,
     219           0 :     /* trace              */ NULL,
     220           0 :     /* sha                */ NULL,
     221           0 :     /* mem_regions        */ NULL,
     222           0 :     /* mem_regions_cnt    */ 0,
     223           0 :     /* mem_region_accs    */ NULL,
     224           0 :     /* is_deprecated      */ 0,
     225           0 :     /* direct mapping     */ direct_mapping,
     226           0 :     /* dump_syscall_to_pb */ 0 );
     227           0 :   if ( FD_UNLIKELY( vm == NULL ) ) {
     228           0 :     FD_LOG_WARNING(( "NULL vm" ));
     229           0 :     return FD_EXECUTOR_INSTR_ERR_PROGRAM_ENVIRONMENT_SETUP_FAILURE;
     230           0 :   }
     231             : 
     232           0 :   int validate_result = fd_vm_validate( vm );
     233           0 :   if( FD_UNLIKELY( validate_result!=FD_VM_SUCCESS ) ) {
     234           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     235           0 :   }
     236             : 
     237             :   /* Queue the program for reverification */
     238           0 :   instr_ctx->txn_ctx->programs_to_reverify[instr_ctx->txn_ctx->programs_to_reverify_cnt++] = *program_key;
     239             : 
     240           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     241           0 : }
     242             : 
     243             : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L195-L218 */
     244             : static int
     245             : write_program_data( fd_exec_instr_ctx_t *   instr_ctx,
     246             :                     ushort                  instr_acc_idx,
     247             :                     ulong                   program_data_offset,
     248             :                     uchar *                 bytes,
     249           0 :                     ulong                   bytes_len ) {
     250           0 :   int err;
     251             : 
     252             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L202 */
     253           0 :   fd_guarded_borrowed_account_t program = {0};
     254           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, instr_acc_idx, &program );
     255             : 
     256             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L203 */
     257           0 :   uchar * data = NULL;
     258           0 :   ulong   dlen = 0UL;
     259           0 :   err = fd_borrowed_account_get_data_mut( &program, &data, &dlen );
     260           0 :   if( FD_UNLIKELY( err ) ) {
     261           0 :     return err;
     262           0 :   }
     263             : 
     264           0 :   ulong write_offset = fd_ulong_sat_add( program_data_offset, bytes_len );
     265           0 :   if( FD_UNLIKELY( fd_borrowed_account_get_data_len( &program )<write_offset ) ) {
     266             :     /* Max msg_sz: 24 - 6 + 2*20 = 58 < 127 => we can use printf */
     267           0 :     fd_log_collector_printf_dangerous_max_127( instr_ctx,
     268           0 :       "Write overflow %lu < %lu", fd_borrowed_account_get_data_len( &program ), write_offset );
     269           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     270           0 :   }
     271             : 
     272           0 :   if( FD_UNLIKELY( program_data_offset>dlen ) ) {
     273           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     274           0 :   }
     275             : 
     276           0 :   if( FD_LIKELY( bytes_len ) ) {
     277           0 :     fd_memcpy( data+program_data_offset, bytes, bytes_len );
     278           0 :   }
     279             : 
     280           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     281           0 : }
     282             : 
     283             : fd_bpf_upgradeable_loader_state_t *
     284             : fd_bpf_loader_program_get_state( fd_txn_account_t const * acct,
     285             :                                  fd_spad_t *              spad,
     286           0 :                                  int *                    opt_err ) {
     287           0 :   int err;
     288           0 :   fd_bpf_upgradeable_loader_state_t * res = fd_bincode_decode_spad(
     289           0 :       bpf_upgradeable_loader_state,
     290           0 :       spad,
     291           0 :       fd_txn_account_get_data( acct ),
     292           0 :       fd_txn_account_get_data_len( acct ),
     293           0 :       &err );
     294             : 
     295           0 :   if( opt_err ) {
     296           0 :     *opt_err = FD_UNLIKELY( err ) ? FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA : FD_EXECUTOR_INSTR_SUCCESS;
     297           0 :   }
     298             : 
     299           0 :   return FD_UNLIKELY( err ) ? NULL : res;
     300           0 : }
     301             : 
     302             : /* Mirrors solana_sdk::transaction_context::BorrowedAccount::set_state()
     303             :    https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L973 */
     304             : int
     305             : fd_bpf_loader_v3_program_set_state( fd_borrowed_account_t * borrowed_acct,
     306           0 :                                     fd_bpf_upgradeable_loader_state_t * state ) {
     307           0 :   ulong state_size = fd_bpf_upgradeable_loader_state_size( state );
     308             : 
     309           0 :   uchar * data = NULL;
     310           0 :   ulong   dlen = 0UL;
     311             : 
     312           0 :   int err = fd_borrowed_account_get_data_mut( borrowed_acct, &data, &dlen );
     313           0 :   if( FD_UNLIKELY( err ) ) {
     314           0 :     return err;
     315           0 :   }
     316             : 
     317           0 :   if( FD_UNLIKELY( state_size>dlen ) ) {
     318           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     319           0 :   }
     320             : 
     321           0 :   fd_bincode_encode_ctx_t ctx = {
     322           0 :     .data    = data,
     323           0 :     .dataend = data + state_size
     324           0 :   };
     325             : 
     326           0 :   err = fd_bpf_upgradeable_loader_state_encode( state, &ctx );
     327           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     328           0 :     return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR;
     329           0 :   }
     330             : 
     331           0 :   return FD_BINCODE_SUCCESS;
     332           0 : }
     333             : 
     334             : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1299-L1331 */
     335             : static int
     336             : common_close_account( fd_pubkey_t * authority_address,
     337             :                       fd_exec_instr_ctx_t * instr_ctx,
     338           0 :                       fd_bpf_upgradeable_loader_state_t * state ) {
     339           0 :   int err;
     340             : 
     341             :   /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L1307 */
     342           0 :   if( FD_UNLIKELY( !authority_address ) ) {
     343           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     344           0 :   }
     345             : 
     346             :   /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L1312-L1313 */
     347           0 :   fd_pubkey_t const * acc_key = NULL;
     348           0 :   err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 2UL, &acc_key );
     349           0 :   if( FD_UNLIKELY( err ) ) {
     350           0 :     return err;
     351           0 :   }
     352             : 
     353           0 :   if( FD_UNLIKELY( memcmp( authority_address, acc_key, sizeof(fd_pubkey_t) ) ) ) {
     354           0 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     355           0 :   }
     356             : 
     357             :   /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L1319-L1322 */
     358           0 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 2UL, &err ) ) ) {
     359             :     /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
     360           0 :     if( FD_UNLIKELY( !!err ) ) return err;
     361           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     362           0 :   }
     363             : 
     364             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L1324 */
     365           0 :   fd_guarded_borrowed_account_t close_account = {0};
     366           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &close_account );
     367             : 
     368             :   /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L1326 */
     369           0 :   fd_guarded_borrowed_account_t recipient_account = {0};
     370           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 1UL, &recipient_account );
     371             : 
     372           0 :   err = fd_borrowed_account_checked_add_lamports( &recipient_account,
     373           0 :                                                   fd_borrowed_account_get_lamports( &close_account ) );
     374           0 :   if( FD_UNLIKELY( err ) ) {
     375           0 :     return err;
     376           0 :   }
     377             : 
     378           0 :   err = fd_borrowed_account_set_lamports( &close_account, 0UL );
     379           0 :   if( FD_UNLIKELY( err ) ) {
     380           0 :     return err;
     381           0 :   }
     382             : 
     383           0 :   state->discriminant = fd_bpf_upgradeable_loader_state_enum_uninitialized;
     384           0 :   err = fd_bpf_loader_v3_program_set_state( &close_account, state );
     385           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     386           0 :     return err;
     387           0 :   }
     388             : 
     389           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     390           0 : }
     391             : 
     392             : 
     393             : /* Every loader-owned BPF program goes through this function, which goes into the VM.
     394             : 
     395             :    https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1332-L1501 */
     396             : int
     397             : fd_bpf_execute( fd_exec_instr_ctx_t *            instr_ctx,
     398             :                 fd_program_cache_entry_t const * cache_entry,
     399           0 :                 uchar                            is_deprecated ) {
     400             : 
     401           0 :   int err                       = FD_EXECUTOR_INSTR_SUCCESS;
     402           0 :   fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_new( fd_spad_alloc( instr_ctx->txn_ctx->spad,
     403           0 :                                                                        fd_sbpf_syscalls_align(),
     404           0 :                                                                        fd_sbpf_syscalls_footprint() ) );
     405           0 :   if( FD_UNLIKELY( !syscalls ) ) {
     406           0 :     FD_LOG_CRIT(( "Unable to allocate syscalls" ));
     407           0 :   }
     408             : 
     409             :   /* TODO do we really need to re-do this on every instruction? */
     410           0 :   fd_vm_syscall_register_slot( syscalls,
     411           0 :                                instr_ctx->txn_ctx->slot,
     412           0 :                                &instr_ctx->txn_ctx->features,
     413           0 :                                0 );
     414             : 
     415             :   /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1362-L1368 */
     416           0 :   ulong                   input_sz                                = 0UL;
     417           0 :   ulong                   pre_lens[256]                           = {0};
     418           0 :   fd_vm_input_region_t    input_mem_regions[1000]                 = {0}; /* We can have a max of (3 * num accounts + 1) regions */
     419           0 :   fd_vm_acc_region_meta_t acc_region_metas[256]                   = {0}; /* instr acc idx to idx */
     420           0 :   uint                    input_mem_regions_cnt                   = 0U;
     421           0 :   int                     direct_mapping                          = FD_FEATURE_ACTIVE_BANK( instr_ctx->txn_ctx->bank, bpf_account_data_direct_mapping );
     422             : 
     423           0 :   uchar * input = NULL;
     424           0 :   err = fd_bpf_loader_input_serialize_parameters( instr_ctx, &input_sz, pre_lens,
     425           0 :                                                   input_mem_regions, &input_mem_regions_cnt,
     426           0 :                                                   acc_region_metas, direct_mapping,
     427           0 :                                                   is_deprecated, &input );
     428           0 :   if( FD_UNLIKELY( err ) ) {
     429           0 :     return err;
     430           0 :   }
     431             : 
     432           0 :   if( FD_UNLIKELY( input==NULL ) ) {
     433           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     434           0 :   }
     435             : 
     436           0 :   fd_sha256_t _sha[1];
     437           0 :   fd_sha256_t * sha = fd_sha256_join( fd_sha256_new( _sha ) );
     438             : 
     439           0 :   fd_vm_t _vm[1];
     440           0 :   fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
     441             : 
     442           0 :   ulong pre_insn_cus = instr_ctx->txn_ctx->compute_budget_details.compute_meter;
     443           0 :   ulong heap_size    = instr_ctx->txn_ctx->compute_budget_details.heap_size;
     444             : 
     445             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L275-L278 */
     446           0 :   ulong heap_cost = calculate_heap_cost( heap_size, FD_VM_HEAP_COST );
     447           0 :   int heap_cost_result = fd_exec_consume_cus( instr_ctx->txn_ctx, heap_cost );
     448           0 :   if( FD_UNLIKELY( heap_cost_result ) ) {
     449           0 :     return FD_EXECUTOR_INSTR_ERR_PROGRAM_ENVIRONMENT_SETUP_FAILURE;
     450           0 :   }
     451             : 
     452             :   /* For dumping syscalls for seed corpora */
     453           0 :   int dump_syscall_to_pb = instr_ctx->txn_ctx->capture_ctx &&
     454           0 :                            instr_ctx->txn_ctx->slot >= instr_ctx->txn_ctx->capture_ctx->dump_proto_start_slot &&
     455           0 :                            instr_ctx->txn_ctx->capture_ctx->dump_syscall_to_pb;
     456             : 
     457             :   /* TODO: (topointon): correctly set check_size in vm setup */
     458           0 :   vm = fd_vm_init(
     459           0 :     /* vm                    */ vm,
     460           0 :     /* instr_ctx             */ instr_ctx,
     461           0 :     /* heap_max              */ heap_size,
     462           0 :     /* entry_cu              */ instr_ctx->txn_ctx->compute_budget_details.compute_meter,
     463           0 :     /* rodata                */ fd_program_cache_get_rodata( cache_entry ),
     464           0 :     /* rodata_sz             */ cache_entry->rodata_sz,
     465           0 :     /* text                  */ (ulong *)((ulong)fd_program_cache_get_rodata( cache_entry ) + (ulong)cache_entry->text_off), /* Note: text_off is byte offset */
     466           0 :     /* text_cnt              */ cache_entry->text_cnt,
     467           0 :     /* text_off              */ cache_entry->text_off,
     468           0 :     /* text_sz               */ cache_entry->text_sz,
     469           0 :     /* entry_pc              */ cache_entry->entry_pc,
     470           0 :     /* calldests             */ fd_program_cache_get_calldests( cache_entry ),
     471           0 :     /* sbpf_version          */ cache_entry->sbpf_version,
     472           0 :     /* syscalls              */ syscalls,
     473           0 :     /* trace                 */ NULL,
     474           0 :     /* sha                   */ sha,
     475           0 :     /* input_mem_regions     */ input_mem_regions,
     476           0 :     /* input_mem_regions_cnt */ input_mem_regions_cnt,
     477           0 :     /* acc_region_metas      */ acc_region_metas,
     478           0 :     /* is_deprecated         */ is_deprecated,
     479           0 :     /* direct_mapping        */ direct_mapping,
     480           0 :     /* dump_syscall_to_pb    */ dump_syscall_to_pb );
     481           0 :   if( FD_UNLIKELY( !vm ) ) {
     482             :     /* We throw an error here because it could be the case that the given heap_size > HEAP_MAX.
     483             :        In this case, Agave fails the transaction but does not error out.
     484             : 
     485             :        https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1396 */
     486           0 :     FD_LOG_WARNING(( "null vm" ));
     487           0 :     return FD_EXECUTOR_INSTR_ERR_PROGRAM_ENVIRONMENT_SETUP_FAILURE;
     488           0 :   }
     489             : 
     490           0 :   if( FD_UNLIKELY( instr_ctx->txn_ctx->fuzz_config.enable_vm_tracing ) ) {
     491           0 :     ulong event_max      = FD_RUNTIME_VM_TRACE_EVENT_MAX;
     492           0 :     ulong event_data_max = FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX;
     493           0 :     vm->trace = fd_vm_trace_join( fd_vm_trace_new( fd_spad_alloc(
     494           0 :     instr_ctx->txn_ctx->spad, fd_vm_trace_align(), fd_vm_trace_footprint( event_max, event_data_max ) ), event_max, event_data_max ) );
     495           0 :     if( FD_UNLIKELY( !vm->trace ) ) FD_LOG_ERR(( "unable to create trace; make sure you've compiled with sufficient spad size " ));
     496           0 :   }
     497             : 
     498           0 :   int exec_err = fd_vm_exec( vm );
     499           0 :   instr_ctx->txn_ctx->compute_budget_details.compute_meter = vm->cu;
     500             : 
     501           0 :   if( FD_UNLIKELY( vm->trace ) ) {
     502           0 :     err = fd_vm_trace_printf( vm->trace, vm->syscalls );
     503           0 :     if( FD_UNLIKELY( err ) ) {
     504           0 :       FD_LOG_WARNING(( "fd_vm_trace_printf failed (%i-%s)", err, fd_vm_strerror( err ) ));
     505           0 :     }
     506           0 :   }
     507             : 
     508             :   /* Log consumed compute units and return data.
     509             :      https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/lib.rs#L1418-L1429 */
     510           0 :   fd_log_collector_program_consumed( instr_ctx, pre_insn_cus-vm->cu, pre_insn_cus );
     511           0 :   if( FD_UNLIKELY( instr_ctx->txn_ctx->return_data.len ) ) {
     512           0 :     fd_log_collector_program_return( instr_ctx );
     513           0 :   }
     514             : 
     515             :   /* We have a big error-matching arm here
     516             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1674-L1744 */
     517             : 
     518             :   /* Handle non-zero return status with successful VM execution. This is
     519             :      the Ok(status) case, hence exec_err must be 0 for this case to be hit.
     520             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1675-L1678 */
     521           0 :   if( FD_LIKELY( !exec_err ) ) {
     522           0 :     ulong status = vm->reg[0];
     523           0 :     if( FD_UNLIKELY( status ) ) {
     524           0 :       err = program_error_to_instr_error( status, &instr_ctx->txn_ctx->custom_err );
     525           0 :       FD_VM_PREPARE_ERR_OVERWRITE( vm );
     526           0 :       FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     527           0 :       return err;
     528           0 :     }
     529           0 :   } else {
     530             :     /* https://github.com/anza-xyz/agave/blob/v2.1.13/programs/bpf_loader/src/lib.rs#L1434-L1439 */
     531             :     /* (SIMD-182) Consume ALL requested CUs on non-Syscall errors */
     532           0 :     if( FD_FEATURE_ACTIVE_BANK( instr_ctx->txn_ctx->bank, deplete_cu_meter_on_vm_failure ) &&
     533           0 :         exec_err!=FD_VM_ERR_EBPF_SYSCALL_ERROR ) {
     534           0 :       instr_ctx->txn_ctx->compute_budget_details.compute_meter = 0UL;
     535           0 :     }
     536             : 
     537             :     /* Direct mapping access violation case
     538             :        Edge case with error codes: if direct mapping is enabled, the EBPF error is an access violation,
     539             :        and the access type was a store, a different error code is returned to give developers more insight
     540             :        as to what caused the error.
     541             :        https://github.com/anza-xyz/agave/blob/v2.0.9/programs/bpf_loader/src/lib.rs#L1436-L1470 */
     542           0 :     if( FD_UNLIKELY( direct_mapping && exec_err==FD_VM_ERR_EBPF_ACCESS_VIOLATION &&
     543           0 :                      vm->segv_vaddr!=ULONG_MAX &&
     544           0 :                      vm->segv_access_type==FD_VM_ACCESS_TYPE_ST ) ) {
     545             :       /* vaddrs start at 0xFFFFFFFF + 1, so anything below it would not correspond to any account metadata. */
     546           0 :       if( FD_UNLIKELY( vm->segv_vaddr>>32UL==0UL ) ) {
     547           0 :         return FD_EXECUTOR_INSTR_ERR_PROGRAM_FAILED_TO_COMPLETE;
     548           0 :       }
     549             : 
     550             :       /* Find the account meta corresponding to the vaddr */
     551           0 :       ulong vaddr_offset = vm->segv_vaddr & FD_VM_OFFSET_MASK;
     552           0 :       ulong acc_region_addl_off = is_deprecated ? 0UL : MAX_PERMITTED_DATA_INCREASE;
     553             : 
     554             :       /* If the vaddr doesn't live in the input region, then we don't need to
     555             :          bother trying to iterate through all of the borrowed accounts. */
     556           0 :       if( FD_VADDR_TO_REGION( vm->segv_vaddr )!=FD_VM_INPUT_REGION ) {
     557           0 :         return FD_EXECUTOR_INSTR_ERR_PROGRAM_FAILED_TO_COMPLETE;
     558           0 :       }
     559             : 
     560             :       /* If the vaddr of the access violation falls within the bounds of a
     561             :          serialized account vaddr range, then try to retrieve a more specific
     562             :          vm error based on the account's accesss permissions. */
     563           0 :       for( ushort i=0UL; i<instr_ctx->instr->acct_cnt; i++ ) {
     564             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L1455 */
     565           0 :         fd_guarded_borrowed_account_t instr_acc = {0};
     566           0 :         FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, i, &instr_acc );
     567             : 
     568           0 :         ulong idx = acc_region_metas[i].region_idx;
     569           0 :         if( input_mem_regions[idx].vaddr_offset<=vaddr_offset && vaddr_offset<input_mem_regions[idx].vaddr_offset+pre_lens[i]+acc_region_addl_off ) {
     570             : 
     571             :           /* Found an input mem region!
     572             :              https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L1515-L1528 */
     573           0 :           if( !FD_FEATURE_ACTIVE_BANK( instr_ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) &&
     574           0 :               fd_borrowed_account_is_executable( &instr_acc ) ) {
     575           0 :             err = FD_EXECUTOR_INSTR_ERR_EXECUTABLE_DATA_MODIFIED;
     576           0 :           } else if( fd_borrowed_account_is_writable( &instr_acc ) ) {
     577           0 :             err = FD_EXECUTOR_INSTR_ERR_EXTERNAL_DATA_MODIFIED;
     578           0 :           } else {
     579           0 :             err = FD_EXECUTOR_INSTR_ERR_READONLY_DATA_MODIFIED;
     580           0 :           }
     581           0 :           return err;
     582           0 :         }
     583           0 :       }
     584           0 :     }
     585             : 
     586             :     /* The error kind should have been set in the VM. Match it and set
     587             :        the error code accordingly. There are no direct permalinks here -
     588             :        this is all a result of Agave's complex nested error-code handling
     589             :        and our design decisions for making our error codes match. */
     590             : 
     591             :     /* Instr error case. Set the error kind and return the instruction error */
     592           0 :     if( instr_ctx->txn_ctx->exec_err_kind==FD_EXECUTOR_ERR_KIND_INSTR ) {
     593           0 :       err = instr_ctx->txn_ctx->exec_err;
     594           0 :       FD_VM_PREPARE_ERR_OVERWRITE( vm );
     595           0 :       FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     596           0 :       return err;
     597           0 :     }
     598             : 
     599             :     /* Syscall error case. The VM would have also set the syscall error
     600             :        code in the txn_ctx exec_err. */
     601           0 :     if( instr_ctx->txn_ctx->exec_err_kind==FD_EXECUTOR_ERR_KIND_SYSCALL ) {
     602           0 :       err = instr_ctx->txn_ctx->exec_err;
     603           0 :       FD_VM_PREPARE_ERR_OVERWRITE( vm );
     604           0 :       FD_VM_ERR_FOR_LOG_SYSCALL( vm, err );
     605           0 :       return FD_EXECUTOR_INSTR_ERR_PROGRAM_FAILED_TO_COMPLETE;
     606           0 :     }
     607             : 
     608             :     /* An access violation that takes place inside a syscall will
     609             :        cause `exec_res` to be set to EbpfError::SyscallError,
     610             :        but the `txn_ctx->exec_err_kind` will be set to EBPF and
     611             :        `txn_ctx->exec_err` will be set to the EBPF error. In this
     612             :        specific case, there is nothing to do since the error and error
     613             :        kind area already set correctly. Otherwise, we need to log the
     614             :        EBPF error. */
     615           0 :     if( exec_err!=FD_VM_ERR_EBPF_SYSCALL_ERROR ) {
     616           0 :       FD_VM_PREPARE_ERR_OVERWRITE( vm );
     617           0 :       FD_VM_ERR_FOR_LOG_EBPF( vm, exec_err );
     618           0 :     }
     619             : 
     620           0 :     return FD_EXECUTOR_INSTR_ERR_PROGRAM_FAILED_TO_COMPLETE;
     621           0 :   }
     622             : 
     623           0 :   err = fd_bpf_loader_input_deserialize_parameters( instr_ctx, pre_lens, input, input_sz, direct_mapping, is_deprecated );
     624           0 :   if( FD_UNLIKELY( err ) ) {
     625           0 :     return err;
     626           0 :   }
     627             : 
     628           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     629           0 : }
     630             : 
     631             : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1358-L1539 */
     632             : static int
     633             : common_extend_program( fd_exec_instr_ctx_t * instr_ctx,
     634             :                        uint                  additional_bytes,
     635           0 :                        uchar                 check_authority ) {
     636           0 :   int err;
     637             : 
     638             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1366 */
     639           0 :   fd_pubkey_t const * program_id = NULL;
     640           0 :   err = fd_exec_instr_ctx_get_last_program_key( instr_ctx, &program_id );
     641           0 :   if( FD_UNLIKELY( err ) ) {
     642           0 :     return err;
     643           0 :   }
     644             : 
     645             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1368-L1370 */
     646           0 :   #define PROGRAM_DATA_ACCOUNT_INDEX (0)
     647           0 :   #define PROGRAM_ACCOUNT_INDEX      (1)
     648           0 :   #define AUTHORITY_ACCOUNT_INDEX    (2)
     649             : 
     650             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1371-L1372 */
     651           0 :   uchar optional_payer_account_index = check_authority ? 4 : 3;
     652             : 
     653             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1374-L1377 */
     654           0 :   if( FD_UNLIKELY( additional_bytes==0U ) ) {
     655           0 :     fd_log_collector_msg_literal( instr_ctx, "Additional bytes must be greater than 0" );
     656           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     657           0 :   }
     658             : 
     659             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1379-L1381 */
     660           0 :   fd_guarded_borrowed_account_t programdata_account = {0};
     661           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, PROGRAM_DATA_ACCOUNT_INDEX, &programdata_account );
     662           0 :   fd_pubkey_t * programdata_key = programdata_account.acct->pubkey;
     663             : 
     664             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1383-L1386 */
     665           0 :   if( FD_UNLIKELY( memcmp( program_id, fd_borrowed_account_get_owner( &programdata_account ), sizeof(fd_pubkey_t) ) ) ) {
     666           0 :     fd_log_collector_msg_literal( instr_ctx, "ProgramData owner is invalid" );
     667           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     668           0 :   }
     669             : 
     670             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1387-L1390 */
     671           0 :   if( FD_UNLIKELY( !fd_borrowed_account_is_writable( &programdata_account ) ) ) {
     672           0 :     fd_log_collector_msg_literal( instr_ctx, "ProgramData is not writable" );
     673           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     674           0 :   }
     675             : 
     676             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1392-L1393 */
     677           0 :   fd_guarded_borrowed_account_t program_account = {0};
     678           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, PROGRAM_ACCOUNT_INDEX, &program_account );
     679             : 
     680             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1394-L1397 */
     681           0 :   if( FD_UNLIKELY( !fd_borrowed_account_is_writable( &program_account ) ) ) {
     682           0 :     fd_log_collector_msg_literal( instr_ctx, "Program account is not writable" );
     683           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     684           0 :   }
     685             : 
     686             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1398-L1401 */
     687           0 :   if( FD_UNLIKELY( memcmp( program_id, fd_borrowed_account_get_owner( &program_account ), sizeof(fd_pubkey_t) ) ) ) {
     688           0 :     fd_log_collector_msg_literal( instr_ctx, "Program account not owned by loader" );
     689           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     690           0 :   }
     691             : 
     692             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1403-L1419 */
     693           0 :   fd_bpf_upgradeable_loader_state_t * program_state = fd_bpf_loader_program_get_state( program_account.acct, instr_ctx->txn_ctx->spad, &err );
     694           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     695           0 :     return err;
     696           0 :   }
     697           0 :   if( fd_bpf_upgradeable_loader_state_is_program( program_state ) ) {
     698           0 :     if( FD_UNLIKELY( memcmp( &program_state->inner.program.programdata_address, programdata_key, sizeof(fd_pubkey_t) ) ) ) {
     699           0 :       fd_log_collector_msg_literal( instr_ctx, "Program account does not match ProgramData account" );
     700           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     701           0 :     }
     702           0 :   } else {
     703           0 :     fd_log_collector_msg_literal( instr_ctx, "Invalid Program account" );
     704           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     705           0 :   }
     706             : 
     707             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1420 */
     708           0 :   fd_borrowed_account_drop( &program_account );
     709             : 
     710             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1422-L1432 */
     711           0 :   ulong old_len = fd_borrowed_account_get_data_len( &programdata_account );
     712           0 :   ulong new_len = fd_ulong_sat_add( old_len, additional_bytes );
     713           0 :   if( FD_UNLIKELY( new_len>MAX_PERMITTED_DATA_LENGTH ) ) {
     714             :     /* Max msg_sz: 85 - 6 + 2*20 = 119 < 127 => we can use printf */
     715           0 :     fd_log_collector_printf_dangerous_max_127( instr_ctx,
     716           0 :       "Extended ProgramData length of %lu bytes exceeds max account data length of %lu bytes", new_len, MAX_PERMITTED_DATA_LENGTH );
     717           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC;
     718           0 :   }
     719             : 
     720             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1434-L1437 */
     721           0 :   fd_sol_sysvar_clock_t clock[1];
     722           0 :   if( FD_UNLIKELY( !fd_sysvar_cache_clock_read( instr_ctx->sysvar_cache, clock ) ) ) {
     723           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     724           0 :   }
     725           0 :   ulong clock_slot = clock->slot;
     726             : 
     727             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1439-L1478 */
     728           0 :   fd_pubkey_t * upgrade_authority_address = NULL;
     729           0 :   fd_bpf_upgradeable_loader_state_t * programdata_state = fd_bpf_loader_program_get_state( programdata_account.acct, instr_ctx->txn_ctx->spad, &err );
     730           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     731           0 :     return err;
     732           0 :   }
     733           0 :   if( fd_bpf_upgradeable_loader_state_is_program_data( programdata_state ) ) {
     734             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1444-L1447 */
     735           0 :     if( FD_UNLIKELY( clock_slot==programdata_state->inner.program_data.slot ) ) {
     736           0 :       fd_log_collector_msg_literal( instr_ctx, "Program was extended in this block already" );
     737           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     738           0 :     }
     739             : 
     740             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1449-L1455 */
     741           0 :     if( FD_UNLIKELY( !programdata_state->inner.program_data.has_upgrade_authority_address ) ) {
     742           0 :       fd_log_collector_msg_literal( instr_ctx, "Cannot extend ProgramData accounts that are not upgradeable" );
     743           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     744           0 :     }
     745             : 
     746             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1457-L1472 */
     747           0 :     if( check_authority ) {
     748             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1458-L1463 */
     749           0 :       fd_pubkey_t const * authority_key = NULL;
     750           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, AUTHORITY_ACCOUNT_INDEX, &authority_key );
     751           0 :       if( FD_UNLIKELY( err ) ) {
     752           0 :         return err;
     753           0 :       }
     754             : 
     755             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1464-L1467 */
     756           0 :       if( FD_UNLIKELY( !fd_pubkey_eq( &programdata_state->inner.program_data.upgrade_authority_address, authority_key ) ) ) {
     757           0 :         fd_log_collector_msg_literal( instr_ctx, "Incorrect upgrade authority provided" );
     758           0 :         return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     759           0 :       }
     760             : 
     761             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1468-L1471 */
     762           0 :       if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, AUTHORITY_ACCOUNT_INDEX, &err ) ) ) {
     763             :         /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
     764           0 :         if( FD_UNLIKELY( !!err ) ) return err;
     765           0 :         fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
     766           0 :         return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     767           0 :       }
     768           0 :     }
     769             : 
     770             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1474 */
     771           0 :     fd_bpf_upgradeable_loader_state_program_data_t * pd = &programdata_state->inner.program_data;
     772           0 :     upgrade_authority_address = pd->has_upgrade_authority_address ? &pd->upgrade_authority_address : NULL;
     773           0 :   } else {
     774             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1476-L1477 */
     775           0 :     fd_log_collector_msg_literal( instr_ctx, "ProgramData state is invalid" );
     776           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     777           0 :   }
     778             : 
     779             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1480-L1485 */
     780           0 :   fd_rent_t const * rent             = fd_bank_rent_query( instr_ctx->txn_ctx->bank );
     781           0 :   ulong             balance          = fd_borrowed_account_get_lamports( &programdata_account );
     782           0 :   ulong             min_balance      = fd_ulong_max( fd_rent_exempt_minimum_balance( rent, new_len ), 1UL );
     783           0 :   ulong             required_payment = fd_ulong_sat_sub( min_balance, balance );
     784             : 
     785             :   /* Borrowed accounts need to be dropped before native invocations. Note:
     786             :      the programdata account is manually released and acquired within the
     787             :      extend instruction to preserve the local variable scoping to maintain
     788             :      readability. The scoped macro still successfully handles the case of
     789             :      freeing a write lock in case of an early termination. */
     790             : 
     791             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1488 */
     792           0 :   fd_borrowed_account_drop( &programdata_account );
     793             : 
     794             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1492-L1502 */
     795           0 :   if( FD_UNLIKELY( required_payment>0UL ) ) {
     796             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1493-L1496 */
     797           0 :     fd_pubkey_t const * payer_key = NULL;
     798           0 :     err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, optional_payer_account_index, &payer_key );
     799           0 :     if( FD_UNLIKELY( err ) ) {
     800           0 :       return err;
     801           0 :     }
     802             : 
     803             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1498-L1501 */
     804           0 :     uchar instr_data[FD_TXN_MTU];
     805           0 :     fd_system_program_instruction_t instr = {
     806           0 :       .discriminant = fd_system_program_instruction_enum_transfer,
     807           0 :       .inner = {
     808           0 :         .transfer = required_payment
     809           0 :       }
     810           0 :     };
     811             : 
     812           0 :     fd_bincode_encode_ctx_t encode_ctx = {
     813           0 :       .data    = instr_data,
     814           0 :       .dataend = instr_data + FD_TXN_MTU
     815           0 :     };
     816             : 
     817             :     // This should never fail.
     818           0 :     int err = fd_system_program_instruction_encode( &instr, &encode_ctx );
     819           0 :     if( FD_UNLIKELY( err ) ) {
     820           0 :       return FD_EXECUTOR_INSTR_ERR_FATAL;
     821           0 :     }
     822             : 
     823           0 :     fd_vm_rust_account_meta_t * acct_metas = (fd_vm_rust_account_meta_t *)
     824           0 :                                               fd_spad_alloc( instr_ctx->txn_ctx->spad,
     825           0 :                                                              FD_VM_RUST_ACCOUNT_META_ALIGN,
     826           0 :                                                              2UL * sizeof(fd_vm_rust_account_meta_t) );
     827           0 :     fd_native_cpi_create_account_meta( payer_key,       1UL, 1UL, &acct_metas[ 0UL ] );
     828           0 :     fd_native_cpi_create_account_meta( programdata_key, 0UL, 1UL, &acct_metas[ 1UL ] );
     829             : 
     830           0 :     err = fd_native_cpi_native_invoke( instr_ctx,
     831           0 :                                         &fd_solana_system_program_id,
     832           0 :                                         instr_data,
     833           0 :                                         FD_TXN_MTU,
     834           0 :                                         acct_metas,
     835           0 :                                         2UL,
     836           0 :                                         NULL,
     837           0 :                                         0UL );
     838           0 :     if( FD_UNLIKELY( err ) ) {
     839           0 :       return err;
     840           0 :     }
     841           0 :   }
     842             : 
     843             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1506-L1507 */
     844           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, PROGRAM_DATA_ACCOUNT_INDEX, &programdata_account );
     845             : 
     846             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1508 */
     847           0 :   err = fd_borrowed_account_set_data_length( &programdata_account, new_len );
     848           0 :   if( FD_UNLIKELY( err ) ) {
     849           0 :     return err;
     850           0 :   }
     851             : 
     852             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1510 */
     853           0 :   ulong programdata_data_offset = PROGRAMDATA_METADATA_SIZE;
     854             : 
     855             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1517-L1520 */
     856           0 :   if( FD_UNLIKELY( programdata_data_offset>fd_borrowed_account_get_data_len( &programdata_account ) ) ) {
     857           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     858           0 :   }
     859           0 :   uchar const * programdata_data = fd_borrowed_account_get_data( &programdata_account ) + programdata_data_offset;
     860           0 :   ulong         programdata_size = new_len - PROGRAMDATA_METADATA_SIZE;
     861             : 
     862             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1512-L1522 */
     863           0 :   err = fd_deploy_program( instr_ctx, program_account.acct->pubkey, programdata_data, programdata_size, instr_ctx->txn_ctx->spad );
     864           0 :   if( FD_UNLIKELY( err ) ) {
     865           0 :     return err;
     866           0 :   }
     867             : 
     868             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1523 */
     869           0 :   fd_borrowed_account_drop( &programdata_account );
     870             : 
     871             :   /* Setting the discriminant and upgrade authority address here can likely
     872             :      be a no-op because these values shouldn't change. These can probably be
     873             :      removed, but can help to mirror against Agave client's implementation.
     874             :      The set_state function also contains an ownership check. */
     875             : 
     876             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1525-L1526 */
     877           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &programdata_account );
     878             : 
     879             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1527-L1530 */
     880           0 :   programdata_state->discriminant            = fd_bpf_upgradeable_loader_state_enum_program_data;
     881           0 :   programdata_state->inner.program_data.slot = clock_slot;
     882           0 :   programdata_state->inner.program_data.has_upgrade_authority_address = !!upgrade_authority_address;
     883           0 :   if( upgrade_authority_address ) programdata_state->inner.program_data.upgrade_authority_address = *upgrade_authority_address;
     884             : 
     885           0 :   err = fd_bpf_loader_v3_program_set_state( &programdata_account, programdata_state );
     886           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     887           0 :     return err;
     888           0 :   }
     889             : 
     890             :   /* Max msg_sz: 41 - 2 + 20 = 57 < 127 => we can use printf
     891             :      https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1532-L1536 */
     892           0 :   fd_log_collector_printf_dangerous_max_127( instr_ctx,
     893           0 :     "Extended ProgramData account by %u bytes", additional_bytes );
     894             : 
     895             :   /* programdata account is dropped when it goes out of scope */
     896             : 
     897           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     898             : 
     899           0 :   #undef PROGRAM_DATA_ACCOUNT_INDEX
     900           0 :   #undef PROGRAM_ACCOUNT_INDEX
     901           0 :   #undef AUTHORITY_ACCOUNT_INDEX
     902           0 : }
     903             : 
     904             : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L566-L1444 */
     905             : static int
     906           0 : process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) {
     907           0 :   uchar const * data = instr_ctx->instr->data;
     908           0 :   fd_spad_t *   spad = instr_ctx->txn_ctx->spad;
     909             : 
     910           0 :   int err;
     911           0 :   fd_bpf_upgradeable_loader_program_instruction_t * instruction =
     912           0 :     fd_bincode_decode_spad(
     913           0 :       bpf_upgradeable_loader_program_instruction, spad,
     914           0 :       data,
     915           0 :       instr_ctx->instr->data_sz>FD_TXN_MTU ? FD_TXN_MTU: instr_ctx->instr->data_sz,
     916           0 :       &err );
     917           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     918           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     919           0 :   }
     920             : 
     921             :   /* https://github.com/anza-xyz/agave/blob/v2.2.0/programs/bpf_loader/src/lib.rs#L510 */
     922           0 :   fd_pubkey_t const * program_id = NULL;
     923           0 :   err = fd_exec_instr_ctx_get_last_program_key( instr_ctx, &program_id );
     924           0 :   if( FD_UNLIKELY( err ) ) {
     925           0 :     return err;
     926           0 :   }
     927             : 
     928           0 :   switch( instruction->discriminant ) {
     929             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L476-L493 */
     930           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_initialize_buffer: {
     931           0 :       if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 2U ) ) ) {
     932           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     933           0 :       }
     934             : 
     935             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L479 */
     936           0 :       fd_guarded_borrowed_account_t buffer = {0};
     937           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &buffer );
     938           0 :       fd_bpf_upgradeable_loader_state_t * buffer_state = fd_bpf_loader_program_get_state( buffer.acct,
     939           0 :                                                                                           spad,
     940           0 :                                                                                           &err );
     941           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     942           0 :         return err;
     943           0 :       }
     944             : 
     945           0 :       if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_uninitialized( buffer_state ) ) ) {
     946           0 :         fd_log_collector_msg_literal( instr_ctx, "Buffer account is already initialized" );
     947           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
     948           0 :       }
     949             : 
     950             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L487-L489 */
     951           0 :       fd_pubkey_t const * authority_key = NULL;
     952           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &authority_key );
     953           0 :       if( FD_UNLIKELY( err ) ) {
     954           0 :         return err;
     955           0 :       }
     956             : 
     957           0 :       buffer_state->discriminant                       = fd_bpf_upgradeable_loader_state_enum_buffer;
     958           0 :       buffer_state->inner.buffer.has_authority_address = 1;
     959           0 :       buffer_state->inner.buffer.authority_address     = *authority_key;
     960             : 
     961           0 :       err = fd_bpf_loader_v3_program_set_state( &buffer, buffer_state );
     962           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     963           0 :         return err;
     964           0 :       }
     965             : 
     966             :       /* implicit drop of buffer account */
     967             : 
     968           0 :       break;
     969           0 :     }
     970             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L494-L525 */
     971           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_write: {
     972           0 :       if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 2U ) ) ) {
     973           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     974           0 :       }
     975             : 
     976             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L497 */
     977           0 :       fd_guarded_borrowed_account_t buffer = {0};
     978           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &buffer );
     979             : 
     980           0 :        fd_bpf_upgradeable_loader_state_t * loader_state = fd_bpf_loader_program_get_state( buffer.acct,
     981           0 :                                                                                            spad,
     982           0 :                                                                                            &err );
     983           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     984           0 :         return err;
     985           0 :       }
     986             : 
     987           0 :       if( fd_bpf_upgradeable_loader_state_is_buffer( loader_state ) ) {
     988           0 :         if( FD_UNLIKELY( !loader_state->inner.buffer.has_authority_address ) ) {
     989           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer is immutable" );
     990           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     991           0 :         }
     992             : 
     993             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L505-L507 */
     994           0 :         fd_pubkey_t const * authority_key = NULL;
     995           0 :         err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &authority_key );
     996           0 :         if( FD_UNLIKELY( err ) ) {
     997           0 :           return err;
     998           0 :         }
     999             : 
    1000           0 :         if( FD_UNLIKELY( !fd_pubkey_eq( &loader_state->inner.buffer.authority_address, authority_key ) ) ) {
    1001           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect buffer authority provided" );
    1002           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1003           0 :         }
    1004           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL, &err ) ) ) {
    1005             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1006           0 :           if( FD_UNLIKELY( !!err ) ) return err;
    1007           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer authority did not sign" );
    1008           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1009           0 :         }
    1010           0 :       } else {
    1011           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid Buffer account" );
    1012           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1013           0 :       }
    1014             : 
    1015             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L520 */
    1016           0 :       fd_borrowed_account_drop( &buffer );
    1017             : 
    1018           0 :       ulong program_data_offset = fd_ulong_sat_add( BUFFER_METADATA_SIZE, instruction->inner.write.offset );
    1019           0 :       err = write_program_data( instr_ctx,
    1020           0 :                                 0UL,
    1021           0 :                                 program_data_offset,
    1022           0 :                                 instruction->inner.write.bytes,
    1023           0 :                                 instruction->inner.write.bytes_len );
    1024           0 :       if( FD_UNLIKELY( err ) ) {
    1025           0 :         return err;
    1026           0 :       }
    1027             : 
    1028           0 :       break;
    1029           0 :     }
    1030             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L526-L702 */
    1031           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_deploy_with_max_data_len: {
    1032             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L527-L541 */
    1033           0 :       if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 4U ) ) ) {
    1034           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1035           0 :       }
    1036             : 
    1037             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L529-L534 */
    1038           0 :       fd_pubkey_t const * payer_key       = NULL;
    1039           0 :       fd_pubkey_t const * programdata_key = NULL;
    1040             : 
    1041           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 0UL, &payer_key );
    1042           0 :       if( FD_UNLIKELY( err ) ) {
    1043           0 :         return err;
    1044           0 :       }
    1045             : 
    1046           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &programdata_key );
    1047           0 :       if( FD_UNLIKELY( err ) ) {
    1048           0 :         return err;
    1049           0 :       }
    1050             : 
    1051             :       /* rent is accessed directly from the epoch bank and the clock from the
    1052             :         slot context. However, a check must be done to make sure that the
    1053             :         sysvars are correctly included in the set of transaction accounts. */
    1054           0 :       err = fd_sysvar_instr_acct_check( instr_ctx, 4UL, &fd_sysvar_rent_id );
    1055           0 :       if( FD_UNLIKELY( err ) ) {
    1056           0 :         return err;
    1057           0 :       }
    1058           0 :       err = fd_sysvar_instr_acct_check( instr_ctx, 5UL, &fd_sysvar_clock_id );
    1059           0 :       if( FD_UNLIKELY( err ) ) {
    1060           0 :         return err;
    1061           0 :       }
    1062             : 
    1063           0 :       fd_sol_sysvar_clock_t clock_;
    1064           0 :       fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( instr_ctx->sysvar_cache, &clock_ );
    1065           0 :       if( FD_UNLIKELY( !clock ) ) {
    1066           0 :         return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR;
    1067           0 :       }
    1068             : 
    1069             :       /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L538 */
    1070           0 :       if( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 8U ) ) {
    1071           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1072           0 :       }
    1073             : 
    1074             :       /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L539-L541 */
    1075           0 :       fd_pubkey_t const * authority_key = NULL;
    1076           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 7UL, &authority_key );
    1077           0 :       if( FD_UNLIKELY( err ) ) return err;
    1078             : 
    1079             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L542-L560 */
    1080             :       /* Verify Program account */
    1081             : 
    1082           0 :       fd_bpf_upgradeable_loader_state_t * loader_state   = NULL;
    1083           0 :       fd_pubkey_t *                       new_program_id = NULL;
    1084           0 :       fd_rent_t const *                   rent           = fd_bank_rent_query( instr_ctx->txn_ctx->bank );
    1085             : 
    1086             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L545 */
    1087           0 :       fd_guarded_borrowed_account_t program = {0};
    1088           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 2UL, &program );
    1089             : 
    1090           0 :       loader_state = fd_bpf_loader_program_get_state( program.acct,
    1091           0 :                                                       spad,
    1092           0 :                                                       &err );
    1093             : 
    1094           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1095           0 :         return err;
    1096           0 :       }
    1097           0 :       if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_uninitialized( loader_state ) ) ) {
    1098           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account already initialized" );
    1099           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
    1100           0 :       }
    1101           0 :       if( FD_UNLIKELY( fd_borrowed_account_get_data_len( &program )<SIZE_OF_PROGRAM ) ) {
    1102           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account too small" );
    1103           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1104           0 :       }
    1105           0 :       if( FD_UNLIKELY( fd_borrowed_account_get_lamports( &program )<
    1106           0 :                        fd_rent_exempt_minimum_balance( rent, fd_borrowed_account_get_data_len( &program ) ) ) ) {
    1107           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not rent-exempt" );
    1108           0 :         return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT;
    1109           0 :       }
    1110           0 :       new_program_id = program.acct->pubkey;
    1111             : 
    1112             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L560 */
    1113           0 :       fd_borrowed_account_drop( &program );
    1114             : 
    1115             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L561-L600 */
    1116             :       /* Verify Buffer account */
    1117             : 
    1118           0 :       fd_pubkey_t * buffer_key       = NULL;
    1119           0 :       ulong buffer_data_offset       = 0UL;
    1120           0 :       ulong buffer_data_len          = 0UL;
    1121           0 :       ulong programdata_len          = 0UL;
    1122             : 
    1123             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L564-L565 */
    1124           0 :       fd_guarded_borrowed_account_t buffer = {0};
    1125           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 3UL, &buffer );
    1126             : 
    1127           0 :       fd_bpf_upgradeable_loader_state_t * buffer_state = fd_bpf_loader_program_get_state( buffer.acct, spad, &err );
    1128           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1129           0 :         return err;
    1130           0 :       }
    1131             : 
    1132           0 :       if( fd_bpf_upgradeable_loader_state_is_buffer( buffer_state ) ) {
    1133           0 :         if( FD_UNLIKELY( (authority_key==NULL) != (!buffer_state->inner.buffer.has_authority_address) ||
    1134           0 :             (authority_key!=NULL && !fd_pubkey_eq( &buffer_state->inner.buffer.authority_address, authority_key ) ) ) ) {
    1135           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer and upgrade authority don't match" );
    1136           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1137           0 :         }
    1138           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 7UL, &err ) ) ) {
    1139             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1140           0 :           if( FD_UNLIKELY( !!err ) ) return err;
    1141           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
    1142           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1143           0 :         }
    1144           0 :       } else {
    1145           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid Buffer account" );
    1146           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1147           0 :       }
    1148           0 :       buffer_key         = buffer.acct->pubkey;
    1149           0 :       buffer_data_offset = BUFFER_METADATA_SIZE;
    1150           0 :       buffer_data_len    = fd_ulong_sat_sub( fd_borrowed_account_get_data_len( &buffer ), buffer_data_offset );
    1151             :       /* UpgradeableLoaderState::size_of_program_data( max_data_len ) */
    1152           0 :       programdata_len    = fd_ulong_sat_add( PROGRAMDATA_METADATA_SIZE,
    1153           0 :                                              instruction->inner.deploy_with_max_data_len.max_data_len );
    1154             : 
    1155           0 :       if( FD_UNLIKELY( fd_borrowed_account_get_data_len( &buffer )<BUFFER_METADATA_SIZE || buffer_data_len==0UL ) ) {
    1156           0 :         fd_log_collector_msg_literal( instr_ctx, "Buffer account too small" );
    1157           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1158           0 :       }
    1159             : 
    1160           0 :       if( FD_UNLIKELY( instruction->inner.deploy_with_max_data_len.max_data_len<buffer_data_len ) ) {
    1161           0 :         fd_log_collector_msg_literal( instr_ctx, "Max data length is too small to hold Buffer data" );
    1162           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1163           0 :       }
    1164             : 
    1165           0 :       if( FD_UNLIKELY( programdata_len>MAX_PERMITTED_DATA_LENGTH ) ) {
    1166           0 :         fd_log_collector_msg_literal( instr_ctx, "Max data length is too large" );
    1167           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1168           0 :       }
    1169             : 
    1170             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L590 */
    1171           0 :       fd_borrowed_account_drop( &buffer );
    1172             : 
    1173             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L602-L608 */
    1174             :       /* Create ProgramData account */
    1175             : 
    1176           0 :       fd_pubkey_t derived_address[ 1UL ];
    1177           0 :       uchar const * seeds[ 1UL ];
    1178           0 :       seeds[ 0UL ]    = (uchar const *)new_program_id;
    1179           0 :       ulong seed_sz   = sizeof(fd_pubkey_t);
    1180           0 :       uchar bump_seed = 0;
    1181           0 :       err = fd_pubkey_find_program_address( program_id, 1UL, seeds, &seed_sz, derived_address,
    1182           0 :                                             &bump_seed, &instr_ctx->txn_ctx->custom_err );
    1183           0 :       if( FD_UNLIKELY( err ) ) {
    1184             :         /* TODO: We should handle these errors more gracefully instead of just killing the client (e.g. excluding the transaction
    1185             :            from the block). */
    1186           0 :         FD_LOG_ERR(( "Unable to find a viable program address bump seed" )); // Solana panics, error code is undefined
    1187           0 :         return err;
    1188           0 :       }
    1189           0 :       if( FD_UNLIKELY( memcmp( derived_address, programdata_key, sizeof(fd_pubkey_t) ) ) ) {
    1190           0 :         fd_log_collector_msg_literal( instr_ctx, "ProgramData address is not derived" );
    1191           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1192           0 :       }
    1193             : 
    1194             :       /* Drain the Buffer account to payer before paying for programdata account in a local scope
    1195             :          https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L612-L628 */
    1196             : 
    1197           0 :       do {
    1198             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L615 */
    1199           0 :         fd_guarded_borrowed_account_t payer = {0};
    1200           0 :         FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &payer );
    1201             : 
    1202             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L613 */
    1203           0 :         fd_guarded_borrowed_account_t buffer = {0};
    1204           0 :         FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 3UL, &buffer );
    1205             : 
    1206           0 :         err = fd_borrowed_account_checked_add_lamports( &payer, fd_borrowed_account_get_lamports( &buffer ) );
    1207           0 :         if( FD_UNLIKELY( err ) ) {
    1208           0 :           return err;
    1209           0 :         }
    1210           0 :         err = fd_borrowed_account_set_lamports( &buffer, 0UL );
    1211           0 :         if( FD_UNLIKELY( err ) ) {
    1212           0 :           return err;
    1213           0 :         }
    1214           0 :       } while (0);
    1215             : 
    1216             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L628-L642 */
    1217             :       /* Pass an extra account to avoid the overly strict unbalanced instruction error */
    1218             :       /* Invoke the system program to create the new account */
    1219           0 :       uchar instr_data[FD_TXN_MTU];
    1220           0 :       fd_system_program_instruction_create_account_t create_acct = {
    1221           0 :         .lamports = fd_rent_exempt_minimum_balance( rent, programdata_len ),
    1222           0 :         .space    = programdata_len,
    1223           0 :         .owner    = *program_id,
    1224           0 :       };
    1225           0 :       if( !create_acct.lamports ) {
    1226           0 :         create_acct.lamports = 1UL;
    1227           0 :       }
    1228             : 
    1229           0 :       fd_system_program_instruction_t instr = {
    1230           0 :         .discriminant = fd_system_program_instruction_enum_create_account,
    1231           0 :         .inner = {
    1232           0 :           .create_account = create_acct,
    1233           0 :         }
    1234           0 :       };
    1235             : 
    1236           0 :       fd_bincode_encode_ctx_t encode_ctx = {
    1237           0 :         .data    = instr_data,
    1238           0 :         .dataend = instr_data + FD_TXN_MTU
    1239           0 :       };
    1240             : 
    1241             :       // This should never fail.
    1242           0 :       int err = fd_system_program_instruction_encode( &instr, &encode_ctx );
    1243           0 :       if( FD_UNLIKELY( err ) ) {
    1244           0 :         return FD_EXECUTOR_INSTR_ERR_FATAL;
    1245           0 :       }
    1246             : 
    1247           0 :       fd_vm_rust_account_meta_t * acct_metas = (fd_vm_rust_account_meta_t*)
    1248           0 :                                                 fd_spad_alloc( instr_ctx->txn_ctx->spad,
    1249           0 :                                                                FD_VM_RUST_ACCOUNT_META_ALIGN,
    1250           0 :                                                                3UL * sizeof(fd_vm_rust_account_meta_t) );
    1251           0 :       fd_native_cpi_create_account_meta( payer_key,       1U, 1U, &acct_metas[ 0UL ] );
    1252           0 :       fd_native_cpi_create_account_meta( programdata_key, 1U, 1U, &acct_metas[ 1UL ] );
    1253           0 :       fd_native_cpi_create_account_meta( buffer_key,      0U, 1U, &acct_metas[ 2UL ] );
    1254             : 
    1255             :       /* caller_program_id == program_id */
    1256           0 :       fd_pubkey_t signers[ 1UL ];
    1257           0 :       err = fd_pubkey_derive_pda( program_id, 1UL, seeds, &seed_sz, &bump_seed, signers, &instr_ctx->txn_ctx->custom_err );
    1258           0 :       if( FD_UNLIKELY( err ) ) {
    1259           0 :         return err;
    1260           0 :       }
    1261           0 :       err = fd_native_cpi_native_invoke( instr_ctx,
    1262           0 :                                          &fd_solana_system_program_id,
    1263           0 :                                          instr_data,
    1264           0 :                                          FD_TXN_MTU,
    1265           0 :                                          acct_metas,
    1266           0 :                                          3UL,
    1267           0 :                                          signers,
    1268           0 :                                          1UL );
    1269           0 :       if( FD_UNLIKELY( err ) ) {
    1270           0 :         return err;
    1271           0 :       }
    1272             : 
    1273             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L644-L665 */
    1274             :       /* Load and verify the program bits */
    1275             : 
    1276             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L648-L649 */
    1277           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 3UL, &buffer );
    1278             : 
    1279           0 :       if( FD_UNLIKELY( buffer_data_offset>fd_borrowed_account_get_data_len( &buffer ) ) ) {
    1280           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1281           0 :       }
    1282             : 
    1283           0 :       const uchar * buffer_data = fd_borrowed_account_get_data( &buffer ) + buffer_data_offset;
    1284             : 
    1285           0 :       err = fd_deploy_program( instr_ctx, program.acct->pubkey, buffer_data, buffer_data_len, instr_ctx->txn_ctx->spad );
    1286           0 :       if( FD_UNLIKELY( err ) ) {
    1287           0 :         return err;
    1288           0 :       }
    1289             : 
    1290             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L657 */
    1291           0 :       fd_borrowed_account_drop( &buffer );
    1292             : 
    1293             :       /* Update the ProgramData account and record the program bits in a local scope
    1294             :          https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L669-L691 */
    1295           0 :       do {
    1296             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L670-L671 */
    1297           0 :         fd_guarded_borrowed_account_t programdata = {0};
    1298           0 :         FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 1UL, &programdata );
    1299             : 
    1300           0 :         fd_bpf_upgradeable_loader_state_t programdata_loader_state = {
    1301           0 :           .discriminant = fd_bpf_upgradeable_loader_state_enum_program_data,
    1302           0 :           .inner.program_data = {
    1303           0 :             .slot                          = clock->slot,
    1304           0 :             .has_upgrade_authority_address = !!authority_key,
    1305           0 :             .upgrade_authority_address     = authority_key ? *authority_key : (fd_pubkey_t){{0}},
    1306           0 :           },
    1307           0 :         };
    1308           0 :         err = fd_bpf_loader_v3_program_set_state( &programdata, &programdata_loader_state );
    1309           0 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1310           0 :           return err;
    1311           0 :         }
    1312             : 
    1313             :         /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L675-L689 */
    1314           0 :         if( FD_UNLIKELY( PROGRAMDATA_METADATA_SIZE+buffer_data_len>fd_borrowed_account_get_data_len( &programdata ) ) ) {
    1315           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1316           0 :         }
    1317           0 :         if( FD_UNLIKELY( buffer_data_offset>fd_borrowed_account_get_data_len( &buffer ) ) ) {
    1318           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1319           0 :         }
    1320             : 
    1321           0 :         uchar * programdata_data = NULL;
    1322           0 :         ulong   programdata_dlen = 0UL;
    1323           0 :         err = fd_borrowed_account_get_data_mut( &programdata, &programdata_data, &programdata_dlen );
    1324           0 :         if( FD_UNLIKELY( err ) ) {
    1325           0 :           return err;
    1326           0 :         }
    1327             : 
    1328           0 :         uchar *   dst_slice = programdata_data + PROGRAMDATA_METADATA_SIZE;
    1329           0 :         ulong dst_slice_len = buffer_data_len;
    1330             : 
    1331             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L683-L684 */
    1332           0 :         fd_guarded_borrowed_account_t buffer = {0};
    1333           0 :         FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 3UL, &buffer );
    1334             : 
    1335           0 :         if( FD_UNLIKELY( buffer_data_offset>fd_borrowed_account_get_data_len( &buffer ) ) ) {
    1336           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1337           0 :         }
    1338           0 :         const uchar * src_slice = fd_borrowed_account_get_data( &buffer ) + buffer_data_offset;
    1339           0 :         fd_memcpy( dst_slice, src_slice, dst_slice_len );
    1340             :         /* Update buffer data length.
    1341             :           BUFFER_METADATA_SIZE == UpgradeableLoaderState::size_of_buffer(0) */
    1342           0 :         err = fd_borrowed_account_set_data_length( &buffer, BUFFER_METADATA_SIZE );
    1343           0 :         if( FD_UNLIKELY( err ) ) {
    1344           0 :           return err;
    1345           0 :         }
    1346           0 :       } while(0);
    1347             : 
    1348             :       /* Max msg_sz: 19 - 2 + 45 = 62 < 127 => we can use printf */
    1349           0 :       fd_log_collector_printf_dangerous_max_127( instr_ctx, "Deployed program %s", FD_BASE58_ENC_32_ALLOCA( program_id ) );
    1350             : 
    1351             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L692-L699 */
    1352             : 
    1353             :       /* Update the Program account
    1354             :          https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L694-L695 */
    1355           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 2UL, &program );
    1356             : 
    1357           0 :       loader_state->discriminant = fd_bpf_upgradeable_loader_state_enum_program;
    1358           0 :       loader_state->inner.program.programdata_address =  *programdata_key;
    1359           0 :       err = fd_bpf_loader_v3_program_set_state( &program, loader_state );
    1360           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1361           0 :         return err;
    1362           0 :       }
    1363           0 :       err = fd_borrowed_account_set_executable( &program, 1 );
    1364           0 :       if( FD_UNLIKELY( err ) ) {
    1365           0 :         return err;
    1366           0 :       }
    1367             : 
    1368           0 :       FD_LOG_INFO(( "Program deployed %s", FD_BASE58_ENC_32_ALLOCA( program.acct->pubkey ) ));
    1369             : 
    1370             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L700 */
    1371           0 :       fd_borrowed_account_drop( &program );
    1372             : 
    1373           0 :       break;
    1374           0 :     }
    1375             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L703-L891 */
    1376           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_upgrade: {
    1377             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L704-L714 */
    1378           0 :       if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 3U ) ) ) {
    1379           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1380           0 :       }
    1381             : 
    1382             :       /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L706-L708 */
    1383           0 :       fd_pubkey_t const * programdata_key = NULL;
    1384           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 0UL, &programdata_key );
    1385           0 :       if( FD_UNLIKELY( err ) ) {
    1386           0 :         return err;
    1387           0 :       }
    1388             : 
    1389             :       /* rent is accessed directly from the epoch bank and the clock from the
    1390             :         slot context. However, a check must be done to make sure that the
    1391             :         sysvars are correctly included in the set of transaction accounts. */
    1392           0 :       err = fd_sysvar_instr_acct_check( instr_ctx, 4UL, &fd_sysvar_rent_id );
    1393           0 :       if( FD_UNLIKELY( err ) ) {
    1394           0 :         return err;
    1395           0 :       }
    1396           0 :       err = fd_sysvar_instr_acct_check( instr_ctx, 5UL, &fd_sysvar_clock_id );
    1397           0 :       if( FD_UNLIKELY( err ) ) {
    1398           0 :         return err;
    1399           0 :       }
    1400             : 
    1401           0 :       if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 7U ) ) ) {
    1402           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1403           0 :       }
    1404             : 
    1405             :       /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L713-L715 */
    1406           0 :       fd_pubkey_t const * authority_key = NULL;
    1407           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 6UL, &authority_key );
    1408           0 :       if( FD_UNLIKELY( err ) ) return err;
    1409             : 
    1410             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L716-L745 */
    1411             :       /* Verify Program account */
    1412             : 
    1413             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L719-L720 */
    1414           0 :       fd_guarded_borrowed_account_t program = {0};
    1415           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 1UL, &program );
    1416             : 
    1417             :       /* https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L758-L765 */
    1418           0 :       if( FD_UNLIKELY( !FD_FEATURE_ACTIVE_BANK( instr_ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) &&
    1419           0 :                        !fd_borrowed_account_is_executable( &program ) ) ) {
    1420           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not executable" );
    1421           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_NOT_EXECUTABLE;
    1422           0 :       }
    1423           0 :       if( FD_UNLIKELY( !fd_borrowed_account_is_writable( &program ) ) ) {
    1424           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not writeable" );
    1425           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1426           0 :       }
    1427           0 :       if( FD_UNLIKELY( memcmp( fd_borrowed_account_get_owner( &program ), program_id, sizeof(fd_pubkey_t) ) ) ) {
    1428           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not owned by loader" );
    1429           0 :         return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
    1430           0 :       }
    1431           0 :       fd_bpf_upgradeable_loader_state_t * program_state = fd_bpf_loader_program_get_state( program.acct, spad, &err );
    1432           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1433           0 :         return err;
    1434           0 :       }
    1435           0 :       if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_is_program( program_state ) ) ) {
    1436           0 :         if( FD_UNLIKELY( memcmp( &program_state->inner.program.programdata_address, programdata_key, sizeof(fd_pubkey_t) ) ) ) {
    1437           0 :           fd_log_collector_msg_literal( instr_ctx, "Program and ProgramData account mismatch" );
    1438           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1439           0 :         }
    1440           0 :       } else {
    1441           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid Program account" );
    1442           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1443           0 :       }
    1444             : 
    1445             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L746 */
    1446           0 :       fd_borrowed_account_drop( &program );
    1447             : 
    1448             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L747-L773 */
    1449             :       /* Verify Buffer account */
    1450             : 
    1451           0 :       ulong buffer_lamports    = 0UL;
    1452           0 :       ulong buffer_data_offset = 0UL;
    1453           0 :       ulong buffer_data_len    = 0UL;
    1454             : 
    1455             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L750-L751 */
    1456           0 :       fd_guarded_borrowed_account_t buffer = {0};
    1457           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 2UL, &buffer );
    1458             : 
    1459           0 :       fd_bpf_upgradeable_loader_state_t * buffer_state = fd_bpf_loader_program_get_state( buffer.acct, spad, &err );
    1460           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1461           0 :         return err;
    1462           0 :       }
    1463           0 :       if( fd_bpf_upgradeable_loader_state_is_buffer( buffer_state ) ) {
    1464           0 :         if( FD_UNLIKELY( (authority_key==NULL) != (!buffer_state->inner.buffer.has_authority_address) ||
    1465           0 :             (authority_key!=NULL && !fd_pubkey_eq( &buffer_state->inner.buffer.authority_address, authority_key ) ) ) ) {
    1466           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer and upgrade authority don't match" );
    1467           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1468           0 :         }
    1469           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 6UL, &err ) ) ) {
    1470             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1471           0 :           if( FD_UNLIKELY( !!err ) ) return err;
    1472           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
    1473           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1474           0 :         }
    1475           0 :       } else {
    1476           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid Buffer account" );
    1477           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1478           0 :       }
    1479           0 :       buffer_lamports    = fd_borrowed_account_get_lamports( &buffer );
    1480           0 :       buffer_data_offset = BUFFER_METADATA_SIZE;
    1481           0 :       buffer_data_len    = fd_ulong_sat_sub( fd_borrowed_account_get_data_len( &buffer ), buffer_data_offset );
    1482           0 :       if( FD_UNLIKELY( fd_borrowed_account_get_data_len( &buffer )<BUFFER_METADATA_SIZE || buffer_data_len==0UL ) ) {
    1483           0 :         fd_log_collector_msg_literal( instr_ctx, "Buffer account too small" );
    1484           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1485           0 :       }
    1486             : 
    1487             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L774 */
    1488           0 :       fd_borrowed_account_drop( &buffer );
    1489             : 
    1490             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L775-L823 */
    1491             :       /* Verify ProgramData account */
    1492             : 
    1493           0 :       ulong                               programdata_data_offset      = PROGRAMDATA_METADATA_SIZE;
    1494           0 :       fd_bpf_upgradeable_loader_state_t * programdata_state            = NULL;
    1495           0 :       ulong                               programdata_balance_required = 0UL;
    1496             : 
    1497             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L778-L779 */
    1498           0 :       fd_guarded_borrowed_account_t programdata = {0};
    1499           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &programdata );
    1500             : 
    1501           0 :       fd_rent_t const * rent = fd_bank_rent_query( instr_ctx->txn_ctx->bank );
    1502             : 
    1503           0 :       programdata_balance_required = fd_ulong_max( 1UL, fd_rent_exempt_minimum_balance( rent, fd_borrowed_account_get_data_len( &programdata ) ) );
    1504             : 
    1505           0 :       if( FD_UNLIKELY( fd_borrowed_account_get_data_len( &programdata )<fd_ulong_sat_add( PROGRAMDATA_METADATA_SIZE, buffer_data_len ) ) ) {
    1506           0 :         fd_log_collector_msg_literal( instr_ctx, "ProgramData account not large enough" );
    1507           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1508           0 :       }
    1509           0 :       if( FD_UNLIKELY( fd_ulong_sat_add( fd_borrowed_account_get_lamports( &programdata ), buffer_lamports )<programdata_balance_required ) ) {
    1510           0 :         fd_log_collector_msg_literal( instr_ctx, "Buffer account balance too low to fund upgrade" );
    1511           0 :         return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    1512           0 :       }
    1513           0 :       programdata_state = fd_bpf_loader_program_get_state( programdata.acct, spad, &err );
    1514           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1515           0 :         return err;
    1516           0 :       }
    1517             : 
    1518           0 :       fd_sol_sysvar_clock_t clock_;
    1519           0 :       fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( instr_ctx->sysvar_cache, &clock_ );
    1520           0 :       if( FD_UNLIKELY( !clock ) ) {
    1521           0 :         return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR;
    1522           0 :       }
    1523             : 
    1524           0 :       if( fd_bpf_upgradeable_loader_state_is_program_data( programdata_state ) ) {
    1525           0 :         if( FD_UNLIKELY( clock->slot==programdata_state->inner.program_data.slot ) ) {
    1526           0 :           fd_log_collector_msg_literal( instr_ctx, "Program was deployed in this block already" );
    1527           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1528           0 :         }
    1529           0 :         if( FD_UNLIKELY( !programdata_state->inner.program_data.has_upgrade_authority_address ) ) {
    1530           0 :           fd_log_collector_msg_literal( instr_ctx, "Prrogram not upgradeable" );
    1531           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1532           0 :         }
    1533           0 :         if( FD_UNLIKELY( !fd_pubkey_eq( &programdata_state->inner.program_data.upgrade_authority_address, authority_key ) ) ) {
    1534           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect upgrade authority provided" );
    1535           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1536           0 :         }
    1537           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 6UL, &err ) ) ) {
    1538             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1539           0 :           if( FD_UNLIKELY( !!err ) ) return err;
    1540           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
    1541           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1542           0 :         }
    1543           0 :       } else {
    1544           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid ProgramData account" );
    1545           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1546           0 :       }
    1547             : 
    1548             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L824 */
    1549           0 :       fd_borrowed_account_drop( &programdata );
    1550             : 
    1551             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L825-L845 */
    1552             :       /* Load and verify the program bits */
    1553             : 
    1554             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L827-L828 */
    1555           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 2UL, &buffer );
    1556             : 
    1557           0 :       if( FD_UNLIKELY( buffer_data_offset>fd_borrowed_account_get_data_len( &buffer ) ) ) {
    1558           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1559           0 :       }
    1560             : 
    1561           0 :       const uchar * buffer_data = fd_borrowed_account_get_data( &buffer ) + buffer_data_offset;
    1562           0 :       err = fd_deploy_program( instr_ctx, program.acct->pubkey, buffer_data, buffer_data_len, instr_ctx->txn_ctx->spad );
    1563           0 :       if( FD_UNLIKELY( err ) ) {
    1564           0 :         return err;
    1565           0 :       }
    1566             : 
    1567             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L836 */
    1568           0 :       fd_borrowed_account_drop( &buffer );
    1569             : 
    1570             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L849-L850 */
    1571           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &programdata );
    1572             : 
    1573             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L846-L874 */
    1574             :       /* Update the ProgramData account, record the upgraded data, and zero the rest in a local scope */
    1575           0 :       do {
    1576           0 :         programdata_state->discriminant                                     = fd_bpf_upgradeable_loader_state_enum_program_data;
    1577           0 :         programdata_state->inner.program_data.slot                          = clock->slot;
    1578           0 :         programdata_state->inner.program_data.has_upgrade_authority_address = 1;
    1579           0 :         programdata_state->inner.program_data.upgrade_authority_address     = *authority_key;
    1580           0 :         err = fd_bpf_loader_v3_program_set_state( &programdata, programdata_state );
    1581           0 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1582           0 :           return err;
    1583           0 :         }
    1584             : 
    1585             :         /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L846-L875 */
    1586             :         /* We want to copy over the data and zero out the rest */
    1587           0 :         if( FD_UNLIKELY( programdata_data_offset+buffer_data_len>fd_borrowed_account_get_data_len( &programdata ) ) ) {
    1588           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1589           0 :         }
    1590             : 
    1591           0 :         uchar * programdata_data = NULL;
    1592           0 :         ulong   programdata_dlen = 0UL;
    1593           0 :         err = fd_borrowed_account_get_data_mut( &programdata, &programdata_data, &programdata_dlen );
    1594           0 :         if( FD_UNLIKELY( err ) ) {
    1595           0 :           return err;
    1596           0 :         }
    1597           0 :         uchar * dst_slice     = programdata_data + programdata_data_offset;
    1598           0 :         ulong   dst_slice_len = buffer_data_len;
    1599             : 
    1600             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L863-L864 */
    1601           0 :         fd_guarded_borrowed_account_t buffer = {0};
    1602           0 :         FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 2UL, &buffer );
    1603             : 
    1604           0 :         if( FD_UNLIKELY( buffer_data_offset>fd_borrowed_account_get_data_len( &buffer ) ) ){
    1605           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1606           0 :         }
    1607             : 
    1608           0 :         const uchar * src_slice = fd_borrowed_account_get_data( &buffer ) + buffer_data_offset;
    1609           0 :         fd_memcpy( dst_slice, src_slice, dst_slice_len );
    1610           0 :         fd_memset( dst_slice + dst_slice_len, 0, fd_borrowed_account_get_data_len( &programdata ) - programdata_data_offset - dst_slice_len );
    1611             : 
    1612             :         /* implicit drop of buffer */
    1613           0 :       } while (0);
    1614             : 
    1615             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L876-L891 */
    1616             :       /* Fund ProgramData to rent-exemption, spill the rest */
    1617             : 
    1618             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L878-L879 */
    1619           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 2UL, &buffer );
    1620             : 
    1621             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L880-L881 */
    1622           0 :       fd_guarded_borrowed_account_t spill = {0};
    1623           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 3UL, &spill );
    1624             : 
    1625           0 :       ulong spill_addend = fd_ulong_sat_sub( fd_ulong_sat_add( fd_borrowed_account_get_lamports( &programdata ), buffer_lamports ),
    1626           0 :                                             programdata_balance_required );
    1627           0 :       err = fd_borrowed_account_checked_add_lamports( &spill, spill_addend );
    1628           0 :       if( FD_UNLIKELY( err ) ) {
    1629           0 :         return err;
    1630           0 :       }
    1631           0 :       err = fd_borrowed_account_set_lamports( &buffer, 0UL );
    1632           0 :       if( FD_UNLIKELY( err ) ) {
    1633           0 :         return err;
    1634           0 :       }
    1635           0 :       err = fd_borrowed_account_set_lamports( &programdata, programdata_balance_required );
    1636           0 :       if( FD_UNLIKELY( err ) ) {
    1637           0 :         return err;
    1638           0 :       }
    1639             : 
    1640             :       /* Buffer account set_data_length */
    1641           0 :       err = fd_borrowed_account_set_data_length( &buffer, BUFFER_METADATA_SIZE );
    1642           0 :       if( FD_UNLIKELY( err ) ) {
    1643           0 :         return err;
    1644           0 :       }
    1645             : 
    1646             :       /* buffer is dropped when it goes out of scope */
    1647             :       /* spill is dropped when it goes out of scope */
    1648             :       /* programdata is dropped when it goes out of scope */
    1649             : 
    1650             :       /* Max msg_sz: 19 - 2 + 45 = 62 < 127 => we can use printf */
    1651             :       //TODO: this is likely the incorrect program_id, do we have new_program_id?
    1652           0 :       fd_log_collector_printf_dangerous_max_127( instr_ctx, "Upgraded program %s", FD_BASE58_ENC_32_ALLOCA( program_id ) );
    1653             : 
    1654           0 :       break;
    1655           0 :     }
    1656             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L893-L957 */
    1657           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_set_authority: {
    1658           0 :       int err;
    1659           0 :       if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 2U ) ) ) {
    1660           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1661           0 :       }
    1662             : 
    1663             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L896-L897 */
    1664           0 :       fd_guarded_borrowed_account_t account = {0};
    1665           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &account );
    1666             : 
    1667             :       /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L898-L900 */
    1668           0 :       fd_pubkey_t const * present_authority_key = NULL;
    1669           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &present_authority_key );
    1670           0 :       if( FD_UNLIKELY( err ) ) {
    1671           0 :         return err;
    1672           0 :       }
    1673             : 
    1674             :       /* Don't check the error here because the new_authority key is allowed to be NULL until further checks.
    1675             :          https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L901-L906 */
    1676           0 :       fd_pubkey_t const * new_authority = NULL;
    1677           0 :       fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 2UL, &new_authority );
    1678             : 
    1679           0 :       fd_bpf_upgradeable_loader_state_t * account_state = fd_bpf_loader_program_get_state( account.acct,
    1680           0 :                                                                                            spad,
    1681           0 :                                                                                            &err );
    1682           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1683           0 :         return err;
    1684           0 :       }
    1685             : 
    1686           0 :       if( fd_bpf_upgradeable_loader_state_is_buffer( account_state ) ) {
    1687           0 :         if( FD_UNLIKELY( !new_authority ) ) {
    1688           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer authority is not optional" );
    1689           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1690           0 :         }
    1691           0 :         if( FD_UNLIKELY( !account_state->inner.buffer.has_authority_address ) ) {
    1692           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer is immutable" );
    1693           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1694           0 :         }
    1695           0 :         if( FD_UNLIKELY( !fd_pubkey_eq( &account_state->inner.buffer.authority_address, present_authority_key ) ) ) {
    1696           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect buffer authority provided" );
    1697           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1698           0 :         }
    1699           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL, &err ) ) ) {
    1700             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1701           0 :           if( FD_UNLIKELY( !!err ) ) return err;
    1702           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer authority did not sign" );
    1703           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1704           0 :         }
    1705             : 
    1706             :         /* copy in the authority public key into the authority address.
    1707             :            https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L926-L928 */
    1708           0 :         account_state->inner.buffer.has_authority_address = !!new_authority;
    1709           0 :         if( new_authority ) {
    1710           0 :           account_state->inner.buffer.authority_address = *new_authority;
    1711           0 :         }
    1712             : 
    1713           0 :         err = fd_bpf_loader_v3_program_set_state( &account, account_state );
    1714           0 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1715           0 :           return err;
    1716           0 :         }
    1717           0 :       } else if( fd_bpf_upgradeable_loader_state_is_program_data( account_state ) ) {
    1718           0 :         if( FD_UNLIKELY( !account_state->inner.program_data.has_upgrade_authority_address ) ) {
    1719           0 :           fd_log_collector_msg_literal( instr_ctx, "Program not upgradeable" );
    1720           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1721           0 :         }
    1722           0 :         if( FD_UNLIKELY( !fd_pubkey_eq( &account_state->inner.program_data.upgrade_authority_address, present_authority_key ) ) ) {
    1723           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect upgrade authority provided" );
    1724           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1725           0 :         }
    1726           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL, &err ) ) ) {
    1727             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1728           0 :           if( FD_UNLIKELY( !!err ) ) return err;
    1729           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
    1730           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1731           0 :         }
    1732             : 
    1733             :         /* copy in the authority public key into the upgrade authority address.
    1734             :            https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L946-L949 */
    1735           0 :         account_state->inner.program_data.has_upgrade_authority_address = !!new_authority;
    1736           0 :         if( new_authority ) {
    1737           0 :           account_state->inner.program_data.upgrade_authority_address = *new_authority;
    1738           0 :         }
    1739             : 
    1740           0 :         err = fd_bpf_loader_v3_program_set_state( &account, account_state );
    1741           0 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1742           0 :           return err;
    1743           0 :         }
    1744           0 :       } else {
    1745           0 :         fd_log_collector_msg_literal( instr_ctx, "Account does not support authorities" );
    1746           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1747           0 :       }
    1748             : 
    1749             :       /* Max msg_sz: 16 - 2 + 45 = 59 < 127 => we can use printf */
    1750           0 :       if( new_authority ) {
    1751           0 :         fd_log_collector_printf_dangerous_max_127( instr_ctx, "New authority Some(%s)", FD_BASE58_ENC_32_ALLOCA( new_authority ) );
    1752           0 :       } else {
    1753           0 :         fd_log_collector_printf_dangerous_max_127( instr_ctx, "New authority None" );
    1754           0 :       }
    1755             : 
    1756             :       /* implicit drop of account */
    1757             : 
    1758           0 :       break;
    1759           0 :     }
    1760             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L958-L1030 */
    1761           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_set_authority_checked: {
    1762           0 :       int err;
    1763           0 :       if( !FD_FEATURE_ACTIVE_BANK( instr_ctx->txn_ctx->bank, enable_bpf_loader_set_authority_checked_ix ) ) {
    1764           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    1765           0 :       }
    1766             : 
    1767           0 :       if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 3U ) ) ) {
    1768           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1769           0 :       }
    1770             : 
    1771             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L968-L969 */
    1772           0 :       fd_guarded_borrowed_account_t account = {0};
    1773           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &account );
    1774             : 
    1775             :       /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L970-L975 */
    1776           0 :       fd_pubkey_t const * present_authority_key = NULL;
    1777           0 :       fd_pubkey_t const * new_authority_key     = NULL;
    1778             : 
    1779           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &present_authority_key );
    1780           0 :       if( FD_UNLIKELY( err ) ) return err;
    1781             : 
    1782           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 2UL, &new_authority_key );
    1783           0 :       if( FD_UNLIKELY( err ) ) return err;
    1784             : 
    1785           0 :       fd_bpf_upgradeable_loader_state_t * account_state = fd_bpf_loader_program_get_state( account.acct, spad, &err );
    1786           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1787           0 :         return err;
    1788           0 :       }
    1789             : 
    1790           0 :       if( fd_bpf_upgradeable_loader_state_is_buffer( account_state ) ) {
    1791           0 :         if( FD_UNLIKELY( !account_state->inner.buffer.has_authority_address ) ) {
    1792           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer is immutable" );
    1793           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1794           0 :         }
    1795           0 :         if( FD_UNLIKELY( !fd_pubkey_eq( &account_state->inner.buffer.authority_address, present_authority_key ) ) ) {
    1796           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect buffer authority provided" );
    1797           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1798           0 :         }
    1799           0 :         int instr_err_code = 0;
    1800           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL, &instr_err_code ) ) ) {
    1801             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1802           0 :           if( FD_UNLIKELY( !!instr_err_code ) ) return instr_err_code;
    1803           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer authority did not sign" );
    1804           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1805           0 :         }
    1806           0 :         instr_err_code = 0;
    1807           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 2UL, &instr_err_code ) ) ) {
    1808             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1809           0 :           if( FD_UNLIKELY( !!instr_err_code ) ) return instr_err_code;
    1810           0 :           fd_log_collector_msg_literal( instr_ctx, "New authority did not sign" );
    1811           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1812           0 :         }
    1813           0 :         account_state->inner.buffer.has_authority_address = 1;
    1814           0 :         account_state->inner.buffer.authority_address     = *new_authority_key;
    1815           0 :         err = fd_bpf_loader_v3_program_set_state( &account, account_state );
    1816           0 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1817           0 :           return err;
    1818           0 :         }
    1819           0 :       } else if( fd_bpf_upgradeable_loader_state_is_program_data( account_state ) ) {
    1820           0 :         if( FD_UNLIKELY( !account_state->inner.program_data.has_upgrade_authority_address ) ) {
    1821           0 :           fd_log_collector_msg_literal( instr_ctx, "Program not upgradeable" );
    1822           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1823           0 :         }
    1824           0 :         if( FD_UNLIKELY( !fd_pubkey_eq( &account_state->inner.program_data.upgrade_authority_address, present_authority_key ) ) ) {
    1825           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect upgrade authority provided" );
    1826           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1827           0 :         }
    1828           0 :         int instr_err_code = 0;
    1829           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL, &instr_err_code ) ) ) {
    1830             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1831           0 :           if( FD_UNLIKELY( !!instr_err_code ) ) return instr_err_code;
    1832           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
    1833           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1834           0 :         }
    1835           0 :         instr_err_code = 0;
    1836           0 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 2UL, &instr_err_code ) ) ) {
    1837             :           /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1838           0 :           if( FD_UNLIKELY( !!instr_err_code ) ) return instr_err_code;
    1839           0 :           fd_log_collector_msg_literal( instr_ctx, "New authority did not sign" );
    1840           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1841           0 :         }
    1842           0 :         account_state->inner.program_data.has_upgrade_authority_address = 1;
    1843           0 :         account_state->inner.program_data.upgrade_authority_address     = *new_authority_key;
    1844           0 :         err = fd_bpf_loader_v3_program_set_state( &account, account_state );
    1845           0 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1846           0 :           return err;
    1847           0 :         }
    1848           0 :       } else {
    1849           0 :         fd_log_collector_msg_literal( instr_ctx, "Account does not support authorities" );
    1850           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1851           0 :       }
    1852             : 
    1853             :       /* Max msg_sz: 16 - 2 + 45 = 59 < 127 => we can use printf */
    1854           0 :       fd_log_collector_printf_dangerous_max_127( instr_ctx, "New authority %s", FD_BASE58_ENC_32_ALLOCA( new_authority_key ) );
    1855             : 
    1856             :       /* implicit drop of account */
    1857             : 
    1858           0 :       break;
    1859           0 :     }
    1860             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1031-L1134 */
    1861           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_close: {
    1862           0 :       int err;
    1863             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1032-L1046 */
    1864           0 :       if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 2U ) ) ) {
    1865           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1866           0 :       }
    1867             : 
    1868             :       /* It's safe to directly access the instruction accounts because we already checked for two
    1869             :          instruction accounts previously.
    1870             :          https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L1034-L1035 */
    1871           0 :       if( FD_UNLIKELY( instr_ctx->instr->accounts[ 0UL ].index_in_transaction ==
    1872           0 :                        instr_ctx->instr->accounts[ 1UL ].index_in_transaction ) ) {
    1873           0 :         fd_log_collector_msg_literal( instr_ctx, "Recipient is the same as the account being closed" );
    1874           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1875           0 :       }
    1876             : 
    1877             :       /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L1043-L1044 */
    1878           0 :       fd_guarded_borrowed_account_t close_account = {0};
    1879           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &close_account );
    1880             : 
    1881           0 :       fd_pubkey_t * close_key = close_account.acct->pubkey;
    1882           0 :       fd_bpf_upgradeable_loader_state_t * close_account_state = fd_bpf_loader_program_get_state( close_account.acct, spad, &err );
    1883           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1884           0 :         return err;
    1885           0 :       }
    1886             :       /* Close account set data length */
    1887           0 :       err = fd_borrowed_account_set_data_length( &close_account, SIZE_OF_UNINITIALIZED );
    1888           0 :       if( FD_UNLIKELY( err ) ) {
    1889           0 :         return err;
    1890           0 :       }
    1891             : 
    1892             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1049-L1056 */
    1893           0 :       if( fd_bpf_upgradeable_loader_state_is_uninitialized( close_account_state ) ) {
    1894             : 
    1895             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L1050-L1051 */
    1896           0 :         fd_guarded_borrowed_account_t recipient_account = {0};
    1897           0 :         FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 1UL, &recipient_account );
    1898             : 
    1899           0 :         err = fd_borrowed_account_checked_add_lamports( &recipient_account, fd_borrowed_account_get_lamports( &close_account ) );
    1900           0 :         if( FD_UNLIKELY( err ) ) {
    1901           0 :           return err;
    1902           0 :         }
    1903           0 :         err = fd_borrowed_account_set_lamports( &close_account, 0UL );
    1904           0 :         if( FD_UNLIKELY( err ) ) {
    1905           0 :           return err;
    1906           0 :         }
    1907             :         /* Max msg_sz: 23 - 2 + 45 = 66 < 127 => we can use printf */
    1908           0 :         fd_log_collector_printf_dangerous_max_127( instr_ctx,
    1909           0 :           "Closed Uninitialized %s", FD_BASE58_ENC_32_ALLOCA( close_key ) );
    1910             : 
    1911             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1057-L1068 */
    1912           0 :       } else if( fd_bpf_upgradeable_loader_state_is_buffer( close_account_state ) ) {
    1913             : 
    1914             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L1059 */
    1915           0 :         fd_borrowed_account_drop( &close_account );
    1916             : 
    1917           0 :         if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 3U ) ) ) {
    1918           0 :           return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1919           0 :         }
    1920             : 
    1921           0 :         fd_bpf_upgradeable_loader_state_buffer_t * state_buf = &close_account_state->inner.buffer;
    1922           0 :         err = common_close_account(
    1923           0 :             state_buf->has_authority_address ? &state_buf->authority_address : NULL,
    1924           0 :             instr_ctx,
    1925           0 :             close_account_state );
    1926           0 :         if( FD_UNLIKELY( err ) ) return err;
    1927             : 
    1928             :         /* Max msg_sz: 16 - 2 + 45 = 63 < 127 => we can use printf */
    1929           0 :         fd_log_collector_printf_dangerous_max_127( instr_ctx,
    1930           0 :           "Closed Buffer %s", FD_BASE58_ENC_32_ALLOCA( close_key ) );
    1931             : 
    1932             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1069-L1129 */
    1933           0 :       } else if( fd_bpf_upgradeable_loader_state_is_program_data( close_account_state ) ) {
    1934           0 :         int err;
    1935           0 :         if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 4U ) ) ) {
    1936           0 :           return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1937           0 :         }
    1938             : 
    1939             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L1074 */
    1940           0 :         fd_borrowed_account_drop( &close_account );
    1941             : 
    1942             :         /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L1075-L1076 */
    1943           0 :         fd_guarded_borrowed_account_t program_account = {0};
    1944           0 :         FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK(instr_ctx, 3UL, &program_account );
    1945             : 
    1946           0 :         if( FD_UNLIKELY( !fd_borrowed_account_is_writable( &program_account ) ) ) {
    1947           0 :           fd_log_collector_msg_literal( instr_ctx, "Program account is not writable" );
    1948           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1949           0 :         }
    1950           0 :         if( FD_UNLIKELY( memcmp( fd_borrowed_account_get_owner( &program_account ), program_id, sizeof(fd_pubkey_t) ) ) ) {
    1951           0 :           fd_log_collector_msg_literal( instr_ctx, "Program account not owned by loader" );
    1952           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
    1953           0 :         }
    1954           0 :         fd_sol_sysvar_clock_t clock_;
    1955           0 :         fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( instr_ctx->sysvar_cache, &clock_ );
    1956           0 :         if( FD_UNLIKELY( !clock ) ) {
    1957           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    1958           0 :         }
    1959           0 :         if( FD_UNLIKELY( clock->slot==close_account_state->inner.program_data.slot ) ) {
    1960           0 :           fd_log_collector_msg_literal( instr_ctx,"Program was deployed in this block already" );
    1961           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1962           0 :         }
    1963             : 
    1964           0 :         fd_bpf_upgradeable_loader_state_t * program_state = fd_bpf_loader_program_get_state( program_account.acct, spad, &err );
    1965           0 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1966           0 :           return err;
    1967           0 :         }
    1968           0 :         if( fd_bpf_upgradeable_loader_state_is_program( program_state ) ) {
    1969           0 :           if( FD_UNLIKELY( memcmp( &program_state->inner.program.programdata_address, close_key, sizeof(fd_pubkey_t) ) ) ) {
    1970           0 :             fd_log_collector_msg_literal( instr_ctx,"Program account does not match ProgramData account" );
    1971           0 :             return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1972           0 :           }
    1973             : 
    1974             :           /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L1105 */
    1975           0 :           fd_borrowed_account_drop( &program_account );
    1976             : 
    1977           0 :           fd_bpf_upgradeable_loader_state_program_data_t * pd = &close_account_state->inner.program_data;
    1978           0 :           err = common_close_account(
    1979           0 :               pd->has_upgrade_authority_address ? &pd->upgrade_authority_address : NULL,
    1980           0 :               instr_ctx,
    1981           0 :               close_account_state );
    1982           0 :           if( FD_UNLIKELY( err ) ) return err;
    1983             : 
    1984             :           /* The Agave client updates the account state upon closing an account
    1985             :              in their loaded program cache. Checking for a program can be
    1986             :              checked by checking to see if the programdata account's loader state
    1987             :              is unitialized. The firedancer implementation also removes closed
    1988             :              accounts from the loaded program cache at the end of a slot. Closed
    1989             :              accounts are not checked from the cache, instead the account state
    1990             :              is looked up. */
    1991             : 
    1992           0 :         } else {
    1993           0 :           fd_log_collector_msg_literal( instr_ctx, "Invalid program account" );
    1994           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1995           0 :         }
    1996             : 
    1997             :         /* Max msg_sz: 17 - 2 + 45 = 60 < 127 => we can use printf */
    1998           0 :         fd_log_collector_printf_dangerous_max_127( instr_ctx,
    1999           0 :           "Closed Program %s", FD_BASE58_ENC_32_ALLOCA( close_key ) );
    2000             : 
    2001             :         /* program account is dropped when it goes out of scope */
    2002           0 :       } else {
    2003           0 :         fd_log_collector_msg_literal( instr_ctx, "Account does not support closing" );
    2004           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    2005           0 :       }
    2006             : 
    2007             :       /* implicit drop of close account */
    2008           0 :       break;
    2009           0 :     }
    2010             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1158-L1170 */
    2011           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_extend_program: {
    2012           0 :       if( FD_UNLIKELY( FD_FEATURE_ACTIVE_BANK( instr_ctx->txn_ctx->bank, enable_extend_program_checked ) ) ) {
    2013           0 :         fd_log_collector_msg_literal( instr_ctx, "ExtendProgram was superseded by ExtendProgramChecked" );
    2014           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2015           0 :       }
    2016           0 :       err = common_extend_program( instr_ctx, instruction->inner.extend_program.additional_bytes, 0 );
    2017           0 :       if( FD_UNLIKELY( err ) ) {
    2018           0 :         return err;
    2019           0 :       }
    2020             : 
    2021           0 :       break;
    2022           0 :     }
    2023             :     /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1171-L1179 */
    2024           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_extend_program_checked: {
    2025           0 :       if( FD_UNLIKELY( !FD_FEATURE_ACTIVE_BANK( instr_ctx->txn_ctx->bank, enable_extend_program_checked ) ) ) {
    2026           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2027           0 :       }
    2028           0 :       err = common_extend_program( instr_ctx, instruction->inner.extend_program_checked.additional_bytes, 1 );
    2029           0 :       if( FD_UNLIKELY( err ) ) {
    2030           0 :         return err;
    2031           0 :       }
    2032             : 
    2033           0 :       break;
    2034           0 :     }
    2035             :     /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1338-L1508 */
    2036           0 :     case fd_bpf_upgradeable_loader_program_instruction_enum_migrate: {
    2037             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1339-L1344 */
    2038           0 :       if( FD_UNLIKELY( !FD_FEATURE_ACTIVE_BANK( instr_ctx->txn_ctx->bank, enable_loader_v4 ) ) ) {
    2039           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2040           0 :       }
    2041             : 
    2042             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1346 */
    2043           0 :       if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( instr_ctx, 3U ) ) ) {
    2044           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    2045           0 :       }
    2046             : 
    2047             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1347-L1349 */
    2048           0 :       fd_pubkey_t const * programdata_address = NULL;
    2049           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 0UL, &programdata_address );
    2050           0 :       if( FD_UNLIKELY( err ) ) {
    2051           0 :         return err;
    2052           0 :       }
    2053             : 
    2054             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1350-L1352 */
    2055           0 :       fd_pubkey_t const * program_address = NULL;
    2056           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 1UL, &program_address );
    2057           0 :       if( FD_UNLIKELY( err ) ) {
    2058           0 :         return err;
    2059           0 :       }
    2060             : 
    2061             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1353-L1355 */
    2062           0 :       fd_pubkey_t const * provided_authority_address = NULL;
    2063           0 :       err = fd_exec_instr_ctx_get_key_of_account_at_index( instr_ctx, 2UL, &provided_authority_address );
    2064           0 :       if( FD_UNLIKELY( err ) ) {
    2065           0 :         return err;
    2066           0 :       }
    2067             : 
    2068             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1356-L1359 */
    2069           0 :       fd_sol_sysvar_clock_t clock_;
    2070           0 :       fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( instr_ctx->sysvar_cache, &clock_ );
    2071           0 :       if( FD_UNLIKELY( !clock ) ) {
    2072           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2073           0 :       }
    2074           0 :       ulong clock_slot = clock->slot;
    2075             : 
    2076             :       /* Verify ProgramData account
    2077             :          https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1362-L1363 */
    2078           0 :       fd_guarded_borrowed_account_t programdata = {0};
    2079           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 0UL, &programdata );
    2080             : 
    2081             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1364-L1367 */
    2082           0 :       if( FD_UNLIKELY( !fd_borrowed_account_is_writable( &programdata ) ) ) {
    2083           0 :         fd_log_collector_msg_literal( instr_ctx, "ProgramData account not writeable" );
    2084           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    2085           0 :       }
    2086             : 
    2087             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1368-L1387 */
    2088           0 :       ulong         program_len               = 0UL;
    2089           0 :       fd_pubkey_t * upgrade_authority_address = NULL;
    2090           0 :       fd_bpf_upgradeable_loader_state_t * programdata_state = fd_bpf_loader_program_get_state( programdata.acct, spad, &err );
    2091           0 :       if( FD_LIKELY( err==FD_BINCODE_SUCCESS && fd_bpf_upgradeable_loader_state_is_program_data( programdata_state ) ) ) {
    2092             : 
    2093             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1374-L1377 */
    2094           0 :         if( FD_UNLIKELY( clock_slot==programdata_state->inner.program_data.slot ) ) {
    2095           0 :           fd_log_collector_msg_literal( instr_ctx, "Program was deployed in this block already" );
    2096           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    2097           0 :         }
    2098             : 
    2099             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1378-L1384 */
    2100           0 :         program_len = fd_ulong_sat_sub( fd_borrowed_account_get_data_len( &programdata ), PROGRAMDATA_METADATA_SIZE );
    2101           0 :         fd_bpf_upgradeable_loader_state_program_data_t * pd = &programdata_state->inner.program_data;
    2102           0 :         upgrade_authority_address = pd->has_upgrade_authority_address ? &programdata_state->inner.program_data.upgrade_authority_address : NULL;
    2103           0 :       }
    2104             : 
    2105             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1388 */
    2106           0 :       ulong programdata_funds = fd_borrowed_account_get_lamports( &programdata );
    2107             : 
    2108             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1389 */
    2109           0 :       fd_borrowed_account_drop( &programdata );
    2110             : 
    2111             :       /* Verify authority signature
    2112             :          https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1391-L1398 */
    2113           0 :       fd_pubkey_t const * authority_key_to_compare = upgrade_authority_address ? upgrade_authority_address : program_address;
    2114           0 :       if( FD_UNLIKELY( memcmp( fd_solana_migration_authority.key, provided_authority_address->key, sizeof(fd_pubkey_t) ) &&
    2115           0 :                        memcmp( authority_key_to_compare->key, provided_authority_address->key, sizeof(fd_pubkey_t) ) ) ) {
    2116           0 :         fd_log_collector_msg_literal( instr_ctx, "Incorrect migration authority provided" );
    2117           0 :         return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    2118           0 :       }
    2119             : 
    2120             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1399-L1402 */
    2121           0 :       if( FD_UNLIKELY( !instr_ctx->instr->accounts[ 2UL ].is_signer ) ) {
    2122           0 :         fd_log_collector_msg_literal( instr_ctx, "Migration authority did not sign" );
    2123           0 :         return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    2124           0 :       }
    2125             : 
    2126             :       /* Verify Program account
    2127             :          https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1404-L1406 */
    2128           0 :       fd_guarded_borrowed_account_t program = {0};
    2129           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( instr_ctx, 1UL, &program );
    2130             : 
    2131             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1407-L1410 */
    2132           0 :       if( FD_UNLIKELY( !fd_borrowed_account_is_writable( &program ) ) ) {
    2133           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not writeable" );
    2134           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    2135           0 :       }
    2136             : 
    2137             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1411-L1414 */
    2138           0 :       if( FD_UNLIKELY( memcmp( fd_borrowed_account_get_owner( &program ), program_id, sizeof(fd_pubkey_t) ) ) ) {
    2139           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not owned by loader" );
    2140           0 :         return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
    2141           0 :       }
    2142             : 
    2143             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1415-L1426 */
    2144           0 :       fd_bpf_upgradeable_loader_state_t * program_state = fd_bpf_loader_program_get_state( program.acct, spad, &err );
    2145           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    2146           0 :         return err;
    2147           0 :       }
    2148             : 
    2149           0 :       if( FD_LIKELY( fd_bpf_upgradeable_loader_state_is_program( program_state ) ) ) {
    2150           0 :         if( FD_UNLIKELY( memcmp( programdata_address->key, program_state->inner.program.programdata_address.key, sizeof(fd_pubkey_t) ) ) ) {
    2151           0 :           fd_log_collector_msg_literal( instr_ctx, "Program and ProgramData account mismatch" );
    2152           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    2153           0 :         }
    2154           0 :       } else {
    2155           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid Program account" );
    2156           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2157           0 :       }
    2158             : 
    2159             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1427 */
    2160           0 :       err = fd_borrowed_account_set_data_from_slice( &program, NULL, 0UL );
    2161           0 :       if( FD_UNLIKELY( err ) ) {
    2162           0 :         return err;
    2163           0 :       }
    2164             : 
    2165             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1428 */
    2166           0 :       err = fd_borrowed_account_checked_add_lamports( &program , programdata_funds );
    2167           0 :       if( FD_UNLIKELY( err ) ) {
    2168           0 :         return err;
    2169           0 :       }
    2170             : 
    2171             :       /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1268 */
    2172           0 :       err = fd_borrowed_account_set_owner( &program, &fd_solana_bpf_loader_v4_program_id );
    2173           0 :       if( FD_UNLIKELY( err ) ) {
    2174           0 :         return err;
    2175           0 :       }
    2176             : 
    2177             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1434 */
    2178           0 :       fd_borrowed_account_drop( &program );
    2179             : 
    2180             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1436-L1437 */
    2181           0 :       err = fd_exec_instr_ctx_try_borrow_instr_account( instr_ctx , 0U, &programdata );
    2182           0 :       if( FD_UNLIKELY( err ) ) {
    2183           0 :         return err;
    2184           0 :       }
    2185             : 
    2186             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1438 */
    2187           0 :       err = fd_borrowed_account_set_lamports( &programdata, 0UL );
    2188           0 :       if( FD_UNLIKELY( err ) ) {
    2189           0 :         return err;
    2190           0 :       }
    2191             : 
    2192             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1439 */
    2193           0 :       fd_borrowed_account_drop( &programdata );
    2194             : 
    2195           0 :       FD_SPAD_FRAME_BEGIN( instr_ctx->txn_ctx->spad ) {
    2196           0 :         uchar                              instr_data[FD_TXN_MTU];
    2197           0 :         fd_loader_v4_program_instruction_t instr      = {0};
    2198           0 :         fd_bincode_encode_ctx_t            encode_ctx = {0};
    2199           0 :         fd_vm_rust_account_meta_t *        acct_metas = fd_spad_alloc( instr_ctx->txn_ctx->spad,
    2200           0 :                                                                        FD_VM_RUST_ACCOUNT_META_ALIGN,
    2201           0 :                                                                        3UL * sizeof(fd_vm_rust_account_meta_t) );
    2202             : 
    2203             :         /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1441-L1484 */
    2204           0 :         if( FD_LIKELY( program_len>0UL ) ) {
    2205             : 
    2206             :           /* Set program length
    2207             :              https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1442-L1451 */
    2208           0 :           fd_native_cpi_create_account_meta( program_address,            0, 1, &acct_metas[0] );
    2209           0 :           fd_native_cpi_create_account_meta( provided_authority_address, 1, 0, &acct_metas[1] );
    2210           0 :           fd_native_cpi_create_account_meta( program_address,            0, 1, &acct_metas[2] );
    2211             : 
    2212           0 :           instr = (fd_loader_v4_program_instruction_t) {
    2213           0 :             .discriminant = fd_loader_v4_program_instruction_enum_set_program_length,
    2214           0 :             .inner = {
    2215           0 :               .set_program_length = {
    2216           0 :                 .new_size = (uint)program_len
    2217           0 :               }
    2218           0 :             }
    2219           0 :           };
    2220             : 
    2221           0 :           encode_ctx = (fd_bincode_encode_ctx_t) {
    2222           0 :             .data    = instr_data,
    2223           0 :             .dataend = instr_data + FD_TXN_MTU
    2224           0 :           };
    2225             : 
    2226             :           // This should never fail.
    2227           0 :           err = fd_loader_v4_program_instruction_encode( &instr, &encode_ctx );
    2228           0 :           if( FD_UNLIKELY( err ) ) {
    2229           0 :             return FD_EXECUTOR_INSTR_ERR_FATAL;
    2230           0 :           }
    2231             : 
    2232           0 :           err = fd_native_cpi_native_invoke( instr_ctx,
    2233           0 :                                              &fd_solana_bpf_loader_v4_program_id,
    2234           0 :                                              instr_data,
    2235           0 :                                              FD_TXN_MTU,
    2236           0 :                                              acct_metas,
    2237           0 :                                              3UL,
    2238           0 :                                              NULL,
    2239           0 :                                              0UL );
    2240           0 :           if( FD_UNLIKELY( err ) ) {
    2241           0 :             return err;
    2242           0 :           }
    2243             : 
    2244             :           /* Copy
    2245             :              https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1453-L1464 */
    2246           0 :           fd_native_cpi_create_account_meta( program_address,            0, 1, &acct_metas[0] );
    2247           0 :           fd_native_cpi_create_account_meta( provided_authority_address, 1, 0, &acct_metas[1] );
    2248           0 :           fd_native_cpi_create_account_meta( programdata_address,        0, 0, &acct_metas[2] );
    2249             : 
    2250           0 :           instr = (fd_loader_v4_program_instruction_t) {
    2251           0 :             .discriminant = fd_loader_v4_program_instruction_enum_copy,
    2252           0 :             .inner = {
    2253           0 :               .copy = {
    2254           0 :                 .destination_offset = 0U,
    2255           0 :                 .source_offset      = 0U,
    2256           0 :                 .length             = (uint)program_len
    2257           0 :               }
    2258           0 :             }
    2259           0 :           };
    2260             : 
    2261           0 :           encode_ctx = (fd_bincode_encode_ctx_t) {
    2262           0 :             .data    = instr_data,
    2263           0 :             .dataend = instr_data + FD_TXN_MTU
    2264           0 :           };
    2265             : 
    2266             :           // This should never fail.
    2267           0 :           err = fd_loader_v4_program_instruction_encode( &instr, &encode_ctx );
    2268           0 :           if( FD_UNLIKELY( err ) ) {
    2269           0 :             return FD_EXECUTOR_INSTR_ERR_FATAL;
    2270           0 :           }
    2271             : 
    2272           0 :           err = fd_native_cpi_native_invoke( instr_ctx,
    2273           0 :                                              &fd_solana_bpf_loader_v4_program_id,
    2274           0 :                                              instr_data,
    2275           0 :                                              FD_TXN_MTU,
    2276           0 :                                              acct_metas,
    2277           0 :                                              3UL,
    2278           0 :                                              NULL,
    2279           0 :                                              0UL );
    2280           0 :           if( FD_UNLIKELY( err ) ) {
    2281           0 :             return err;
    2282           0 :           }
    2283             : 
    2284             :           /* Deploy
    2285             :              https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1466-L1473 */
    2286           0 :           fd_native_cpi_create_account_meta( program_address,            0, 1, &acct_metas[0] );
    2287           0 :           fd_native_cpi_create_account_meta( provided_authority_address, 1, 0, &acct_metas[1] );
    2288             : 
    2289           0 :           instr = (fd_loader_v4_program_instruction_t) {
    2290           0 :             .discriminant = fd_loader_v4_program_instruction_enum_deploy,
    2291           0 :           };
    2292             : 
    2293           0 :           encode_ctx = (fd_bincode_encode_ctx_t) {
    2294           0 :             .data    = instr_data,
    2295           0 :             .dataend = instr_data + FD_TXN_MTU
    2296           0 :           };
    2297             : 
    2298             :           // This should never fail.
    2299           0 :           err = fd_loader_v4_program_instruction_encode( &instr, &encode_ctx );
    2300           0 :           if( FD_UNLIKELY( err ) ) {
    2301           0 :             return FD_EXECUTOR_INSTR_ERR_FATAL;
    2302           0 :           }
    2303             : 
    2304           0 :           err = fd_native_cpi_native_invoke( instr_ctx,
    2305           0 :                                             &fd_solana_bpf_loader_v4_program_id,
    2306           0 :                                             instr_data,
    2307           0 :                                             FD_TXN_MTU,
    2308           0 :                                             acct_metas,
    2309           0 :                                             2UL,
    2310           0 :                                             NULL,
    2311           0 :                                             0UL );
    2312           0 :           if( FD_UNLIKELY( err ) ) {
    2313           0 :             return err;
    2314           0 :           }
    2315             : 
    2316             :           /* Finalize (if no upgrade authority address provided)
    2317             :              https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1475-L1484 */
    2318           0 :           if( upgrade_authority_address==NULL ) {
    2319           0 :             fd_native_cpi_create_account_meta( program_address,            0, 1, &acct_metas[0] );
    2320           0 :             fd_native_cpi_create_account_meta( provided_authority_address, 1, 0, &acct_metas[1] );
    2321           0 :             fd_native_cpi_create_account_meta( program_address,            0, 0, &acct_metas[2] );
    2322             : 
    2323           0 :             instr = (fd_loader_v4_program_instruction_t) {
    2324           0 :               .discriminant = fd_loader_v4_program_instruction_enum_finalize,
    2325           0 :             };
    2326             : 
    2327           0 :             encode_ctx = (fd_bincode_encode_ctx_t) {
    2328           0 :               .data    = instr_data,
    2329           0 :               .dataend = instr_data + FD_TXN_MTU
    2330           0 :             };
    2331             : 
    2332             :             // This should never fail.
    2333           0 :             err = fd_loader_v4_program_instruction_encode( &instr, &encode_ctx );
    2334           0 :             if( FD_UNLIKELY( err ) ) {
    2335           0 :               return FD_EXECUTOR_INSTR_ERR_FATAL;
    2336           0 :             }
    2337             : 
    2338           0 :             err = fd_native_cpi_native_invoke( instr_ctx,
    2339           0 :                                               &fd_solana_bpf_loader_v4_program_id,
    2340           0 :                                               instr_data,
    2341           0 :                                               FD_TXN_MTU,
    2342           0 :                                               acct_metas,
    2343           0 :                                               3UL,
    2344           0 :                                               NULL,
    2345           0 :                                               0UL );
    2346           0 :             if( FD_UNLIKELY( err ) ) {
    2347           0 :               return err;
    2348           0 :             }
    2349           0 :           } else if( !memcmp( fd_solana_migration_authority.key, provided_authority_address->key, sizeof(fd_pubkey_t) ) ) {
    2350             : 
    2351             :             /* Transfer authority
    2352             :                https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1486-L1494 */
    2353           0 :             fd_native_cpi_create_account_meta( program_address,            0, 1, &acct_metas[0] );
    2354           0 :             fd_native_cpi_create_account_meta( provided_authority_address, 1, 0, &acct_metas[1] );
    2355           0 :             fd_native_cpi_create_account_meta( upgrade_authority_address,  1, 0, &acct_metas[2] );
    2356             : 
    2357           0 :             instr = (fd_loader_v4_program_instruction_t) {
    2358           0 :               .discriminant = fd_loader_v4_program_instruction_enum_transfer_authority,
    2359           0 :             };
    2360             : 
    2361           0 :             encode_ctx = (fd_bincode_encode_ctx_t) {
    2362           0 :               .data    = instr_data,
    2363           0 :               .dataend = instr_data + FD_TXN_MTU
    2364           0 :             };
    2365             : 
    2366             :             // This should never fail.
    2367           0 :             err = fd_loader_v4_program_instruction_encode( &instr, &encode_ctx );
    2368           0 :             if( FD_UNLIKELY( err ) ) {
    2369           0 :               return FD_EXECUTOR_INSTR_ERR_FATAL;
    2370           0 :             }
    2371             : 
    2372           0 :             err = fd_native_cpi_native_invoke( instr_ctx,
    2373           0 :                                               &fd_solana_bpf_loader_v4_program_id,
    2374           0 :                                               instr_data,
    2375           0 :                                               FD_TXN_MTU,
    2376           0 :                                               acct_metas,
    2377           0 :                                               3UL,
    2378           0 :                                               NULL,
    2379           0 :                                               0UL );
    2380           0 :             if( FD_UNLIKELY( err ) ) {
    2381           0 :               return err;
    2382           0 :             }
    2383           0 :           }
    2384           0 :         }
    2385           0 :       } FD_SPAD_FRAME_END;
    2386             : 
    2387             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1500-L1501 */
    2388           0 :       err = fd_exec_instr_ctx_try_borrow_instr_account( instr_ctx , 0U, &programdata );
    2389           0 :       if( FD_UNLIKELY( err ) ) {
    2390           0 :         return err;
    2391           0 :       }
    2392             : 
    2393             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1502 */
    2394           0 :       err = fd_borrowed_account_set_data_from_slice( &programdata, NULL, 0UL );
    2395           0 :       if( FD_UNLIKELY( err ) ) {
    2396           0 :         return err;
    2397           0 :       }
    2398             : 
    2399             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1504 */
    2400           0 :       fd_borrowed_account_drop( &programdata );
    2401             : 
    2402             :       /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1506 */
    2403           0 :       fd_log_collector_printf_dangerous_max_127( instr_ctx, "Migrated program %s", FD_BASE58_ENC_32_ALLOCA( program_address ) );
    2404             : 
    2405           0 :       break;
    2406           0 :     }
    2407           0 :     default: {
    2408           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2409           0 :     }
    2410           0 :   }
    2411           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
    2412           0 : }
    2413             : 
    2414             : /* process_instruction_inner() */
    2415             : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L394-L564 */
    2416             : int
    2417           0 : fd_bpf_loader_program_execute( fd_exec_instr_ctx_t * ctx ) {
    2418           0 :   FD_SPAD_FRAME_BEGIN( ctx->txn_ctx->spad ) {
    2419             :     /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L491-L529 */
    2420             : 
    2421             :     /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L403-L404 */
    2422           0 :     fd_guarded_borrowed_account_t program_account = {0};
    2423           0 :     int err = fd_exec_instr_ctx_try_borrow_last_program_account( ctx, &program_account );
    2424           0 :     if( FD_UNLIKELY( err ) ) {
    2425           0 :       return err;
    2426           0 :     }
    2427             : 
    2428             :     /* https://github.com/anza-xyz/agave/blob/v2.2.0/programs/bpf_loader/src/lib.rs#L409 */
    2429           0 :     fd_pubkey_t const * program_id = NULL;
    2430           0 :     err = fd_exec_instr_ctx_get_last_program_key( ctx, &program_id );
    2431           0 :     if( FD_UNLIKELY( err ) ) {
    2432           0 :       return err;
    2433           0 :     }
    2434             : 
    2435             :     /* Program management instruction */
    2436           0 :     if( FD_UNLIKELY( !memcmp( &fd_solana_native_loader_id, fd_borrowed_account_get_owner( &program_account ), sizeof(fd_pubkey_t) ) ) ) {
    2437             :       /* https://github.com/anza-xyz/agave/blob/v2.2.3/programs/bpf_loader/src/lib.rs#L416 */
    2438           0 :       fd_borrowed_account_drop( &program_account );
    2439             : 
    2440           0 :       if( FD_UNLIKELY( !memcmp( &fd_solana_bpf_loader_upgradeable_program_id, program_id, sizeof(fd_pubkey_t) ) ) ) {
    2441           0 :         FD_EXEC_CU_UPDATE( ctx, UPGRADEABLE_LOADER_COMPUTE_UNITS );
    2442           0 :         return process_loader_upgradeable_instruction( ctx );
    2443           0 :       } else if( FD_UNLIKELY( !memcmp( &fd_solana_bpf_loader_program_id, program_id, sizeof(fd_pubkey_t) ) ) ) {
    2444           0 :         FD_EXEC_CU_UPDATE( ctx, DEFAULT_LOADER_COMPUTE_UNITS );
    2445           0 :         fd_log_collector_msg_literal( ctx, "BPF loader management instructions are no longer supported" );
    2446           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2447           0 :       } else if( FD_UNLIKELY( !memcmp( &fd_solana_bpf_loader_deprecated_program_id, program_id, sizeof(fd_pubkey_t) ) ) ) {
    2448           0 :         FD_EXEC_CU_UPDATE( ctx, DEPRECATED_LOADER_COMPUTE_UNITS );
    2449           0 :         fd_log_collector_msg_literal( ctx, "Deprecated loader is no longer supported" );
    2450           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2451           0 :       } else {
    2452           0 :         fd_log_collector_msg_literal( ctx, "Invalid BPF loader id" );
    2453             :         /* https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L429-L436 */
    2454           0 :         if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2455           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2456           0 :         }
    2457           0 :         return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
    2458           0 :       }
    2459           0 :     }
    2460             : 
    2461             :     /* https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L445-L452 */
    2462             :     /* Program invocation. Any invalid programs will be caught here or at the program load. */
    2463           0 :     if( FD_UNLIKELY( !FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) &&
    2464           0 :                      !fd_borrowed_account_is_executable( &program_account ) ) ) {
    2465           0 :       fd_log_collector_msg_literal( ctx, "Program is not executable" );
    2466           0 :       return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
    2467           0 :     }
    2468             : 
    2469             :     /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L551-L563 */
    2470             :     /* The Agave client stores a loaded program type state in its implementation
    2471             :       of the loaded program cache. It checks to see if an account is able to be
    2472             :       executed. It is possible for a program to be in the DelayVisibility state or
    2473             :       Closed state but it won't be reflected in the Firedancer cache. Program
    2474             :       accounts that are in this state should exit with an invalid account data
    2475             :       error. For programs that are recently deployed or upgraded, they should not
    2476             :       be allowed to be executed for the remainder of the slot. For closed
    2477             :       accounts, they're uninitialized and shouldn't be executed as well.
    2478             : 
    2479             :       For the former case the slot that the
    2480             :       program was last updated in is in the program data account.
    2481             :       This means that if the slot in the program data account is greater than or
    2482             :       equal to the current execution slot, then the account is in a
    2483             :       'LoadedProgramType::DelayVisiblity' state.
    2484             : 
    2485             :       The latter case as described above is a tombstone account which is in a Closed
    2486             :       state. This occurs when a program data account is closed. However, our cache
    2487             :       does not track this. Instead, this can be checked for by seeing if the program
    2488             :       account's respective program data account is uninitialized. This should only
    2489             :       happen when the account is closed.
    2490             : 
    2491             :       Every error that comes out of this block is mapped to an InvalidAccountData instruction error in Agave. */
    2492             : 
    2493           0 :     fd_account_meta_t const * metadata = fd_borrowed_account_get_acc_meta( &program_account );
    2494           0 :     uchar is_deprecated = !memcmp( metadata->owner, &fd_solana_bpf_loader_deprecated_program_id, sizeof(fd_pubkey_t) );
    2495             : 
    2496           0 :     if( !memcmp( metadata->owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) {
    2497           0 :       fd_bpf_upgradeable_loader_state_t * program_account_state = fd_bpf_loader_program_get_state( program_account.acct, ctx->txn_ctx->spad, &err );
    2498           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    2499           0 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    2500           0 :         if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2501           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2502           0 :         }
    2503           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2504           0 :       }
    2505             : 
    2506             :       /* https://github.com/anza-xyz/agave/blob/v2.0.9/svm/src/program_loader.rs#L96-L98
    2507             :          Program account and program data account discriminants get checked when loading in program accounts
    2508             :          into the program cache. If the discriminants are incorrect, the program is marked as closed. */
    2509           0 :       if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_program( program_account_state ) ) ) {
    2510             :         /* https://github.com/anza-xyz/agave/tree/v3.0.5/programs/bpf_loader/src/lib.rs#L424-L433
    2511             :            Agave's program cache will add any non-migrating built-ins as built-in
    2512             :            accounts, even though they might be owned by the BPF loader. In these
    2513             :            cases, Agave does not log this message. Meanwhile, non-migrating
    2514             :            built-in programs do not use the BPF loader, by definition. */
    2515           0 :         if( !fd_is_non_migrating_builtin_program( program_id ) ) {
    2516           0 :           fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    2517           0 :         }
    2518           0 :         if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2519           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2520           0 :         }
    2521           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2522           0 :       }
    2523             : 
    2524           0 :       fd_txn_account_t * program_data_account = NULL;
    2525           0 :       fd_pubkey_t *      programdata_pubkey   = (fd_pubkey_t *)&program_account_state->inner.program.programdata_address;
    2526           0 :       err = fd_exec_txn_ctx_get_executable_account( ctx->txn_ctx,
    2527           0 :                                                     programdata_pubkey,
    2528           0 :                                                     &program_data_account,
    2529           0 :                                                     fd_txn_account_check_exists );
    2530           0 :       if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
    2531           0 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    2532           0 :         if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2533           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2534           0 :         }
    2535           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2536           0 :       }
    2537             : 
    2538           0 :       if( FD_UNLIKELY( fd_txn_account_get_data_len( program_data_account )<PROGRAMDATA_METADATA_SIZE ) ) {
    2539           0 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    2540           0 :         if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2541           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2542           0 :         }
    2543           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2544           0 :       }
    2545             : 
    2546           0 :       fd_bpf_upgradeable_loader_state_t * program_data_account_state = fd_bpf_loader_program_get_state( program_data_account,
    2547           0 :                                                                                                         ctx->txn_ctx->spad,
    2548           0 :                                                                                                         &err );
    2549           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    2550           0 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    2551           0 :         if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2552           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2553           0 :         }
    2554           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2555           0 :       }
    2556             : 
    2557             :       /* https://github.com/anza-xyz/agave/blob/v2.0.9/svm/src/program_loader.rs#L100-L104
    2558             :          Same as above comment. Program data discriminant must be set correctly. */
    2559           0 :       if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_program_data( program_data_account_state ) ) ) {
    2560             :         /* The account is closed. */
    2561           0 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    2562           0 :         if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2563           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2564           0 :         }
    2565           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2566           0 :       }
    2567             : 
    2568           0 :       ulong program_data_slot = program_data_account_state->inner.program_data.slot;
    2569           0 :       if( FD_UNLIKELY( program_data_slot>=ctx->txn_ctx->slot ) ) {
    2570             :         /* The account was likely just deployed or upgraded. Corresponds to
    2571             :           'LoadedProgramType::DelayVisibility' */
    2572           0 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    2573           0 :         if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2574           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2575           0 :         }
    2576           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2577           0 :       }
    2578           0 :     }
    2579             : 
    2580             :     /* Sadly, we have to tie the cache in with consensus. We tried our
    2581             :        best to avoid this, but Agave's program loading logic is too
    2582             :        complex to solely rely on checks without significant redundancy.
    2583             : 
    2584             :        For example, devnet and testnet have older programs that were
    2585             :        deployed before stricter ELF / VM validation checks were put in
    2586             :        place, causing these older programs to fail newer validation
    2587             :        checks and be unexecutable. At the instruction level, we have no
    2588             :        way of checking if this validation passed or not here without
    2589             :        querying our program cache, otherwise we would have to copy-paste
    2590             :        all of our validation checks here.
    2591             : 
    2592             :        Any failures here would indicate an attempt to interact with a
    2593             :        deployed programs that either failed to load or failed bytecode
    2594             :        verification. This applies for v1, v2, and v3 programs. This
    2595             :        could also theoretically cause some currently-deployed programs
    2596             :        to fail in the future if ELF / VM checks are eventually made
    2597             :        stricter. */
    2598           0 :     fd_program_cache_entry_t const * cache_entry = NULL;
    2599           0 :     if( FD_UNLIKELY( fd_program_cache_load_entry( ctx->txn_ctx->funk,
    2600           0 :                                                   ctx->txn_ctx->xid,
    2601           0 :                                                   program_id,
    2602           0 :                                                   &cache_entry )!=0 ) ) {
    2603           0 :       fd_log_collector_msg_literal( ctx, "Program is not cached" );
    2604             : 
    2605             :       /* https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L460-L467 */
    2606           0 :       if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2607           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2608           0 :       }
    2609           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2610           0 :     }
    2611             : 
    2612             :     /* The program may be in the cache but could have failed verification in the current epoch. */
    2613           0 :     if( FD_UNLIKELY( cache_entry->failed_verification ) ) {
    2614           0 :       fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    2615           0 :       if( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, remove_accounts_executable_flag_checks ) ) {
    2616           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    2617           0 :       }
    2618           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    2619           0 :     }
    2620             : 
    2621             :     /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/bpf_loader/src/lib.rs#L446 */
    2622           0 :     fd_borrowed_account_drop( &program_account );
    2623             : 
    2624           0 :     return fd_bpf_execute( ctx, cache_entry, is_deprecated );
    2625           0 :   } FD_SPAD_FRAME_END;
    2626           0 : }
    2627             : 
    2628             : 
    2629             : /* Public APIs */
    2630             : 
    2631             : int
    2632             : fd_directly_invoke_loader_v3_deploy( fd_bank_t *               bank,
    2633             :                                      fd_funk_t *               funk,
    2634             :                                      fd_funk_txn_xid_t const * xid,
    2635             :                                      fd_pubkey_t const *       program_key,
    2636             :                                      uchar const *             elf,
    2637             :                                      ulong                     elf_sz,
    2638           0 :                                      fd_spad_t *               runtime_spad ) {
    2639             :   /* Set up a dummy instr and txn context */
    2640           0 :   fd_exec_txn_ctx_t * txn_ctx = fd_exec_txn_ctx_join( fd_exec_txn_ctx_new( fd_spad_alloc( runtime_spad, FD_EXEC_TXN_CTX_ALIGN, FD_EXEC_TXN_CTX_FOOTPRINT ) ), runtime_spad, fd_wksp_containing( runtime_spad ) );
    2641             : 
    2642           0 :   fd_exec_txn_ctx_setup( bank,
    2643           0 :                          funk,
    2644           0 :                          xid,
    2645           0 :                          NULL,
    2646           0 :                          txn_ctx,
    2647           0 :                          NULL );
    2648             : 
    2649           0 :   fd_exec_txn_ctx_setup_basic( txn_ctx );
    2650           0 :   txn_ctx->instr_stack_sz = 1;
    2651           0 :   fd_exec_instr_ctx_t * instr_ctx = &txn_ctx->instr_stack[0];
    2652           0 :   *instr_ctx = (fd_exec_instr_ctx_t) {
    2653           0 :     .instr     = NULL,
    2654           0 :     .txn_ctx   = txn_ctx,
    2655           0 :   };
    2656             : 
    2657             :   /* Important note: this function is called at the epoch boundary and
    2658             :      does not do anything with the `programs_to_reverify` field in the
    2659             :      transaction context. This is fine though because when this function
    2660             :      is called, the program will not exist in the cache yet (because it
    2661             :      does not exist on-chain as a BPF program yet). There is no queueing
    2662             :      needed because the next time the program is invoked, the program
    2663             :      cache updating logic will see that the cache entry is missing and
    2664             :      will insert it then. */
    2665           0 :   return fd_deploy_program( instr_ctx, program_key, elf, elf_sz, runtime_spad );
    2666           0 : }

Generated by: LCOV version 1.14