LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_address_lookup_table_program.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 571 614 93.0 %
Date: 2024-11-13 11:58:15 Functions: 13 13 100.0 %

          Line data    Source code
       1             : #include "fd_address_lookup_table_program.h"
       2             : #include "fd_program_util.h"
       3             : #include "../fd_executor.h"
       4             : #include "../context/fd_exec_txn_ctx.h"
       5             : #include "../fd_acc_mgr.h"
       6             : #include "../fd_pubkey_utils.h"
       7             : #include "../fd_account.h"
       8             : #include "../sysvar/fd_sysvar_clock.h"
       9             : #include "../sysvar/fd_sysvar_slot_hashes.h"
      10             : #include "../../../ballet/ed25519/fd_curve25519.h"
      11             : #include "../../vm/syscall/fd_vm_syscall.h"
      12             : #include "fd_native_cpi.h"
      13             : 
      14             : #include <string.h>
      15             : 
      16             : struct fd_addrlut {
      17             :   fd_address_lookup_table_state_t state;
      18             : 
      19             :   fd_pubkey_t const * addr;  /* points into account data */
      20             :   ulong               addr_cnt;
      21             : };
      22             : 
      23             : typedef struct fd_addrlut fd_addrlut_t;
      24             : 
      25        5781 : #define FD_ADDRLUT_META_SZ       (56UL)
      26           0 : #define FD_ADDRLUT_MAX_ADDR_CNT (256UL)
      27             : #define DEFAULT_COMPUTE_UNITS   (750UL)
      28          69 : #define MAX_ENTRIES             FD_SYSVAR_SLOT_HASHES_CAP
      29             : 
      30             : static fd_addrlut_t *
      31        2127 : fd_addrlut_new( void * mem ) {
      32             : 
      33        2127 :   if( FD_UNLIKELY( !mem ) ) {
      34           0 :     FD_LOG_WARNING(( "NULL mem" ));
      35           0 :     return NULL;
      36           0 :   }
      37             : 
      38        2127 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, alignof(fd_addrlut_t) ) ) ) {
      39           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      40           0 :     return NULL;
      41           0 :   }
      42             : 
      43        2127 :   return fd_type_pun( mem );
      44        2127 : }
      45             : 
      46             : static int
      47             : fd_addrlut_deserialize( fd_addrlut_t * lut,
      48             :                         uchar const *  data,
      49        2127 :                         ulong          data_sz ) {
      50             : 
      51        2127 :   lut = fd_addrlut_new( lut ); FD_TEST( lut );
      52             : 
      53        2127 :   fd_bincode_decode_ctx_t decode =
      54        2127 :     { .data    = data,
      55        2127 :       .dataend = data+data_sz };
      56        2127 :   if( FD_UNLIKELY( fd_address_lookup_table_state_decode( &lut->state, &decode )!=FD_BINCODE_SUCCESS ) )
      57         684 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      58             : 
      59        1443 :   if( lut->state.discriminant==fd_address_lookup_table_state_enum_uninitialized )
      60          27 :     return FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT;
      61        1416 :   FD_TEST( lut->state.discriminant == fd_address_lookup_table_state_enum_lookup_table );
      62             : 
      63        1416 :   if( data_sz < FD_ADDRLUT_META_SZ )
      64           6 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      65             : 
      66        1410 :   uchar const * raw_addr_data    = data   +FD_ADDRLUT_META_SZ;
      67        1410 :   ulong         raw_addr_data_sz = data_sz-FD_ADDRLUT_META_SZ;
      68             : 
      69        1410 :   if( !fd_ulong_is_aligned( raw_addr_data_sz, 32UL ) )
      70          24 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      71             : 
      72        1386 :   lut->addr     = fd_type_pun_const( raw_addr_data );
      73        1386 :   lut->addr_cnt = raw_addr_data_sz / 32UL;
      74             : 
      75        1386 :   return FD_EXECUTOR_INSTR_SUCCESS;
      76        1410 : }
      77             : 
      78             : static int
      79             : fd_addrlut_serialize_meta( fd_address_lookup_table_state_t const * state,
      80             :                            uchar * data,
      81         516 :                            ulong   data_sz ) {
      82             : 
      83             :   /* TODO can this ever get hit?  All code paths to this function seem
      84             :      to check account data size during deserialization. */
      85         516 :   if( FD_UNLIKELY( data_sz<FD_ADDRLUT_META_SZ ) )
      86           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      87             : 
      88         516 :   fd_bincode_encode_ctx_t encode =
      89         516 :     { .data    = data,
      90         516 :       .dataend = data+FD_ADDRLUT_META_SZ };
      91         516 :   fd_memset( data, 0, (ulong)encode.dataend - (ulong)encode.data );
      92             : 
      93         516 :   int bin_err = fd_address_lookup_table_state_encode( state, &encode );
      94         516 :   FD_TEST( !bin_err );
      95             : 
      96         516 :   return FD_EXECUTOR_INSTR_SUCCESS;
      97         516 : }
      98             : 
      99             : static ulong
     100         765 : slot_hashes_position( fd_slot_hash_t const * hashes, ulong slot ) {
     101             :   /* Logic is copied from slice::binary_search_by() in Rust
     102             :      Returns the slot hash position of the input slot. */
     103         765 :   ulong start = 0UL;
     104         765 :   ulong end = deq_fd_slot_hash_t_cnt( hashes );
     105             : 
     106        4053 :   while( start < end ) {
     107        3504 :     ulong mid      = start + (end - start) / 2UL;
     108        3504 :     ulong mid_slot = deq_fd_slot_hash_t_peek_index_const( hashes, mid )->slot;
     109             : 
     110        3504 :     if( mid_slot == slot ) {
     111         216 :       return mid;
     112        3288 :     } else if( mid_slot > slot ) {
     113        1623 :       start = mid + 1UL;
     114        1665 :     } else {
     115        1665 :       end = mid;
     116        1665 :     }
     117        3504 :   }
     118             : 
     119         549 :   return ULONG_MAX;
     120         765 : }
     121             : 
     122             : /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L81-L104 */
     123             : static uchar
     124             : fd_addrlut_status( fd_lookup_table_meta_t const * state,
     125             :                    ulong                          current_slot,
     126             :                    fd_slot_hash_t const *         slot_hashes,
     127        7818 :                    ulong *                        remaining_blocks ) {
     128             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L82-L83 */
     129        7818 :   if( state->deactivation_slot==ULONG_MAX ) {
     130        7449 :     return FD_ADDRLUT_STATUS_ACTIVATED;
     131        7449 :   }
     132             : 
     133             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L84-L87 */
     134         369 :   if( state->deactivation_slot==current_slot ) {
     135          66 :     *remaining_blocks = MAX_ENTRIES + 1UL;
     136          66 :     return FD_ADDRLUT_STATUS_DEACTIVATING;
     137          66 :   }
     138             : 
     139             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L88-L100 */
     140         303 :   ulong slot_hash_position = slot_hashes_position( slot_hashes, state->deactivation_slot );
     141         303 :   if( slot_hash_position!=ULONG_MAX ) {
     142           3 :     *remaining_blocks = MAX_ENTRIES - slot_hash_position;
     143           3 :     return FD_ADDRLUT_STATUS_DEACTIVATING;
     144           3 :   }
     145             : 
     146             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L102 */
     147         300 :   return FD_ADDRLUT_STATUS_DEACTIVATED;
     148         303 : }
     149             : 
     150             : /* Note on uses of fd_borrowed_account_acquire_write_is_safe:
     151             : 
     152             :    In some places of this program, the Agave implementation acquires a
     153             :    "mutable borrow" on the account that is immediately dropped before
     154             :    any borrow can occur.  In other words, this borrow attempt only
     155             :    introduces a "borrow failed" error case into the protocol but
     156             :    otherwise introduces no side effects.  i.e.
     157             : 
     158             :      if not fd_borrowed_account_acquire_write():
     159             :        return FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED
     160             :      ... read only operations ...
     161             :      fd_borrowed_account_release_write()
     162             :      ... arbitrary logic ...
     163             : 
     164             :    Is equivalent to
     165             : 
     166             :      if not fd_borrowed_account_acquire_write_is_safe():
     167             :        return FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED
     168             :      ... read only operations ...
     169             :      ... arbitrary logic ... */
     170             : 
     171             : static int
     172             : create_lookup_table( fd_exec_instr_ctx_t *       ctx,
     173        2157 :                      fd_addrlut_create_t const * create ) {
     174             : 
     175        2157 : # define ACC_IDX_LUT       (0UL)
     176        2157 : # define ACC_IDX_AUTHORITY (1UL)
     177        2157 : # define ACC_IDX_PAYER     (2UL)
     178             : 
     179             :   /* Prepare LUT account **********************************************/
     180             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L58-L59 */
     181             : 
     182             :   /* try_borrow_instruction_account => get_index_of_instruction_account_in_transaction */
     183        2157 :   ulong               lut_lamports = 0UL;
     184        2157 :   fd_pubkey_t const * lut_key      = NULL;
     185        2157 :   uchar const *       lut_owner    = NULL;
     186        8502 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     187             : 
     188             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L60-L62 */
     189        2115 :   lut_lamports = lut_acct->const_meta->info.lamports;
     190        2115 :   lut_key      = lut_acct->pubkey;
     191        2115 :   lut_owner    = lut_acct->const_meta->info.owner;
     192             : 
     193             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L63-L70 */
     194        2115 :   if( !FD_FEATURE_ACTIVE( ctx->slot_ctx, relax_authority_signer_check_for_lookup_table_creation )
     195        2115 :       && lut_acct->const_meta->dlen != 0UL ) {
     196         720 :     fd_log_collector_msg_literal( ctx, "Table account must not be allocated" );
     197         720 :     return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
     198         720 :   }
     199             : 
     200        2115 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     201             : 
     202             :   /* Prepare authority account ****************************************/
     203             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L73-L74 */
     204             : 
     205        1395 :   fd_pubkey_t const * authority_key = NULL;
     206             :   /* try_borrow_instruction_account => get_index_of_instruction_account_in_transaction */
     207        5562 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_AUTHORITY, authority_acct ) {
     208             : 
     209             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L75 */
     210        1389 :   authority_key = authority_acct->pubkey;
     211             : 
     212             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L76-L83 */
     213        1389 :   if( !FD_FEATURE_ACTIVE( ctx->slot_ctx, relax_authority_signer_check_for_lookup_table_creation )
     214        1389 :       && !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) {
     215         213 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     216         213 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     217         213 :   }
     218             : 
     219        1389 :   } FD_BORROWED_ACCOUNT_DROP( authority_acct );
     220             : 
     221             :   /* Prepare payer account ********************************************/
     222             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L86-L87 */
     223             : 
     224             :   /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     225        1176 :   fd_pubkey_t const * payer_key = NULL; 
     226        4668 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_PAYER, payer_acct ) {
     227             : 
     228        1164 :   payer_key = payer_acct->pubkey;
     229             : 
     230             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L89-L92 */
     231        1164 :   if( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_PAYER ) ) {
     232         291 :     fd_log_collector_msg_literal( ctx, "Payer account must be a signer" );
     233         291 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     234         291 :   }
     235             : 
     236        1164 :   } FD_BORROWED_ACCOUNT_DROP( payer_acct );
     237             : 
     238         873 :   ulong derivation_slot = 1UL;
     239             : 
     240         873 :   do {
     241         873 :     fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes( ctx->slot_ctx->sysvar_cache );
     242         873 :     if( FD_UNLIKELY( !slot_hashes ) )
     243         411 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     244             : 
     245             :     /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L97 */
     246         462 :     ulong is_recent_slot = slot_hashes_position( slot_hashes->hashes, create->recent_slot )!=ULONG_MAX;
     247         462 :     if( FD_UNLIKELY( !is_recent_slot ) ) {
     248             :       /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L100-L105 */
     249             :       /* Max msg_sz: 24 - 3 + 20 = 41 < 127 => we can use printf */
     250         249 :       fd_log_collector_printf_dangerous_max_127( ctx, "%lu is not a recent slot", create->recent_slot );
     251         249 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     252         249 :     } else {
     253         213 :       derivation_slot = create->recent_slot;
     254         213 :     }
     255         462 :   } while(0);
     256             : 
     257             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L109-L118 */
     258         213 :   fd_pubkey_t derived_tbl_key[1];
     259         213 :   uchar *     seeds[2];
     260         213 :   ulong       seed_szs[2] = { sizeof(fd_pubkey_t), sizeof(ulong) };
     261         213 :   seeds[0] = (uchar *)authority_key;
     262         213 :   seeds[1] = (uchar *)&derivation_slot;
     263         213 :   int err = fd_pubkey_derive_pda( ctx, &fd_solana_address_lookup_table_program_id, 
     264         213 :                                   2UL, seeds, seed_szs, (uchar*)&create->bump_seed, derived_tbl_key );
     265         213 :   if( FD_UNLIKELY( err ) ) {
     266          72 :     return err;
     267          72 :   }
     268             : 
     269             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L120-L127 */
     270         141 :   if( FD_UNLIKELY( 0!=memcmp( lut_key->key, derived_tbl_key->key, sizeof(fd_pubkey_t) ) ) ) {
     271             :     /* Max msg_sz: 44 - 2 + 45 = 87 < 127 => we can use printf */
     272          51 :     fd_log_collector_printf_dangerous_max_127( ctx,
     273          51 :       "Table address must match derived address: %s", FD_BASE58_ENC_32_ALLOCA( derived_tbl_key ) );
     274          51 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     275          51 :   }
     276             : 
     277             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L129-L135 */
     278          90 :   if( FD_FEATURE_ACTIVE( ctx->slot_ctx, relax_authority_signer_check_for_lookup_table_creation )
     279          90 :       && 0==memcmp( lut_owner, fd_solana_address_lookup_table_program_id.key, sizeof(fd_pubkey_t) ) ) {
     280           0 :     return FD_EXECUTOR_INSTR_SUCCESS;
     281           0 :   }
     282             : 
     283             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L137-L142 */
     284             : 
     285          90 :   fd_epoch_bank_t * epoch_bank        = fd_exec_epoch_ctx_epoch_bank( ctx->slot_ctx->epoch_ctx );
     286          90 :   fd_rent_t       * rent              = &epoch_bank->rent;
     287          90 :   ulong             tbl_acct_data_len = 0x38UL;
     288          90 :   ulong             required_lamports = fd_rent_exempt_minimum_balance( rent, tbl_acct_data_len );
     289          90 :                     required_lamports = fd_ulong_max( required_lamports, 1UL );
     290          90 :                     required_lamports = fd_ulong_sat_sub( required_lamports, lut_lamports );
     291             : 
     292             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L144-L149 */
     293          90 :   if( required_lamports>0UL ) {
     294             :     // Create account metas
     295          90 :     FD_SCRATCH_SCOPE_BEGIN {
     296          90 :       fd_vm_rust_account_meta_t * acct_metas = (fd_vm_rust_account_meta_t *)
     297          90 :                                                 fd_scratch_alloc( FD_VM_RUST_ACCOUNT_META_ALIGN, 2 * sizeof(fd_vm_rust_account_meta_t) );
     298          90 :       fd_native_cpi_create_account_meta( payer_key, 1, 1, &acct_metas[0] );
     299          90 :       fd_native_cpi_create_account_meta( lut_key,   0, 1, &acct_metas[1] );
     300             : 
     301             :       // Create signers list
     302          90 :       fd_pubkey_t signers[16];
     303          90 :       ulong signers_cnt = 1;
     304          90 :       signers[0] = *payer_key;
     305             : 
     306             :       // Create system program instruction
     307          90 :       fd_system_program_instruction_t instr = {0};
     308          90 :       instr.discriminant = fd_system_program_instruction_enum_transfer;
     309          90 :       instr.inner.transfer = required_lamports;
     310             : 
     311          90 :       int err = fd_native_cpi_execute_system_program_instruction(
     312          90 :         ctx,
     313          90 :         &instr,
     314          90 :         acct_metas,
     315          90 :         2,
     316          90 :         signers,
     317          90 :         signers_cnt
     318          90 :       );
     319          90 :       if( FD_UNLIKELY( err ) ) {
     320          60 :         return err;
     321          60 :       }
     322          90 :     } FD_SCRATCH_SCOPE_END;
     323          90 :   }
     324             : 
     325          30 :   FD_SCRATCH_SCOPE_BEGIN {
     326          30 :     fd_vm_rust_account_meta_t * acct_metas = ( fd_vm_rust_account_meta_t * )
     327          30 :                                               fd_scratch_alloc( FD_VM_RUST_ACCOUNT_META_ALIGN, sizeof(fd_vm_rust_account_meta_t) );
     328          30 :     fd_native_cpi_create_account_meta( lut_key, 1, 1, &acct_metas[0] );
     329             : 
     330             :     // Create signers list
     331          30 :     fd_pubkey_t signers[16];
     332          30 :     ulong signers_cnt = 1;
     333          30 :     signers[0] = *lut_key;
     334             : 
     335             :     // Create system program instruction
     336          30 :     fd_system_program_instruction_t instr = {0};
     337          30 :     instr.discriminant = fd_system_program_instruction_enum_allocate;
     338          30 :     instr.inner.allocate = 56;
     339             : 
     340             :     // Execute allocate instruction
     341          30 :     int err = fd_native_cpi_execute_system_program_instruction(
     342          30 :       ctx,
     343          30 :       &instr,
     344          30 :       acct_metas,
     345          30 :       1,
     346          30 :       signers,
     347          30 :       signers_cnt
     348          30 :     );
     349          30 :     if( FD_UNLIKELY( err ) ) {
     350           6 :       return err;
     351           6 :     }
     352             : 
     353          24 :     instr.discriminant = fd_system_program_instruction_enum_assign;
     354          24 :     instr.inner.assign = fd_solana_address_lookup_table_program_id;
     355             : 
     356             :     // Execute assign instruction
     357          24 :     err = fd_native_cpi_execute_system_program_instruction(
     358          24 :       ctx,
     359          24 :       &instr,
     360          24 :       acct_metas,
     361          24 :       1,
     362          24 :       signers,
     363          24 :       signers_cnt
     364          24 :     );
     365          24 :     if( FD_UNLIKELY( err ) ) {
     366           3 :       return err;
     367           3 :     }
     368          30 :   } FD_SCRATCH_SCOPE_END;
     369             : 
     370             : 
     371          84 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     372          21 :   fd_address_lookup_table_state_t state[1];
     373          21 :   fd_address_lookup_table_state_new( state );
     374          21 :   state->discriminant = fd_address_lookup_table_state_enum_lookup_table;
     375          21 :   fd_address_lookup_table_new( &state->inner.lookup_table );
     376          21 :   fd_memcpy( state->inner.lookup_table.meta.authority.key, authority_key->key, 32UL );
     377          21 :   state->inner.lookup_table.meta.has_authority = 1;
     378          21 :   state->inner.lookup_table.meta.deactivation_slot = ULONG_MAX;
     379             : 
     380          21 :   uchar * data = NULL;
     381          21 :   ulong   dlen = 0UL;
     382          21 :   int err = fd_account_get_data_mut( ctx, ACC_IDX_LUT, &data, &dlen );
     383          21 :   if( FD_UNLIKELY( err ) ) { 
     384           0 :     return err;
     385           0 :   }
     386             : 
     387          21 :   int state_err = fd_addrlut_serialize_meta( state, data, sizeof(fd_address_lookup_table_state_t) );
     388          21 :   if( FD_UNLIKELY( state_err ) ) { return state_err; }
     389             : 
     390          21 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     391             : 
     392          21 :   return FD_EXECUTOR_INSTR_SUCCESS;
     393             : 
     394          21 : # undef ACC_IDX_LUT
     395          21 : # undef ACC_IDX_AUTHORITY
     396          21 : # undef ACC_IDX_PAYER
     397          21 : }
     398             : 
     399             : static int
     400         855 : freeze_lookup_table( fd_exec_instr_ctx_t * ctx ) {
     401             : 
     402         855 : # define ACC_IDX_LUT       (0UL)
     403         855 : # define ACC_IDX_AUTHORITY (1UL)
     404             : 
     405             :   /* Prepare LUT account **********************************************/
     406             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L176-177 */
     407             : 
     408             :   /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     409        3375 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     410             : 
     411             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L178-L181 */
     412         840 :   if( FD_UNLIKELY( 0!=memcmp( lut_acct->const_meta->info.owner, fd_solana_address_lookup_table_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     413         405 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     414         405 :   }
     415             : 
     416         840 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     417             : 
     418             :   /* Prepare authority account ****************************************/
     419             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L183-L184 */
     420             : 
     421             :   /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     422         435 :   fd_pubkey_t const * authority_key = NULL;
     423        1731 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_AUTHORITY, authority_acct ) {
     424             : 
     425         432 :   authority_key = authority_acct->pubkey;
     426             : 
     427             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L186-L189 */
     428         432 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) ) {
     429          36 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     430          36 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     431          36 :   }
     432             : 
     433         432 :   } FD_BORROWED_ACCOUNT_DROP( authority_acct );
     434             : 
     435             :   /* Update lookup table account **************************************/
     436             : 
     437        1584 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     438             : 
     439             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L194 */
     440         396 :   uchar const * lut_data    = lut_acct->const_data;
     441         396 :   ulong         lut_data_sz = lut_acct->const_meta->dlen;
     442             : 
     443             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L195 */
     444         396 :   fd_addrlut_t lut[1];
     445         396 :   int err = fd_addrlut_deserialize( lut, lut_data, lut_data_sz );
     446         396 :   if( FD_UNLIKELY( err ) ) { 
     447         183 :     return err;
     448         183 :   }
     449             : 
     450         213 :   fd_address_lookup_table_t * state = &lut->state.inner.lookup_table;
     451             : 
     452             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L197-L200 */
     453         213 :   if( FD_UNLIKELY( !state->meta.has_authority ) ) {
     454           6 :     fd_log_collector_msg_literal( ctx, "Lookup table is already frozen");
     455           6 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     456           6 :   }
     457             : 
     458             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L201-L203 */
     459         207 :   if( FD_UNLIKELY( 0!=memcmp( state->meta.authority.key, authority_key->key, sizeof(fd_pubkey_t) ) ) ) {
     460          21 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     461          21 :   }
     462             : 
     463             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L204-L207 */
     464         186 :   if( FD_UNLIKELY( state->meta.deactivation_slot!=ULONG_MAX ) ) {
     465           6 :     fd_log_collector_msg_literal( ctx, "Deactivated tables cannot be frozen" );
     466           6 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     467           6 :   }
     468             : 
     469             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L208-L211 */
     470         180 :   if( FD_UNLIKELY( !lut->addr_cnt ) ) {
     471          18 :     fd_log_collector_msg_literal( ctx, "Empty lookup tables cannot be frozen" );
     472          18 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     473          18 :   }
     474             : 
     475         162 :   uchar *data = NULL;
     476         162 :   ulong dlen  = 0UL;
     477         162 :   err = fd_account_get_data_mut( ctx, ACC_IDX_LUT, &data, &dlen );
     478         162 :   if( FD_UNLIKELY( err ) ) {
     479          75 :     return err;
     480          75 :   }
     481             : 
     482             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L213-L218 */
     483          87 :   state->meta.has_authority = 0;
     484             : 
     485          87 :   err = fd_addrlut_serialize_meta( &lut->state, data, dlen );
     486          87 :   if( FD_UNLIKELY( err ) ) { 
     487           0 :     return err;
     488           0 :   }
     489             : 
     490         396 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     491             : 
     492          87 :   return FD_EXECUTOR_INSTR_SUCCESS;
     493         396 : # undef ACC_IDX_LUT
     494         396 : # undef ACC_IDX_AUTHORITY
     495         396 : }
     496             : 
     497             : static int
     498             : extend_lookup_table( fd_exec_instr_ctx_t *       ctx,
     499         975 :                      fd_addrlut_extend_t const * extend ) {
     500             : 
     501         975 : # define ACC_IDX_LUT       (0UL)
     502         975 : # define ACC_IDX_AUTHORITY (1UL)
     503         975 : # define ACC_IDX_PAYER     (2UL)
     504             : 
     505             :   /* Prepare LUT account **********************************************/
     506             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L230-L236 */
     507             : 
     508         975 :   fd_pubkey_t const * lut_key = NULL;
     509             : 
     510             :   /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     511        3891 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     512             : 
     513         972 :   lut_key = lut_acct->pubkey;
     514             : 
     515             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L233-235 */
     516         972 :   if( FD_UNLIKELY( 0!=memcmp( lut_acct->const_meta->info.owner, fd_solana_address_lookup_table_program_id.key, sizeof(fd_pubkey_t) ) ) )
     517         225 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     518             : 
     519         972 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     520             : 
     521             :   /* Prepare authority account ****************************************/
     522             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L238-L245 */
     523             : 
     524         747 :   fd_pubkey_t const * authority_key = NULL;
     525             : 
     526             :   /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     527        2979 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_AUTHORITY, authority_acct ) {
     528             : 
     529         744 :   authority_key = authority_acct->pubkey;
     530             : 
     531             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L241-L244 */
     532         744 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) ) {
     533         105 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     534         105 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     535         105 :   }
     536             : 
     537         744 :   } FD_BORROWED_ACCOUNT_DROP( authority_acct );
     538             : 
     539             :   /* Update lookup table account **************************************/
     540             : 
     541         639 :   uchar const * lut_data          = NULL;
     542         639 :   ulong         lut_data_sz       = 0UL;
     543         639 :   ulong         lut_lamports      = 0UL;
     544         639 :   ulong         new_table_data_sz = 0UL;
     545             : 
     546             : 
     547        2556 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     548             : 
     549         639 :   lut_data     = lut_acct->const_data;
     550         639 :   lut_data_sz  = lut_acct->const_meta->dlen;
     551         639 :   lut_lamports = lut_acct->const_meta->info.lamports;
     552             : 
     553             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L251 */
     554         639 :   fd_addrlut_t lut[1];
     555         639 :   int err = fd_addrlut_deserialize( lut, (uchar *)lut_data, lut_data_sz );
     556         639 :   if( FD_UNLIKELY( err ) ) { 
     557         180 :     return err; 
     558         180 :   }
     559             : 
     560         459 :   fd_address_lookup_table_t * state = &lut->state.inner.lookup_table;
     561             : 
     562             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L253-L255 */
     563         459 :   if( FD_UNLIKELY( !state->meta.has_authority ) ) {
     564           6 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     565           6 :   }
     566             : 
     567             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L256-L258 */
     568         453 :   if( FD_UNLIKELY( 0!=memcmp( state->meta.authority.key, authority_key->key, sizeof(fd_pubkey_t) ) ) ) {
     569          30 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     570          30 :   }
     571             : 
     572             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L259-L262 */
     573         423 :   if( FD_UNLIKELY( state->meta.deactivation_slot != ULONG_MAX ) ) {
     574           6 :     fd_log_collector_msg_literal( ctx, "Deactivated tables cannot be extended" );
     575           6 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     576           6 :   }
     577             : 
     578             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L263-L269 */
     579         417 :   if( FD_UNLIKELY( lut->addr_cnt >= FD_ADDRLUT_MAX_ADDR_CNT ) ) {
     580           0 :     fd_log_collector_msg_literal( ctx, "Lookup table is full and cannot contain more addresses" );
     581           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     582           0 :   }
     583             : 
     584             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L271-L274 */
     585         417 :   if( FD_UNLIKELY( !extend->new_addrs_len ) ) {
     586           6 :     fd_log_collector_msg_literal( ctx, "Must extend with at least one address" );
     587           6 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     588           6 :   }
     589             : 
     590             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L276-L279 */
     591         411 :   ulong old_addr_cnt = lut->addr_cnt;
     592         411 :   ulong new_addr_cnt = lut->addr_cnt + extend->new_addrs_len;
     593         411 :   if( FD_UNLIKELY( new_addr_cnt > FD_ADDRLUT_MAX_ADDR_CNT ) ) {
     594             :     /* Max msg_sz: 65 - 6 + 20*2 = 99 < 127 => we can use printf */
     595           0 :     fd_log_collector_printf_dangerous_max_127( ctx,
     596           0 :       "Extended lookup table length %lu would exceed max capacity of %lu", new_addr_cnt, FD_ADDRLUT_MAX_ADDR_CNT );
     597           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     598           0 :   }
     599             : 
     600             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L290 */
     601         411 :   fd_sol_sysvar_clock_t clock[1];
     602         411 :   if( FD_UNLIKELY( !fd_sysvar_clock_read( clock, ctx->slot_ctx ) ) )
     603           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     604             : 
     605             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L291-L299 */
     606         411 :   if( clock->slot!=state->meta.last_extended_slot ) {
     607         411 :     state->meta.last_extended_slot             = clock->slot;
     608         411 :     state->meta.last_extended_slot_start_index = (uchar)lut->addr_cnt;
     609         411 :   }
     610             : 
     611             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/address-lookup-table/src/processor.rs#L302
     612         411 :   new_table_data_sz = FD_ADDRLUT_META_SZ + new_addr_cnt * sizeof(fd_pubkey_t);
     613             : 
     614             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/address-lookup-table/src/processor.rs#L308
     615         411 :   if( FD_UNLIKELY( !fd_account_can_data_be_changed( ctx->instr, ACC_IDX_LUT, &err ) ) ) {
     616         102 :     return err;
     617         102 :   }
     618             : 
     619         309 :   int modify_err = fd_instr_borrowed_account_modify( ctx, lut_acct->pubkey, new_table_data_sz, &lut_acct );
     620         309 :   if( FD_UNLIKELY( modify_err ) ) {
     621           0 :     return FD_EXECUTOR_INSTR_ERR_FATAL;
     622           0 :   }
     623             : 
     624             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L307-L310 */
     625         309 :   err = fd_addrlut_serialize_meta( &lut->state, lut_acct->data, lut_acct->meta->dlen );
     626         309 :   if( FD_UNLIKELY( err ) ) { 
     627           0 :     return err;
     628           0 :   }
     629             : 
     630             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L311-L313 */
     631         309 :   do {
     632         309 :     uchar * new_keys = lut_acct->data + FD_ADDRLUT_META_SZ + old_addr_cnt * sizeof(fd_pubkey_t);
     633         309 :     fd_memcpy( new_keys, extend->new_addrs, extend->new_addrs_len * sizeof(fd_pubkey_t) );
     634         309 :   } while(0);
     635         309 :   lut_acct->meta->dlen = new_table_data_sz;
     636         309 :   lut->addr            = (fd_pubkey_t *)(lut_acct->data + FD_ADDRLUT_META_SZ);
     637         309 :   lut->addr_cnt        = new_addr_cnt;
     638             : 
     639         639 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     640             : 
     641             : 
     642             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L317-L321 */
     643         309 :   fd_epoch_bank_t * epoch_bank        = fd_exec_epoch_ctx_epoch_bank( ctx->slot_ctx->epoch_ctx );
     644         309 :   fd_rent_t       * rent              = &epoch_bank->rent;
     645         309 :   ulong             required_lamports = fd_rent_exempt_minimum_balance( rent, new_table_data_sz );
     646         309 :                     required_lamports = fd_ulong_max    ( required_lamports, 1UL );
     647         309 :                     required_lamports = fd_ulong_sat_sub( required_lamports, lut_lamports );
     648             : 
     649         309 :   if( required_lamports ) {
     650         276 :     fd_pubkey_t const * payer_key = NULL;
     651             : 
     652             :     /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     653        1086 :     FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_PAYER, payer_acct ) {
     654             : 
     655         270 :     payer_key = payer_acct->pubkey;
     656             :     /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L327-L330 */
     657         270 :     if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_PAYER ) ) ) {
     658          21 :       fd_log_collector_msg_literal( ctx, "Payer account must be a signer" );
     659          21 :       return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     660          21 :     }
     661             : 
     662         270 :     } FD_BORROWED_ACCOUNT_DROP( payer_acct );
     663             : 
     664             : 
     665         249 :     FD_SCRATCH_SCOPE_BEGIN {
     666             :       // Create account metas
     667         249 :       fd_vm_rust_account_meta_t * acct_metas = (fd_vm_rust_account_meta_t *)
     668         249 :                                                 fd_scratch_alloc( FD_VM_RUST_ACCOUNT_META_ALIGN, 2 * sizeof(fd_vm_rust_account_meta_t) );
     669         249 :       fd_native_cpi_create_account_meta( payer_key, 1, 1, &acct_metas[0] );
     670         249 :       fd_native_cpi_create_account_meta( lut_key,   0, 1, &acct_metas[1] );
     671             : 
     672             :       // Create signers list
     673         249 :       fd_pubkey_t signers[16];
     674         249 :       ulong signers_cnt = 1UL;
     675         249 :       signers[0]        = *payer_key;
     676             : 
     677             :       // Create system program instruction
     678         249 :       fd_system_program_instruction_t instr = {0};
     679         249 :       instr.discriminant                    = fd_system_program_instruction_enum_transfer;
     680         249 :       instr.inner.transfer                  = required_lamports;
     681             : 
     682         249 :       int err = fd_native_cpi_execute_system_program_instruction( ctx,
     683         249 :                                                                   &instr,
     684         249 :                                                                   acct_metas,
     685         249 :                                                                   2UL,
     686         249 :                                                                   signers,
     687         249 :                                                                   signers_cnt );
     688         249 :       if( FD_UNLIKELY( err ) ) {
     689         216 :         return err;
     690         216 :       }
     691         249 :     } FD_SCRATCH_SCOPE_END;
     692         249 :   }
     693             : 
     694          66 :   return FD_EXECUTOR_INSTR_SUCCESS;
     695             : 
     696         309 : # undef ACC_IDX_LUT
     697         309 : # undef ACC_IDX_AUTHORITY
     698         309 : # undef ACC_IDX_PAYER
     699         309 : }
     700             : 
     701             : static int
     702         567 : deactivate_lookup_table( fd_exec_instr_ctx_t * ctx ) {
     703             : 
     704         567 : # define ACC_IDX_LUT       (0UL)
     705         567 : # define ACC_IDX_AUTHORITY (1UL)
     706             : 
     707             :   /* Prepare LUT account **********************************************/
     708             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L346-L351 */
     709             : 
     710             :   /* try_borrow_instruction_account => get_index_of_instruction_account_in_transaction */
     711        2259 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     712             : 
     713             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L348-L350 */
     714         564 :   if( FD_UNLIKELY( 0!=memcmp( lut_acct->const_meta->info.owner, fd_solana_address_lookup_table_program_id.key, sizeof(fd_pubkey_t) ) ) )
     715         126 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     716             : 
     717         564 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     718             : 
     719             :   /* Prepare authority account ****************************************/
     720             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L353-L360 */
     721             : 
     722             :   /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     723         438 :   fd_pubkey_t const * authority_key = NULL;
     724        1743 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_AUTHORITY, authority_acct ) {
     725             : 
     726         435 :   authority_key = authority_acct->pubkey;
     727             : 
     728             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L356-L359 */
     729         435 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) ) {
     730          51 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     731          51 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     732          51 :   }
     733             : 
     734         435 :   } FD_BORROWED_ACCOUNT_DROP( authority_acct );
     735             : 
     736             :   /* Update lookup table account **************************************/
     737             : 
     738        1536 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     739             : 
     740             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L364 */
     741         384 :   uchar const * lut_data    = lut_acct->const_data;
     742         384 :   ulong         lut_data_sz = lut_acct->const_meta->dlen;
     743             : 
     744             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L365 */
     745         384 :   fd_addrlut_t lut[1];
     746         384 :   int err = fd_addrlut_deserialize( lut, (uchar *)lut_data, lut_data_sz );
     747         384 :   if( FD_UNLIKELY( err ) ) { 
     748         156 :     return err;
     749         156 :   }
     750             : 
     751         228 :   fd_address_lookup_table_t * state = &lut->state.inner.lookup_table;
     752             : 
     753             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L367-L370 */
     754         228 :   if( FD_UNLIKELY( !state->meta.has_authority ) ) {
     755           6 :     fd_log_collector_msg_literal( ctx, "Lookup table is already frozen" );
     756           6 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     757           6 :   }
     758             : 
     759             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L371-L373 */
     760         222 :   if( FD_UNLIKELY( 0!=memcmp( state->meta.authority.key, authority_key->key, sizeof(fd_pubkey_t) ) ) ) {
     761          15 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     762          15 :   }
     763             : 
     764             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L374-L377 */
     765         207 :   if( FD_UNLIKELY( state->meta.deactivation_slot != ULONG_MAX ) ) {
     766           6 :     fd_log_collector_msg_literal( ctx, "Lookup table is already deactivated" );
     767           6 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     768           6 :   }
     769             : 
     770             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L380 */
     771         201 :   fd_sol_sysvar_clock_t clock[1];
     772         201 :   if( FD_UNLIKELY( !fd_sysvar_clock_read( clock, ctx->slot_ctx ) ) ) {
     773           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     774           0 :   }
     775             : 
     776         201 :   uchar * data = NULL;
     777         201 :   ulong   dlen = 0UL;
     778         201 :   err = fd_account_get_data_mut ( ctx, ACC_IDX_LUT, &data, &dlen );
     779         201 :   if( FD_UNLIKELY( err ) ) {
     780         102 :     return err;
     781         102 :   }
     782             : 
     783             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L381 */
     784          99 :   state->meta.deactivation_slot = clock->slot;
     785             : 
     786             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L383-L386 */
     787          99 :   err = fd_addrlut_serialize_meta( &lut->state, data, dlen );
     788          99 :   if( FD_UNLIKELY( err ) ) { 
     789           0 :     return err;
     790           0 :   }
     791             : 
     792         384 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     793             : 
     794          99 :   return FD_EXECUTOR_INSTR_SUCCESS;
     795             : 
     796         384 : # undef ACC_IDX_LUT
     797         384 : # undef ACC_IDX_AUTHORITY
     798         384 : }
     799             : 
     800             : static int
     801        1671 : close_lookup_table( fd_exec_instr_ctx_t * ctx ) {
     802             : 
     803        1671 : # define ACC_IDX_LUT       (0UL)
     804        1671 : # define ACC_IDX_AUTHORITY (1UL)
     805        1671 : # define ACC_IDX_RECIPIENT (2UL)
     806             : 
     807             :   /* Prepare LUT account **********************************************/
     808             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L395-L400 */
     809             : 
     810             :   /* try_borrow_instruction_account => get_index_of_instruction_account_in_transaction */
     811        6666 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     812             : 
     813             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L397-L399 */
     814        1665 :   if( FD_UNLIKELY( 0!=memcmp( lut_acct->const_meta->info.owner, fd_solana_address_lookup_table_program_id.key, sizeof(fd_pubkey_t) ) ) )
     815         864 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     816             : 
     817        1665 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     818             : 
     819             :   /* Prepare authority account ****************************************/
     820             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L402-L409 */
     821             : 
     822             :   /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     823         801 :   fd_pubkey_t const * authority_key = NULL;
     824        3195 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_AUTHORITY, authority_acct ) {
     825             : 
     826         798 :   authority_key = authority_acct->pubkey;
     827             : 
     828             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L405-L408 */
     829         798 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) ) {
     830          78 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     831          78 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     832          78 :   }
     833             : 
     834         798 :   } FD_BORROWED_ACCOUNT_DROP( authority_acct );
     835             : 
     836             :   /* Update lookup table account **************************************/
     837             : 
     838             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L411 */
     839         720 :   if( FD_UNLIKELY( ctx->instr->acct_cnt<3 ) ) {
     840           6 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     841           6 :   }
     842             : 
     843             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L412-L420 */
     844         714 :   if( FD_UNLIKELY( ctx->instr->borrowed_accounts[0]==ctx->instr->borrowed_accounts[2] ) ) {
     845           6 :     fd_log_collector_msg_literal( ctx, "Lookup table cannot be the recipient of reclaimed lamports" );
     846           6 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     847           6 :   }
     848             : 
     849         708 :   ulong         withdrawn_lamports = 0UL;
     850         708 :   uchar const * lut_data           = NULL;
     851         708 :   ulong         lut_data_sz        = 0UL;
     852             : 
     853        2832 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     854             : 
     855         708 :   withdrawn_lamports = lut_acct->const_meta->info.lamports;
     856         708 :   lut_data           = lut_acct->const_data;
     857         708 :   lut_data_sz        = lut_acct->const_meta->dlen;
     858             : 
     859             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L426 */
     860         708 :   fd_addrlut_t lut[1];
     861         708 :   int err = fd_addrlut_deserialize( lut, (uchar *)lut_data, lut_data_sz );
     862         708 :   if( FD_UNLIKELY( err ) ) { 
     863         222 :     return err;
     864         222 :   }
     865             : 
     866         486 :   fd_address_lookup_table_t * state = &lut->state.inner.lookup_table;
     867             : 
     868             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L428-L431 */
     869         486 :   if( FD_UNLIKELY( !state->meta.has_authority ) ) {
     870           6 :     fd_log_collector_msg_literal( ctx,  "Lookup table is frozen" );
     871           6 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     872           6 :   }
     873             : 
     874             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L432-L434 */
     875         480 :   if( FD_UNLIKELY( 0!=memcmp( state->meta.authority.key, authority_key->key, sizeof(fd_pubkey_t) ) ) ) {
     876          27 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     877          27 :   }
     878             : 
     879             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L437 */
     880         453 :   fd_sol_sysvar_clock_t clock[1];
     881         453 :   if( FD_UNLIKELY( !fd_sysvar_clock_read( clock, ctx->slot_ctx ) ) ) {
     882           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     883           0 :   }
     884             : 
     885             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L438 */
     886         453 :   fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes( ctx->slot_ctx->sysvar_cache );
     887         453 :   if( FD_UNLIKELY( !slot_hashes ) ) { 
     888          30 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     889          30 :   }
     890             : 
     891             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L440 */
     892         423 :   ulong remaining_blocks = 0UL;
     893         423 :   int status = fd_addrlut_status( &state->meta, clock->slot, slot_hashes->hashes, &remaining_blocks );
     894             : 
     895         423 :   switch( status ) {
     896          75 :     case FD_ADDRLUT_STATUS_ACTIVATED:
     897          75 :       fd_log_collector_msg_literal( ctx, "Lookup table is not deactivated" );
     898          75 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     899          57 :     case FD_ADDRLUT_STATUS_DEACTIVATING:
     900             :       /* Max msg_sz: 65 - 3 + 20 = 82 < 127 => we can use printf */
     901          57 :       fd_log_collector_printf_dangerous_max_127( ctx,
     902          57 :         "Table cannot be closed until it's fully deactivated in %lu blocks", remaining_blocks );
     903          57 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     904         291 :     case FD_ADDRLUT_STATUS_DEACTIVATED:
     905         291 :       break;
     906           0 :     default:
     907           0 :       __builtin_unreachable();
     908         423 :   }
     909             :   
     910         708 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     911             : 
     912             :   /* Add lamports to recipient ****************************************/
     913             : 
     914             :   /* try_borrow_instruction_account => get_index_of_instruction_account_in_transaction */
     915        1164 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_RECIPIENT, recipient_acct ) {
     916             : 
     917         291 :   int err = fd_account_checked_add_lamports( ctx, ACC_IDX_RECIPIENT, withdrawn_lamports );
     918         291 :   if( FD_UNLIKELY( err ) ) {
     919         177 :     return err;
     920         177 :   }
     921             : 
     922         291 :   } FD_BORROWED_ACCOUNT_DROP( recipient_acct );
     923             : 
     924             :   /* Delete LUT account ***********************************************/
     925             : 
     926         456 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     927             : 
     928         114 :   int err;
     929         114 :   if( FD_UNLIKELY( !fd_account_can_data_be_changed( ctx->instr, ACC_IDX_LUT, &err ) ) ) {
     930          51 :     return err;
     931          51 :   }
     932             : 
     933          63 :   err = fd_account_set_lamports( ctx, ACC_IDX_LUT, 0UL );
     934          63 :   if( FD_UNLIKELY( err ) ) {
     935           0 :     return err;
     936           0 :   }
     937          63 :   err = fd_account_set_data_length( ctx, ACC_IDX_LUT, 0UL );
     938          63 :   if( FD_UNLIKELY( err ) ) {
     939           0 :     return err;
     940           0 :   }
     941             : 
     942         114 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     943             : 
     944          63 :   return FD_EXECUTOR_INSTR_SUCCESS;
     945             : 
     946         114 : # undef ACC_IDX_LUT
     947         114 : # undef ACC_IDX_AUTHORITY
     948         114 : # undef ACC_IDX_RECIPIENT
     949         114 : }
     950             : 
     951             : int
     952       10914 : fd_address_lookup_table_program_execute( fd_exec_instr_ctx_t * ctx ) {
     953       10914 :   FD_EXEC_CU_UPDATE( ctx, DEFAULT_COMPUTE_UNITS );
     954             : 
     955        7542 :   uchar const * instr_data    = ctx->instr->data;
     956        7542 :   ulong         instr_data_sz = ctx->instr->data_sz;
     957        7542 :   if( FD_UNLIKELY( instr_data==NULL ) ) {
     958         132 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     959         132 :   }
     960             : 
     961        7410 :   FD_SCRATCH_SCOPE_BEGIN {
     962             : 
     963        7410 :     fd_bincode_decode_ctx_t decode = {
     964        7410 :       .valloc  = fd_scratch_virtual(),
     965        7410 :       .data    = instr_data,
     966        7410 :       .dataend = instr_data + instr_data_sz
     967        7410 :     };
     968        7410 :     fd_addrlut_instruction_t instr[1];
     969             :     /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L28 */
     970        7410 :     if( FD_UNLIKELY( fd_addrlut_instruction_decode( instr, &decode ) ||
     971        7410 :                      (ulong)instr_data + 1232UL < (ulong)decode.data ) ) {
     972        1185 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     973        1185 :     }
     974             : 
     975        6225 :     switch( instr->discriminant ) {
     976        2157 :     case fd_addrlut_instruction_enum_create_lut:
     977        2157 :       return create_lookup_table( ctx, &instr->inner.create_lut );
     978         855 :     case fd_addrlut_instruction_enum_freeze_lut:
     979         855 :       return freeze_lookup_table( ctx );
     980         975 :     case fd_addrlut_instruction_enum_extend_lut:
     981         975 :       return extend_lookup_table( ctx, &instr->inner.extend_lut );
     982         567 :     case fd_addrlut_instruction_enum_deactivate_lut:
     983         567 :       return deactivate_lookup_table( ctx );
     984        1671 :     case fd_addrlut_instruction_enum_close_lut:
     985        1671 :       return close_lookup_table( ctx );
     986           0 :     default:
     987           0 :       break;
     988        6225 :     }
     989        7410 :   } FD_SCRATCH_SCOPE_END;
     990             : 
     991           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     992        7410 : }
     993             : 
     994             : /**********************************************************************/
     995             : /* Public API                                                         */
     996             : /**********************************************************************/
     997             : 
     998             : /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L72-L78 */
     999             : static uchar
    1000             : is_active( fd_address_lookup_table_t const * self,
    1001             :            ulong                             current_slot,
    1002        7395 :            fd_slot_hash_t const *            slot_hashes ) {
    1003             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L73-L77 */
    1004        7395 :   ulong _dummy[1];
    1005        7395 :   switch( fd_addrlut_status( &self->meta, current_slot, slot_hashes, _dummy ) ) {
    1006        7374 :     case FD_ADDRLUT_STATUS_ACTIVATED:
    1007        7386 :     case FD_ADDRLUT_STATUS_DEACTIVATING:
    1008        7386 :       return 1;
    1009           9 :     case FD_ADDRLUT_STATUS_DEACTIVATED:
    1010           9 :       return 0;
    1011           0 :     default:
    1012           0 :       __builtin_unreachable();
    1013        7395 :   }
    1014        7395 : }
    1015             : 
    1016             : /* Sets active_addresses_len on success
    1017             :    https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L142-L164 */
    1018             : int
    1019             : fd_get_active_addresses_len( fd_address_lookup_table_t * self,
    1020             :                              ulong                       current_slot,
    1021             :                              fd_slot_hash_t const *      slot_hashes,
    1022             :                              ulong                       addresses_len,
    1023        7395 :                              ulong *                     active_addresses_len ) {
    1024             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L147-L152 */
    1025        7395 :   if( FD_UNLIKELY( !is_active( self, current_slot, slot_hashes ) ) ) {
    1026           9 :     return FD_RUNTIME_TXN_ERR_ADDRESS_LOOKUP_TABLE_NOT_FOUND;
    1027           9 :   }
    1028             : 
    1029             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L157-L161 */
    1030        7386 :   *active_addresses_len = ( current_slot > self->meta.last_extended_slot )
    1031        7386 :       ? addresses_len
    1032        7386 :       : self->meta.last_extended_slot_start_index;
    1033             :   
    1034        7386 :   return FD_RUNTIME_EXECUTE_SUCCESS;
    1035        7395 : }

Generated by: LCOV version 1.14