LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_borrowed_account.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 117 137 85.4 %
Date: 2026-10-22 18:10:43 Functions: 9 9 100.0 %

          Line data    Source code
       1             : #include "fd_borrowed_account.h"
       2             : #include "fd_runtime.h"
       3             : 
       4             : #if FD_HAS_AVX512
       5             : #include "../../util/simd/fd_avx512.h"
       6             : #elif FD_HAS_AVX
       7             : #include "../../util/simd/fd_avx.h"
       8             : #endif
       9             : 
      10             : FD_FN_PURE int
      11        1316 : fd_borrowed_account_is_zeroed( fd_borrowed_account_t const * borrowed_acct ) {
      12        1316 :   uchar const * data    = borrowed_acct->acc->data;
      13        1316 :   ulong         data_sz = borrowed_acct->acc->data_len;
      14             : 
      15             :   /* Peel the loop to avoid unaligned accesses. */
      16        3332 :   while( data_sz && ( (ulong)data & 0x3fUL ) ) {
      17        2016 :     if( FD_UNLIKELY( *data ) ) return 0;
      18        2016 :     data++;
      19        2016 :     data_sz--;
      20        2016 :   }
      21             : 
      22        1316 : #if FD_HAS_AVX512
      23     1187679 :   while( data_sz>=512UL ) {
      24     1186369 :     wwv_t x0 = wwv_or( wwv_ldu( data       ), wwv_ldu( data+ 64UL ) );
      25     1186369 :     wwv_t x1 = wwv_or( wwv_ldu( data+128UL ), wwv_ldu( data+192UL ) );
      26     1186369 :     wwv_t x2 = wwv_or( wwv_ldu( data+256UL ), wwv_ldu( data+320UL ) );
      27     1186369 :     wwv_t x3 = wwv_or( wwv_ldu( data+384UL ), wwv_ldu( data+448UL ) );
      28     1186369 :     wwv_t x  = wwv_or( wwv_or( x0, x1 ), wwv_or( x2, x3 ) );
      29     1186369 :     if( FD_UNLIKELY( _mm512_test_epi64_mask( x, x ) ) ) return 0;
      30     1186363 :     data    += 512UL;
      31     1186363 :     data_sz -= 512UL;
      32     1186363 :   }
      33             : #elif FD_HAS_AVX
      34             :   while( data_sz>=256UL ) {
      35             :     wv_t x0 = wv_or( wv_ldu( data       ), wv_ldu( data+ 32UL ) );
      36             :     wv_t x1 = wv_or( wv_ldu( data+ 64UL ), wv_ldu( data+ 96UL ) );
      37             :     wv_t x2 = wv_or( wv_ldu( data+128UL ), wv_ldu( data+160UL ) );
      38             :     wv_t x3 = wv_or( wv_ldu( data+192UL ), wv_ldu( data+224UL ) );
      39             :     wv_t x  = wv_or( wv_or( x0, x1 ), wv_or( x2, x3 ) );
      40             :     if( FD_UNLIKELY( !_mm256_testz_si256( x, x ) ) ) return 0;
      41             :     data    += 256UL;
      42             :     data_sz -= 256UL;
      43             :   }
      44             : #endif
      45             : 
      46      132517 :   for( ulong i=0UL; i<data_sz; i++ )
      47      131215 :     if( FD_UNLIKELY( data[i] ) ) return 0;
      48             : 
      49        1302 :   return 1;
      50        1310 : }
      51             : 
      52             : int
      53             : fd_borrowed_account_get_data_mut( fd_borrowed_account_t * borrowed_acct,
      54             :                                   uchar * *               data_out,
      55        4464 :                                   ulong *                 dlen_out ) {
      56             : 
      57             :   /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L824 */
      58        4464 :   int err;
      59        4464 :   fd_borrowed_account_can_data_be_changed( borrowed_acct, &err );
      60        4464 :   if( FD_UNLIKELY( err ) ) {
      61          11 :     return err;
      62          11 :   }
      63             : 
      64        4453 :   *borrowed_acct->touched = 1;
      65             : 
      66        4453 :   if ( data_out != NULL )
      67        4453 :     *data_out = borrowed_acct->acc->data;
      68        4453 :   if ( dlen_out != NULL )
      69        4453 :     *dlen_out = borrowed_acct->acc->data_len;
      70             : 
      71        4453 :   return FD_EXECUTOR_INSTR_SUCCESS;
      72        4464 : }
      73             : 
      74             : int
      75             : fd_borrowed_account_set_owner( fd_borrowed_account_t * borrowed_acct,
      76        1407 :                                fd_pubkey_t const *     owner ) {
      77             : 
      78             :   /* Only the owner can assign a new owner
      79             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L741 */
      80        1407 :   if( FD_UNLIKELY( !fd_borrowed_account_is_owned_by_current_program( borrowed_acct ) ) ) {
      81          79 :     return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID;
      82          79 :   }
      83             : 
      84             :   /* And only if the account is writable
      85             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L745 */
      86        1328 :   if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) {
      87          12 :     return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID;
      88          12 :   }
      89             : 
      90             :   /* And only if the data is zero-initialized or empty
      91             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L753 */
      92        1316 :   if( FD_UNLIKELY( !fd_borrowed_account_is_zeroed( borrowed_acct ) ) ) {
      93          14 :     return FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID;
      94          14 :   }
      95             : 
      96             :   /* Don't copy the account if the owner does not change
      97             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L757 */
      98        1302 :   if( !memcmp( borrowed_acct->acc->owner, owner, sizeof(fd_pubkey_t) ) ) {
      99           0 :     return FD_EXECUTOR_INSTR_SUCCESS;
     100           0 :   }
     101             : 
     102        1302 :   *borrowed_acct->touched = 1;
     103             : 
     104             :   /* Copy into owner
     105             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L761 */
     106        1302 :   fd_memcpy( borrowed_acct->acc->owner, owner, sizeof(fd_pubkey_t) );
     107        1302 :   return FD_EXECUTOR_INSTR_SUCCESS;
     108        1302 : }
     109             : 
     110             : /* Overwrites the number of lamports of this account (transaction wide)
     111             :    https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L773 */
     112             : int
     113             : fd_borrowed_account_set_lamports( fd_borrowed_account_t * borrowed_acct,
     114        4551 :                                   ulong                   lamports ) {
     115             : 
     116             :   /* An account not owned by the program cannot have its balance decrease
     117             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L775 */
     118        4551 :   if( FD_UNLIKELY( (!fd_borrowed_account_is_owned_by_current_program( borrowed_acct )) &&
     119        4551 :                    (lamports<borrowed_acct->acc->lamports) ) ) {
     120          10 :     return FD_EXECUTOR_INSTR_ERR_EXTERNAL_ACCOUNT_LAMPORT_SPEND;
     121          10 :   }
     122             : 
     123             :   /* The balance of read-only may not change
     124             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L779 */
     125        4541 :   if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) {
     126         154 :     return FD_EXECUTOR_INSTR_ERR_READONLY_LAMPORT_CHANGE;
     127         154 :   }
     128             : 
     129             :   /* Don't copy the account if the lamports do not change
     130             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L787 */
     131        4387 :   if( borrowed_acct->acc->lamports==lamports ) {
     132          94 :     return FD_EXECUTOR_INSTR_SUCCESS;
     133          94 :   }
     134             : 
     135        4293 :   *borrowed_acct->touched = 1;
     136             : 
     137        4293 :   borrowed_acct->acc->lamports = lamports;
     138        4293 :   return FD_EXECUTOR_INSTR_SUCCESS;
     139        4387 : }
     140             : 
     141             : int
     142             : fd_borrowed_account_set_data_from_slice( fd_borrowed_account_t * borrowed_acct,
     143             :                                          uchar const *           data,
     144         315 :                                          ulong                   data_sz ) {
     145             : 
     146             :   /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/instruction_accounts.rs#L181-L184 */
     147         315 :   int err;
     148         315 :   if ( FD_UNLIKELY( !fd_borrowed_account_can_data_be_resized( borrowed_acct, data_sz, &err ) ) ) {
     149          63 :     return err;
     150          63 :   }
     151             : 
     152         252 :   *borrowed_acct->touched = 1;
     153             : 
     154             :   /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L868 */
     155         252 :   if( FD_UNLIKELY( !fd_borrowed_account_update_accounts_resize_delta( borrowed_acct, data_sz, &err ) ) ) {
     156           0 :     return err;
     157           0 :   }
     158             : 
     159             :   /* AccountSharedData::set_data_from_slice() */
     160         252 :   borrowed_acct->acc->data_len = (uint)data_sz;
     161         252 :   fd_memcpy( borrowed_acct->acc->data, data, data_sz );
     162             : 
     163         252 :   return FD_EXECUTOR_INSTR_SUCCESS;
     164         252 : }
     165             : 
     166             : int
     167             : fd_borrowed_account_set_data_length( fd_borrowed_account_t * borrowed_acct,
     168        1122 :                                      ulong                   new_len ) {
     169        1122 :   int err = FD_EXECUTOR_INSTR_SUCCESS;
     170             : 
     171             :   /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/instruction_accounts.rs#L197-L204 */
     172        1122 :   if( FD_UNLIKELY( !fd_borrowed_account_can_data_be_resized( borrowed_acct, new_len, &err ) ) ) {
     173          23 :     return err;
     174          23 :   }
     175             : 
     176        1099 :   ulong old_len = borrowed_acct->acc->data_len;
     177             : 
     178             :   /* Don't copy the account if the length does not change
     179             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L886 */
     180        1099 :   if( old_len==new_len ) {
     181          96 :     return FD_EXECUTOR_INSTR_SUCCESS;
     182          96 :   }
     183             : 
     184        1003 :   *borrowed_acct->touched = 1;
     185             : 
     186             :   /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L890 */
     187        1003 :   if( FD_UNLIKELY( !fd_borrowed_account_update_accounts_resize_delta( borrowed_acct, new_len, &err ) ) ) {
     188           0 :     return err;
     189           0 :   }
     190             : 
     191             :   /* Resize the account
     192             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L891 */
     193        1003 :   ulong memset_sz = fd_ulong_sat_sub( new_len, borrowed_acct->acc->data_len );
     194        1003 :   fd_memset( borrowed_acct->acc->data+borrowed_acct->acc->data_len, 0, memset_sz );
     195        1003 :   borrowed_acct->acc->data_len = (uint)new_len;
     196             : 
     197        1003 :   return FD_EXECUTOR_INSTR_SUCCESS;
     198        1003 : }
     199             : 
     200             : int
     201             : fd_borrowed_account_set_executable( fd_borrowed_account_t * borrowed_acct,
     202         174 :                                     int                     is_executable ) {
     203             :   /* To become executable an account must be rent exempt
     204             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1003-L1006 */
     205         174 :   fd_rent_t const * rent = &borrowed_acct->instr_ctx->bank->f.rent;
     206         174 :   if( FD_UNLIKELY( borrowed_acct->acc->lamports<fd_rent_exempt_minimum_balance( rent, borrowed_acct->acc->data_len ) ) ) {
     207           0 :     return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT;
     208           0 :   }
     209             : 
     210             :   /* Only the owner can set the executable flag
     211             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1011 */
     212         174 :   if( FD_UNLIKELY( !fd_borrowed_account_is_owned_by_current_program( borrowed_acct ) ) ) {
     213           0 :     return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_MODIFIED;
     214           0 :   }
     215             : 
     216             :   /* And only if the account is writable
     217             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1015 */
     218         174 :   if( FD_UNLIKELY( !fd_borrowed_account_is_writable( borrowed_acct ) ) ) {
     219           0 :     return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_MODIFIED;
     220           0 :   }
     221             : 
     222             :   /* Don't copy the account if the executable flag does not change
     223             :      https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1023 */
     224         174 :   if( fd_borrowed_account_is_executable( borrowed_acct ) == is_executable ) {
     225           0 :     return FD_EXECUTOR_INSTR_SUCCESS;
     226           0 :   }
     227             : 
     228         174 :   *borrowed_acct->touched = 1;
     229             : 
     230             :   /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1027 */
     231         174 :   borrowed_acct->acc->executable = !!is_executable;
     232             : 
     233         174 :   return FD_EXECUTOR_INSTR_SUCCESS;
     234         174 : }
     235             : 
     236             : int
     237             : fd_borrowed_account_update_accounts_resize_delta( fd_borrowed_account_t * borrowed_acct,
     238             :                                                   ulong                   new_len,
     239        1255 :                                                   int *                   err ) {
     240        1255 :   fd_exec_instr_ctx_t const * instr_ctx  = borrowed_acct->instr_ctx;
     241        1255 :   long                        size_delta = fd_long_sat_sub( (long)new_len, (long)borrowed_acct->acc->data_len );
     242             : 
     243             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/transaction-context/src/transaction_accounts.rs#L303-L313 */
     244        1255 :   instr_ctx->txn_out->details.accounts_resize_delta = fd_long_sat_add( instr_ctx->txn_out->details.accounts_resize_delta, size_delta );
     245        1255 :   *err = FD_EXECUTOR_INSTR_SUCCESS;
     246        1255 :   return 1;
     247        1255 : }
     248             : 
     249             : int
     250             : fd_borrowed_account_can_data_be_resized( fd_borrowed_account_t const * borrowed_acct,
     251             :                                          ulong                         new_length,
     252       25629 :                                          int *                         err ) {
     253             :   /* The new length can not exceed the maximum permitted length
     254             :      https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/transaction_accounts.rs#L319-L322 */
     255       25629 :   if( FD_UNLIKELY( new_length>MAX_PERMITTED_DATA_LENGTH ) ) {
     256           0 :     *err = FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC;
     257           0 :     return 0;
     258           0 :   }
     259             : 
     260             :   /* The resize can not exceed the per-transaction maximum
     261             :      https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/transaction_accounts.rs#L323-L329 */
     262       25629 :   long length_delta              = fd_long_sat_sub( (long)new_length, (long)borrowed_acct->acc->data_len );
     263       25629 :   long new_accounts_resize_delta = fd_long_sat_add( borrowed_acct->instr_ctx->txn_out->details.accounts_resize_delta, length_delta );
     264       25629 :   if( FD_UNLIKELY( new_accounts_resize_delta>MAX_PERMITTED_ACCOUNT_DATA_ALLOCS_PER_TXN ) ) {
     265           0 :     *err = FD_EXECUTOR_INSTR_ERR_MAX_ACCS_DATA_ALLOCS_EXCEEDED;
     266           0 :     return 0;
     267           0 :   }
     268             : 
     269             :   /* The account data can only be resized if it can be changed
     270             :      https://github.com/anza-xyz/agave/blob/v4.2.0-beta.0/transaction-context/src/instruction_accounts.rs#L351-L357 */
     271       25629 :   return fd_borrowed_account_can_data_be_changed( borrowed_acct, err );
     272       25629 : }

Generated by: LCOV version 1.14