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: 51 611 8.3 %
Date: 2025-01-08 12:08:44 Functions: 4 13 30.8 %

          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           0 : #define FD_ADDRLUT_META_SZ       (56UL)
      26           0 : #define FD_ADDRLUT_MAX_ADDR_CNT (256UL)
      27             : #define DEFAULT_COMPUTE_UNITS   (750UL)
      28          12 : #define MAX_ENTRIES             FD_SYSVAR_SLOT_HASHES_CAP
      29             : 
      30             : static fd_addrlut_t *
      31           0 : fd_addrlut_new( void * mem ) {
      32             : 
      33           0 :   if( FD_UNLIKELY( !mem ) ) {
      34           0 :     FD_LOG_WARNING(( "NULL mem" ));
      35           0 :     return NULL;
      36           0 :   }
      37             : 
      38           0 :   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           0 :   return fd_type_pun( mem );
      44           0 : }
      45             : 
      46             : static int
      47             : fd_addrlut_deserialize( fd_addrlut_t * lut,
      48             :                         uchar const *  data,
      49           0 :                         ulong          data_sz ) {
      50             : 
      51           0 :   lut = fd_addrlut_new( lut ); FD_TEST( lut );
      52             : 
      53           0 :   fd_bincode_decode_ctx_t decode =
      54           0 :     { .data    = data,
      55           0 :       .dataend = data+data_sz };
      56           0 :   if( FD_UNLIKELY( fd_address_lookup_table_state_decode( &lut->state, &decode )!=FD_BINCODE_SUCCESS ) )
      57           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      58             : 
      59           0 :   if( lut->state.discriminant==fd_address_lookup_table_state_enum_uninitialized )
      60           0 :     return FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT;
      61           0 :   FD_TEST( lut->state.discriminant == fd_address_lookup_table_state_enum_lookup_table );
      62             : 
      63           0 :   if( data_sz < FD_ADDRLUT_META_SZ )
      64           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      65             : 
      66           0 :   uchar const * raw_addr_data    = data   +FD_ADDRLUT_META_SZ;
      67           0 :   ulong         raw_addr_data_sz = data_sz-FD_ADDRLUT_META_SZ;
      68             : 
      69           0 :   if( !fd_ulong_is_aligned( raw_addr_data_sz, 32UL ) )
      70           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      71             : 
      72           0 :   lut->addr     = fd_type_pun_const( raw_addr_data );
      73           0 :   lut->addr_cnt = raw_addr_data_sz / 32UL;
      74             : 
      75           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
      76           0 : }
      77             : 
      78             : static int
      79             : fd_addrlut_serialize_meta( fd_address_lookup_table_state_t const * state,
      80             :                            uchar * data,
      81           0 :                            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           0 :   if( FD_UNLIKELY( data_sz<FD_ADDRLUT_META_SZ ) )
      86           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      87             : 
      88           0 :   fd_bincode_encode_ctx_t encode =
      89           0 :     { .data    = data,
      90           0 :       .dataend = data+FD_ADDRLUT_META_SZ };
      91           0 :   fd_memset( data, 0, (ulong)encode.dataend - (ulong)encode.data );
      92             : 
      93           0 :   int bin_err = fd_address_lookup_table_state_encode( state, &encode );
      94           0 :   FD_TEST( !bin_err );
      95             : 
      96           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
      97           0 : }
      98             : 
      99             : static ulong
     100          12 : 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          12 :   ulong start = 0UL;
     104          12 :   ulong end = deq_fd_slot_hash_t_cnt( hashes );
     105             : 
     106          39 :   while( start < end ) {
     107          30 :     ulong mid      = start + (end - start) / 2UL;
     108          30 :     ulong mid_slot = deq_fd_slot_hash_t_peek_index_const( hashes, mid )->slot;
     109             : 
     110          30 :     if( mid_slot == slot ) {
     111           3 :       return mid;
     112          27 :     } else if( mid_slot > slot ) {
     113          15 :       start = mid + 1UL;
     114          15 :     } else {
     115          12 :       end = mid;
     116          12 :     }
     117          30 :   }
     118             : 
     119           9 :   return ULONG_MAX;
     120          12 : }
     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        7560 :                    ulong *                        remaining_blocks ) {
     128             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L82-L83 */
     129        7560 :   if( state->deactivation_slot==ULONG_MAX ) {
     130        7539 :     return FD_ADDRLUT_STATUS_ACTIVATED;
     131        7539 :   }
     132             : 
     133             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L84-L87 */
     134          21 :   if( state->deactivation_slot==current_slot ) {
     135           9 :     *remaining_blocks = MAX_ENTRIES + 1UL;
     136           9 :     return FD_ADDRLUT_STATUS_DEACTIVATING;
     137           9 :   }
     138             : 
     139             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L88-L100 */
     140          12 :   ulong slot_hash_position = slot_hashes_position( slot_hashes, state->deactivation_slot );
     141          12 :   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           9 :   return FD_ADDRLUT_STATUS_DEACTIVATED;
     148          12 : }
     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           0 :                      fd_addrlut_create_t const * create ) {
     174             : 
     175           0 : # define ACC_IDX_LUT       (0UL)
     176           0 : # define ACC_IDX_AUTHORITY (1UL)
     177           0 : # 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           0 :   ulong               lut_lamports = 0UL;
     184           0 :   fd_pubkey_t const * lut_key      = NULL;
     185           0 :   uchar const *       lut_owner    = NULL;
     186           0 :   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           0 :   lut_lamports = lut_acct->const_meta->info.lamports;
     190           0 :   lut_key      = lut_acct->pubkey;
     191           0 :   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           0 :   if( !FD_FEATURE_ACTIVE( ctx->slot_ctx, relax_authority_signer_check_for_lookup_table_creation )
     195           0 :       && lut_acct->const_meta->dlen != 0UL ) {
     196           0 :     fd_log_collector_msg_literal( ctx, "Table account must not be allocated" );
     197           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
     198           0 :   }
     199             : 
     200           0 :   } 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           0 :   fd_pubkey_t const * authority_key = NULL;
     206             :   /* try_borrow_instruction_account => get_index_of_instruction_account_in_transaction */
     207           0 :   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           0 :   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           0 :   if( !FD_FEATURE_ACTIVE( ctx->slot_ctx, relax_authority_signer_check_for_lookup_table_creation )
     214           0 :       && !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) {
     215           0 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     216           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     217           0 :   }
     218             : 
     219           0 :   } 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           0 :   fd_pubkey_t const * payer_key = NULL; 
     226           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_PAYER, payer_acct ) {
     227             : 
     228           0 :   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           0 :   if( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_PAYER ) ) {
     232           0 :     fd_log_collector_msg_literal( ctx, "Payer account must be a signer" );
     233           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     234           0 :   }
     235             : 
     236           0 :   } FD_BORROWED_ACCOUNT_DROP( payer_acct );
     237             : 
     238           0 :   ulong derivation_slot = 1UL;
     239             : 
     240           0 :   do {
     241           0 :     fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes( ctx->slot_ctx->sysvar_cache );
     242           0 :     if( FD_UNLIKELY( !slot_hashes ) )
     243           0 :       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           0 :     ulong is_recent_slot = slot_hashes_position( slot_hashes->hashes, create->recent_slot )!=ULONG_MAX;
     247           0 :     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           0 :       fd_log_collector_printf_dangerous_max_127( ctx, "%lu is not a recent slot", create->recent_slot );
     251           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     252           0 :     } else {
     253           0 :       derivation_slot = create->recent_slot;
     254           0 :     }
     255           0 :   } while(0);
     256             : 
     257             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L109-L118 */
     258           0 :   fd_pubkey_t derived_tbl_key[1];
     259           0 :   uchar *     seeds[2];
     260           0 :   ulong       seed_szs[2] = { sizeof(fd_pubkey_t), sizeof(ulong) };
     261           0 :   seeds[0] = (uchar *)authority_key;
     262           0 :   seeds[1] = (uchar *)&derivation_slot;
     263           0 :   int err = fd_pubkey_derive_pda( &fd_solana_address_lookup_table_program_id, 2UL, seeds, 
     264           0 :                                   seed_szs, (uchar*)&create->bump_seed, derived_tbl_key, &ctx->txn_ctx->custom_err );
     265           0 :   if( FD_UNLIKELY( err ) ) {
     266           0 :     return err;
     267           0 :   }
     268             : 
     269             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L120-L127 */
     270           0 :   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           0 :     fd_log_collector_printf_dangerous_max_127( ctx,
     273           0 :       "Table address must match derived address: %s", FD_BASE58_ENC_32_ALLOCA( derived_tbl_key ) );
     274           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     275           0 :   }
     276             : 
     277             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L129-L135 */
     278           0 :   if( FD_FEATURE_ACTIVE( ctx->slot_ctx, relax_authority_signer_check_for_lookup_table_creation )
     279           0 :       && 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           0 :   fd_epoch_bank_t * epoch_bank        = fd_exec_epoch_ctx_epoch_bank( ctx->slot_ctx->epoch_ctx );
     286           0 :   fd_rent_t       * rent              = &epoch_bank->rent;
     287           0 :   ulong             tbl_acct_data_len = 0x38UL;
     288           0 :   ulong             required_lamports = fd_rent_exempt_minimum_balance( rent, tbl_acct_data_len );
     289           0 :                     required_lamports = fd_ulong_max( required_lamports, 1UL );
     290           0 :                     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           0 :   if( required_lamports>0UL ) {
     294             :     // Create account metas
     295           0 :     FD_SPAD_FRAME_BEGIN( ctx->txn_ctx->spad ) {
     296           0 :       fd_vm_rust_account_meta_t * acct_metas = (fd_vm_rust_account_meta_t *)
     297           0 :                                                 fd_spad_alloc( ctx->txn_ctx->spad, FD_VM_RUST_ACCOUNT_META_ALIGN, 2 * sizeof(fd_vm_rust_account_meta_t) );
     298           0 :       fd_native_cpi_create_account_meta( payer_key, 1, 1, &acct_metas[0] );
     299           0 :       fd_native_cpi_create_account_meta( lut_key,   0, 1, &acct_metas[1] );
     300             : 
     301             :       // Create signers list
     302           0 :       fd_pubkey_t signers[16];
     303           0 :       ulong signers_cnt = 1;
     304           0 :       signers[0] = *payer_key;
     305             : 
     306             :       // Create system program instruction
     307           0 :       fd_system_program_instruction_t instr = {0};
     308           0 :       instr.discriminant = fd_system_program_instruction_enum_transfer;
     309           0 :       instr.inner.transfer = required_lamports;
     310             : 
     311           0 :       int err = fd_native_cpi_execute_system_program_instruction(
     312           0 :         ctx,
     313           0 :         &instr,
     314           0 :         acct_metas,
     315           0 :         2,
     316           0 :         signers,
     317           0 :         signers_cnt
     318           0 :       );
     319           0 :       if( FD_UNLIKELY( err ) ) {
     320           0 :         return err;
     321           0 :       }
     322           0 :     } FD_SPAD_FRAME_END;
     323           0 :   }
     324             : 
     325           0 :   FD_SPAD_FRAME_BEGIN( ctx->txn_ctx->spad ) {
     326           0 :     fd_vm_rust_account_meta_t * acct_metas = ( fd_vm_rust_account_meta_t * )
     327           0 :                                               fd_spad_alloc( ctx->txn_ctx->spad, FD_VM_RUST_ACCOUNT_META_ALIGN, sizeof(fd_vm_rust_account_meta_t) );
     328           0 :     fd_native_cpi_create_account_meta( lut_key, 1, 1, &acct_metas[0] );
     329             : 
     330             :     // Create signers list
     331           0 :     fd_pubkey_t signers[16];
     332           0 :     ulong signers_cnt = 1;
     333           0 :     signers[0] = *lut_key;
     334             : 
     335             :     // Create system program instruction
     336           0 :     fd_system_program_instruction_t instr = {0};
     337           0 :     instr.discriminant = fd_system_program_instruction_enum_allocate;
     338           0 :     instr.inner.allocate = 56;
     339             : 
     340             :     // Execute allocate instruction
     341           0 :     int err = fd_native_cpi_execute_system_program_instruction(
     342           0 :       ctx,
     343           0 :       &instr,
     344           0 :       acct_metas,
     345           0 :       1,
     346           0 :       signers,
     347           0 :       signers_cnt
     348           0 :     );
     349           0 :     if( FD_UNLIKELY( err ) ) {
     350           0 :       return err;
     351           0 :     }
     352             : 
     353           0 :     instr.discriminant = fd_system_program_instruction_enum_assign;
     354           0 :     instr.inner.assign = fd_solana_address_lookup_table_program_id;
     355             : 
     356             :     // Execute assign instruction
     357           0 :     err = fd_native_cpi_execute_system_program_instruction(
     358           0 :       ctx,
     359           0 :       &instr,
     360           0 :       acct_metas,
     361           0 :       1,
     362           0 :       signers,
     363           0 :       signers_cnt
     364           0 :     );
     365           0 :     if( FD_UNLIKELY( err ) ) {
     366           0 :       return err;
     367           0 :     }
     368           0 :   } FD_SPAD_FRAME_END;
     369             : 
     370             : 
     371           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     372           0 :   fd_address_lookup_table_state_t state[1];
     373           0 :   fd_address_lookup_table_state_new( state );
     374           0 :   state->discriminant = fd_address_lookup_table_state_enum_lookup_table;
     375           0 :   fd_address_lookup_table_new( &state->inner.lookup_table );
     376           0 :   fd_memcpy( state->inner.lookup_table.meta.authority.key, authority_key->key, 32UL );
     377           0 :   state->inner.lookup_table.meta.has_authority = 1;
     378           0 :   state->inner.lookup_table.meta.deactivation_slot = ULONG_MAX;
     379             : 
     380           0 :   uchar * data = NULL;
     381           0 :   ulong   dlen = 0UL;
     382           0 :   int err = fd_account_get_data_mut( ctx, ACC_IDX_LUT, &data, &dlen );
     383           0 :   if( FD_UNLIKELY( err ) ) { 
     384           0 :     return err;
     385           0 :   }
     386             : 
     387           0 :   int state_err = fd_addrlut_serialize_meta( state, data, sizeof(fd_address_lookup_table_state_t) );
     388           0 :   if( FD_UNLIKELY( state_err ) ) { return state_err; }
     389             : 
     390           0 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     391             : 
     392           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     393             : 
     394           0 : # undef ACC_IDX_LUT
     395           0 : # undef ACC_IDX_AUTHORITY
     396           0 : # undef ACC_IDX_PAYER
     397           0 : }
     398             : 
     399             : static int
     400           0 : freeze_lookup_table( fd_exec_instr_ctx_t * ctx ) {
     401             : 
     402           0 : # define ACC_IDX_LUT       (0UL)
     403           0 : # 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           0 :   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           0 :   if( FD_UNLIKELY( 0!=memcmp( lut_acct->const_meta->info.owner, fd_solana_address_lookup_table_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     413           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     414           0 :   }
     415             : 
     416           0 :   } 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           0 :   fd_pubkey_t const * authority_key = NULL;
     423           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_AUTHORITY, authority_acct ) {
     424             : 
     425           0 :   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           0 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) ) {
     429           0 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     430           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     431           0 :   }
     432             : 
     433           0 :   } FD_BORROWED_ACCOUNT_DROP( authority_acct );
     434             : 
     435             :   /* Update lookup table account **************************************/
     436             : 
     437           0 :   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           0 :   uchar const * lut_data    = lut_acct->const_data;
     441           0 :   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           0 :   fd_addrlut_t lut[1];
     445           0 :   int err = fd_addrlut_deserialize( lut, lut_data, lut_data_sz );
     446           0 :   if( FD_UNLIKELY( err ) ) { 
     447           0 :     return err;
     448           0 :   }
     449             : 
     450           0 :   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           0 :   if( FD_UNLIKELY( !state->meta.has_authority ) ) {
     454           0 :     fd_log_collector_msg_literal( ctx, "Lookup table is already frozen");
     455           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     456           0 :   }
     457             : 
     458             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L201-L203 */
     459           0 :   if( FD_UNLIKELY( 0!=memcmp( state->meta.authority.key, authority_key->key, sizeof(fd_pubkey_t) ) ) ) {
     460           0 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     461           0 :   }
     462             : 
     463             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L204-L207 */
     464           0 :   if( FD_UNLIKELY( state->meta.deactivation_slot!=ULONG_MAX ) ) {
     465           0 :     fd_log_collector_msg_literal( ctx, "Deactivated tables cannot be frozen" );
     466           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     467           0 :   }
     468             : 
     469             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L208-L211 */
     470           0 :   if( FD_UNLIKELY( !lut->addr_cnt ) ) {
     471           0 :     fd_log_collector_msg_literal( ctx, "Empty lookup tables cannot be frozen" );
     472           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     473           0 :   }
     474             : 
     475           0 :   uchar *data = NULL;
     476           0 :   ulong dlen  = 0UL;
     477           0 :   err = fd_account_get_data_mut( ctx, ACC_IDX_LUT, &data, &dlen );
     478           0 :   if( FD_UNLIKELY( err ) ) {
     479           0 :     return err;
     480           0 :   }
     481             : 
     482             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L213-L218 */
     483           0 :   state->meta.has_authority = 0;
     484             : 
     485           0 :   err = fd_addrlut_serialize_meta( &lut->state, data, dlen );
     486           0 :   if( FD_UNLIKELY( err ) ) { 
     487           0 :     return err;
     488           0 :   }
     489             : 
     490           0 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     491             : 
     492           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     493           0 : # undef ACC_IDX_LUT
     494           0 : # undef ACC_IDX_AUTHORITY
     495           0 : }
     496             : 
     497             : static int
     498             : extend_lookup_table( fd_exec_instr_ctx_t *       ctx,
     499           0 :                      fd_addrlut_extend_t const * extend ) {
     500             : 
     501           0 : # define ACC_IDX_LUT       (0UL)
     502           0 : # define ACC_IDX_AUTHORITY (1UL)
     503           0 : # 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           0 :   fd_pubkey_t const * lut_key = NULL;
     509             : 
     510             :   /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     511           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     512             : 
     513           0 :   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           0 :   if( FD_UNLIKELY( 0!=memcmp( lut_acct->const_meta->info.owner, fd_solana_address_lookup_table_program_id.key, sizeof(fd_pubkey_t) ) ) )
     517           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     518             : 
     519           0 :   } 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           0 :   fd_pubkey_t const * authority_key = NULL;
     525             : 
     526             :   /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     527           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_AUTHORITY, authority_acct ) {
     528             : 
     529           0 :   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           0 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) ) {
     533           0 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     534           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     535           0 :   }
     536             : 
     537           0 :   } FD_BORROWED_ACCOUNT_DROP( authority_acct );
     538             : 
     539             :   /* Update lookup table account **************************************/
     540             : 
     541           0 :   uchar const * lut_data          = NULL;
     542           0 :   ulong         lut_data_sz       = 0UL;
     543           0 :   ulong         lut_lamports      = 0UL;
     544           0 :   ulong         new_table_data_sz = 0UL;
     545             : 
     546             : 
     547           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     548             : 
     549           0 :   lut_data     = lut_acct->const_data;
     550           0 :   lut_data_sz  = lut_acct->const_meta->dlen;
     551           0 :   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           0 :   fd_addrlut_t lut[1];
     555           0 :   int err = fd_addrlut_deserialize( lut, (uchar *)lut_data, lut_data_sz );
     556           0 :   if( FD_UNLIKELY( err ) ) { 
     557           0 :     return err; 
     558           0 :   }
     559             : 
     560           0 :   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           0 :   if( FD_UNLIKELY( !state->meta.has_authority ) ) {
     564           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     565           0 :   }
     566             : 
     567             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L256-L258 */
     568           0 :   if( FD_UNLIKELY( 0!=memcmp( state->meta.authority.key, authority_key->key, sizeof(fd_pubkey_t) ) ) ) {
     569           0 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     570           0 :   }
     571             : 
     572             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L259-L262 */
     573           0 :   if( FD_UNLIKELY( state->meta.deactivation_slot != ULONG_MAX ) ) {
     574           0 :     fd_log_collector_msg_literal( ctx, "Deactivated tables cannot be extended" );
     575           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     576           0 :   }
     577             : 
     578             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L263-L269 */
     579           0 :   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           0 :   if( FD_UNLIKELY( !extend->new_addrs_len ) ) {
     586           0 :     fd_log_collector_msg_literal( ctx, "Must extend with at least one address" );
     587           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     588           0 :   }
     589             : 
     590             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L276-L279 */
     591           0 :   ulong old_addr_cnt = lut->addr_cnt;
     592           0 :   ulong new_addr_cnt = lut->addr_cnt + extend->new_addrs_len;
     593           0 :   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           0 :   fd_sol_sysvar_clock_t clock[1];
     602           0 :   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           0 :   if( clock->slot!=state->meta.last_extended_slot ) {
     607           0 :     state->meta.last_extended_slot             = clock->slot;
     608           0 :     state->meta.last_extended_slot_start_index = (uchar)lut->addr_cnt;
     609           0 :   }
     610             : 
     611             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/address-lookup-table/src/processor.rs#L302
     612           0 :   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           0 :   if( FD_UNLIKELY( !fd_account_can_data_be_changed( ctx, ACC_IDX_LUT, &err ) ) ) {
     616           0 :     return err;
     617           0 :   }
     618             : 
     619           0 :   int modify_err = fd_instr_borrowed_account_modify( ctx, lut_acct->pubkey, new_table_data_sz, &lut_acct );
     620           0 :   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           0 :   err = fd_addrlut_serialize_meta( &lut->state, lut_acct->data, lut_acct->meta->dlen );
     626           0 :   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           0 :   do {
     632           0 :     uchar * new_keys = lut_acct->data + FD_ADDRLUT_META_SZ + old_addr_cnt * sizeof(fd_pubkey_t);
     633           0 :     fd_memcpy( new_keys, extend->new_addrs, extend->new_addrs_len * sizeof(fd_pubkey_t) );
     634           0 :   } while(0);
     635           0 :   lut_acct->meta->dlen = new_table_data_sz;
     636           0 :   lut->addr            = (fd_pubkey_t *)(lut_acct->data + FD_ADDRLUT_META_SZ);
     637           0 :   lut->addr_cnt        = new_addr_cnt;
     638             : 
     639           0 :   } 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           0 :   fd_epoch_bank_t * epoch_bank        = fd_exec_epoch_ctx_epoch_bank( ctx->slot_ctx->epoch_ctx );
     644           0 :   fd_rent_t       * rent              = &epoch_bank->rent;
     645           0 :   ulong             required_lamports = fd_rent_exempt_minimum_balance( rent, new_table_data_sz );
     646           0 :                     required_lamports = fd_ulong_max    ( required_lamports, 1UL );
     647           0 :                     required_lamports = fd_ulong_sat_sub( required_lamports, lut_lamports );
     648             : 
     649           0 :   if( required_lamports ) {
     650           0 :     fd_pubkey_t const * payer_key = NULL;
     651             : 
     652             :     /* try_borrow_account => get_index_of_instruction_account_in_transaction */
     653           0 :     FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_PAYER, payer_acct ) {
     654             : 
     655           0 :     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           0 :     if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_PAYER ) ) ) {
     658           0 :       fd_log_collector_msg_literal( ctx, "Payer account must be a signer" );
     659           0 :       return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     660           0 :     }
     661             : 
     662           0 :     } FD_BORROWED_ACCOUNT_DROP( payer_acct );
     663             : 
     664             : 
     665           0 :     FD_SPAD_FRAME_BEGIN( ctx->txn_ctx->spad ) {
     666             :       // Create account metas
     667           0 :       fd_vm_rust_account_meta_t * acct_metas = (fd_vm_rust_account_meta_t *)
     668           0 :                                                 fd_spad_alloc( ctx->txn_ctx->spad, FD_VM_RUST_ACCOUNT_META_ALIGN, 2 * sizeof(fd_vm_rust_account_meta_t) );
     669           0 :       fd_native_cpi_create_account_meta( payer_key, 1, 1, &acct_metas[0] );
     670           0 :       fd_native_cpi_create_account_meta( lut_key,   0, 1, &acct_metas[1] );
     671             : 
     672             :       // Create signers list
     673           0 :       fd_pubkey_t signers[16];
     674           0 :       ulong signers_cnt = 1UL;
     675           0 :       signers[0]        = *payer_key;
     676             : 
     677             :       // Create system program instruction
     678           0 :       fd_system_program_instruction_t instr = {0};
     679           0 :       instr.discriminant                    = fd_system_program_instruction_enum_transfer;
     680           0 :       instr.inner.transfer                  = required_lamports;
     681             : 
     682           0 :       int err = fd_native_cpi_execute_system_program_instruction( ctx,
     683           0 :                                                                   &instr,
     684           0 :                                                                   acct_metas,
     685           0 :                                                                   2UL,
     686           0 :                                                                   signers,
     687           0 :                                                                   signers_cnt );
     688           0 :       if( FD_UNLIKELY( err ) ) {
     689           0 :         return err;
     690           0 :       }
     691           0 :     } FD_SPAD_FRAME_END;
     692           0 :   }
     693             : 
     694           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     695             : 
     696           0 : # undef ACC_IDX_LUT
     697           0 : # undef ACC_IDX_AUTHORITY
     698           0 : # undef ACC_IDX_PAYER
     699           0 : }
     700             : 
     701             : static int
     702           0 : deactivate_lookup_table( fd_exec_instr_ctx_t * ctx ) {
     703             : 
     704           0 : # define ACC_IDX_LUT       (0UL)
     705           0 : # 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           0 :   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           0 :   if( FD_UNLIKELY( 0!=memcmp( lut_acct->const_meta->info.owner, fd_solana_address_lookup_table_program_id.key, sizeof(fd_pubkey_t) ) ) )
     715           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     716             : 
     717           0 :   } 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           0 :   fd_pubkey_t const * authority_key = NULL;
     724           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_AUTHORITY, authority_acct ) {
     725             : 
     726           0 :   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           0 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) ) {
     730           0 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     731           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     732           0 :   }
     733             : 
     734           0 :   } FD_BORROWED_ACCOUNT_DROP( authority_acct );
     735             : 
     736             :   /* Update lookup table account **************************************/
     737             : 
     738           0 :   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           0 :   uchar const * lut_data    = lut_acct->const_data;
     742           0 :   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           0 :   fd_addrlut_t lut[1];
     746           0 :   int err = fd_addrlut_deserialize( lut, (uchar *)lut_data, lut_data_sz );
     747           0 :   if( FD_UNLIKELY( err ) ) { 
     748           0 :     return err;
     749           0 :   }
     750             : 
     751           0 :   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           0 :   if( FD_UNLIKELY( !state->meta.has_authority ) ) {
     755           0 :     fd_log_collector_msg_literal( ctx, "Lookup table is already frozen" );
     756           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     757           0 :   }
     758             : 
     759             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L371-L373 */
     760           0 :   if( FD_UNLIKELY( 0!=memcmp( state->meta.authority.key, authority_key->key, sizeof(fd_pubkey_t) ) ) ) {
     761           0 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     762           0 :   }
     763             : 
     764             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L374-L377 */
     765           0 :   if( FD_UNLIKELY( state->meta.deactivation_slot != ULONG_MAX ) ) {
     766           0 :     fd_log_collector_msg_literal( ctx, "Lookup table is already deactivated" );
     767           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     768           0 :   }
     769             : 
     770             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L380 */
     771           0 :   fd_sol_sysvar_clock_t clock[1];
     772           0 :   if( FD_UNLIKELY( !fd_sysvar_clock_read( clock, ctx->slot_ctx ) ) ) {
     773           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     774           0 :   }
     775             : 
     776           0 :   uchar * data = NULL;
     777           0 :   ulong   dlen = 0UL;
     778           0 :   err = fd_account_get_data_mut ( ctx, ACC_IDX_LUT, &data, &dlen );
     779           0 :   if( FD_UNLIKELY( err ) ) {
     780           0 :     return err;
     781           0 :   }
     782             : 
     783             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L381 */
     784           0 :   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           0 :   err = fd_addrlut_serialize_meta( &lut->state, data, dlen );
     788           0 :   if( FD_UNLIKELY( err ) ) { 
     789           0 :     return err;
     790           0 :   }
     791             : 
     792           0 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     793             : 
     794           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     795             : 
     796           0 : # undef ACC_IDX_LUT
     797           0 : # undef ACC_IDX_AUTHORITY
     798           0 : }
     799             : 
     800             : static int
     801           0 : close_lookup_table( fd_exec_instr_ctx_t * ctx ) {
     802             : 
     803           0 : # define ACC_IDX_LUT       (0UL)
     804           0 : # define ACC_IDX_AUTHORITY (1UL)
     805           0 : # 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           0 :   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           0 :   if( FD_UNLIKELY( 0!=memcmp( lut_acct->const_meta->info.owner, fd_solana_address_lookup_table_program_id.key, sizeof(fd_pubkey_t) ) ) )
     815           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     816             : 
     817           0 :   } 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           0 :   fd_pubkey_t const * authority_key = NULL;
     824           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_AUTHORITY, authority_acct ) {
     825             : 
     826           0 :   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           0 :   if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, ACC_IDX_AUTHORITY ) ) ) {
     830           0 :     fd_log_collector_msg_literal( ctx, "Authority account must be a signer" );
     831           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     832           0 :   }
     833             : 
     834           0 :   } 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           0 :   if( FD_UNLIKELY( ctx->instr->acct_cnt<3 ) ) {
     840           0 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     841           0 :   }
     842             : 
     843             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L412-L420 */
     844           0 :   if( FD_UNLIKELY( ctx->instr->borrowed_accounts[0]==ctx->instr->borrowed_accounts[2] ) ) {
     845           0 :     fd_log_collector_msg_literal( ctx, "Lookup table cannot be the recipient of reclaimed lamports" );
     846           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     847           0 :   }
     848             : 
     849           0 :   ulong         withdrawn_lamports = 0UL;
     850           0 :   uchar const * lut_data           = NULL;
     851           0 :   ulong         lut_data_sz        = 0UL;
     852             : 
     853           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     854             : 
     855           0 :   withdrawn_lamports = lut_acct->const_meta->info.lamports;
     856           0 :   lut_data           = lut_acct->const_data;
     857           0 :   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           0 :   fd_addrlut_t lut[1];
     861           0 :   int err = fd_addrlut_deserialize( lut, (uchar *)lut_data, lut_data_sz );
     862           0 :   if( FD_UNLIKELY( err ) ) { 
     863           0 :     return err;
     864           0 :   }
     865             : 
     866           0 :   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           0 :   if( FD_UNLIKELY( !state->meta.has_authority ) ) {
     870           0 :     fd_log_collector_msg_literal( ctx,  "Lookup table is frozen" );
     871           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE;
     872           0 :   }
     873             : 
     874             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L432-L434 */
     875           0 :   if( FD_UNLIKELY( 0!=memcmp( state->meta.authority.key, authority_key->key, sizeof(fd_pubkey_t) ) ) ) {
     876           0 :     return FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY;
     877           0 :   }
     878             : 
     879             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L437 */
     880           0 :   fd_sol_sysvar_clock_t clock[1];
     881           0 :   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           0 :   fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes( ctx->slot_ctx->sysvar_cache );
     887           0 :   if( FD_UNLIKELY( !slot_hashes ) ) { 
     888           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
     889           0 :   }
     890             : 
     891             :   /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L440 */
     892           0 :   ulong remaining_blocks = 0UL;
     893           0 :   int status = fd_addrlut_status( &state->meta, clock->slot, slot_hashes->hashes, &remaining_blocks );
     894             : 
     895           0 :   switch( status ) {
     896           0 :     case FD_ADDRLUT_STATUS_ACTIVATED:
     897           0 :       fd_log_collector_msg_literal( ctx, "Lookup table is not deactivated" );
     898           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     899           0 :     case FD_ADDRLUT_STATUS_DEACTIVATING:
     900             :       /* Max msg_sz: 65 - 3 + 20 = 82 < 127 => we can use printf */
     901           0 :       fd_log_collector_printf_dangerous_max_127( ctx,
     902           0 :         "Table cannot be closed until it's fully deactivated in %lu blocks", remaining_blocks );
     903           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     904           0 :     case FD_ADDRLUT_STATUS_DEACTIVATED:
     905           0 :       break;
     906           0 :     default:
     907           0 :       __builtin_unreachable();
     908           0 :   }
     909             :   
     910           0 :   } 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           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_RECIPIENT, recipient_acct ) {
     916             : 
     917           0 :   int err = fd_account_checked_add_lamports( ctx, ACC_IDX_RECIPIENT, withdrawn_lamports );
     918           0 :   if( FD_UNLIKELY( err ) ) {
     919           0 :     return err;
     920           0 :   }
     921             : 
     922           0 :   } FD_BORROWED_ACCOUNT_DROP( recipient_acct );
     923             : 
     924             :   /* Delete LUT account ***********************************************/
     925             : 
     926           0 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, ACC_IDX_LUT, lut_acct ) {
     927             : 
     928           0 :   int err;
     929           0 :   err = fd_account_set_data_length( ctx, ACC_IDX_LUT, 0UL );
     930           0 :   if( FD_UNLIKELY( err ) ) {
     931           0 :     return err;
     932           0 :   }
     933             : 
     934           0 :   err = fd_account_set_lamports( ctx, ACC_IDX_LUT, 0UL );
     935           0 :   if( FD_UNLIKELY( err ) ) {
     936           0 :     return err;
     937           0 :   }
     938             : 
     939           0 :   } FD_BORROWED_ACCOUNT_DROP( lut_acct );
     940             : 
     941           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     942             : 
     943           0 : # undef ACC_IDX_LUT
     944           0 : # undef ACC_IDX_AUTHORITY
     945           0 : # undef ACC_IDX_RECIPIENT
     946           0 : }
     947             : 
     948             : int
     949           0 : fd_address_lookup_table_program_execute( fd_exec_instr_ctx_t * ctx ) {
     950           0 :   FD_EXEC_CU_UPDATE( ctx, DEFAULT_COMPUTE_UNITS );
     951             : 
     952           0 :   uchar const * instr_data    = ctx->instr->data;
     953           0 :   ulong         instr_data_sz = ctx->instr->data_sz;
     954           0 :   if( FD_UNLIKELY( instr_data==NULL ) ) {
     955           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     956           0 :   }
     957             : 
     958           0 :   FD_SPAD_FRAME_BEGIN( ctx->txn_ctx->spad ) {
     959             : 
     960           0 :     fd_bincode_decode_ctx_t decode = {
     961           0 :       .valloc  = fd_spad_virtual( ctx->txn_ctx->spad ),
     962           0 :       .data    = instr_data,
     963           0 :       .dataend = instr_data + instr_data_sz
     964           0 :     };
     965           0 :     fd_addrlut_instruction_t instr[1];
     966             :     /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L28 */
     967           0 :     if( FD_UNLIKELY( fd_addrlut_instruction_decode( instr, &decode ) ||
     968           0 :                      (ulong)instr_data + 1232UL < (ulong)decode.data ) ) {
     969           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     970           0 :     }
     971             : 
     972           0 :     switch( instr->discriminant ) {
     973           0 :     case fd_addrlut_instruction_enum_create_lut:
     974           0 :       return create_lookup_table( ctx, &instr->inner.create_lut );
     975           0 :     case fd_addrlut_instruction_enum_freeze_lut:
     976           0 :       return freeze_lookup_table( ctx );
     977           0 :     case fd_addrlut_instruction_enum_extend_lut:
     978           0 :       return extend_lookup_table( ctx, &instr->inner.extend_lut );
     979           0 :     case fd_addrlut_instruction_enum_deactivate_lut:
     980           0 :       return deactivate_lookup_table( ctx );
     981           0 :     case fd_addrlut_instruction_enum_close_lut:
     982           0 :       return close_lookup_table( ctx );
     983           0 :     default:
     984           0 :       break;
     985           0 :     }
     986           0 :   } FD_SPAD_FRAME_END;
     987             : 
     988           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     989           0 : }
     990             : 
     991             : /**********************************************************************/
     992             : /* Public API                                                         */
     993             : /**********************************************************************/
     994             : 
     995             : /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L72-L78 */
     996             : static uchar
     997             : is_active( fd_address_lookup_table_t const * self,
     998             :            ulong                             current_slot,
     999        7560 :            fd_slot_hash_t const *            slot_hashes ) {
    1000             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L73-L77 */
    1001        7560 :   ulong _dummy[1];
    1002        7560 :   switch( fd_addrlut_status( &self->meta, current_slot, slot_hashes, _dummy ) ) {
    1003        7539 :     case FD_ADDRLUT_STATUS_ACTIVATED:
    1004        7551 :     case FD_ADDRLUT_STATUS_DEACTIVATING:
    1005        7551 :       return 1;
    1006           9 :     case FD_ADDRLUT_STATUS_DEACTIVATED:
    1007           9 :       return 0;
    1008           0 :     default:
    1009           0 :       __builtin_unreachable();
    1010        7560 :   }
    1011        7560 : }
    1012             : 
    1013             : /* Sets active_addresses_len on success
    1014             :    https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L142-L164 */
    1015             : int
    1016             : fd_get_active_addresses_len( fd_address_lookup_table_t * self,
    1017             :                              ulong                       current_slot,
    1018             :                              fd_slot_hash_t const *      slot_hashes,
    1019             :                              ulong                       addresses_len,
    1020        7560 :                              ulong *                     active_addresses_len ) {
    1021             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L147-L152 */
    1022        7560 :   if( FD_UNLIKELY( !is_active( self, current_slot, slot_hashes ) ) ) {
    1023           9 :     return FD_RUNTIME_TXN_ERR_ADDRESS_LOOKUP_TABLE_NOT_FOUND;
    1024           9 :   }
    1025             : 
    1026             :   /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L157-L161 */
    1027        7551 :   *active_addresses_len = ( current_slot > self->meta.last_extended_slot )
    1028        7551 :       ? addresses_len
    1029        7551 :       : self->meta.last_extended_slot_start_index;
    1030             :   
    1031        7551 :   return FD_RUNTIME_EXECUTE_SUCCESS;
    1032        7560 : }

Generated by: LCOV version 1.14