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: 684 1784 38.3 %
Date: 2026-03-19 18:19:27 Functions: 10 11 90.9 %

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

Generated by: LCOV version 1.14