LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_account.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 107 160 66.9 %
Date: 2024-11-13 11:58:15 Functions: 45 391 11.5 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_fd_account_h
       2             : #define HEADER_fd_src_flamenco_runtime_fd_account_h
       3             : 
       4             : /* fd_account.h contains safe API helpers for accounts.
       5             : 
       6             :    ### Account Existence
       7             : 
       8             :    "Does an account exist?" is not trivial to answer.  We can instead
       9             :    look at qualifiers:
      10             : 
      11             :      A: Does a database record exist?
      12             :      B: Is the native (lamport) balance greater than zero?
      13             :      C: Is the account "dead"?
      14             : 
      15             :    From the on-chain program's perspective, even addresses that have
      16             :    never been interacted with can be read.  That account would show up
      17             :    as zero balance, zero owner (system program), and has no data.  This
      18             :    means, logically, for all possible 2^256 account addresses, it
      19             :    appears that an account exists.  We call such accounts "dead"
      20             :    accounts (C).
      21             : 
      22             :    C also implies B.  There are may be intermediate account states
      23             :    however where an account has zero balance, but is still owned by a
      24             :    program.  Thus, B does not necessarily imply C.
      25             : 
      26             :    Obviously, we only have finite database space.  Whenever an account
      27             :    becomes dead, we try to free the record.  If no funk record for
      28             :    an account exists (C), it is dead (A).  This doesn't always work, so
      29             :    sometimes there is a leftover record containing a dead account.
      30             :    (Also called a "tombstone")
      31             : 
      32             :    For the on-chain program developer this means:  DO NOT assume a funk
      33             :    record exists for all accounts.  DO NOT look at the funk record
      34             :    pointer, as its existence is U.B. for dead accounts.
      35             : 
      36             :    See fd_acc_exists and the below helper functions for safe use in
      37             :    native programs. */
      38             : 
      39             : #include "fd_executor_err.h"
      40             : #include "fd_system_ids.h"
      41             : #include "context/fd_exec_epoch_ctx.h"
      42             : #include "context/fd_exec_txn_ctx.h"
      43             : #include "program/fd_program_util.h"
      44             : #include "sysvar/fd_sysvar_rent.h"
      45             : #include <assert.h>  /* TODO remove */
      46             : 
      47             : /* FD_ACC_SZ_MAX is the hardcoded size limit of a Solana account. */
      48             : 
      49           0 : #define MAX_PERMITTED_DATA_LENGTH                 (10UL<<20) /* 10MiB */
      50             : #define MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN (10UL<<21) /* 20MiB */
      51             : 
      52             : FD_PROTOTYPES_BEGIN
      53             : 
      54             : /* Instruction account APIs *******************************************/
      55             : 
      56             : /* Assert that enougha ccounts were supplied to this instruction. Returns 
      57             :    FD_EXECUTOR_INSTR_SUCCESS if the number of accounts is as expected and 
      58             :    FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS otherwise.
      59             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L492-L503 */
      60             : static inline int
      61             : fd_account_check_num_insn_accounts( fd_exec_instr_ctx_t * ctx,
      62        1977 :                                     uint                  expected_accounts ) {
      63             : 
      64        1977 :   if( FD_UNLIKELY( ctx->instr->acct_cnt<expected_accounts ) ) {
      65           0 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
      66           0 :   }
      67        1977 :   return FD_EXECUTOR_INSTR_SUCCESS;
      68        1977 : }
      69             : 
      70             : /* fd_account_get_owner mirrors Anza function 
      71             :    solana_sdk::transaction_context:Borrowed_account::get_owner.  Returns 0
      72             :    iff the owner is retrieved successfully.
      73             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L734-L738 */
      74             : static inline fd_pubkey_t const *
      75             : fd_account_get_owner( fd_exec_instr_ctx_t const * ctx,
      76           0 :                       ulong                       instr_acc_idx ) {
      77           0 :   fd_borrowed_account_t * account = NULL;
      78           0 :   do {
      79           0 :     int err = fd_instr_borrowed_account_view_idx( ctx, (uchar)instr_acc_idx, &account );
      80           0 :     if( FD_UNLIKELY( err ) ) {
      81           0 :       FD_LOG_ERR(( "fd_instr_borrowed_account_view_idx failed (%d-%s)", err, fd_acc_mgr_strerror( err ) ));
      82           0 :     }
      83           0 :   } while(0);
      84           0 : 
      85           0 :   return (fd_pubkey_t const *) account->const_meta->info.owner;
      86           0 : }
      87             : 
      88             : /* fd_account_set_owner mirrors Anza function 
      89             :    solana_sdk::transaction_context:Borrowed_account::set_owner.  Returns 0
      90             :    iff the owner is set successfully.  Acquires a writable handle. */
      91             : int
      92             : fd_account_set_owner( fd_exec_instr_ctx_t const * ctx,
      93             :                       ulong                       instr_acc_idx,
      94             :                       fd_pubkey_t const *         owner );
      95             : 
      96             : /* fd_account_get_lamports mirrors Anza function
      97             :    solana_sdk::transaction_context::BorrowedAccount::get_lamports.
      98             :    Returns current number of lamports in account.  Well behaved if meta
      99             :    is NULL. */
     100             : 
     101             : static inline ulong
     102           0 : fd_account_get_lamports( fd_account_meta_t const * meta ) {
     103           0 :   if( FD_UNLIKELY( !meta ) ) return 0UL;  /* (!meta) considered an internal error */
     104           0 :   return meta->info.lamports;
     105           0 : }
     106             : 
     107             : static inline ulong
     108             : fd_account_get_lamports2( fd_exec_instr_ctx_t const * ctx,
     109          27 :                           ulong                       instr_acc_idx ) {
     110          27 :   fd_borrowed_account_t * account = NULL;
     111          27 :   do {
     112          27 :     int err = fd_instr_borrowed_account_view_idx( ctx, (uchar)instr_acc_idx, &account );
     113          27 :     if( FD_UNLIKELY( err ) ) {
     114           0 :       return 0UL;
     115           0 :     }
     116          27 :   } while(0);
     117             : 
     118          27 :   return account->const_meta->info.lamports;
     119          27 : }
     120             : 
     121             : /* fd_account_set_lamports mirrors Anza function
     122             :    solana_sdk::transaction_context::BorrowedAccount::set_lamports.
     123             :    Runs through a sequence of permission checks, then sets the account
     124             :    balance.  Does not update global capitalization.  On success, returns
     125             :    0 and updates meta->lamports.  On failure, returns an
     126             :    FD_EXECUTOR_INSTR_ERR_{...} code.  Acquires a writable handle. */
     127             : 
     128             : int
     129             : fd_account_set_lamports( fd_exec_instr_ctx_t const * ctx,
     130             :                          ulong                       instr_acc_idx,
     131             :                          ulong                       lamports );
     132             : 
     133             : /* 
     134             :   fd_account_checked_{add,sub}_lamports mirros Anza 
     135             :    add/removes lamports to/from an
     136             :    account.  Does not update global capitalization.  Returns 0 on
     137             :    success or an FD_EXECUTOR_INSTR_ERR_{...} code on failure.
     138             :    Gracefully handles underflow.  Acquires a writable handle. 
     139             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L798-L817 */
     140             : 
     141             : static inline int
     142             : fd_account_checked_add_lamports( fd_exec_instr_ctx_t const * ctx,
     143             :                                  ulong                       instr_acc_idx,
     144        4254 :                                  ulong                       lamports ) {
     145             : 
     146        4254 :   fd_borrowed_account_t * account = NULL;
     147        4254 :   do {
     148        4254 :     int err = fd_instr_borrowed_account_modify_idx( ctx, (uchar)instr_acc_idx, 0UL, &account );
     149        4254 :     if( FD_UNLIKELY( err ) ) { 
     150           0 :       FD_LOG_ERR(( "fd_instr_borrowed_account_modify_idx failed (%d-%s)", err, fd_acc_mgr_strerror( err ) ));
     151           0 :     }
     152        4254 :   } while(0);
     153             : 
     154        4254 :   ulong balance_post = 0UL;
     155        4254 :   int err = fd_ulong_checked_add( account->const_meta->info.lamports, lamports, &balance_post );
     156        4254 :   if( FD_UNLIKELY( err ) ) {
     157         216 :     return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
     158         216 :   }
     159             : 
     160        4038 :   return fd_account_set_lamports( ctx, instr_acc_idx, balance_post );
     161        4254 : }
     162             : 
     163             : static inline int
     164             : fd_account_checked_sub_lamports( fd_exec_instr_ctx_t const * ctx,
     165             :                                  ulong                       instr_acc_idx,
     166        3867 :                                  ulong                       lamports ) {
     167             : 
     168        3867 :   fd_borrowed_account_t * account = NULL;
     169        3867 :   do {
     170        3867 :     int err = fd_instr_borrowed_account_modify_idx( ctx, (uchar)instr_acc_idx, 0UL, &account );
     171        3867 :     if( FD_UNLIKELY( err ) ) { 
     172           0 :       FD_LOG_ERR(( "fd_instr_borrowed_account_modify_idx failed (%d-%s)", err, fd_acc_mgr_strerror( err ) ));
     173           0 :     }
     174        3867 :   } while(0);
     175             : 
     176        3867 :   ulong balance_post = 0UL;
     177        3867 :   int err = fd_ulong_checked_sub( account->const_meta->info.lamports, lamports, &balance_post );
     178        3867 :   if( FD_UNLIKELY( err ) ) {
     179           3 :     return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
     180           3 :   }
     181             : 
     182        3864 :   return fd_account_set_lamports( ctx, instr_acc_idx, balance_post );
     183        3867 : }
     184             : 
     185             : /* fd_account_get_data_mut mirrors Anza function 
     186             :    solana_sdk::transaction_context::BorrowedAccount::set_lamports. 
     187             :    Returns a writable slice of the account data (transaction wide).
     188             :    Acquires a writable handle. This function assumes that the relevant
     189             :    borrowed has already acquired exclusive write access.
     190             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L824-L831 */
     191             : int 
     192             : fd_account_get_data_mut( fd_exec_instr_ctx_t const * ctx, 
     193             :                          ulong                       instr_acc_idx,
     194             :                          uchar * *                   data_out,
     195             :                          ulong *                     dlen_out );
     196             :               
     197             : /* TODO: Implement fd_account_spare_data_capacity_mut which is used in direct mapping */
     198             : 
     199             : /* fd_account_set_data_from_slice mirrors Anza function
     200             :    solana_sdk::transaction_context::BorrowedAccount::set_data_from_slice.
     201             :    In the firedancer client, it also mirrors the Anza function
     202             :    solana_sdk::transaction_context::BorrowedAccount::set_data.
     203             :    Assumes that destination account already has enough space to fit
     204             :    data.  Acquires a writable handle.
     205             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L867-882 */
     206             : 
     207             : int
     208             : fd_account_set_data_from_slice( fd_exec_instr_ctx_t const * ctx,
     209             :                                 ulong                       instr_acc_idx,
     210             :                                 uchar const *               data,
     211             :                                 ulong                       data_sz );
     212             : 
     213             : /* fd_account_set_data_length mirrors Anza function
     214             :    solana_sdk::transaction_context::BorrowedAccount::set_data_length.
     215             :    Acquires a writable handle. Returns 0 on success.
     216             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L994-L900 */
     217             : 
     218             : int
     219             : fd_account_set_data_length( fd_exec_instr_ctx_t const * ctx,
     220             :                             ulong                       instr_acc_idx,
     221             :                             ulong                       new_len );
     222             : 
     223             : /* fd_account_is_rent_exempt_at_data_length mirrors Anza function
     224             :    solana_sdk::transaction_context::BorrowedAccount::is_rent_exempt_at_data_length.
     225             :    Returns 1 if an account is rent exempt at it's current data length.
     226             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L990-997 */
     227             : 
     228             : static inline int
     229             : fd_account_is_rent_exempt_at_data_length( fd_exec_instr_ctx_t const * ctx,
     230           0 :                                           fd_account_meta_t   const * meta ) {
     231           0 :   assert( meta != NULL );
     232           0 :   fd_rent_t rent    = ctx->epoch_ctx->epoch_bank.rent;
     233           0 :   ulong min_balance = fd_rent_exempt_minimum_balance( &rent, meta->dlen );
     234           0 :   return meta->info.lamports >= min_balance; 
     235           0 : }
     236             : 
     237             : /* fd_account_is_executable returns 1 if the given account has the
     238             :    executable flag set.  Otherwise, returns 0.  Mirrors Anza's
     239             :    solana_sdk::transaction_context::BorrowedAccount::is_executable.
     240             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L1001-1003 */
     241             : 
     242             : FD_FN_PURE static inline int
     243       38892 : fd_account_is_executable( fd_account_meta_t const * meta ) {
     244       38892 :   return !!meta->info.executable;
     245       38892 : }
     246             : 
     247             : /* fd_account_set_executable mirrors Anza function
     248             :    solana_sdk::transaction_context::BorrowedAccount::set_executable.
     249             :    Returns FD_EXECUTOR_INSTR_SUCCESS if the set is successful.
     250             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L1007-1035 */
     251             : 
     252             : int
     253             : fd_account_set_executable( fd_exec_instr_ctx_t const * ctx,
     254             :                            ulong                       instr_acc_idx,
     255             :                            int                         is_executable );
     256             : 
     257             : /* fd_account_get_rent_epoch mirrors Anza function 
     258             :    solana_sdk::transaction_context::BorrowedAccount::get_rent_epoch. 
     259             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L1040-1042 */
     260             : 
     261             : static inline ulong
     262           0 : fd_account_get_rent_epoch( fd_account_meta_t const * meta ) {
     263           0 :   assert( meta != NULL );
     264           0 :   return meta->info.rent_epoch;
     265           0 : }
     266             : 
     267             : /* fd_account_is_{signer,writable} mirror the Anza functions
     268             :    solana_sdk::transaction_context::BorrowedAccount::is_{signer,writer}.
     269             :    Returns 1 if the account is a signer or is writable and 0 otherwise.
     270             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L1044-1068 */
     271             : 
     272             : static inline int
     273             : fd_account_is_signer( fd_exec_instr_ctx_t const * ctx,
     274           0 :                       ulong                       instr_acc_idx ) {
     275           0 :   if( FD_UNLIKELY( instr_acc_idx >= ctx->instr->acct_cnt ) ) {
     276           0 :     return 0;
     277           0 :   }
     278           0 :   return fd_instr_acc_is_signer_idx( ctx->instr, instr_acc_idx );
     279           0 : }
     280             : 
     281             : static inline int
     282             : fd_account_is_writable( fd_exec_instr_ctx_t const * ctx,
     283           0 :                         ulong                       instr_acc_idx ) {
     284           0 :   if( FD_UNLIKELY( instr_acc_idx >= ctx->instr->acct_cnt ) ) {
     285           0 :     return 0;
     286           0 :   }
     287           0 : 
     288           0 :   return fd_instr_acc_is_writable_idx( ctx->instr, instr_acc_idx );
     289           0 : }
     290             : 
     291             : /* fd_account_is_owned_by_current_program returns 1 if the given
     292             :    account is owned by the program invoked in the current instruction.
     293             :    Otherwise, returns 0.  Mirrors Anza's
     294             :    solana_sdk::transaction_context::BorrowedAccount::is_owned_by_current_program */
     295             : 
     296             : FD_FN_PURE static inline int
     297             : fd_account_is_owned_by_current_program( fd_instr_info_t const *   info,
     298       28998 :                                         fd_account_meta_t const * acct ) {
     299       28998 :   return 0==memcmp( info->program_id_pubkey.key, acct->info.owner, sizeof(fd_pubkey_t) );
     300       28998 : }
     301             : 
     302             : /* fd_account_can_data_be changed mirrors Anza function 
     303             :    solana_sdk::transaction_context::BorrowedAccount::can_data_be_changed.
     304             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L1078-L1094 */
     305             : static inline int
     306             : fd_account_can_data_be_changed( fd_instr_info_t const * instr,
     307             :                                 ulong                   instr_acc_idx,
     308       14748 :                                 int *                   err ) {
     309             : 
     310       14748 :   assert( instr_acc_idx < instr->acct_cnt );
     311       14748 :   fd_account_meta_t const * meta = instr->borrowed_accounts[ instr_acc_idx ]->const_meta;
     312             : 
     313       14748 :   if( FD_UNLIKELY( fd_account_is_executable( meta ) ) ) {
     314        1314 :     *err = FD_EXECUTOR_INSTR_ERR_EXECUTABLE_DATA_MODIFIED;
     315        1314 :     return 0;
     316        1314 :   }
     317             : 
     318       13434 :   if( FD_UNLIKELY( !fd_instr_acc_is_writable_idx( instr, instr_acc_idx ) ) ) {
     319         984 :     *err = FD_EXECUTOR_INSTR_ERR_READONLY_DATA_MODIFIED;
     320         984 :     return 0;
     321         984 :   }
     322             : 
     323       12450 :   if( FD_UNLIKELY( !fd_account_is_owned_by_current_program( instr, meta ) ) ) {
     324        1236 :     *err = FD_EXECUTOR_INSTR_ERR_EXTERNAL_DATA_MODIFIED;
     325        1236 :     return 0;
     326        1236 :   }
     327             : 
     328       11214 :   err = FD_EXECUTOR_INSTR_SUCCESS;
     329       11214 :   return 1;
     330       12450 : }
     331             : 
     332             : /* fd_account_can_data_be_resized mirrors Anza function 
     333             :    solana_sdk::transaction_context::BorrowedAccount::can_data_be_resized 
     334             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L1096-L1119
     335             : */
     336             : static inline int
     337             : fd_account_can_data_be_resized( fd_exec_instr_ctx_t const * instr_ctx,
     338             :                                 fd_account_meta_t const *   acct,
     339             :                                 ulong                       new_length,
     340        6072 :                                 int *                       err ) {
     341             :   /* Only the owner can change the length of the data */
     342        6072 :   if( FD_UNLIKELY( ( acct->dlen != new_length ) &
     343        6072 :                    ( !fd_account_is_owned_by_current_program( instr_ctx->instr, acct ) ) ) ) {
     344           3 :     *err = FD_EXECUTOR_INSTR_ERR_ACC_DATA_SIZE_CHANGED;
     345           3 :     return 0;
     346           3 :   }
     347             : 
     348             :   /* The new length can not exceed the maximum permitted length */
     349        6069 :   if( FD_UNLIKELY( new_length>MAX_PERMITTED_DATA_LENGTH ) ) {
     350           0 :     *err = FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC;
     351           0 :     return 0;
     352           0 :   }
     353             : 
     354             :   /* The resize can not exceed the per-transaction maximum
     355             :      https://github.com/firedancer-io/agave/blob/1e460f466da60a63c7308e267c053eec41dc1b1c/sdk/src/transaction_context.rs#L1107-L1111 */
     356        6069 :   ulong length_delta = fd_ulong_sat_sub( new_length, acct->dlen );
     357        6069 :   ulong new_accounts_resize_delta = fd_ulong_sat_add( instr_ctx->txn_ctx->accounts_resize_delta, length_delta );
     358        6069 :   if( FD_UNLIKELY( new_accounts_resize_delta>MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN ) ) {
     359           0 :     *err = FD_EXECUTOR_INSTR_ERR_MAX_ACCS_DATA_ALLOCS_EXCEEDED;
     360           0 :     return 0;
     361           0 :   }
     362             : 
     363        6069 :   *err = FD_EXECUTOR_INSTR_SUCCESS;
     364        6069 :   return 1;
     365        6069 : }
     366             : 
     367             : /* fd_account_update_acounts_resize_delta mirrors Anza function
     368             :    solana_sdk::transaction_context:BorrowedAccount::update_accounts_resize_delta. 
     369             :    https://github.com/anza-xyz/agave/blob/b5f5c3cdd3f9a5859c49ebc27221dc27e143d760/sdk/src/transaction_context.rs#L1128-L1138 */
     370             : 
     371             : int
     372             : fd_account_update_accounts_resize_delta( fd_exec_instr_ctx_t const * ctx,
     373             :                                          ulong                       instr_acc_idx,
     374             :                                          ulong                       new_len,
     375             :                                          int *                       err );
     376             : 
     377             : FD_FN_PURE static inline int
     378        1974 : fd_account_is_zeroed( fd_account_meta_t const * acct ) {
     379             :   // TODO: optimize this
     380        1974 :   uchar const * data = ((uchar *) acct) + acct->hlen;
     381  5790563646 :   for( ulong i=0UL; i < acct->dlen; i++ )
     382  5790561729 :     if( data[i] != 0 )
     383          57 :       return 0;
     384        1917 :   return 1;
     385        1974 : }
     386             : 
     387             : /* fd_account_find_idx_of_insn_account returns the idx of the instruction account
     388             :     or -1 if the account is not found
     389             :     https://github.com/anza-xyz/agave/blob/d5a84daebd2a7225684aa3f722b330e9d5381e76/sdk/src/transaction_context.rs#L527
     390             :  */
     391             : static inline int
     392             : fd_account_find_idx_of_insn_account( fd_exec_instr_ctx_t const * ctx,
     393         792 :                                      fd_pubkey_t *               pubkey ) {
     394        5571 :   for( ushort i=0; i<ctx->instr->acct_cnt; i++ ) {
     395        5562 :     if( 0==memcmp( pubkey, &ctx->instr->acct_pubkeys[i], sizeof(fd_pubkey_t) ) ) {
     396         783 :       return (int)i;
     397         783 :     }
     398        5562 :   }
     399           9 :   return -1;
     400         792 : }
     401             : 
     402             : /* Transaction account APIs *******************************************/
     403             : 
     404             : /* https://github.com/anza-xyz/agave/blob/92ad51805862fbb47dc40968dff9f93b57395b51/sdk/program/src/message/legacy.rs#L636 */
     405             : static inline int
     406      133044 : fd_txn_account_is_writable_idx( fd_exec_txn_ctx_t const * txn_ctx, int idx ) {
     407      133044 :   int acct_addr_cnt = txn_ctx->txn_descriptor->acct_addr_cnt;
     408      133044 :   if( txn_ctx->txn_descriptor->transaction_version == FD_TXN_V0 ) {
     409      126066 :     acct_addr_cnt += txn_ctx->txn_descriptor->addr_table_adtl_cnt;
     410      126066 :   }
     411             : 
     412      133044 :   if( idx==acct_addr_cnt ) {
     413           3 :     return 0;
     414           3 :   }
     415             : 
     416      133041 :   if( fd_pubkey_is_active_reserved_key(&txn_ctx->accounts[idx] ) 
     417      133041 :       || ( FD_FEATURE_ACTIVE( txn_ctx->slot_ctx, add_new_reserved_account_keys ) && fd_pubkey_is_pending_reserved_key( &txn_ctx->accounts[idx] ) )) {
     418       36462 :     return 0;
     419       36462 :   }
     420             : 
     421       96579 :   if( fd_txn_account_is_demotion( txn_ctx, idx ) ) {
     422       14055 :     return 0;
     423       14055 :   }
     424             : 
     425       82524 :   return fd_txn_is_writable( txn_ctx->txn_descriptor, idx );
     426       96579 : }
     427             : 
     428             : FD_PROTOTYPES_END
     429             : 
     430             : #include "fd_account_old.h"
     431             : 
     432             : #endif /* HEADER_fd_src_flamenco_runtime_fd_account_h */

Generated by: LCOV version 1.14