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: 812 1431 56.7 %
Date: 2025-01-08 12:08:44 Functions: 12 16 75.0 %

          Line data    Source code
       1             : #include "fd_bpf_loader_program.h"
       2             : 
       3             : /* For additional context see https://solana.com/docs/programs/deploying#state-accounts */
       4             : 
       5             : #include "../fd_pubkey_utils.h"
       6             : #include "../../../ballet/base58/fd_base58.h"
       7             : #include "../../../ballet/sbpf/fd_sbpf_loader.h"
       8             : #include "../sysvar/fd_sysvar_clock.h"
       9             : #include "../sysvar/fd_sysvar_rent.h"
      10             : #include "../sysvar/fd_sysvar_cache.h"
      11             : #include "../../vm/syscall/fd_vm_syscall.h"
      12             : #include "../../vm/fd_vm.h"
      13             : #include "../fd_executor.h"
      14             : #include "fd_bpf_loader_serialization.h"
      15             : #include "fd_native_cpi.h"
      16             : 
      17             : #include <stdlib.h>
      18             : 
      19             : static char * trace_buf;
      20             : 
      21         423 : static void __attribute__((constructor)) make_buf(void) {
      22         423 :   trace_buf = (char*)malloc(256*1024);
      23         423 : }
      24             : 
      25           0 : static void __attribute__((destructor)) free_buf(void) {
      26           0 :   free(trace_buf);
      27           0 : }
      28             : 
      29             : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L67-L69 */
      30             : #define DEFAULT_LOADER_COMPUTE_UNITS     (570UL )
      31             : #define DEPRECATED_LOADER_COMPUTE_UNITS  (1140UL)
      32             : #define UPGRADEABLE_LOADER_COMPUTE_UNITS (2370UL)
      33             : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/sdk/program/src/bpf_loader_upgradeable.rs#L29-L120 */
      34             : #define SIZE_OF_PROGRAM                  (36UL  ) /* UpgradeableLoaderState::size_of_program() */
      35         852 : #define BUFFER_METADATA_SIZE             (37UL  ) /* UpgradeableLoaderState::size_of_buffer_metadata() */
      36        1077 : #define PROGRAMDATA_METADATA_SIZE        (45UL  ) /* UpgradeableLoaderState::size_of_programdata_metadata() */
      37          54 : #define SIZE_OF_UNINITIALIZED            (4UL   ) /* UpgradeableLoaderState::size_of_uninitialized() */
      38             : 
      39             : /* https://github.com/anza-xyz/agave/blob/ced98f1ebe73f7e9691308afa757323003ff744f/sdk/program/src/program_error.rs#L290-L335 */
      40             : static inline int
      41             : program_error_to_instr_error( ulong  err,
      42         303 :                               uint * custom_err ) {
      43         303 :   switch( err ) {
      44          45 :     case CUSTOM_ZERO:
      45          45 :       *custom_err = 0;
      46          45 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
      47           0 :     case INVALID_ARGUMENT:
      48           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
      49           0 :     case INVALID_INSTRUCTION_DATA:
      50           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
      51           0 :     case INVALID_ACCOUNT_DATA:
      52           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      53           0 :     case ACCOUNT_DATA_TOO_SMALL:
      54           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
      55           0 :     case INSUFFICIENT_FUNDS:
      56           0 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
      57           0 :     case INCORRECT_PROGRAM_ID:
      58           0 :       return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
      59           0 :     case MISSING_REQUIRED_SIGNATURES:
      60           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
      61           0 :     case ACCOUNT_ALREADY_INITIALIZED:
      62           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
      63           0 :     case UNINITIALIZED_ACCOUNT:
      64           0 :       return FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT;
      65          57 :     case NOT_ENOUGH_ACCOUNT_KEYS:
      66          57 :       return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
      67           0 :     case ACCOUNT_BORROW_FAILED:
      68           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED;
      69           0 :     case MAX_SEED_LENGTH_EXCEEDED:
      70           0 :       return FD_EXECUTOR_INSTR_ERR_MAX_SEED_LENGTH_EXCEEDED;
      71           0 :     case INVALID_SEEDS:
      72           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_SEEDS;
      73           0 :     case BORSH_IO_ERROR:
      74           0 :       return FD_EXECUTOR_INSTR_ERR_BORSH_IO_ERROR;
      75           0 :     case ACCOUNT_NOT_RENT_EXEMPT:
      76           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_NOT_RENT_EXEMPT;
      77           0 :     case UNSUPPORTED_SYSVAR:
      78           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
      79           0 :     case ILLEGAL_OWNER:
      80           0 :       return FD_EXECUTOR_INSTR_ERR_ILLEGAL_OWNER;
      81           0 :     case MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED:
      82           0 :       return FD_EXECUTOR_INSTR_ERR_MAX_ACCS_DATA_ALLOCS_EXCEEDED;
      83           0 :     case INVALID_ACCOUNT_DATA_REALLOC:
      84           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC;
      85           0 :     case MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED:
      86           0 :       return FD_EXECUTOR_INSTR_ERR_MAX_INSN_TRACE_LENS_EXCEEDED;
      87           0 :     case BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS:
      88           0 :       return FD_EXECUTOR_INSTR_ERR_BUILTINS_MUST_CONSUME_CUS;
      89           0 :     case INVALID_ACCOUNT_OWNER:
      90           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
      91           0 :     case ARITHMETIC_OVERFLOW:
      92           0 :       return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
      93           0 :     case IMMUTABLE:
      94           0 :       return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
      95           0 :     case INCORRECT_AUTHORITY:
      96           0 :       return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
      97         201 :     default:
      98         201 :       if( err>>BUILTIN_BIT_SHIFT == 0 ) {
      99         201 :         *custom_err = (uint)err;
     100         201 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     101         201 :       }
     102           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ERR;
     103         303 :   }
     104         303 : }
     105             : 
     106             : int
     107             : fd_bpf_loader_v2_is_executable( fd_exec_slot_ctx_t * slot_ctx,
     108           0 :                                 fd_pubkey_t const *  pubkey ) {
     109           0 :   FD_BORROWED_ACCOUNT_DECL(rec);
     110           0 :   int read_result = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, pubkey, rec );
     111           0 :   if( read_result != FD_ACC_MGR_SUCCESS ) {
     112           0 :     return -1;
     113           0 :   }
     114             : 
     115           0 :   if( memcmp( rec->const_meta->info.owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) != 0 &&
     116           0 :       memcmp( rec->const_meta->info.owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) != 0 ) {
     117           0 :     return -1;
     118           0 :   }
     119             : 
     120           0 :   if( rec->const_meta->info.executable != 1 ) {
     121           0 :     return -1;
     122           0 :   }
     123             : 
     124           0 :   return 0;
     125           0 : }
     126             : 
     127             : 
     128             : /* This is literally called before every single instruction execution */
     129             : int
     130             : fd_bpf_loader_v3_is_executable( fd_exec_slot_ctx_t *        slot_ctx,
     131             :                                 fd_pubkey_t const *         pubkey,
     132           0 :                                 fd_exec_instr_ctx_t const * instr_ctx ) {
     133           0 :   int err = 0;
     134           0 :   fd_account_meta_t const * meta = fd_acc_mgr_view_raw( slot_ctx->acc_mgr, slot_ctx->funk_txn,
     135           0 :                                                         (fd_pubkey_t *) pubkey, NULL, &err, NULL );
     136           0 :   if( FD_UNLIKELY( !fd_acc_exists( meta ) ) ) {
     137           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     138           0 :   }
     139             : 
     140           0 :   if( FD_UNLIKELY( memcmp( meta->info.owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     141           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     142           0 :   }
     143             : 
     144           0 :   if( FD_UNLIKELY( meta->info.executable!=1 ) ) {
     145           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_NOT_EXECUTABLE;
     146           0 :   }
     147             : 
     148           0 :   fd_bincode_decode_ctx_t ctx = {
     149           0 :     .data    = (uchar *)meta     + meta->hlen,
     150           0 :     .dataend = (char *) ctx.data + meta->dlen,
     151           0 :     .valloc  = fd_spad_virtual( instr_ctx->txn_ctx->spad ),
     152           0 :   };
     153             : 
     154           0 :   fd_bpf_upgradeable_loader_state_t loader_state = {0};
     155           0 :   if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode( &loader_state, &ctx ) ) ) {
     156           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     157           0 :   }
     158             : 
     159           0 :   if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_program( &loader_state ) ) ) {
     160           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     161           0 :   }
     162             : 
     163             :   /* Check if programdata account exists */
     164           0 :   fd_account_meta_t const * programdata_meta =
     165           0 :     (fd_account_meta_t const *)fd_acc_mgr_view_raw( slot_ctx->acc_mgr, slot_ctx->funk_txn,
     166           0 :                                                     (fd_pubkey_t *) &loader_state.inner.program.programdata_address, NULL, &err, NULL );
     167           0 :   if( FD_UNLIKELY( !fd_acc_exists( programdata_meta ) ) ) {
     168           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     169           0 :   }
     170             : 
     171           0 :   return 0;
     172           0 : }
     173             : 
     174             : /* TODO: This can be combined with the other bpf loader state decode function */
     175             : fd_account_meta_t const *
     176             : read_bpf_upgradeable_loader_state_for_program( fd_exec_txn_ctx_t *                 txn_ctx,
     177             :                                                uchar                               program_id,
     178             :                                                fd_bpf_upgradeable_loader_state_t * result,
     179       57417 :                                                int *                               opt_err ) {
     180       57417 :   fd_borrowed_account_t * rec = NULL;
     181       57417 :   int err = fd_txn_borrowed_account_view_idx( txn_ctx, program_id, &rec );
     182       57417 :   if( FD_UNLIKELY( err ) ) {
     183           0 :     *opt_err = err;
     184           0 :     return NULL;
     185           0 :   }
     186             : 
     187       57417 :   fd_bincode_decode_ctx_t ctx = {
     188       57417 :     .data    = rec->const_data,
     189       57417 :     .dataend = rec->const_data + rec->const_meta->dlen,
     190       57417 :     .valloc  = fd_spad_virtual( txn_ctx->spad ),
     191       57417 :   };
     192             : 
     193       57417 :   if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode( result, &ctx ) ) ) {
     194       34959 :     *opt_err = FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     195       34959 :     return NULL;
     196       34959 :   }
     197             : 
     198       22458 :   return rec->const_meta;
     199       57417 : }
     200             : 
     201             : /* https://github.com/anza-xyz/agave/blob/9b22f28104ec5fd606e4bb39442a7600b38bb671/programs/bpf_loader/src/lib.rs#L216-L229 */
     202             : static ulong
     203        1029 : calculate_heap_cost( ulong heap_size, ulong heap_cost, int * err ) {
     204        2058 :   #define KIBIBYTE_MUL_PAGES       (1024UL * 32UL)
     205        1029 :   #define KIBIBYTE_MUL_PAGES_SUB_1 (KIBIBYTE_MUL_PAGES - 1UL)
     206             : 
     207        1029 :   heap_size = fd_ulong_sat_add( heap_size, KIBIBYTE_MUL_PAGES_SUB_1 );
     208             : 
     209        1029 :   if( FD_UNLIKELY( heap_size==0UL ) ) {
     210           0 :     *err = FD_EXECUTOR_INSTR_ERR_GENERIC_ERR;
     211           0 :     return 0UL;
     212           0 :   }
     213             : 
     214        1029 :   heap_size = fd_ulong_sat_mul( fd_ulong_sat_sub( heap_size / KIBIBYTE_MUL_PAGES, 1UL ), heap_cost );
     215        1029 :   return heap_size;
     216             : 
     217        1029 :   #undef KIBIBYTE_MUL_PAGES
     218        1029 :   #undef KIBIBYTE_MUL_PAGES_SUB_1
     219        1029 : }
     220             : 
     221             : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L105-L171
     222             : 
     223             :    Our arguments to deploy_program are different from the Agave version because
     224             :    we handle the caching of deployed programs differently. In Firedancer we
     225             :    lack the concept of ProgramCacheEntryType entirely.
     226             :    https://github.com/anza-xyz/agave/blob/114d94a25e9631f9bf6349c4b833d7900ef1fb1c/program-runtime/src/loaded_programs.rs#L158
     227             : 
     228             :    In Agave there is a separate caching structure that is used to store the
     229             :    deployed programs. In Firedancer the deployed, validated program is stored as
     230             :   metadata for the account in the funk record.
     231             : 
     232             :    See https://github.com/firedancer-io/firedancer/blob/9c1df680b3f38bebb0597e089766ec58f3b41e85/src/flamenco/runtime/program/fd_bpf_loader_v3_program.c#L1640
     233             :    for how we handle the concept of 'LoadedProgramType::DelayVisibility' in Firedancer.
     234             : 
     235             :    As a concrete example, our version of deploy_program does not have the
     236             :    'account_size' argument because we do not update the funk record here. */
     237             : int
     238             : fd_deploy_program( fd_exec_instr_ctx_t * instr_ctx,
     239             :                    uchar const *         programdata,
     240             :                    ulong                 programdata_size,
     241             :                    fd_valloc_t           valloc /* Majority of use cases this is a txn ctx spad under the hood; for native to bpf migration this is scratch backed since it's an epoch level event. */
     242         924 :               ) {
     243         924 :   int deploy_mode    = 1;
     244         924 :   int direct_mapping = FD_FEATURE_ACTIVE( instr_ctx->slot_ctx, bpf_account_data_direct_mapping );
     245         924 :   fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_new( fd_valloc_malloc( valloc,
     246         924 :                                                                           fd_sbpf_syscalls_align(),
     247         924 :                                                                           fd_sbpf_syscalls_footprint() ) );
     248         924 :   if( FD_UNLIKELY( !syscalls ) ) {
     249             :     //TODO: full log including err
     250           0 :     fd_log_collector_msg_literal( instr_ctx, "Failed to register syscalls" );
     251           0 :     return FD_EXECUTOR_INSTR_ERR_PROGRAM_ENVIRONMENT_SETUP_FAILURE;
     252           0 :   }
     253         924 :   fd_vm_syscall_register_slot( syscalls, instr_ctx->slot_ctx, 1);
     254             : 
     255             :   /* Load executable */
     256         924 :   fd_sbpf_elf_info_t  _elf_info[ 1UL ];
     257         924 :   uint min_sbpf_version, max_sbpf_version;
     258         924 :   fd_bpf_get_sbpf_versions( &min_sbpf_version, &max_sbpf_version, instr_ctx->slot_ctx );
     259         924 :   fd_sbpf_elf_info_t * elf_info = fd_sbpf_elf_peek( _elf_info, programdata, programdata_size, deploy_mode, min_sbpf_version, max_sbpf_version );
     260         924 :   if( FD_UNLIKELY( !elf_info ) ) {
     261             :     //TODO: actual log, this is a custom Firedancer msg
     262         243 :     fd_log_collector_msg_literal( instr_ctx, "Failed to load or verify Elf" );
     263         243 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     264         243 :   }
     265             : 
     266             :   /* Allocate rodata segment */
     267         681 :   void * rodata = fd_valloc_malloc( valloc, FD_SBPF_PROG_RODATA_ALIGN, elf_info->rodata_footprint );
     268         681 :   if( FD_UNLIKELY( !rodata ) ) {
     269           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     270           0 :   }
     271             : 
     272             :   /* Allocate program buffer */
     273         681 :   ulong  prog_align        = fd_sbpf_program_align();
     274         681 :   ulong  prog_footprint    = fd_sbpf_program_footprint( elf_info );
     275         681 :   fd_sbpf_program_t * prog = fd_sbpf_program_new( fd_valloc_malloc( valloc, prog_align, prog_footprint ), elf_info, rodata );
     276         681 :   if( FD_UNLIKELY( !prog ) ) {
     277           0 :     FD_LOG_ERR(( "fd_sbpf_program_new() failed: %s", fd_sbpf_strerror() ));
     278           0 :   }
     279             : 
     280             :   /* Load program */
     281         681 :   int err = fd_sbpf_program_load( prog, programdata, programdata_size, syscalls, deploy_mode );
     282         681 :   if( FD_UNLIKELY( err ) ) {
     283         618 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     284         618 :   }
     285             : 
     286             :   /* Validate the program */
     287          63 :   fd_vm_t _vm[ 1UL ];
     288          63 :   fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
     289             : 
     290          63 :   vm = fd_vm_init(
     291          63 :     /* vm              */ vm,
     292          63 :     /* instr_ctx       */ instr_ctx,
     293          63 :     /* heap_max        */ instr_ctx->txn_ctx->heap_size,
     294          63 :     /* entry_cu        */ instr_ctx->txn_ctx->compute_meter,
     295          63 :     /* rodata          */ prog->rodata,
     296          63 :     /* rodata_sz       */ prog->rodata_sz,
     297          63 :     /* text            */ prog->text,
     298          63 :     /* text_cnt        */ prog->text_cnt,
     299          63 :     /* text_off        */ prog->text_off, /* FIXME: What if text_off is not multiple of 8 */
     300          63 :     /* text_sz         */ prog->text_sz,
     301          63 :     /* entry_pc        */ prog->entry_pc,
     302          63 :     /* calldests       */ prog->calldests,
     303          63 :     /* sbpf_version    */ elf_info->sbpf_version,
     304          63 :     /* syscalls        */ syscalls,
     305             :     /* trace           */ NULL,
     306             :     /* sha             */ NULL,
     307             :     /* mem_regions     */ NULL,
     308          63 :     /* mem_regions_cnt */ 0,
     309             :     /* mem_region_accs */ NULL,
     310          63 :     /* is_deprecated   */ 0,
     311          63 :     /* direct mapping */  direct_mapping );
     312          63 :   if ( FD_UNLIKELY( vm == NULL ) ) {
     313           0 :     FD_LOG_WARNING(( "NULL vm" ));
     314           0 :     return FD_EXECUTOR_INSTR_ERR_PROGRAM_ENVIRONMENT_SETUP_FAILURE;
     315           0 :   }
     316             : 
     317          63 :   int validate_result = fd_vm_validate( vm );
     318          63 :   if( FD_UNLIKELY( validate_result!=FD_VM_SUCCESS ) ) {
     319          27 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     320          27 :   }
     321          36 :   return FD_EXECUTOR_INSTR_SUCCESS;
     322          63 : }
     323             : 
     324             : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L195-L218 */
     325             : static int
     326             : write_program_data( fd_exec_instr_ctx_t *   instr_ctx,
     327             :                     ulong                   instr_acc_idx,
     328             :                     ulong                   program_data_offset,
     329             :                     uchar *                 bytes,
     330          48 :                     ulong                   bytes_len ) {
     331         192 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, instr_acc_idx, program ) {
     332             : 
     333          48 :   uchar * data = NULL;
     334          48 :   ulong   dlen = 0UL;
     335          48 :   int err = fd_account_get_data_mut( instr_ctx, instr_acc_idx, &data, &dlen );
     336          48 :   if( FD_UNLIKELY( err ) ) {
     337           3 :     return err;
     338           3 :   }
     339             : 
     340          45 :   ulong write_offset = fd_ulong_sat_add( program_data_offset, bytes_len );
     341          45 :   if( FD_UNLIKELY( program->const_meta->dlen<write_offset ) ) {
     342             :     /* Max msg_sz: 24 - 6 + 2*20 = 58 < 127 => we can use printf */
     343           0 :     fd_log_collector_printf_dangerous_max_127( instr_ctx,
     344           0 :       "Write overflow %lu < %lu", program->const_meta->dlen, write_offset );
     345           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     346           0 :   }
     347             : 
     348          45 :   if( FD_UNLIKELY( program_data_offset>dlen ) ) {
     349           0 :     FD_LOG_WARNING(( "Write offset out of bounds" )); // custom check/log
     350           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     351           0 :   }
     352             : 
     353          45 :   if( FD_LIKELY( bytes_len ) ) {
     354          42 :     fd_memcpy( data+program_data_offset, bytes, bytes_len );
     355          42 :   }
     356             : 
     357          48 :   } FD_BORROWED_ACCOUNT_DROP( program );
     358             : 
     359          45 :   return FD_EXECUTOR_INSTR_SUCCESS;
     360          48 : }
     361             : 
     362             : /* get_state() */
     363             : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/sdk/src/transaction_context.rs#L968-L972 */
     364             : int
     365             : fd_bpf_loader_v3_program_get_state( fd_exec_instr_ctx_t const *         instr_ctx,
     366             :                                     fd_borrowed_account_t const *       borrowed_acc,
     367        4602 :                                     fd_bpf_upgradeable_loader_state_t * state ) {
     368             :     /* Check to see if the buffer account is already initialized */
     369        4602 :     fd_bincode_decode_ctx_t ctx = {
     370        4602 :       .data    = borrowed_acc->const_data,
     371        4602 :       .dataend = borrowed_acc->const_data + borrowed_acc->const_meta->dlen,
     372        4602 :       .valloc  = fd_spad_virtual( instr_ctx->txn_ctx->spad ),
     373        4602 :     };
     374             : 
     375        4602 :     int err = fd_bpf_upgradeable_loader_state_decode( state, &ctx );
     376        4602 :     if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     377          66 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     378          66 :     }
     379        4536 :     return FD_BINCODE_SUCCESS;
     380        4602 : }
     381             : 
     382             : /* set_state() */
     383             : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/sdk/src/transaction_context.rs#L976-L985 */
     384             : int
     385             : fd_bpf_loader_v3_program_set_state( fd_exec_instr_ctx_t *               instr_ctx,
     386             :                                     ulong                               instr_acc_idx,
     387         120 :                                     fd_bpf_upgradeable_loader_state_t * state ) {
     388         120 :   ulong state_size = fd_bpf_upgradeable_loader_state_size( state );
     389             : 
     390         120 :   uchar * data = NULL;
     391         120 :   ulong   dlen = 0UL;
     392             : 
     393         120 :   int err = fd_account_get_data_mut( instr_ctx, instr_acc_idx, &data, &dlen );
     394         120 :   if( FD_UNLIKELY( err ) ) {
     395           3 :     return err;
     396           3 :   }
     397             : 
     398         117 :   if( FD_UNLIKELY( state_size>dlen ) ) {
     399           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     400           0 :   }
     401             : 
     402         117 :   fd_bincode_encode_ctx_t ctx = {
     403         117 :     .data    = data,
     404         117 :     .dataend = data + state_size
     405         117 :   };
     406             : 
     407         117 :   err = fd_bpf_upgradeable_loader_state_encode( state, &ctx );
     408         117 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     409           0 :     return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR;
     410           0 :   }
     411             : 
     412         117 :   return FD_BINCODE_SUCCESS;
     413         117 : }
     414             : 
     415             : /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1299-L1331 */
     416             : static int
     417             : common_close_account( fd_pubkey_t * authority_address,
     418             :                       fd_exec_instr_ctx_t * instr_ctx,
     419          30 :                       fd_bpf_upgradeable_loader_state_t * state ) {
     420          30 :   uchar const *       instr_acc_idxs = instr_ctx->instr->acct_txn_idxs;
     421          30 :   fd_pubkey_t const * txn_accs       = instr_ctx->txn_ctx->accounts;
     422             : 
     423          30 :   if( FD_UNLIKELY( !authority_address ) ) {
     424           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     425           0 :   }
     426          30 :   if( FD_UNLIKELY( memcmp( authority_address, &txn_accs[ instr_acc_idxs[ 2UL ] ], sizeof(fd_pubkey_t) ) ) ) {
     427           0 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     428           0 :   }
     429          30 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 2UL ) ) ) {
     430          30 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     431          30 :   }
     432             : 
     433           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, close_account     ) {
     434           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 1UL, recipient_account ) {
     435             : 
     436           0 :   int err = fd_account_checked_add_lamports( instr_ctx, 1UL, close_account->const_meta->info.lamports );
     437           0 :   if( FD_UNLIKELY( err ) ) {
     438           0 :     return err;
     439           0 :   }
     440           0 :   err = fd_account_set_lamports( instr_ctx, 0UL, 0UL );
     441           0 :   if( FD_UNLIKELY( err ) ) {
     442           0 :     return err;
     443           0 :   }
     444             : 
     445           0 :   state->discriminant = fd_bpf_upgradeable_loader_state_enum_uninitialized;
     446           0 :   err = fd_bpf_loader_v3_program_set_state( instr_ctx, 0UL, state );
     447           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     448           0 :     FD_LOG_WARNING(( "Bpf loader state write for close account failed" ));
     449           0 :     return err;
     450           0 :   }
     451             : 
     452           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     453             : 
     454           0 :   } FD_BORROWED_ACCOUNT_DROP( recipient_account );
     455           0 :   } FD_BORROWED_ACCOUNT_DROP( close_account     );
     456           0 : }
     457             : 
     458             : 
     459             : /* Every loader-owned BPF program goes through this function, which goes into the VM.
     460             : 
     461             :    https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1332-L1501 */
     462             : int
     463        1029 : fd_bpf_execute( fd_exec_instr_ctx_t * instr_ctx, fd_sbpf_validated_program_t * prog, uchar is_deprecated ) {
     464             : 
     465        1029 :   fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_new( fd_spad_alloc( instr_ctx->txn_ctx->spad,
     466        1029 :                                                                        fd_sbpf_syscalls_align(),
     467        1029 :                                                                        fd_sbpf_syscalls_footprint() ) );
     468        1029 :   FD_TEST( syscalls );
     469             : 
     470             :   /* TODO do we really need to re-do this on every instruction? */
     471        1029 :   fd_vm_syscall_register_slot( syscalls, instr_ctx->slot_ctx, 0 );
     472             : 
     473             :   /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1362-L1368 */
     474        1029 :   ulong                   input_sz                = 0UL;
     475        1029 :   ulong                   pre_lens[256]           = {0};
     476        1029 :   fd_vm_input_region_t    input_mem_regions[1000] = {0}; /* We can have a max of (3 * num accounts + 1) regions */
     477        1029 :   fd_vm_acc_region_meta_t acc_region_metas[256]   = {0}; /* instr acc idx to idx */
     478        1029 :   uint                    input_mem_regions_cnt   = 0U;
     479        1029 :   int                     direct_mapping          = FD_FEATURE_ACTIVE( instr_ctx->slot_ctx, bpf_account_data_direct_mapping );
     480             : 
     481        1029 :   uchar * input = NULL;
     482        1029 :   if( FD_UNLIKELY( is_deprecated ) ) {
     483         219 :     input = fd_bpf_loader_input_serialize_unaligned( *instr_ctx, &input_sz, pre_lens,
     484         219 :                                                      input_mem_regions, &input_mem_regions_cnt,
     485         219 :                                                      acc_region_metas, !direct_mapping );
     486         810 :   } else {
     487         810 :     input = fd_bpf_loader_input_serialize_aligned( *instr_ctx, &input_sz, pre_lens,
     488         810 :                                                    input_mem_regions, &input_mem_regions_cnt,
     489         810 :                                                    acc_region_metas, !direct_mapping );
     490         810 :   }
     491             : 
     492        1029 :   if( FD_UNLIKELY( input==NULL ) ) {
     493           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
     494           0 :   }
     495             : 
     496        1029 :   fd_sha256_t _sha[1];
     497        1029 :   fd_sha256_t * sha = fd_sha256_join( fd_sha256_new( _sha ) );
     498             : 
     499        1029 :   fd_vm_t _vm[1];
     500        1029 :   fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
     501             : 
     502        1029 :   ulong pre_insn_cus = instr_ctx->txn_ctx->compute_meter;
     503        1029 :   ulong heap_max = true ? instr_ctx->txn_ctx->heap_size : FD_VM_HEAP_DEFAULT; /* TODO:FIXME: fix this */
     504             : 
     505             :   /* TODO: (topointon): correctly set check_size in vm setup */
     506        1029 :   vm = fd_vm_init(
     507        1029 :     /* vm                    */ vm,
     508        1029 :     /* instr_ctx             */ instr_ctx,
     509        1029 :     /* heap_max              */ heap_max, /* TODO configure heap allocator */
     510        1029 :     /* entry_cu              */ instr_ctx->txn_ctx->compute_meter,
     511        1029 :     /* rodata                */ prog->rodata,
     512        1029 :     /* rodata_sz             */ prog->rodata_sz,
     513        1029 :     /* text                  */ (ulong *)((ulong)prog->rodata + (ulong)prog->text_off), /* Note: text_off is byte offset */
     514        1029 :     /* text_cnt              */ prog->text_cnt,
     515        1029 :     /* text_off              */ prog->text_off,
     516        1029 :     /* text_sz               */ prog->text_sz,
     517        1029 :     /* entry_pc              */ prog->entry_pc,
     518        1029 :     /* calldests             */ prog->calldests,
     519        1029 :     /* sbpf_version          */ prog->sbpf_version,
     520        1029 :     /* syscalls              */ syscalls,
     521             :     /* trace                 */ NULL,
     522        1029 :     /* sha                   */ sha,
     523        1029 :     /* input_mem_regions     */ input_mem_regions,
     524        1029 :     /* input_mem_regions_cnt */ input_mem_regions_cnt,
     525        1029 :     /* acc_region_metas      */ acc_region_metas,
     526        1029 :     /* is_deprecated         */ is_deprecated,
     527        1029 :     /* direct_mapping        */ direct_mapping );
     528        1029 :   if ( FD_UNLIKELY( vm == NULL ) ) {
     529             :     /* We throw an error here because it could be the case that the given heap_size > HEAP_MAX.
     530             :        In this case, Agave fails the transaction but does not error out.
     531             : 
     532             :        https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1396 */
     533           0 :     FD_LOG_WARNING(( "null vm" ));
     534           0 :     return FD_EXECUTOR_INSTR_ERR_PROGRAM_ENVIRONMENT_SETUP_FAILURE;
     535           0 :   }
     536             : 
     537        1029 :   fd_valloc_t valloc = fd_spad_virtual( instr_ctx->txn_ctx->spad );
     538             : 
     539             : #ifdef FD_DEBUG_SBPF_TRACES
     540             :   uchar * signature = (uchar*)vm->instr_ctx->txn_ctx->_txn_raw->raw + vm->instr_ctx->txn_ctx->txn_descriptor->signature_off;
     541             :   uchar sig[64];
     542             :   /* TODO (topointon): make this run-time configurable, no need for this ifdef */
     543             :   fd_base58_decode_64( "tkacc4VCh2z9cLsQowCnKqX14DmUUxpRyES755FhUzrFxSFvo8kVk444kNTL7kJxYnnANYwRWAdHCgBJupftZrz", sig );
     544             :   if( FD_UNLIKELY( !memcmp( signature, sig, 64UL ) ) ) {
     545             :     ulong event_max = FD_RUNTIME_VM_TRACE_EVENT_MAX;
     546             :     ulong event_data_max = FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX;
     547             :     vm->trace = fd_vm_trace_join( fd_vm_trace_new( fd_valloc_malloc(
     548             :     valloc, fd_vm_trace_align(), fd_vm_trace_footprint( event_max, event_data_max ) ), event_max, event_data_max ) );
     549             :     if( FD_UNLIKELY( !vm->trace ) ) FD_LOG_ERR(( "unable to create trace; make sure you've compiled with sufficient spad size " ));
     550             :   }
     551             : #endif
     552             : 
     553             :   /* https://github.com/anza-xyz/agave/blob/9b22f28104ec5fd606e4bb39442a7600b38bb671/programs/bpf_loader/src/lib.rs#L288-L298 */
     554        1029 :   ulong heap_size = instr_ctx->txn_ctx->heap_size;
     555        1029 :   ulong heap_cost = FD_VM_HEAP_COST;
     556        1029 :   int heap_err = 0;
     557        1029 :   ulong heap_cost_result = calculate_heap_cost( heap_size, heap_cost, &heap_err );
     558             : 
     559        1029 :   if( FD_UNLIKELY( heap_err ) ) {
     560           0 :     return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR;
     561           0 :   }
     562        1029 :   if( FD_UNLIKELY( heap_cost_result>vm->cu ) ) {
     563           0 :     return FD_EXECUTOR_INSTR_ERR_COMPUTE_BUDGET_EXCEEDED;
     564           0 :   }
     565        1029 :   vm->cu -= heap_cost_result;
     566             : 
     567        1029 :   int exec_err = fd_vm_exec( vm );
     568             :   
     569             :   /* (SIMD-182) Consume ALL requested CUs on non-Syscall errors */
     570        1029 :   if( FD_FEATURE_ACTIVE( instr_ctx->slot_ctx, consume_requested_cu_on_vm_err )
     571        1029 :       && exec_err != FD_VM_ERR_SIGSYSCALL ) {
     572           0 :     instr_ctx->txn_ctx->compute_meter = 0UL;
     573        1029 :   } else {
     574        1029 :     instr_ctx->txn_ctx->compute_meter = vm->cu;
     575        1029 :   }
     576             : 
     577        1029 :   if( FD_UNLIKELY( vm->trace ) ) {
     578           0 :     int err = fd_vm_trace_printf( vm->trace, vm->syscalls );
     579           0 :     if( FD_UNLIKELY( err ) ) {
     580           0 :       FD_LOG_WARNING(( "fd_vm_trace_printf failed (%i-%s)", err, fd_vm_strerror( err ) ));
     581           0 :     }
     582           0 :     fd_valloc_free( valloc, fd_vm_trace_delete( fd_vm_trace_leave( vm->trace ) ) );
     583           0 :   }
     584             : 
     585             :   /* Log consumed compute units and return data.
     586             :      https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/lib.rs#L1418-L1429 */
     587        1029 :   fd_log_collector_program_consumed( instr_ctx, pre_insn_cus-vm->cu, pre_insn_cus );
     588        1029 :   if( FD_UNLIKELY( instr_ctx->txn_ctx->return_data.len ) ) {
     589          33 :     fd_log_collector_program_return( instr_ctx );
     590          33 :   }
     591             : 
     592             :   /* Handles instr + EBPF errors */
     593        1029 :   if( FD_UNLIKELY( exec_err!=FD_VM_SUCCESS ) ) {
     594             :     /* Instr error case */
     595         336 :     if( instr_ctx->txn_ctx->exec_err_kind==FD_EXECUTOR_ERR_KIND_INSTR ) {
     596          18 :       return instr_ctx->txn_ctx->exec_err;
     597          18 :     }
     598             : 
     599             :     /* EBPF error case
     600             :        Edge case with error codes: if direct mapping is enabled, the EBPF error is an access violation,
     601             :        and the access type was a store, a different error code is returned to give developers more insight
     602             :        as to what caused the error.
     603             :        https://github.com/anza-xyz/agave/blob/v2.0.9/programs/bpf_loader/src/lib.rs#L1436-L1470 */
     604         318 :     if( FD_UNLIKELY( direct_mapping && exec_err==FD_VM_ERR_EBPF_ACCESS_VIOLATION && vm->segv_store_vaddr!=ULONG_MAX ) ) {
     605             :       /* vaddrs start at 0xFFFFFFFF + 1, so anything below it would not correspond to any account metadata. */
     606           9 :       if( FD_UNLIKELY( vm->segv_store_vaddr>>32UL==0UL ) ) {
     607           6 :         return FD_EXECUTOR_INSTR_ERR_PROGRAM_FAILED_TO_COMPLETE;
     608           6 :       }
     609             : 
     610             :       /* Find the account meta corresponding to the vaddr */
     611           3 :       ulong vaddr_offset = vm->segv_store_vaddr & FD_VM_OFFSET_MASK;
     612           3 :       ulong acc_region_addl_off = is_deprecated ? 0UL : MAX_PERMITTED_DATA_INCREASE;
     613             : 
     614           9 :       for( ulong i=0UL; i<instr_ctx->instr->acct_cnt; i++ ) {
     615           9 :         fd_borrowed_account_t * instr_acc = instr_ctx->instr->borrowed_accounts[i];
     616           9 :         ulong idx = acc_region_metas[i].region_idx;
     617             : 
     618           9 :         if( input_mem_regions[idx].vaddr_offset<=vaddr_offset && vaddr_offset<input_mem_regions[idx].vaddr_offset+pre_lens[i]+acc_region_addl_off ) {
     619             :           /* Found an input mem region!
     620             :              https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L1515-L1528 */
     621           3 :           int err;
     622           3 :           if( !FD_FEATURE_ACTIVE( instr_ctx->slot_ctx, remove_accounts_executable_flag_checks ) &&
     623           3 :               fd_account_is_executable( instr_acc->const_meta ) ) {
     624           3 :             err = FD_EXECUTOR_INSTR_ERR_EXECUTABLE_DATA_MODIFIED;
     625           3 :           } else if( fd_instr_acc_is_writable_idx( instr_ctx->instr, i ) ) {
     626           0 :             err = FD_EXECUTOR_INSTR_ERR_EXTERNAL_DATA_MODIFIED;
     627           0 :           } else {
     628           0 :             err = FD_EXECUTOR_INSTR_ERR_READONLY_DATA_MODIFIED;
     629           0 :           }
     630           3 :           FD_VM_ERR_FOR_LOG_INSTR( vm, err );
     631           3 :           return err;
     632           3 :         }
     633           9 :       }
     634           3 :     }
     635         309 :     return FD_EXECUTOR_INSTR_ERR_PROGRAM_FAILED_TO_COMPLETE;
     636         318 :   }
     637             : 
     638             :   /* Handles syscall errors
     639             :      TODO: vm should report */
     640         693 :   ulong syscall_err = vm->reg[0];
     641         693 :   if( FD_UNLIKELY( syscall_err ) ) {
     642             :     /* https://github.com/anza-xyz/agave/blob/v2.0.9/programs/bpf_loader/src/lib.rs#L1431-L1434 */
     643         303 :     instr_ctx->txn_ctx->exec_err_kind = FD_EXECUTOR_ERR_KIND_INSTR;
     644         303 :     return program_error_to_instr_error( syscall_err, &instr_ctx->txn_ctx->custom_err );
     645         303 :   }
     646             : 
     647         390 :   int err;
     648         390 :   if( FD_UNLIKELY( is_deprecated ) ) {
     649          12 :     err = fd_bpf_loader_input_deserialize_unaligned( *instr_ctx, pre_lens, input, input_sz, !direct_mapping );
     650          12 :     if( FD_UNLIKELY( err!=0 ) ) {
     651           0 :       return err;
     652           0 :     }
     653         378 :   } else {
     654         378 :     err = fd_bpf_loader_input_deserialize_aligned( *instr_ctx, pre_lens, input, input_sz, !direct_mapping );
     655         378 :     if( FD_UNLIKELY( err!=0 ) ) {
     656           3 :       return err;
     657           3 :     }
     658         378 :   }
     659             : 
     660         387 :   return FD_EXECUTOR_INSTR_SUCCESS;
     661         390 : }
     662             : 
     663             : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L566-L1444 */
     664             : static int
     665        1272 : process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) {
     666        1272 :   uchar const * data = instr_ctx->instr->data;
     667        1272 :   fd_valloc_t valloc = fd_spad_virtual( instr_ctx->txn_ctx->spad );
     668             : 
     669        1272 :   fd_bpf_upgradeable_loader_program_instruction_t instruction = {0};
     670        1272 :   fd_bincode_decode_ctx_t decode_ctx = {0};
     671        1272 :   decode_ctx.data    = data;
     672        1272 :   decode_ctx.dataend = &data[ instr_ctx->instr->data_sz > 1232UL ? 1232UL : instr_ctx->instr->data_sz ];
     673        1272 :   decode_ctx.valloc  = valloc;
     674             : 
     675        1272 :   int err = fd_bpf_upgradeable_loader_program_instruction_decode( &instruction, &decode_ctx );
     676        1272 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     677          12 :     FD_LOG_WARNING(( "Bincode decode for instruction failed" ));
     678          12 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     679          12 :   }
     680             : 
     681        1260 :   uchar const * instr_acc_idxs   = instr_ctx->instr->acct_txn_idxs;
     682        1260 :   fd_pubkey_t const * txn_accs   = instr_ctx->txn_ctx->accounts;
     683        1260 :   fd_pubkey_t const * program_id = &instr_ctx->instr->program_id_pubkey;
     684        1260 :   switch( instruction.discriminant ) {
     685             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L476-L493 */
     686          39 :     case fd_bpf_upgradeable_loader_program_instruction_enum_initialize_buffer: {
     687          39 :       if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 2U ) ) ) {
     688           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     689           0 :       }
     690             : 
     691         156 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, buffer ) {
     692             : 
     693          39 :       fd_bpf_upgradeable_loader_state_t buffer_state = {0};
     694          39 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, buffer, &buffer_state );
     695          39 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     696           6 :         FD_LOG_WARNING(( "Bpf loader state read for buffer account failed" )); // custom log
     697           6 :         return err;
     698           6 :       }
     699             : 
     700          33 :       if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_uninitialized( &buffer_state ) ) ) {
     701           0 :         fd_log_collector_msg_literal( instr_ctx, "Buffer account is already initialized" );
     702           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
     703           0 :       }
     704             : 
     705          33 :       fd_pubkey_t const * authority_key = &txn_accs[ instr_acc_idxs[ 1UL ] ];
     706             : 
     707          33 :       buffer_state.discriminant                   = fd_bpf_upgradeable_loader_state_enum_buffer;
     708          33 :       buffer_state.inner.buffer.authority_address = (fd_pubkey_t*)authority_key;
     709             : 
     710          33 :       err = fd_bpf_loader_v3_program_set_state( instr_ctx, 0UL, &buffer_state );
     711          33 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     712           3 :         FD_LOG_WARNING(( "Bpf loader state write for buffer account failed" )); // custom log
     713           3 :         return err;
     714           3 :       }
     715             : 
     716          39 :       } FD_BORROWED_ACCOUNT_DROP( buffer );
     717             : 
     718          30 :       break;
     719          39 :     }
     720             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L494-L525 */
     721          48 :     case fd_bpf_upgradeable_loader_program_instruction_enum_write: {
     722          48 :       if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 2U ) ) ) {
     723           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     724           0 :       }
     725             : 
     726         192 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, buffer ) {
     727             : 
     728          48 :       fd_bpf_upgradeable_loader_state_t loader_state = {0};
     729          48 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, buffer, &loader_state );
     730          48 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     731           0 :         FD_LOG_WARNING(( "Bpf loader state read for buffer account failed" ));
     732           0 :         return err;
     733           0 :       }
     734             : 
     735          48 :       if( fd_bpf_upgradeable_loader_state_is_buffer( &loader_state ) ) {
     736          48 :         if( FD_UNLIKELY( !loader_state.inner.buffer.authority_address ) ) {
     737           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer is immutable" );
     738           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     739           0 :         }
     740          48 :         fd_pubkey_t const * authority_key = &txn_accs[ instr_acc_idxs[ 1UL ] ];
     741          48 :         if( FD_UNLIKELY( memcmp( loader_state.inner.buffer.authority_address, authority_key, sizeof(fd_pubkey_t) ) ) ) {
     742           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect buffer authority provided" );
     743           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     744           0 :         }
     745          48 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL ) ) ) {
     746           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer authority did not sign" );
     747           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     748           0 :         }
     749          48 :       } else {
     750           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid Buffer account" );
     751           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     752           0 :       }
     753             : 
     754          48 :       } FD_BORROWED_ACCOUNT_DROP( buffer );
     755             : 
     756          48 :       ulong program_data_offset = fd_ulong_sat_add( BUFFER_METADATA_SIZE, instruction.inner.write.offset );
     757          48 :       err = write_program_data( instr_ctx,
     758          48 :                                 0UL,
     759          48 :                                 program_data_offset,
     760          48 :                                 instruction.inner.write.bytes,
     761          48 :                                 instruction.inner.write.bytes_len );
     762          48 :       if( FD_UNLIKELY( err ) ) {
     763           3 :         return err;
     764           3 :       }
     765             : 
     766          45 :       break;
     767          48 :     }
     768             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L526-L702 */
     769         210 :     case fd_bpf_upgradeable_loader_program_instruction_enum_deploy_with_max_data_len: {
     770             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L527-L541 */
     771         210 :       if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 4U ) ) ) {
     772           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     773           0 :       }
     774         210 :       fd_pubkey_t const * payer_key       = &txn_accs[ instr_acc_idxs[ 0UL ] ];
     775         210 :       fd_pubkey_t const * programdata_key = &txn_accs[ instr_acc_idxs[ 1UL ] ];
     776             :       /* rent is accessed directly from the epoch bank and the clock from the
     777             :         slot context. However, a check must be done to make sure that the
     778             :         sysvars are correctly included in the set of transaction accounts. */
     779         210 :       err = fd_check_sysvar_account( instr_ctx, 4UL, &fd_sysvar_rent_id );
     780         210 :       if( FD_UNLIKELY( err ) ) {
     781           0 :         return err;
     782           0 :       }
     783         210 :       err = fd_check_sysvar_account( instr_ctx, 5UL, &fd_sysvar_clock_id );
     784         210 :       if( FD_UNLIKELY( err ) ) {
     785           0 :         return err;
     786           0 :       }
     787             : 
     788         210 :       fd_sol_sysvar_clock_t clock = {0};
     789         210 :       if( FD_UNLIKELY( !fd_sysvar_clock_read( &clock, instr_ctx->slot_ctx ) ) ) {
     790           0 :         return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR;
     791           0 :       }
     792         210 :       if( fd_account_check_num_insn_accounts( instr_ctx, 8U ) ) {
     793           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     794           0 :       }
     795         210 :       fd_pubkey_t const * authority_key = &txn_accs[ instr_acc_idxs[ 7UL ] ];
     796             : 
     797             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L542-L560 */
     798             :       /* Verify Program account */
     799             : 
     800         210 :       fd_bpf_upgradeable_loader_state_t loader_state   = {0};
     801         210 :       fd_pubkey_t *                     new_program_id = NULL;
     802         210 :       fd_epoch_bank_t *                 epoch_bank     = fd_exec_epoch_ctx_epoch_bank( instr_ctx->slot_ctx->epoch_ctx );
     803         210 :       fd_rent_t       *                 rent           = &epoch_bank->rent;
     804         840 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 2UL, program ) {
     805             : 
     806         210 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, program, &loader_state );
     807         210 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     808           0 :         FD_LOG_WARNING(( "Bpf state read for program account failed" ));
     809           0 :         return err;
     810           0 :       }
     811         210 :       if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_uninitialized( &loader_state ) ) ) {
     812           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account already initialized" );
     813           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
     814           0 :       }
     815         210 :       if( FD_UNLIKELY( program->const_meta->dlen<SIZE_OF_PROGRAM ) ) {
     816           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account too small" );
     817           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     818           0 :       }
     819         210 :       if( FD_UNLIKELY( program->const_meta->info.lamports<fd_rent_exempt_minimum_balance( rent,
     820         210 :                                                                                            program->const_meta->dlen ) ) ) {
     821           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not rent-exempt" );
     822           0 :         return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT;
     823           0 :       }
     824         210 :       new_program_id = program->pubkey;
     825             : 
     826         210 :       } FD_BORROWED_ACCOUNT_DROP( program );
     827             : 
     828             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L561-L600 */
     829             :       /* Verify Buffer account */
     830             : 
     831         210 :       fd_borrowed_account_t * buffer = NULL;
     832         210 :       err = fd_instr_borrowed_account_view_idx( instr_ctx, 3UL, &buffer );
     833         210 :       if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     834           0 :         FD_LOG_WARNING(( "Borrowed account lookup for buffer account failed" ));
     835           0 :         return err;
     836           0 :       }
     837             : 
     838         210 :       fd_pubkey_t * buffer_key = NULL;
     839         210 :       ulong buffer_data_offset = 0UL;
     840         210 :       ulong buffer_data_len    = 0UL;
     841         210 :       ulong programdata_len    = 0UL;
     842         840 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 3UL, buffer ) {
     843             : 
     844         210 :       fd_bpf_upgradeable_loader_state_t buffer_state = {0};
     845         210 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, buffer, &buffer_state );
     846         210 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     847          42 :         FD_LOG_WARNING(( "Bincode decode failed for buffer account loader state" ));
     848          42 :         return err;
     849          42 :       }
     850             : 
     851         168 :       if( fd_bpf_upgradeable_loader_state_is_buffer( &buffer_state ) ) {
     852         168 :         if( FD_UNLIKELY( (authority_key==NULL) != (buffer_state.inner.buffer.authority_address == NULL) ||
     853         168 :             (authority_key!=NULL && memcmp( buffer_state.inner.buffer.authority_address, authority_key, sizeof(fd_pubkey_t) ) ) ) ) {
     854           3 :           fd_log_collector_msg_literal( instr_ctx, "Buffer and upgrade authority don't match" );
     855           3 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     856           3 :         }
     857         165 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 7UL ) ) ) {
     858           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
     859           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     860           0 :         }
     861         165 :       } else {
     862           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid Buffer account" );
     863           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     864           0 :       }
     865         165 :       buffer_key         = buffer->pubkey;
     866         165 :       buffer_data_offset = BUFFER_METADATA_SIZE;
     867         165 :       buffer_data_len    = fd_ulong_sat_sub( buffer->const_meta->dlen, buffer_data_offset );
     868             :       /* UpgradeableLoaderState::size_of_program_data( max_data_len ) */
     869         165 :       programdata_len    = fd_ulong_sat_add( PROGRAMDATA_METADATA_SIZE,
     870         165 :                                              instruction.inner.deploy_with_max_data_len.max_data_len );
     871             : 
     872         165 :       if( FD_UNLIKELY( buffer->const_meta->dlen<BUFFER_METADATA_SIZE || buffer_data_len==0UL ) ) {
     873           3 :         fd_log_collector_msg_literal( instr_ctx, "Buffer account too small" );
     874           3 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     875           3 :       }
     876             : 
     877         162 :       if( FD_UNLIKELY( instruction.inner.deploy_with_max_data_len.max_data_len<buffer_data_len ) ) {
     878           0 :         fd_log_collector_msg_literal( instr_ctx, "Max data length is too small to hold Buffer data" );
     879           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     880           0 :       }
     881             : 
     882         162 :       if( FD_UNLIKELY( programdata_len>MAX_PERMITTED_DATA_LENGTH ) ) {
     883           0 :         fd_log_collector_msg_literal( instr_ctx, "Max data length is too large" );
     884           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     885           0 :       }
     886             : 
     887         210 :       } FD_BORROWED_ACCOUNT_DROP( buffer );
     888             : 
     889             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L602-L608 */
     890             :       /* Create ProgramData account */
     891             : 
     892         162 :       fd_pubkey_t derived_address[ 1UL ];
     893         162 :       uchar * seeds[ 1UL ];
     894         162 :       seeds[ 0UL ]    = (uchar *)new_program_id;
     895         162 :       ulong seed_sz   = sizeof(fd_pubkey_t);
     896         162 :       uchar bump_seed = 0;
     897         162 :       err = fd_pubkey_find_program_address( program_id, 1UL, seeds, &seed_sz, derived_address,
     898         162 :                                             &bump_seed, &instr_ctx->txn_ctx->custom_err );
     899         162 :       if( FD_UNLIKELY( err ) ) {
     900             :         /* TODO: We should handle these errors more gracefully instead of just killing the client (e.g. excluding the transaction
     901             :            from the block). */
     902           0 :         FD_LOG_ERR(( "Unable to find a viable program address bump seed" )); // Solana panics, error code is undefined
     903           0 :         return err;
     904           0 :       }
     905         162 :       if( FD_UNLIKELY( memcmp( derived_address, programdata_key, sizeof(fd_pubkey_t) ) ) ) {
     906           0 :         fd_log_collector_msg_literal( instr_ctx, "ProgramData address is not derived" );
     907           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     908           0 :       }
     909             : 
     910             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L610-L627 */
     911             :       /* Drain the Buffer account to payer before paying for programdata account */
     912         648 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, payer  ) {
     913         648 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 3UL, buffer ) {
     914             : 
     915         162 :       err = fd_account_checked_add_lamports( instr_ctx, 0UL, buffer->const_meta->info.lamports );
     916         162 :       if( FD_UNLIKELY( err ) ) {
     917           0 :         return err;
     918           0 :       }
     919         162 :       err = fd_account_set_lamports( instr_ctx, 3UL, 0UL );
     920         162 :       if( FD_UNLIKELY( err ) ) {
     921           0 :         return err;
     922           0 :       }
     923             : 
     924         162 :       } FD_BORROWED_ACCOUNT_DROP( buffer );
     925         162 :       } FD_BORROWED_ACCOUNT_DROP( payer  );
     926             : 
     927             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L628-L642 */
     928             :       /* Pass an extra account to avoid the overly strict unbalanced instruction error */
     929             :       /* Invoke the system program to create the new account */
     930         162 :       fd_system_program_instruction_create_account_t create_acct = {0};
     931         162 :       create_acct.lamports = fd_rent_exempt_minimum_balance( rent, programdata_len );
     932         162 :       if( !create_acct.lamports ) {
     933           0 :         create_acct.lamports = 1UL;
     934           0 :       }
     935         162 :       create_acct.space = programdata_len;
     936         162 :       create_acct.owner = instr_ctx->instr->program_id_pubkey;
     937             : 
     938         162 :       fd_system_program_instruction_t instr = {0};
     939         162 :       instr.discriminant         = fd_system_program_instruction_enum_create_account;
     940         162 :       instr.inner.create_account = create_acct;
     941             : 
     942         162 :       fd_vm_rust_account_meta_t * acct_metas = (fd_vm_rust_account_meta_t*)
     943         162 :                                                 fd_valloc_malloc( valloc,
     944         162 :                                                                   FD_VM_RUST_ACCOUNT_META_ALIGN,
     945         162 :                                                                   3UL * sizeof(fd_vm_rust_account_meta_t) );
     946         162 :       fd_native_cpi_create_account_meta( payer_key,       1U, 1U, &acct_metas[ 0UL ] );
     947         162 :       fd_native_cpi_create_account_meta( programdata_key, 1U, 1U, &acct_metas[ 1UL ] );
     948         162 :       fd_native_cpi_create_account_meta( buffer_key,      0U, 1U, &acct_metas[ 2UL ] );
     949             : 
     950             :       /* caller_program_id == program_id */
     951         162 :       fd_pubkey_t signers[ 1UL ];
     952         162 :       err = fd_pubkey_derive_pda( program_id, 1UL, seeds, &seed_sz, &bump_seed, signers, &instr_ctx->txn_ctx->custom_err );
     953         162 :       if( FD_UNLIKELY( err ) ) {
     954           0 :         return err;
     955           0 :       }
     956             : 
     957         162 :       err = fd_native_cpi_execute_system_program_instruction( instr_ctx, &instr, acct_metas, 3UL, signers, 1UL );
     958         162 :       if( FD_UNLIKELY( err ) ) {
     959           0 :         return err;
     960           0 :       }
     961             : 
     962             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L644-L665 */
     963             :       /* Load and verify the program bits */
     964         648 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 3UL, buffer ) {
     965         162 :       if( FD_UNLIKELY( buffer_data_offset>buffer->const_meta->dlen ) ) {
     966           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     967           0 :       }
     968             : 
     969         162 :       const uchar * buffer_data = buffer->const_data + buffer_data_offset;
     970             : 
     971         162 :       err = fd_deploy_program( instr_ctx, buffer_data, buffer_data_len, fd_spad_virtual( instr_ctx->txn_ctx->spad ) );
     972         162 :       if( FD_UNLIKELY( err ) ) {
     973         162 :         return err;
     974         162 :       }
     975             : 
     976         162 :       } FD_BORROWED_ACCOUNT_DROP( buffer );
     977             : 
     978             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L667-L691 */
     979             :       /* Update the ProgramData account and record the program bits */
     980             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L669-L674 */
     981           0 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 1UL, programdata ) {
     982             : 
     983           0 :       fd_bpf_upgradeable_loader_state_t programdata_loader_state = {
     984           0 :         .discriminant = fd_bpf_upgradeable_loader_state_enum_program_data,
     985           0 :         .inner.program_data = {
     986           0 :           .slot                      = clock.slot,
     987           0 :           .upgrade_authority_address = (fd_pubkey_t *)authority_key,
     988           0 :         },
     989           0 :       };
     990           0 :       err = fd_bpf_loader_v3_program_set_state( instr_ctx, 1UL, &programdata_loader_state );
     991           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
     992           0 :         FD_LOG_WARNING(( "Bpf state write for programdata account failed" ));
     993           0 :         return err;
     994           0 :       }
     995             : 
     996             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L675-L689 */
     997           0 :       if( FD_UNLIKELY( PROGRAMDATA_METADATA_SIZE+buffer_data_len>programdata->const_meta->dlen ) ) {
     998           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     999           0 :       }
    1000           0 :       if( FD_UNLIKELY( buffer_data_offset>buffer->const_meta->dlen ) ) {
    1001           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1002           0 :       }
    1003             : 
    1004           0 :       uchar * programdata_data = NULL;
    1005           0 :       ulong   programdata_dlen = 0UL;
    1006           0 :       err = fd_account_get_data_mut( instr_ctx, 1UL, &programdata_data, &programdata_dlen );
    1007           0 :       if( FD_UNLIKELY( err ) ) {
    1008           0 :         return err;
    1009           0 :       }
    1010             : 
    1011           0 :       uchar *   dst_slice = programdata_data + PROGRAMDATA_METADATA_SIZE;
    1012           0 :       ulong dst_slice_len = buffer_data_len;
    1013             : 
    1014           0 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 3UL, buffer ) {
    1015             : 
    1016           0 :       if( FD_UNLIKELY( buffer_data_offset>buffer->const_meta->dlen ) ) {
    1017           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1018           0 :       }
    1019           0 :       const uchar * src_slice = buffer->const_data + buffer_data_offset;
    1020           0 :       fd_memcpy( dst_slice, src_slice, dst_slice_len );
    1021             :       /* Update buffer data length.
    1022             :          BUFFER_METADATA_SIZE == UpgradeableLoaderState::size_of_buffer(0) */
    1023           0 :       err = fd_account_set_data_length( instr_ctx, 3UL, BUFFER_METADATA_SIZE );
    1024           0 :       if( FD_UNLIKELY( err ) ) {
    1025           0 :         return err;
    1026           0 :       }
    1027             : 
    1028           0 :       } FD_BORROWED_ACCOUNT_DROP( buffer      );
    1029           0 :       } FD_BORROWED_ACCOUNT_DROP( programdata );
    1030             : 
    1031             :       /* Max msg_sz: 19 - 2 + 45 = 62 < 127 => we can use printf */
    1032           0 :       fd_log_collector_printf_dangerous_max_127( instr_ctx, "Deployed program %s", FD_BASE58_ENC_32_ALLOCA( program_id ) );
    1033             : 
    1034             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L692-L699 */
    1035             :       /* Update the Program account */
    1036             : 
    1037           0 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 2UL, program ) {
    1038             : 
    1039           0 :       loader_state.discriminant = fd_bpf_upgradeable_loader_state_enum_program;
    1040           0 :       fd_memcpy( &loader_state.inner.program.programdata_address, programdata_key, sizeof(fd_pubkey_t) );
    1041           0 :       err = fd_bpf_loader_v3_program_set_state( instr_ctx, 2UL, &loader_state );
    1042           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1043           0 :         FD_LOG_WARNING(( "Bincode encode for program account failed" ));
    1044           0 :         return err;
    1045           0 :       }
    1046           0 :       err = fd_account_set_executable( instr_ctx, 2UL, 1 );
    1047           0 :       if( FD_UNLIKELY( err ) ) {
    1048           0 :         FD_LOG_WARNING(( "Couldn't set account to executable" ));
    1049           0 :         return err;
    1050           0 :       }
    1051             : 
    1052           0 :       FD_LOG_INFO(( "Program deployed %s", FD_BASE58_ENC_32_ALLOCA( program->pubkey ) ));
    1053             : 
    1054           0 :       } FD_BORROWED_ACCOUNT_DROP( program );
    1055             : 
    1056           0 :       break;
    1057           0 :     }
    1058             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L703-L891 */
    1059         633 :     case fd_bpf_upgradeable_loader_program_instruction_enum_upgrade: {
    1060             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L704-L714 */
    1061         633 :       if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 3U ) ) ) {
    1062           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1063           0 :       }
    1064         633 :       fd_pubkey_t const * programdata_key = &txn_accs[ instr_acc_idxs[ 0UL ] ];
    1065             : 
    1066             :       /* rent is accessed directly from the epoch bank and the clock from the
    1067             :         slot context. However, a check must be done to make sure that the
    1068             :         sysvars are correctly included in the set of transaction accounts. */
    1069         633 :       err = fd_check_sysvar_account( instr_ctx, 4UL, &fd_sysvar_rent_id );
    1070         633 :       if( FD_UNLIKELY( err ) ) {
    1071           0 :         return err;
    1072           0 :       }
    1073         633 :       err = fd_check_sysvar_account( instr_ctx, 5UL, &fd_sysvar_clock_id );
    1074         633 :       if( FD_UNLIKELY( err ) ) {
    1075           0 :         return err;
    1076           0 :       }
    1077             : 
    1078         633 :       if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 7U ) ) ) {
    1079           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1080           0 :       }
    1081         633 :       fd_pubkey_t const * authority_key = &txn_accs[ instr_acc_idxs[ 6UL ] ];
    1082             : 
    1083             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L716-L745 */
    1084             :       /* Verify Program account */
    1085             : 
    1086        2532 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 1UL, program ) {
    1087             :       
    1088             :       /* https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L758-L765 */
    1089         633 :       if( FD_UNLIKELY( !FD_FEATURE_ACTIVE( instr_ctx->slot_ctx, remove_accounts_executable_flag_checks ) && 
    1090         633 :                        !fd_account_is_executable( program->const_meta ) ) ) {
    1091           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not executable" );
    1092           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_NOT_EXECUTABLE;
    1093           0 :       }
    1094         633 :       if( FD_UNLIKELY( !fd_instr_acc_is_writable( instr_ctx->instr, program->pubkey ) ) ) {
    1095           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not writeable" );
    1096           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1097           0 :       }
    1098         633 :       if( FD_UNLIKELY( memcmp( &program->const_meta->info.owner, program_id, sizeof(fd_pubkey_t) ) ) ) {
    1099           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not owned by loader" );
    1100           0 :         return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
    1101           0 :       }
    1102         633 :       fd_bpf_upgradeable_loader_state_t program_state = {0};
    1103         633 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, program, &program_state );
    1104         633 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1105           0 :         FD_LOG_WARNING(( "Bincode decode for program account failed" ));
    1106           0 :         return err;
    1107           0 :       }
    1108         633 :       if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_is_program( &program_state ) ) ) {
    1109         633 :         if( FD_UNLIKELY( memcmp( &program_state.inner.program.programdata_address, programdata_key, sizeof(fd_pubkey_t) ) ) ) {
    1110           0 :           fd_log_collector_msg_literal( instr_ctx, "Program and ProgramData account mismatch" );
    1111           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1112           0 :         }
    1113         633 :       } else {
    1114           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid Program account" );
    1115           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1116           0 :       }
    1117             : 
    1118         633 :       } FD_BORROWED_ACCOUNT_DROP( program );
    1119             : 
    1120             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L747-L773 */
    1121             :       /* Verify Buffer account */
    1122             : 
    1123         633 :       ulong buffer_lamports    = 0UL;
    1124         633 :       ulong buffer_data_offset = 0UL;
    1125         633 :       ulong buffer_data_len    = 0UL;
    1126             : 
    1127        2532 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 2UL, buffer ) {
    1128             : 
    1129         633 :       fd_bpf_upgradeable_loader_state_t buffer_state = {0};
    1130         633 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, buffer, &buffer_state );
    1131         633 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1132           0 :         FD_LOG_WARNING(( "Bincode decode for buffer account failed" ));
    1133           0 :         return err;
    1134           0 :       }
    1135         633 :       if( fd_bpf_upgradeable_loader_state_is_buffer( &buffer_state ) ) {
    1136         633 :         if( FD_UNLIKELY( (authority_key==NULL) != (buffer_state.inner.buffer.authority_address == NULL) ||
    1137         633 :             (authority_key!=NULL && memcmp( buffer_state.inner.buffer.authority_address, authority_key, sizeof(fd_pubkey_t) ) ) ) ) {
    1138           3 :           fd_log_collector_msg_literal( instr_ctx, "Buffer and upgrade authority don't match" );
    1139           3 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1140           3 :         }
    1141         630 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 6UL ) ) ) {
    1142           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
    1143           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1144           0 :         }
    1145         630 :       } else {
    1146           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid Buffer account" );
    1147           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1148           0 :       }
    1149         630 :       buffer_lamports    = buffer->const_meta->info.lamports;
    1150         630 :       buffer_data_offset = BUFFER_METADATA_SIZE;
    1151         630 :       buffer_data_len    = fd_ulong_sat_sub( buffer->const_meta->dlen, buffer_data_offset );
    1152         630 :       if( FD_UNLIKELY( buffer->const_meta->dlen<BUFFER_METADATA_SIZE || buffer_data_len==0UL ) ) {
    1153          18 :         fd_log_collector_msg_literal( instr_ctx, "Buffer account too small" );
    1154          18 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1155          18 :       }
    1156             : 
    1157         633 :       } FD_BORROWED_ACCOUNT_DROP( buffer );
    1158             : 
    1159             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L775-L823 */
    1160             :       /* Verify ProgramData account */
    1161             : 
    1162         612 :       ulong                             programdata_data_offset      = PROGRAMDATA_METADATA_SIZE;
    1163         612 :       fd_bpf_upgradeable_loader_state_t programdata_state            = {0};
    1164         612 :       fd_sol_sysvar_clock_t             clock                        = {0};
    1165         612 :       ulong                             programdata_balance_required = 0UL;
    1166             : 
    1167        2448 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, programdata ) {
    1168             : 
    1169         612 :       fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( instr_ctx->slot_ctx->epoch_ctx );
    1170         612 :       fd_rent_t       * rent       = &epoch_bank->rent;
    1171             : 
    1172         612 :       programdata_balance_required = fd_ulong_max( 1UL, fd_rent_exempt_minimum_balance( rent, programdata->const_meta->dlen ) );
    1173             : 
    1174         612 :       if( FD_UNLIKELY( programdata->const_meta->dlen<fd_ulong_sat_add( PROGRAMDATA_METADATA_SIZE, buffer_data_len ) ) ) {
    1175           0 :         fd_log_collector_msg_literal( instr_ctx, "ProgramData account not large enough" );
    1176           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1177           0 :       }
    1178         612 :       if( FD_UNLIKELY( fd_ulong_sat_add( programdata->const_meta->info.lamports, buffer_lamports )<programdata_balance_required ) ) {
    1179           0 :         fd_log_collector_msg_literal( instr_ctx, "Buffer account balance too low to fund upgrade" );
    1180           0 :         return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    1181           0 :       }
    1182         612 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, programdata, &programdata_state );
    1183         612 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1184           0 :         FD_LOG_WARNING(( "Bincode decode for programdata account failed" ));
    1185           0 :         return err;
    1186           0 :       }
    1187             : 
    1188         612 :       if( FD_UNLIKELY( !fd_sysvar_clock_read( &clock, instr_ctx->slot_ctx ) ) ) {
    1189           0 :         return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR;
    1190           0 :       }
    1191             : 
    1192         612 :       if( fd_bpf_upgradeable_loader_state_is_program_data( &programdata_state ) ) {
    1193         612 :         if( FD_UNLIKELY( clock.slot==programdata_state.inner.program_data.slot ) ) {
    1194           0 :           fd_log_collector_msg_literal( instr_ctx, "Program was deployed in this block already" );
    1195           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1196           0 :         }
    1197         612 :         if( FD_UNLIKELY( !programdata_state.inner.program_data.upgrade_authority_address ) ) {
    1198           0 :           fd_log_collector_msg_literal( instr_ctx, "Prrogram not upgradeable" );
    1199           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1200           0 :         }
    1201         612 :         if( FD_UNLIKELY( memcmp( programdata_state.inner.program_data.upgrade_authority_address, authority_key, sizeof(fd_pubkey_t) ) ) ) {
    1202           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect upgrade authority provided" );
    1203           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1204           0 :         }
    1205         612 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 6UL ) ) ) {
    1206           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
    1207           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1208           0 :         }
    1209         612 :       } else {
    1210           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid ProgramData account" );
    1211           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1212           0 :       }
    1213             : 
    1214         612 :       } FD_BORROWED_ACCOUNT_DROP( programdata );
    1215             : 
    1216             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L825-L845 */
    1217             :       /* Load and verify the program bits */
    1218             : 
    1219        2448 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 2UL, buffer ) {
    1220             : 
    1221         612 :       if( FD_UNLIKELY( buffer_data_offset>buffer->const_meta->dlen ) ) {
    1222           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1223           0 :       }
    1224             : 
    1225         612 :       const uchar * buffer_data = buffer->const_data + buffer_data_offset;
    1226         612 :       err = fd_deploy_program( instr_ctx, buffer_data, buffer_data_len, fd_spad_virtual( instr_ctx->txn_ctx->spad ) );
    1227         612 :       if( FD_UNLIKELY( err ) ) {
    1228         576 :         return err;
    1229         576 :       }
    1230             : 
    1231         612 :       } FD_BORROWED_ACCOUNT_DROP( buffer );
    1232             : 
    1233             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L846-L874 */
    1234             :       /* Update the ProgramData account, record the upgraded data, and zero the rest */
    1235             : 
    1236         144 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, programdata ) {
    1237             : 
    1238          36 :       programdata_state.discriminant                                 = fd_bpf_upgradeable_loader_state_enum_program_data;
    1239          36 :       programdata_state.inner.program_data.slot                      = clock.slot;
    1240          36 :       programdata_state.inner.program_data.upgrade_authority_address = (fd_pubkey_t *)authority_key;
    1241          36 :       err = fd_bpf_loader_v3_program_set_state( instr_ctx, 0UL, &programdata_state );
    1242          36 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1243           0 :         FD_LOG_WARNING(( "Bpf state write for programdata account failed" ));
    1244           0 :         return err;
    1245           0 :       }
    1246             : 
    1247             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L846-L875 */
    1248             :       /* We want to copy over the data and zero out the rest */
    1249          36 :       if( FD_UNLIKELY( programdata_data_offset+buffer_data_len>programdata->const_meta->dlen ) ) {
    1250           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1251           0 :       }
    1252             : 
    1253          36 :       uchar * programdata_data = NULL;
    1254          36 :       ulong   programdata_dlen = 0UL;
    1255          36 :       err = fd_account_get_data_mut( instr_ctx, 0UL, &programdata_data, &programdata_dlen );
    1256          36 :       if( FD_UNLIKELY( err ) ) {
    1257           0 :         return err;
    1258           0 :       }
    1259          36 :       uchar * dst_slice     = programdata_data + programdata_data_offset;
    1260          36 :       ulong   dst_slice_len = buffer_data_len;
    1261             : 
    1262         144 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 2UL, buffer ) {
    1263             : 
    1264          36 :       if( FD_UNLIKELY( buffer_data_offset>buffer->const_meta->dlen ) ){
    1265           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1266           0 :       }
    1267             : 
    1268          36 :       const uchar * src_slice = buffer->const_data + buffer_data_offset;
    1269          36 :       fd_memcpy( dst_slice, src_slice, dst_slice_len );
    1270          36 :       fd_memset( dst_slice + dst_slice_len, 0, programdata->const_meta->dlen - programdata_data_offset - dst_slice_len );
    1271             : 
    1272          36 :       } FD_BORROWED_ACCOUNT_DROP( buffer );
    1273             : 
    1274             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L876-L891 */
    1275             :       /* Fund ProgramData to rent-exemption, spill the rest */
    1276         144 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 2UL, buffer ) {
    1277         144 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 3UL, spill  ) {
    1278             : 
    1279          36 :       ulong spill_addend = fd_ulong_sat_sub( fd_ulong_sat_add( programdata->const_meta->info.lamports, buffer_lamports ),
    1280          36 :                                              programdata_balance_required );
    1281          36 :       err = fd_account_checked_add_lamports( instr_ctx, 3UL, spill_addend );
    1282          36 :       if( FD_UNLIKELY( err ) ) {
    1283          27 :         return err;
    1284          27 :       }
    1285           9 :       err = fd_account_set_lamports( instr_ctx, 2UL, 0UL );
    1286           9 :       if( FD_UNLIKELY( err ) ) {
    1287           0 :         return err;
    1288           0 :       }
    1289           9 :       err = fd_account_set_lamports( instr_ctx, 0UL, programdata_balance_required );
    1290           9 :       if( FD_UNLIKELY( err ) ) {
    1291           0 :         return err;
    1292           0 :       }
    1293             : 
    1294             :       /* Buffer account set_data_length */
    1295           9 :       err = fd_account_set_data_length( instr_ctx, 2UL, BUFFER_METADATA_SIZE );
    1296           9 :       if( FD_UNLIKELY( err ) ) {
    1297           0 :         return err;
    1298           0 :       }
    1299             : 
    1300          36 :       } FD_BORROWED_ACCOUNT_DROP( spill       );
    1301          36 :       } FD_BORROWED_ACCOUNT_DROP( buffer      );
    1302          36 :       } FD_BORROWED_ACCOUNT_DROP( programdata );
    1303             : 
    1304             :       /* Max msg_sz: 19 - 2 + 45 = 62 < 127 => we can use printf */
    1305             :       //TODO: this is likely the incorrect program_id, do we have new_program_id?
    1306           9 :       fd_log_collector_printf_dangerous_max_127( instr_ctx, "Upgraded program %s", FD_BASE58_ENC_32_ALLOCA( program_id ) );
    1307             : 
    1308           0 :       break;
    1309           9 :     }
    1310             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L893-L957 */
    1311          30 :     case fd_bpf_upgradeable_loader_program_instruction_enum_set_authority: {
    1312          30 :       if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 2U ) ) ) {
    1313           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1314           0 :       }
    1315             : 
    1316         120 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, account ) {
    1317             : 
    1318          30 :       fd_pubkey_t const * present_authority_key = &txn_accs[ instr_acc_idxs[ 1UL ] ];
    1319          30 :       fd_pubkey_t *       new_authority         = NULL;
    1320          30 :       if( FD_UNLIKELY( instr_ctx->instr->acct_cnt>=3UL ) ) {
    1321          30 :         new_authority = (fd_pubkey_t *)&txn_accs[ instr_acc_idxs[ 2UL ] ];
    1322          30 :       }
    1323             : 
    1324          30 :       fd_bpf_upgradeable_loader_state_t account_state = {0};
    1325          30 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, account, &account_state );
    1326          30 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1327           0 :         FD_LOG_WARNING(( "Bincode decode for account failed" ));
    1328           0 :         return err;
    1329           0 :       }
    1330             : 
    1331          30 :       if( fd_bpf_upgradeable_loader_state_is_buffer( &account_state ) ) {
    1332          15 :         if( FD_UNLIKELY( !new_authority ) ) {
    1333           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer authority is not optional" );
    1334           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1335           0 :         }
    1336          15 :         if( FD_UNLIKELY( !account_state.inner.buffer.authority_address ) ) {
    1337           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer is immutable" );
    1338           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1339           0 :         }
    1340          15 :         if( FD_UNLIKELY( memcmp( account_state.inner.buffer.authority_address, present_authority_key, sizeof(fd_pubkey_t) ) ) ) {
    1341           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect buffer authority provided" );
    1342           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1343           0 :         }
    1344          15 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL ) ) ) {
    1345           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer authority did not sign" );
    1346           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1347           0 :         }
    1348          15 :         account_state.inner.buffer.authority_address = new_authority;
    1349          15 :         err = fd_bpf_loader_v3_program_set_state( instr_ctx, 0UL, &account_state );
    1350          15 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1351           0 :           FD_LOG_WARNING(( "Bpf state write for account failed" ));
    1352           0 :           return err;
    1353           0 :         }
    1354          15 :       } else if( fd_bpf_upgradeable_loader_state_is_program_data( &account_state ) ) {
    1355          15 :         if( FD_UNLIKELY( !account_state.inner.program_data.upgrade_authority_address ) ) {
    1356           0 :           fd_log_collector_msg_literal( instr_ctx, "Program not upgradeable" );
    1357           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1358           0 :         }
    1359          15 :         if( FD_UNLIKELY( memcmp( account_state.inner.program_data.upgrade_authority_address, present_authority_key, sizeof(fd_pubkey_t) ) ) ) {
    1360           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect upgrade authority provided" );
    1361           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1362           0 :         }
    1363          15 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL ) ) ) {
    1364           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
    1365           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1366           0 :         }
    1367          15 :         account_state.inner.program_data.upgrade_authority_address = new_authority;
    1368          15 :         err = fd_bpf_loader_v3_program_set_state( instr_ctx, 0UL, &account_state );
    1369          15 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1370           0 :           FD_LOG_WARNING(( "Bincode encode for program data account failed" ));
    1371           0 :           return err;
    1372           0 :         }
    1373          15 :       } else {
    1374           0 :         fd_log_collector_msg_literal( instr_ctx, "Account does not support authorities" );
    1375           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1376           0 :       }
    1377             : 
    1378             :       /* Max msg_sz: 16 - 2 + 45 = 59 < 127 => we can use printf */
    1379          30 :       fd_log_collector_printf_dangerous_max_127( instr_ctx, "New authority %s", FD_BASE58_ENC_32_ALLOCA( new_authority ) );
    1380             : 
    1381          30 :       } FD_BORROWED_ACCOUNT_DROP( account );
    1382             : 
    1383          30 :       break;
    1384          30 :     }
    1385             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L958-L1030 */
    1386          51 :     case fd_bpf_upgradeable_loader_program_instruction_enum_set_authority_checked: {
    1387          51 :       if( !FD_FEATURE_ACTIVE( instr_ctx->slot_ctx, enable_bpf_loader_set_authority_checked_ix ) ) {
    1388          30 :         return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    1389          30 :       }
    1390             : 
    1391          21 :       if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 3U ) ) ) {
    1392           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1393           0 :       }
    1394             : 
    1395          84 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, account ) {
    1396             : 
    1397          21 :       fd_pubkey_t const * present_authority_key = &txn_accs[ instr_acc_idxs[ 1UL ] ];
    1398          21 :       fd_pubkey_t const * new_authority_key     = &txn_accs[ instr_acc_idxs[ 2UL ] ];
    1399             : 
    1400          21 :       fd_bpf_upgradeable_loader_state_t account_state = {0};
    1401          21 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, account, &account_state );
    1402          21 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1403           0 :         FD_LOG_WARNING(( "Bincode decode for account failed" ));
    1404           0 :         return err;
    1405           0 :       }
    1406             : 
    1407          21 :       if( fd_bpf_upgradeable_loader_state_is_buffer( &account_state ) ) {
    1408          12 :         if( FD_UNLIKELY( !account_state.inner.buffer.authority_address ) ) {
    1409           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer is immutable" );
    1410           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1411           0 :         }
    1412          12 :         if( FD_UNLIKELY( memcmp( account_state.inner.buffer.authority_address, present_authority_key, sizeof(fd_pubkey_t) ) ) ) {
    1413           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect buffer authority provided" );
    1414           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1415           0 :         }
    1416          12 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL ) ) ) {
    1417           0 :           fd_log_collector_msg_literal( instr_ctx, "Buffer authority did not sign" );
    1418           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1419           0 :         }
    1420          12 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 2UL ) ) ) {
    1421           0 :           fd_log_collector_msg_literal( instr_ctx, "New authority did not sign" );
    1422           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1423           0 :         }
    1424          12 :         account_state.inner.buffer.authority_address = (fd_pubkey_t*)new_authority_key;
    1425          12 :         err = fd_bpf_loader_v3_program_set_state( instr_ctx, 0UL, &account_state );
    1426          12 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1427           0 :           FD_LOG_WARNING(( "Bincode encode for buffer account failed" ));
    1428           0 :           return err;
    1429           0 :         }
    1430          12 :       } else if( fd_bpf_upgradeable_loader_state_is_program_data( &account_state ) ) {
    1431           9 :         if( FD_UNLIKELY( !account_state.inner.program_data.upgrade_authority_address ) ) {
    1432           0 :           fd_log_collector_msg_literal( instr_ctx, "Program not upgradeable" );
    1433           0 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1434           0 :         }
    1435           9 :         if( FD_UNLIKELY( memcmp( account_state.inner.program_data.upgrade_authority_address, present_authority_key, sizeof(fd_pubkey_t) ) ) ) {
    1436           0 :           fd_log_collector_msg_literal( instr_ctx, "Incorrect upgrade authority provided" );
    1437           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
    1438           0 :         }
    1439           9 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 1UL ) ) ) {
    1440           0 :           fd_log_collector_msg_literal( instr_ctx, "Upgrade authority did not sign" );
    1441           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1442           0 :         }
    1443           9 :         if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( instr_ctx->instr, 2UL ) ) ) {
    1444           0 :           fd_log_collector_msg_literal( instr_ctx, "New authority did not sign" );
    1445           0 :           return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1446           0 :         }
    1447           9 :         account_state.inner.program_data.upgrade_authority_address = (fd_pubkey_t*)new_authority_key;
    1448           9 :         err = fd_bpf_loader_v3_program_set_state( instr_ctx, 0UL, &account_state );
    1449           9 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1450           0 :           FD_LOG_WARNING(( "Bpf state wr encode for program data account failed" ));
    1451           0 :           return err;
    1452           0 :         }
    1453           9 :       } else {
    1454           0 :         fd_log_collector_msg_literal( instr_ctx, "Account does not support authorities" );
    1455           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1456           0 :       }
    1457             : 
    1458             :       /* Max msg_sz: 16 - 2 + 45 = 59 < 127 => we can use printf */
    1459          21 :       fd_log_collector_printf_dangerous_max_127( instr_ctx, "New authority %s", FD_BASE58_ENC_32_ALLOCA( new_authority_key ) );
    1460             : 
    1461          21 :       } FD_BORROWED_ACCOUNT_DROP( account );
    1462             : 
    1463          21 :       break;
    1464          21 :     }
    1465             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1031-L1134 */
    1466          54 :     case fd_bpf_upgradeable_loader_program_instruction_enum_close: {
    1467             : 
    1468             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1032-L1046 */
    1469          54 :       if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 2U ) ) ) {
    1470           0 :         return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1471           0 :       }
    1472          54 :       if( FD_UNLIKELY( instr_acc_idxs[ 0UL ]==instr_acc_idxs[ 1UL ] ) ) {
    1473           0 :         fd_log_collector_msg_literal( instr_ctx, "Recipient is the same as the account being closed" );
    1474           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1475           0 :       }
    1476             : 
    1477         216 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, close_account ) {
    1478             : 
    1479          54 :       fd_pubkey_t * close_key = close_account->pubkey;
    1480          54 :       fd_bpf_upgradeable_loader_state_t close_account_state = {0};
    1481          54 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, close_account, &close_account_state );
    1482          54 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1483           0 :         FD_LOG_WARNING(( "Bpf state read for close account failed" ));
    1484           0 :         return err;
    1485           0 :       }
    1486             :       /* Close account set data length */
    1487          54 :       err = fd_account_set_data_length( instr_ctx, 0UL, SIZE_OF_UNINITIALIZED );
    1488          54 :       if( FD_UNLIKELY( err ) ) {
    1489           0 :         return err;
    1490           0 :       }
    1491             : 
    1492             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1049-L1056 */
    1493          54 :       if( fd_bpf_upgradeable_loader_state_is_uninitialized( &close_account_state ) ) {
    1494             : 
    1495          84 :         FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 1UL, recipient_account ) {
    1496             : 
    1497          21 :         err = fd_account_checked_add_lamports( instr_ctx, 1UL, close_account->const_meta->info.lamports );
    1498          21 :         if( FD_UNLIKELY( err ) ) {
    1499           9 :           return err;
    1500           9 :         }
    1501          12 :         err = fd_account_set_lamports( instr_ctx, 0UL, 0UL );
    1502          12 :         if( FD_UNLIKELY( err ) ) {
    1503           0 :           return err;
    1504           0 :         }
    1505             :         /* Max msg_sz: 23 - 2 + 45 = 66 < 127 => we can use printf */
    1506          12 :         fd_log_collector_printf_dangerous_max_127( instr_ctx,
    1507          12 :           "Closed Uninitialized %s", FD_BASE58_ENC_32_ALLOCA( close_key ) );
    1508             : 
    1509          21 :         } FD_BORROWED_ACCOUNT_DROP( recipient_account );
    1510             : 
    1511             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1057-L1068 */
    1512          33 :       } else if( fd_bpf_upgradeable_loader_state_is_buffer( &close_account_state ) ) {
    1513             : 
    1514          24 :         fd_borrowed_account_release_write( close_account );
    1515             : 
    1516          24 :         if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 3U ) ) ) {
    1517           0 :           return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1518           0 :         }
    1519             : 
    1520          24 :         err = common_close_account( close_account_state.inner.buffer.authority_address, instr_ctx, &close_account_state );
    1521          24 :         if( FD_UNLIKELY( err ) ) {
    1522          24 :           return err;
    1523          24 :         }
    1524             :         /* Max msg_sz: 16 - 2 + 45 = 63 < 127 => we can use printf */
    1525           0 :         fd_log_collector_printf_dangerous_max_127( instr_ctx,
    1526           0 :           "Closed Buffer %s", FD_BASE58_ENC_32_ALLOCA( close_key ) );
    1527             : 
    1528             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1069-L1129 */
    1529           9 :       } else if( fd_bpf_upgradeable_loader_state_is_program_data( &close_account_state ) ) {
    1530           9 :         if( FD_UNLIKELY( fd_account_check_num_insn_accounts( instr_ctx, 4U ) ) ) {
    1531           0 :           return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1532           0 :         }
    1533             : 
    1534           9 :         fd_borrowed_account_release_write( close_account );
    1535             : 
    1536          36 :         FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 3UL, program_account ) {
    1537             : 
    1538           9 :         fd_pubkey_t * program_key = program_account->pubkey;
    1539             : 
    1540           9 :         if( FD_UNLIKELY( !fd_instr_acc_is_writable( instr_ctx->instr, program_key ) ) ) {
    1541           0 :           fd_log_collector_msg_literal( instr_ctx, "Program account is not writable" );
    1542           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1543           0 :         }
    1544           9 :         if( FD_UNLIKELY( memcmp( program_account->const_meta->info.owner, program_id, sizeof(fd_pubkey_t) ) ) ) {
    1545           0 :           fd_log_collector_msg_literal( instr_ctx, "Program account not owned by loader" );
    1546           0 :           return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
    1547           0 :         }
    1548           9 :         fd_sol_sysvar_clock_t clock = {0};
    1549           9 :         if( FD_UNLIKELY( !fd_sysvar_clock_read( &clock, instr_ctx->slot_ctx ) ) ) {
    1550           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    1551           0 :         }
    1552           9 :         if( FD_UNLIKELY( clock.slot==close_account_state.inner.program_data.slot ) ) {
    1553           3 :           fd_log_collector_msg_literal( instr_ctx,"Program was deployed in this block already" );
    1554           3 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1555           3 :         }
    1556             : 
    1557           6 :         fd_bpf_upgradeable_loader_state_t program_state = {0};
    1558           6 :         err = fd_bpf_loader_v3_program_get_state( instr_ctx, program_account, &program_state );
    1559           6 :         if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1560           0 :           FD_LOG_WARNING(( "Bpf state read for program account failed" ));
    1561           0 :           return err;
    1562           0 :         }
    1563           6 :         if( fd_bpf_upgradeable_loader_state_is_program( &program_state ) ) {
    1564           6 :           if( FD_UNLIKELY( memcmp( &program_state.inner.program.programdata_address, close_key, sizeof(fd_pubkey_t) ) ) ) {
    1565           0 :             fd_log_collector_msg_literal( instr_ctx,"Program account does not match ProgramData account" );
    1566           0 :             return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1567           0 :           }
    1568           6 :           fd_borrowed_account_release_write( program_account );
    1569             : 
    1570           6 :           err = common_close_account( close_account_state.inner.program_data.upgrade_authority_address,
    1571           6 :                                       instr_ctx,
    1572           6 :                                       &close_account_state );
    1573           6 :           if( FD_UNLIKELY( err ) ) {
    1574           6 :             return err;
    1575           6 :           }
    1576             : 
    1577             :           /* The Agave client updates the account state upon closing an account
    1578             :              in their loaded program cache. Checking for a program can be
    1579             :              checked by checking to see if the programdata account's loader state
    1580             :              is unitialized. The firedancer implementation also removes closed
    1581             :              accounts from the loaded program cache at the end of a slot. Closed
    1582             :              accounts are not checked from the cache, instead the account state
    1583             :              is looked up. */
    1584             : 
    1585           6 :         } else {
    1586           0 :           fd_log_collector_msg_literal( instr_ctx, "Invalid program account" );
    1587           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1588           0 :         }
    1589             : 
    1590             :         /* Max msg_sz: 17 - 2 + 45 = 60 < 127 => we can use printf */
    1591           0 :         fd_log_collector_printf_dangerous_max_127( instr_ctx,
    1592           0 :           "Closed Program %s", FD_BASE58_ENC_32_ALLOCA( close_key ) );
    1593             : 
    1594           9 :         } FD_BORROWED_ACCOUNT_DROP( program_account );
    1595           9 :       } else {
    1596           0 :         fd_log_collector_msg_literal( instr_ctx, "Account does not support closing" );
    1597           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1598           0 :       }
    1599             : 
    1600          54 :       } FD_BORROWED_ACCOUNT_DROP( close_account );
    1601             : 
    1602          12 :       break;
    1603          54 :     }
    1604             :     /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1136-L1294 */
    1605         195 :     case fd_bpf_upgradeable_loader_program_instruction_enum_extend_program: {
    1606             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1137-L1172 */
    1607         195 :       uint additional_bytes = instruction.inner.extend_program.additional_bytes;
    1608         195 :       if( FD_UNLIKELY( additional_bytes==0U ) ) {
    1609           0 :         fd_log_collector_msg_literal( instr_ctx, "Additional bytes must be greater than 0" );
    1610           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    1611           0 :       }
    1612             : 
    1613         780 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 0UL, programdata_account ) {
    1614             : 
    1615         195 :       fd_borrowed_account_t * programdata_account = NULL;
    1616         195 :       err = fd_instr_borrowed_account_modify_idx( instr_ctx, 0UL, 0UL, &programdata_account );
    1617         195 :       if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
    1618           0 :         FD_LOG_WARNING(( "Borrowed account lookup for programdata account failed" ));
    1619           0 :         return err;
    1620           0 :       }
    1621         195 :       fd_pubkey_t * programdata_key = programdata_account->pubkey;
    1622             : 
    1623         195 :       if( FD_UNLIKELY( memcmp( program_id, programdata_account->const_meta->info.owner, sizeof(fd_pubkey_t) ) ) ) {
    1624          21 :         fd_log_collector_msg_literal( instr_ctx, "ProgramData owner is invalid" );
    1625          21 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
    1626          21 :       }
    1627         174 :       if( FD_UNLIKELY( !fd_instr_acc_is_writable( instr_ctx->instr, programdata_key ) ) ) {
    1628           0 :         fd_log_collector_msg_literal( instr_ctx, "ProgramData is not writable" );
    1629           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1630           0 :       }
    1631             : 
    1632         696 :       FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( instr_ctx, 1UL, program_account ) {
    1633             : 
    1634         174 :       if( FD_UNLIKELY( !fd_instr_acc_is_writable( instr_ctx->instr, program_account->pubkey ) ) ) {
    1635           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account is not writable" );
    1636           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1637           0 :       }
    1638         174 :       if( FD_UNLIKELY( memcmp( program_id, program_account->const_meta->info.owner, sizeof(fd_pubkey_t) ) ) ) {
    1639           0 :         fd_log_collector_msg_literal( instr_ctx, "Program account not owned by loader" );
    1640           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
    1641           0 :       }
    1642             : 
    1643             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1172-L1190 */
    1644         174 :       fd_bpf_upgradeable_loader_state_t program_state = {0};
    1645         174 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, program_account, &program_state );
    1646         174 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1647           0 :         FD_LOG_WARNING(( "Bpf state read for program account failed" ));
    1648           0 :         return err;
    1649           0 :       }
    1650         174 :       if( fd_bpf_upgradeable_loader_state_is_program( &program_state ) ) {
    1651         174 :         if( FD_UNLIKELY( memcmp( &program_state.inner.program.programdata_address, programdata_key, sizeof(fd_pubkey_t) ) ) ) {
    1652           0 :           fd_log_collector_msg_literal( instr_ctx, "Program account does not match ProgramData account" );
    1653           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1654           0 :         }
    1655         174 :       } else {
    1656           0 :         fd_log_collector_msg_literal( instr_ctx, "Invalid program account" );
    1657           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1658           0 :       }
    1659             : 
    1660         174 :       } FD_BORROWED_ACCOUNT_DROP( program_account );
    1661             : 
    1662             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1191-L1230 */
    1663         174 :       ulong old_len = programdata_account->const_meta->dlen;
    1664         174 :       ulong new_len = fd_ulong_sat_add( old_len, additional_bytes );
    1665         174 :       if( FD_UNLIKELY( new_len>MAX_PERMITTED_DATA_LENGTH ) ) {
    1666             :         /* Max msg_sz: 85 - 6 + 2*20 = 119 < 127 => we can use printf */
    1667           0 :         fd_log_collector_printf_dangerous_max_127( instr_ctx,
    1668           0 :           "Extended ProgramData length of %lu bytes exceeds max account data length of %lu bytes", new_len, MAX_PERMITTED_DATA_LENGTH );
    1669           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC;
    1670           0 :       }
    1671             : 
    1672         174 :       fd_sol_sysvar_clock_t clock = {0};
    1673         174 :       if( FD_UNLIKELY( !fd_sysvar_clock_read( &clock, instr_ctx->slot_ctx ) ) ) {
    1674           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    1675           0 :       }
    1676             : 
    1677         174 :       fd_bpf_upgradeable_loader_state_t programdata_state = {0};
    1678         174 :       fd_pubkey_t * upgrade_authority_address = NULL;
    1679         174 :       err = fd_bpf_loader_v3_program_get_state( instr_ctx, programdata_account, &programdata_state );
    1680         174 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1681           0 :         FD_LOG_WARNING(( "Bpf state read for programdata account failed" ));
    1682           0 :         return err;
    1683           0 :       }
    1684         174 :       if( fd_bpf_upgradeable_loader_state_is_program_data( &programdata_state ) ) {
    1685         174 :         if( FD_UNLIKELY( clock.slot==programdata_state.inner.program_data.slot ) ) {
    1686           0 :           fd_log_collector_msg_literal( instr_ctx, "Program was extended in this block already" );
    1687           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
    1688           0 :         }
    1689             : 
    1690         174 :         if( FD_UNLIKELY( !programdata_state.inner.program_data.upgrade_authority_address ) ) {
    1691           3 :           fd_log_collector_msg_literal( instr_ctx, "Cannot extend ProgramData accounts that are not upgradeable" );
    1692           3 :           return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
    1693           3 :         }
    1694         171 :         upgrade_authority_address = programdata_state.inner.program_data.upgrade_authority_address;
    1695         171 :       } else {
    1696           0 :         fd_log_collector_msg_literal( instr_ctx, "ProgramData state is invalid" );
    1697           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1698           0 :       }
    1699             : 
    1700             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1232-L1256 */
    1701         171 :       fd_epoch_bank_t * epoch_bank       = fd_exec_epoch_ctx_epoch_bank( instr_ctx->slot_ctx->epoch_ctx );
    1702         171 :       fd_rent_t       * rent             = &epoch_bank->rent;
    1703         171 :       ulong             balance          = programdata_account->const_meta->info.lamports;
    1704         171 :       ulong             min_balance      = fd_ulong_max( fd_rent_exempt_minimum_balance( rent, new_len ), 1UL );
    1705         171 :       ulong             required_payment = fd_ulong_sat_sub( min_balance, balance );
    1706             : 
    1707             :       /* Borrowed accounts need to be dropped before native invocations. Note:
    1708             :          the programdata account is manually released and acquired within the
    1709             :          extend instruction to preserve the local variable scoping to maintain
    1710             :          readability. The scoped macro still successfully handles the case of
    1711             :          freeing a write lock in case of an early termination. */
    1712         171 :       fd_borrowed_account_release_write( programdata_account );
    1713             : 
    1714         171 :       if( FD_UNLIKELY( required_payment>0UL ) ) {
    1715         129 :         if ( FD_UNLIKELY( instr_ctx->instr->acct_cnt<=3UL ) ) {
    1716          18 :           return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    1717          18 :         }
    1718             : 
    1719         111 :         fd_pubkey_t const * payer_key = &txn_accs[ instr_acc_idxs[ 3UL ] ];
    1720             : 
    1721         111 :         fd_system_program_instruction_t instr = {
    1722         111 :           .discriminant   = fd_system_program_instruction_enum_transfer,
    1723         111 :           .inner.transfer = required_payment
    1724         111 :         };
    1725             : 
    1726         111 :         fd_vm_rust_account_meta_t * acct_metas = (fd_vm_rust_account_meta_t *)
    1727         111 :                                                   fd_valloc_malloc( valloc,
    1728         111 :                                                                     FD_VM_RUST_ACCOUNT_META_ALIGN,
    1729         111 :                                                                     2UL * sizeof(fd_vm_rust_account_meta_t) );
    1730         111 :         fd_native_cpi_create_account_meta( payer_key,       1UL, 1UL, &acct_metas[ 0UL ] );
    1731         111 :         fd_native_cpi_create_account_meta( programdata_key, 0UL, 1UL, &acct_metas[ 1UL ] );
    1732             : 
    1733         111 :         err = fd_native_cpi_execute_system_program_instruction( instr_ctx, &instr, acct_metas, 2UL, NULL, 0UL );
    1734         111 :         if( FD_UNLIKELY( err ) ) {
    1735           3 :           return err;
    1736           3 :         }
    1737         111 :       }
    1738             : 
    1739             :       /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1258-L1293 */
    1740         150 :       if( FD_UNLIKELY( !fd_borrowed_account_acquire_write( programdata_account ) ) ) {
    1741           0 :         return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    1742           0 :       }
    1743             : 
    1744             :       /* Programdata account set data length */
    1745         150 :       int err = fd_account_set_data_length( instr_ctx, 0UL, new_len );
    1746         150 :       if( FD_UNLIKELY( err ) ) {
    1747           0 :         return err;
    1748           0 :       }
    1749             : 
    1750         150 :       if( FD_UNLIKELY( PROGRAMDATA_METADATA_SIZE>programdata_account->const_meta->dlen ) ) {
    1751           0 :         return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
    1752           0 :       }
    1753             : 
    1754         150 :       uchar * programdata_data = programdata_account->data + PROGRAMDATA_METADATA_SIZE;
    1755         150 :       ulong   programdata_size = new_len                   - PROGRAMDATA_METADATA_SIZE;
    1756             : 
    1757         150 :       err = fd_deploy_program( instr_ctx, programdata_data, programdata_size, fd_spad_virtual( instr_ctx->txn_ctx->spad ) );
    1758         150 :       if( FD_UNLIKELY( err ) ) {
    1759         150 :         return err;
    1760         150 :       }
    1761             : 
    1762           0 :       fd_borrowed_account_release_write( programdata_account );
    1763             : 
    1764             :       /* Setting the discriminant and upgrade authority address here can likely
    1765             :          be a no-op because these values shouldn't change. These can probably be
    1766             :          removed, but can help to mirror against Agave client's implementation.
    1767             :          The set_state function also contains an ownership check. */
    1768             : 
    1769           0 :       if( FD_UNLIKELY( !fd_borrowed_account_acquire_write( programdata_account ) ) ) {
    1770           0 :         return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    1771           0 :       }
    1772             : 
    1773           0 :       programdata_state.discriminant                                 = fd_bpf_upgradeable_loader_state_enum_program_data;
    1774           0 :       programdata_state.inner.program_data.slot                      = clock.slot;
    1775           0 :       programdata_state.inner.program_data.upgrade_authority_address = upgrade_authority_address;
    1776             : 
    1777           0 :       err = fd_bpf_loader_v3_program_set_state( instr_ctx, 0UL, &programdata_state );
    1778           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1779           0 :         FD_LOG_WARNING(( "Bincode encode for programdata account failed" ));
    1780           0 :         return err;
    1781           0 :       }
    1782             : 
    1783             :       /* Max msg_sz: 41 - 2 + 20 = 57 < 127 => we can use printf */
    1784           0 :       fd_log_collector_printf_dangerous_max_127( instr_ctx,
    1785           0 :         "Extended ProgramData account by %u bytes", additional_bytes );
    1786             : 
    1787         195 :       } FD_BORROWED_ACCOUNT_DROP( programdata_account );
    1788             : 
    1789           0 :       break;
    1790         195 :     }
    1791           0 :     default: {
    1792           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1793         195 :   }
    1794        1260 :   }
    1795         147 :   return FD_EXECUTOR_INSTR_SUCCESS;
    1796        1260 : }
    1797             : 
    1798             : /* process_instruction_inner() */
    1799             : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L394-L564 */
    1800             : int
    1801        3465 : fd_bpf_loader_program_execute( fd_exec_instr_ctx_t * ctx ) {
    1802        3465 :   FD_SPAD_FRAME_BEGIN( ctx->txn_ctx->spad ) {
    1803             :     /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L491-L529 */
    1804        3465 :     fd_borrowed_account_t * program_account = NULL;
    1805             : 
    1806             :     /* TODO: Agave uses `get_last_program_key`, we should have equivalent semantics:
    1807             :        https://github.com//anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L491-L492 */
    1808        3465 :     fd_pubkey_t const *     program_id      = &ctx->instr->program_id_pubkey;
    1809        3465 :     int err = fd_txn_borrowed_account_view_idx( ctx->txn_ctx, ctx->instr->program_id, &program_account );
    1810        3465 :     if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
    1811           0 :       FD_LOG_WARNING(( "Borrowed account lookup failed for program account" )); // custom log
    1812           0 :       return err;
    1813           0 :     }
    1814             : 
    1815             :     /* Program management instruction */
    1816        3465 :     if( FD_UNLIKELY( !memcmp( &fd_solana_native_loader_id, program_account->const_meta->info.owner, sizeof(fd_pubkey_t) ) ) ) {
    1817        1359 :       if( FD_UNLIKELY( !memcmp( &fd_solana_bpf_loader_upgradeable_program_id, program_id, sizeof(fd_pubkey_t) ) ) ) {
    1818        1275 :         FD_EXEC_CU_UPDATE( ctx, UPGRADEABLE_LOADER_COMPUTE_UNITS );
    1819        1272 :         return process_loader_upgradeable_instruction( ctx );
    1820        1275 :       } else if( FD_UNLIKELY( !memcmp( &fd_solana_bpf_loader_program_id, program_id, sizeof(fd_pubkey_t) ) ) ) {
    1821          78 :         FD_EXEC_CU_UPDATE( ctx, DEFAULT_LOADER_COMPUTE_UNITS );
    1822          78 :         fd_log_collector_msg_literal( ctx, "BPF loader management instructions are no longer supported" );
    1823          78 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1824          78 :       } else if( FD_UNLIKELY( !memcmp( &fd_solana_bpf_loader_deprecated_program_id, program_id, sizeof(fd_pubkey_t) ) ) ) {
    1825           6 :         FD_EXEC_CU_UPDATE( ctx, DEPRECATED_LOADER_COMPUTE_UNITS );
    1826           6 :         fd_log_collector_msg_literal( ctx, "Deprecated loader is no longer supported" );
    1827           6 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1828           6 :       } else {
    1829           0 :         fd_log_collector_msg_literal( ctx, "Invalid BPF loader id" );
    1830             :         /* https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L429-L436 */
    1831           0 :         if( FD_FEATURE_ACTIVE( ctx->slot_ctx, remove_accounts_executable_flag_checks ) ) {
    1832           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1833           0 :         }
    1834           0 :         return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
    1835           0 :       }
    1836        1359 :     }
    1837             : 
    1838             :     /* https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L445-L452 */
    1839             :     /* Program invocation. Any invalid programs will be caught here or at the program load. */
    1840        2106 :     if( FD_UNLIKELY( !FD_FEATURE_ACTIVE( ctx->slot_ctx, remove_accounts_executable_flag_checks ) && 
    1841        2106 :                      !fd_account_is_executable( program_account->const_meta ) ) ) {
    1842           0 :       fd_log_collector_msg_literal( ctx, "Program is not executable" );
    1843           0 :       return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
    1844           0 :     }
    1845             : 
    1846             :     /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L551-L563 */
    1847             :     /* The Agave client stores a loaded program type state in its implementation
    1848             :       of the loaded program cache. It checks to see if an account is able to be
    1849             :       executed. It is possible for a program to be in the DelayVisibility state or
    1850             :       Closed state but it won't be reflected in the Firedancer cache. Program
    1851             :       accounts that are in this state should exit with an invalid account data
    1852             :       error. For programs that are recently deployed or upgraded, they should not
    1853             :       be allowed to be executed for the remainder of the slot. For closed
    1854             :       accounts, they're uninitialized and shouldn't be executed as well.
    1855             : 
    1856             :       For the former case the slot that the
    1857             :       program was last updated in is in the program data account.
    1858             :       This means that if the slot in the program data account is greater than or
    1859             :       equal to the current execution slot, then the account is in a
    1860             :       'LoadedProgramType::DelayVisiblity' state.
    1861             : 
    1862             :       The latter case as described above is a tombstone account which is in a Closed
    1863             :       state. This occurs when a program data account is closed. However, our cache
    1864             :       does not track this. Instead, this can be checked for by seeing if the program
    1865             :       account's respective program data account is uninitialized. This should only
    1866             :       happen when the account is closed.
    1867             : 
    1868             :       Every error that comes out of this block is mapped to an InvalidAccountData instruction error in Agave. */
    1869             : 
    1870        2106 :     fd_borrowed_account_t * program_acc_view = NULL;
    1871        2106 :     int read_result = fd_txn_borrowed_account_view_idx( ctx->txn_ctx, ctx->instr->program_id, &program_acc_view );
    1872        2106 :     if( FD_UNLIKELY( read_result != FD_ACC_MGR_SUCCESS ) ) {
    1873           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    1874           0 :     }
    1875        2106 :     fd_account_meta_t const * metadata = program_acc_view->const_meta;
    1876        2106 :     uchar is_deprecated = !memcmp( metadata->info.owner, &fd_solana_bpf_loader_deprecated_program_id, sizeof(fd_pubkey_t) );
    1877             : 
    1878        2106 :     if( !memcmp( metadata->info.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) {
    1879         921 :       fd_bpf_upgradeable_loader_state_t program_account_state = {0};
    1880         921 :       err = fd_bpf_loader_v3_program_get_state( ctx, program_account, &program_account_state );
    1881         921 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1882           0 :         FD_LOG_WARNING(( "Bpf state read for program account failed" )); // custom log
    1883           0 :         if( FD_FEATURE_ACTIVE( ctx->slot_ctx, remove_accounts_executable_flag_checks ) ) {
    1884           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1885           0 :         }
    1886           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1887           0 :       }
    1888             : 
    1889             :       /* https://github.com/anza-xyz/agave/blob/v2.0.9/svm/src/program_loader.rs#L96-L98
    1890             :          Program account and program data account discriminants get checked when loading in program accounts
    1891             :          into the program cache. If the discriminants are incorrect, the program is marked as closed. */
    1892         921 :       if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_program( &program_account_state ) ) ) {
    1893           3 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    1894           3 :         if( FD_FEATURE_ACTIVE( ctx->slot_ctx, remove_accounts_executable_flag_checks ) ) {
    1895           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1896           0 :         }
    1897           3 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1898           3 :       }
    1899             : 
    1900         918 :       fd_borrowed_account_t * program_data_account = NULL;
    1901         918 :       fd_pubkey_t * programdata_pubkey = (fd_pubkey_t *)&program_account_state.inner.program.programdata_address;
    1902         918 :       err = fd_txn_borrowed_account_executable_view( ctx->txn_ctx, programdata_pubkey, &program_data_account );
    1903         918 :       if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
    1904           9 :         FD_LOG_WARNING(( "Borrowed account lookup for program data account failed" )); // custom log
    1905           9 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1906           9 :       }
    1907             : 
    1908         909 :       if( FD_UNLIKELY( program_data_account->const_meta->dlen<PROGRAMDATA_METADATA_SIZE ) ) {
    1909          72 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    1910          72 :         if( FD_FEATURE_ACTIVE( ctx->slot_ctx, remove_accounts_executable_flag_checks ) ) {
    1911           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1912           0 :         }
    1913          72 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1914          72 :       }
    1915             : 
    1916         837 :       fd_bpf_upgradeable_loader_state_t program_data_account_state = {0};
    1917         837 :       err = fd_bpf_loader_v3_program_get_state( ctx, program_data_account, &program_data_account_state );
    1918         837 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) {
    1919          18 :         FD_LOG_WARNING(( "Bpf state read for program data account failed" )); // custom log
    1920          18 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1921          18 :       }
    1922             : 
    1923             :       /* https://github.com/anza-xyz/agave/blob/v2.0.9/svm/src/program_loader.rs#L100-L104
    1924             :          Same as above comment. Program data discriminant must be set correctly. */
    1925         819 :       if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_program_data( &program_data_account_state ) ) ) {
    1926             :         /* The account is closed. */
    1927           0 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    1928           0 :         if( FD_FEATURE_ACTIVE( ctx->slot_ctx, remove_accounts_executable_flag_checks ) ) {
    1929           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1930           0 :         }
    1931           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1932           0 :       }
    1933             : 
    1934         819 :       ulong program_data_slot = program_data_account_state.inner.program_data.slot;
    1935         819 :       if( FD_UNLIKELY( program_data_slot>=ctx->slot_ctx->slot_bank.slot ) ) {
    1936             :         /* The account was likely just deployed or upgraded. Corresponds to
    1937             :           'LoadedProgramType::DelayVisibility' */
    1938           0 :         fd_log_collector_msg_literal( ctx, "Program is not deployed" );
    1939           0 :         if( FD_FEATURE_ACTIVE( ctx->slot_ctx, remove_accounts_executable_flag_checks ) ) {
    1940           0 :           return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1941           0 :         }
    1942           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1943           0 :       }
    1944         819 :     }
    1945             : 
    1946             :     /* Sadly, we have to tie the cache in with consensus. We tried our best to avoid this,
    1947             :        but Agave's program loading logic is too complex to solely rely on checks without
    1948             :        significant redundancy.
    1949             : 
    1950             :        For example, devnet and testnet have older programs that were deployed before stricter ELF / VM validation
    1951             :        checks were put in place, causing these older programs to fail newer validation checks and
    1952             :        be unexecutable. `fd_bpf_scan_and_create_bpf_program_cache_entry()` will populate our BPF program
    1953             :        cache correctly, but now, we have no way of checking if this validation passed or not here without
    1954             :        querying our program cache, otherwise we would have to copy-paste our validation checks here.
    1955             : 
    1956             :        Any failures here would indicate an attempt to interact with a deployed programs that either failed
    1957             :        to load or failed bytecode verification. This applies for v1, v2, and v3 programs. This could
    1958             :        also theoretically cause some currently-deployed programs to fail in the future if ELF / VM checks
    1959             :        are eventually made stricter.
    1960             : 
    1961             :        TLDR: A program is present in the BPF cache iff it is already deployed AND passes current SBPF and VM checks.
    1962             :        Only then it is considered valid to interact with. */
    1963        2004 :     fd_sbpf_validated_program_t * prog = NULL;
    1964        2004 :     if( FD_UNLIKELY( fd_bpf_load_cache_entry( ctx->slot_ctx, &ctx->instr->program_id_pubkey, &prog )!=0 ) ) {
    1965         975 :       fd_log_collector_msg_literal( ctx, "Program is not cached" );
    1966             : 
    1967             :       /* https://github.com/anza-xyz/agave/blob/89872fdb074e6658646b2b57a299984f0059cc84/programs/bpf_loader/src/lib.rs#L460-L467 */
    1968         975 :       if( FD_FEATURE_ACTIVE( ctx->slot_ctx, remove_accounts_executable_flag_checks ) ) {
    1969           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1970           0 :       }
    1971         975 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1972         975 :     }
    1973             : 
    1974        1029 :     return fd_bpf_execute( ctx, prog, is_deprecated );
    1975        3465 :   } FD_SPAD_FRAME_END;
    1976        3465 : }
    1977             : 
    1978             : 
    1979             : /* Public APIs */
    1980             : 
    1981             : int
    1982             : fd_directly_invoke_loader_v3_deploy( fd_exec_slot_ctx_t * slot_ctx,
    1983             :                                      uchar const *        elf,
    1984           0 :                                      ulong                elf_sz ) {
    1985             :   /* Set up a dummy instr and txn context */
    1986           0 :   fd_exec_txn_ctx_t * txn_ctx = fd_exec_txn_ctx_join( fd_exec_txn_ctx_new( fd_scratch_alloc( FD_EXEC_TXN_CTX_ALIGN, FD_EXEC_TXN_CTX_FOOTPRINT ) ) );
    1987           0 :   fd_exec_txn_ctx_from_exec_slot_ctx( slot_ctx, txn_ctx );
    1988           0 :   fd_exec_txn_ctx_setup_basic( txn_ctx );
    1989           0 :   txn_ctx->instr_stack_sz = 1;
    1990           0 :   fd_exec_instr_ctx_t * instr_ctx = &txn_ctx->instr_stack[0];
    1991           0 :   *instr_ctx = (fd_exec_instr_ctx_t) {
    1992           0 :     .instr     = NULL,
    1993           0 :     .txn_ctx   = txn_ctx,
    1994           0 :     .epoch_ctx = txn_ctx->epoch_ctx,
    1995           0 :     .slot_ctx  = txn_ctx->slot_ctx,
    1996           0 :     .acc_mgr   = txn_ctx->acc_mgr,
    1997           0 :     .funk_txn  = txn_ctx->funk_txn,
    1998           0 :     .parent    = NULL,
    1999           0 :     .index     = 0U,
    2000           0 :     .depth     = 0U,
    2001           0 :     .child_cnt = 0U,
    2002           0 :   };
    2003             : 
    2004           0 :   return fd_deploy_program( instr_ctx, elf, elf_sz, fd_scratch_virtual() );
    2005           0 : }

Generated by: LCOV version 1.14