LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_txn_account.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 176 336 52.4 %
Date: 2025-10-13 04:42:14 Functions: 22 38 57.9 %

          Line data    Source code
       1             : #include "fd_txn_account.h"
       2             : #include "fd_runtime.h"
       3             : 
       4             : void *
       5             : fd_txn_account_new( void *              mem,
       6             :                     fd_pubkey_t const * pubkey,
       7             :                     fd_account_meta_t * meta,
       8        1059 :                     int                 is_mutable ) {
       9        1059 :   if( FD_UNLIKELY( !mem ) ) {
      10           3 :     FD_LOG_WARNING(( "NULL mem" ));
      11           3 :     return NULL;
      12           3 :   }
      13             : 
      14        1056 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, alignof(fd_txn_account_t) ) ) ) {
      15           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      16           0 :     return NULL;
      17           0 :   }
      18             : 
      19        1056 :   if( FD_UNLIKELY( !pubkey ) ) {
      20           3 :     FD_LOG_WARNING(( "NULL pubkey" ));
      21           3 :     return NULL;
      22           3 :   }
      23             : 
      24        1053 :   if( FD_UNLIKELY( !meta ) ) {
      25           3 :     FD_LOG_WARNING(( "NULL meta" ));
      26           3 :     return NULL;
      27           3 :   }
      28             : 
      29        1050 :   fd_txn_account_t * txn_account = (fd_txn_account_t *)mem;
      30             : 
      31        1050 :   fd_memcpy( txn_account->pubkey, pubkey, sizeof(fd_pubkey_t) );
      32             : 
      33        1050 :   txn_account->magic             = FD_TXN_ACCOUNT_MAGIC;
      34             : 
      35        1050 :   txn_account->starting_dlen     = meta->dlen;
      36        1050 :   txn_account->starting_lamports = meta->lamports;
      37             : 
      38        1050 :   uchar * data = (uchar *)meta + sizeof(fd_account_meta_t);
      39             : 
      40        1050 :   txn_account->meta_soff = (long)( (ulong)meta - (ulong)mem );
      41             : 
      42        1050 :   txn_account->meta       = meta;
      43        1050 :   txn_account->data       = data;
      44        1050 :   txn_account->is_mutable = is_mutable;
      45             : 
      46        1050 :   return mem;
      47        1053 : }
      48             : 
      49             : fd_txn_account_t *
      50        1065 : fd_txn_account_join( void * mem, fd_wksp_t * data_wksp ) {
      51        1065 :   if( FD_UNLIKELY( !mem ) ) {
      52           3 :     FD_LOG_WARNING(( "NULL mem" ));
      53           3 :     return NULL;
      54           3 :   }
      55             : 
      56        1062 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, alignof(fd_txn_account_t) ) ) ) {
      57           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      58           0 :     return NULL;
      59           0 :   }
      60             : 
      61        1062 :   if( FD_UNLIKELY( !data_wksp ) ) {
      62           3 :     FD_LOG_WARNING(( "NULL data_wksp" ));
      63           3 :     return NULL;
      64           3 :   }
      65             : 
      66        1059 :   fd_txn_account_t * txn_account = (fd_txn_account_t *)mem;
      67             : 
      68        1059 :   if( FD_UNLIKELY( txn_account->magic != FD_TXN_ACCOUNT_MAGIC ) ) {
      69           6 :     FD_LOG_WARNING(( "wrong magic" ));
      70           6 :     return NULL;
      71           6 :   }
      72             : 
      73        1053 :   if( FD_UNLIKELY( txn_account->meta_soff==0UL ) ) {
      74           0 :     FD_LOG_CRIT(( "invalid meta_soff" ));
      75           0 :   }
      76             : 
      77        1053 :   txn_account->meta = (void *)( (ulong)mem + (ulong)txn_account->meta_soff );
      78        1053 :   txn_account->data = (void *)( (ulong)txn_account->meta + sizeof(fd_account_meta_t) );
      79             : 
      80        1053 :   return txn_account;
      81        1053 : }
      82             : 
      83             : void *
      84          15 : fd_txn_account_leave( fd_txn_account_t * acct ) {
      85             : 
      86          15 :   if( FD_UNLIKELY( !acct ) ) {
      87           3 :     FD_LOG_WARNING(( "NULL acct" ));
      88           3 :     return NULL;
      89           3 :   }
      90             : 
      91          12 :   if( FD_UNLIKELY( acct->magic != FD_TXN_ACCOUNT_MAGIC ) ) {
      92           0 :     FD_LOG_WARNING(( "wrong magic" ));
      93           0 :     return NULL;
      94           0 :   }
      95             : 
      96          12 :   acct->meta = NULL;
      97          12 :   acct->data = NULL;
      98             : 
      99          12 :   return acct;
     100          12 : }
     101             : 
     102             : void *
     103           9 : fd_txn_account_delete( void * mem ) {
     104           9 :   if( FD_UNLIKELY( !mem ) ) {
     105           3 :     FD_LOG_WARNING(( "NULL mem" ));
     106           3 :     return NULL;
     107           3 :   }
     108             : 
     109           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, alignof(fd_txn_account_t) ) ) ) {
     110           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     111           0 :     return NULL;
     112           0 :   }
     113             : 
     114           6 :   fd_txn_account_t * txn_account = (fd_txn_account_t *)mem;
     115             : 
     116           6 :   if( FD_UNLIKELY( txn_account->magic != FD_TXN_ACCOUNT_MAGIC ) ) {
     117           0 :     FD_LOG_WARNING(( "wrong magic" ));
     118           0 :     return NULL;
     119           0 :   }
     120             : 
     121           6 :   txn_account->magic = 0UL;
     122             : 
     123           6 :   return mem;
     124           6 : }
     125             : 
     126             : /* Factory constructors from funk */
     127             : 
     128             : int
     129             : fd_txn_account_init_from_funk_readonly( fd_txn_account_t *        acct,
     130             :                                         fd_pubkey_t const *       pubkey,
     131             :                                         fd_funk_t const *         funk,
     132        4209 :                                         fd_funk_txn_xid_t const * xid ) {
     133             : 
     134        4209 :   int err = FD_ACC_MGR_SUCCESS;
     135        4209 :   fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
     136        4209 :       funk,
     137        4209 :       xid,
     138        4209 :       pubkey,
     139        4209 :       NULL,
     140        4209 :       &err,
     141        4209 :       NULL );
     142             : 
     143        4209 :   if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     144        3675 :     return err;
     145        3675 :   }
     146             : 
     147         534 :   if( FD_UNLIKELY( !fd_txn_account_join( fd_txn_account_new(
     148         534 :         acct,
     149         534 :         pubkey,
     150         534 :         (fd_account_meta_t *)meta,
     151         534 :         0 ), fd_funk_wksp( funk ) ) ) ) {
     152           0 :     FD_LOG_CRIT(( "Failed to join txn account" ));
     153           0 :   }
     154             : 
     155         534 :   return FD_ACC_MGR_SUCCESS;
     156         534 : }
     157             : 
     158             : int
     159             : fd_txn_account_init_from_funk_mutable( fd_txn_account_t *        acct,
     160             :                                        fd_pubkey_t const *       pubkey,
     161             :                                        fd_funk_t *               funk,
     162             :                                        fd_funk_txn_xid_t const * xid,
     163             :                                        int                       do_create,
     164             :                                        ulong                     min_data_sz,
     165         510 :                                        fd_funk_rec_prepare_t *   prepare_out ) {
     166         510 :   memset( prepare_out, 0, sizeof(fd_funk_rec_prepare_t) );
     167         510 :   int err = FD_ACC_MGR_SUCCESS;
     168         510 :   fd_account_meta_t * meta = fd_funk_get_acc_meta_mutable(
     169         510 :       funk,
     170         510 :       xid,
     171         510 :       pubkey,
     172         510 :       do_create,
     173         510 :       min_data_sz,
     174         510 :       NULL,
     175         510 :       prepare_out,
     176         510 :       &err );
     177             : 
     178         510 :   if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     179           0 :     return err;
     180           0 :   }
     181             : 
     182             :   /* exec tile should never call this function, so the global addresses
     183             :      of meta and data should never be used. Instead, populate the
     184             :      prepared_rec field so that any created records can be published
     185             :      with fd_txn_account_mutable_fini. */
     186             : 
     187         510 :   if( FD_UNLIKELY( !fd_txn_account_join( fd_txn_account_new(
     188         510 :         acct,
     189         510 :         pubkey,
     190         510 :         (fd_account_meta_t *)meta,
     191         510 :         1 ), fd_funk_wksp( funk ) ) ) ) {
     192           0 :     FD_LOG_CRIT(( "Failed to join txn account" ));
     193           0 :   }
     194             : 
     195         510 :   return FD_ACC_MGR_SUCCESS;
     196         510 : }
     197             : 
     198             : void
     199             : fd_txn_account_mutable_fini( fd_txn_account_t *        acct,
     200             :                              fd_funk_t *               funk,
     201         510 :                              fd_funk_rec_prepare_t *   prepare ) {
     202         510 :   fd_funk_rec_key_t key = fd_funk_acc_key( acct->pubkey );
     203             : 
     204             :   /* Check that the prepared record is still valid -
     205             :      if these invariants are broken something is very wrong. */
     206         510 :   if( prepare->rec ) {
     207             :     /* Check that the prepared record is not the Funk null value */
     208          45 :     if( !prepare->rec->val_gaddr ) {
     209           0 :       FD_LOG_CRIT(( "invalid prepared record for %s: unexpected NULL funk record value. the record might have been modified by another thread",
     210           0 :                    FD_BASE58_ENC_32_ALLOCA( acct->pubkey ) ));
     211           0 :     }
     212             : 
     213             :     /* Ensure that the prepared record key still matches our key. */
     214          45 :     if( FD_UNLIKELY( memcmp( prepare->rec->pair.key, &key, sizeof(fd_funk_rec_key_t) )!=0 ) ) {
     215           0 :       FD_LOG_CRIT(( "invalid prepared record for %s: the record might have been modified by another thread",
     216           0 :                   FD_BASE58_ENC_32_ALLOCA( acct->pubkey ) ));
     217           0 :     }
     218             : 
     219             :     /* Crashes the app if this key already exists in funk (conflicting
     220             :        write) */
     221          45 :     fd_funk_rec_publish( funk, prepare );
     222          45 :   }
     223         510 : }
     224             : 
     225             : /* read/write mutual exclusion */
     226             : 
     227             : FD_FN_PURE int
     228           0 : fd_txn_account_acquire_write_is_safe( fd_txn_account_t const * acct ) {
     229           0 :   return !acct->refcnt_excl;
     230           0 : }
     231             : 
     232             : /* fd_txn_account_acquire_write acquires write/exclusive access.
     233             :    Causes all other write or read acquire attempts will fail.  Returns 1
     234             :    on success, 0 on failure.
     235             : 
     236             :    Mirrors a try_borrow_mut() call in Agave. */
     237             : int
     238           0 : fd_txn_account_acquire_write( fd_txn_account_t * acct ) {
     239           0 :   if( FD_UNLIKELY( !fd_txn_account_acquire_write_is_safe( acct ) ) ) {
     240           0 :     return 0;
     241           0 :   }
     242           0 :   acct->refcnt_excl = (ushort)1;
     243           0 :   return 1;
     244           0 : }
     245             : 
     246             : /* fd_txn_account_release_write{_private} releases a write/exclusive
     247             :    access handle. The private version should only be used by fd_borrowed_account_drop
     248             :    and fd_borrowed_account_destroy. */
     249             : void
     250           0 : fd_txn_account_release_write( fd_txn_account_t * acct ) {
     251           0 :   if( FD_UNLIKELY( acct->refcnt_excl!=1 ) ) {
     252           0 :     FD_LOG_CRIT(( "refcnt_excl is %d, expected 1", acct->refcnt_excl ));
     253           0 :   }
     254           0 :   acct->refcnt_excl = (ushort)0;
     255           0 : }
     256             : 
     257             : void
     258           0 : fd_txn_account_release_write_private( fd_txn_account_t * acct ) {
     259             :   /* Only release if it is not yet released */
     260           0 :   if( !fd_txn_account_acquire_write_is_safe( acct ) ) {
     261           0 :     fd_txn_account_release_write( acct );
     262           0 :   }
     263           0 : }
     264             : 
     265             : fd_pubkey_t const *
     266         198 : fd_txn_account_get_owner( fd_txn_account_t const * acct ) {
     267         198 :   if( FD_UNLIKELY( !acct->meta ) ) {
     268           0 :     FD_LOG_CRIT(( "account is not setup" ));
     269           0 :   }
     270         198 :   return (fd_pubkey_t const *)acct->meta->owner;
     271         198 : }
     272             : 
     273             : fd_account_meta_t const *
     274         927 : fd_txn_account_get_meta( fd_txn_account_t const * acct ) {
     275         927 :   return acct->meta;
     276         927 : }
     277             : 
     278             : uchar const *
     279        1473 : fd_txn_account_get_data( fd_txn_account_t const * acct ) {
     280        1473 :   return acct->data;
     281        1473 : }
     282             : 
     283             : uchar *
     284          36 : fd_txn_account_get_data_mut( fd_txn_account_t const * acct ) {
     285          36 :   return acct->data;
     286          36 : }
     287             : 
     288             : ulong
     289         555 : fd_txn_account_get_data_len( fd_txn_account_t const * acct ) {
     290         555 :   if( FD_UNLIKELY( !acct->meta ) ) {
     291           0 :     FD_LOG_CRIT(( "account is not setup" ));
     292           0 :   }
     293         555 :   return acct->meta->dlen;
     294         555 : }
     295             : 
     296             : int
     297           0 : fd_txn_account_is_executable( fd_txn_account_t const * acct ) {
     298           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     299           0 :     FD_LOG_CRIT(( "account is not setup" ));
     300           0 :   }
     301           0 :   return !!acct->meta->executable;
     302           0 : }
     303             : 
     304             : ulong
     305         936 : fd_txn_account_get_lamports( fd_txn_account_t const * acct ) {
     306         936 :   if( FD_UNLIKELY( !acct->meta ) ) {
     307           0 :     FD_LOG_CRIT(( "account is not setup" ));
     308           0 :   }
     309         936 :   return acct->meta->lamports;
     310         936 : }
     311             : 
     312             : ulong
     313           6 : fd_txn_account_get_rent_epoch( fd_txn_account_t const * acct ) {
     314           6 :   (void)acct;
     315           6 :   return ULONG_MAX;
     316           6 : }
     317             : 
     318             : void
     319           0 : fd_txn_account_set_meta( fd_txn_account_t * acct, fd_account_meta_t * meta ) {
     320           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     321           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     322           0 :   }
     323           0 :   if( FD_UNLIKELY( !meta ) ) {
     324           0 :     FD_LOG_CRIT(( "account is not setup" ));
     325           0 :   }
     326           0 :   acct->meta = meta;
     327           0 : }
     328             : 
     329             : void
     330          33 : fd_txn_account_set_executable( fd_txn_account_t * acct, int is_executable ) {
     331          33 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     332           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     333           0 :   }
     334          33 :   if( FD_UNLIKELY( !acct->meta ) ) {
     335           0 :     FD_LOG_CRIT(( "account is not setup" ));
     336           0 :   }
     337          33 :   acct->meta->executable = !!is_executable;
     338          33 : }
     339             : 
     340             : void
     341         507 : fd_txn_account_set_owner( fd_txn_account_t * acct, fd_pubkey_t const * owner ) {
     342         507 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     343           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     344           0 :   }
     345         507 :   if( FD_UNLIKELY( !acct->meta ) ) {
     346           0 :     FD_LOG_CRIT(( "account is not setup" ));
     347           0 :   }
     348         507 :   fd_memcpy( acct->meta->owner, owner, sizeof(fd_pubkey_t) );
     349         507 : }
     350             : 
     351             : void
     352         498 : fd_txn_account_set_lamports( fd_txn_account_t * acct, ulong lamports ) {
     353         498 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     354           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     355           0 :   }
     356         498 :   if( FD_UNLIKELY( !acct->meta ) ) {
     357           0 :     FD_LOG_CRIT(( "account is not setup" ));
     358           0 :   }
     359         498 :   acct->meta->lamports = lamports;
     360         498 : }
     361             : 
     362             : int
     363           0 : fd_txn_account_checked_add_lamports( fd_txn_account_t * acct, ulong lamports ) {
     364           0 :   ulong balance_post = 0UL;
     365           0 :   int err = fd_ulong_checked_add( fd_txn_account_get_lamports( acct ), lamports, &balance_post );
     366           0 :   if( FD_UNLIKELY( err ) ) {
     367           0 :     return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
     368           0 :   }
     369             : 
     370           0 :   fd_txn_account_set_lamports( acct, balance_post );
     371           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     372           0 : }
     373             : 
     374             : int
     375           0 : fd_txn_account_checked_sub_lamports( fd_txn_account_t * acct, ulong lamports ) {
     376           0 :   ulong balance_post = 0UL;
     377           0 :   int err = fd_ulong_checked_sub( fd_txn_account_get_lamports( acct ),
     378           0 :                                   lamports,
     379           0 :                                   &balance_post );
     380           0 :   if( FD_UNLIKELY( err ) ) {
     381           0 :     return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
     382           0 :   }
     383             : 
     384           0 :   fd_txn_account_set_lamports( acct, balance_post );
     385           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     386           0 : }
     387             : 
     388             : void
     389             : fd_txn_account_set_data( fd_txn_account_t * acct,
     390             :                          void const *       data,
     391         498 :                          ulong              data_sz ) {
     392         498 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     393           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     394           0 :   }
     395         498 :   if( FD_UNLIKELY( !acct->meta ) ) {
     396           0 :     FD_LOG_CRIT(( "account is not setup" ));
     397           0 :   }
     398         498 :   acct->meta->dlen = (uint)data_sz;
     399         498 :   fd_memcpy( acct->data, data, data_sz );
     400         498 : }
     401             : 
     402             : void
     403          15 : fd_txn_account_set_data_len( fd_txn_account_t * acct, ulong data_len ) {
     404          15 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     405           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     406           0 :   }
     407          15 :   if( FD_UNLIKELY( !acct->meta ) ) {
     408           0 :     FD_LOG_CRIT(( "account is not setup" ));
     409           0 :   }
     410          15 :   acct->meta->dlen = (uint)data_len;
     411          15 : }
     412             : 
     413             : void
     414         462 : fd_txn_account_set_slot( fd_txn_account_t * acct, ulong slot ) {
     415         462 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     416           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     417           0 :   }
     418         462 :   if( FD_UNLIKELY( !acct->meta ) ) {
     419           0 :     FD_LOG_CRIT(( "account is not setup" ));
     420           0 :   }
     421         462 :   acct->meta->slot = slot;
     422         462 : }
     423             : 
     424             : void
     425           0 : fd_txn_account_clear_owner( fd_txn_account_t * acct ) {
     426           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     427           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     428           0 :   }
     429           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     430           0 :     FD_LOG_CRIT(( "account is not setup" ));
     431           0 :   }
     432           0 :   fd_memset( acct->meta->owner, 0, sizeof(fd_pubkey_t) );
     433           0 : }
     434             : 
     435             : void
     436             : fd_txn_account_resize( fd_txn_account_t * acct,
     437           0 :                        ulong              dlen ) {
     438           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     439           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     440           0 :   }
     441           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     442           0 :     FD_LOG_CRIT(( "account is not setup" ));
     443           0 :   }
     444             :   /* Because the memory for an account is preallocated for the transaction
     445             :      up to the max account size, we only need to zero out bytes (for the case
     446             :      where the account grew) and update the account dlen. */
     447           0 :   ulong old_sz    = acct->meta->dlen;
     448           0 :   ulong new_sz    = dlen;
     449           0 :   ulong memset_sz = fd_ulong_sat_sub( new_sz, old_sz );
     450           0 :   fd_memset( acct->data+old_sz, 0, memset_sz );
     451             : 
     452           0 :   acct->meta->dlen = (uint)dlen;
     453           0 : }
     454             : 
     455             : ushort
     456           0 : fd_txn_account_is_borrowed( fd_txn_account_t const * acct ) {
     457           0 :   return !!acct->refcnt_excl;
     458           0 : }
     459             : 
     460             : int
     461           6 : fd_txn_account_is_mutable( fd_txn_account_t const * acct ) {
     462             :   /* A txn account is mutable if meta is non NULL */
     463           6 :   return acct->is_mutable;
     464           6 : }
     465             : 
     466             : int
     467           6 : fd_txn_account_is_readonly( fd_txn_account_t const * acct ) {
     468             :   /* A txn account is readonly if only the meta_ field is non NULL */
     469           6 :   return !acct->is_mutable;
     470           6 : }
     471             : 
     472             : int
     473           0 : fd_txn_account_try_borrow_mut( fd_txn_account_t * acct ) {
     474           0 :   return fd_txn_account_acquire_write( acct );
     475           0 : }
     476             : 
     477             : void
     478           0 : fd_txn_account_drop( fd_txn_account_t * acct ) {
     479           0 :   fd_txn_account_release_write_private( acct );
     480           0 : }
     481             : 
     482             : void
     483           0 : fd_txn_account_set_readonly( fd_txn_account_t * acct ) {
     484           0 :   acct->is_mutable = 0;
     485           0 : }
     486             : 
     487             : void
     488           0 : fd_txn_account_set_mutable( fd_txn_account_t * acct ) {
     489           0 :   acct->is_mutable = 1;
     490           0 : }
     491             : 
     492             : fd_solana_account_meta_t
     493           0 : fd_txn_account_get_solana_meta( fd_txn_account_t const * acct ) {
     494           0 :   fd_solana_account_meta_t meta = {
     495           0 :     .lamports   = acct->meta->lamports,
     496             :     .rent_epoch = ULONG_MAX,
     497           0 :     .executable = acct->meta->executable,
     498           0 :   };
     499           0 :   memcpy( meta.owner, acct->meta->owner, sizeof(fd_pubkey_t) );
     500           0 :   return meta;
     501           0 : }

Generated by: LCOV version 1.14