LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_txn_account.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 139 274 50.7 %
Date: 2026-01-12 05:12:51 Functions: 18 28 64.3 %

          Line data    Source code
       1             : #include "fd_txn_account.h"
       2             : #include "fd_runtime.h"
       3             : #include "../accdb/fd_accdb_sync.h"
       4             : #include "../accdb/fd_accdb_impl_v1.h"
       5             : #include "program/fd_program_util.h"
       6             : 
       7             : void *
       8             : fd_txn_account_new( void *              mem,
       9             :                     fd_pubkey_t const * pubkey,
      10             :                     fd_account_meta_t * meta,
      11          51 :                     int                 is_mutable ) {
      12          51 :   if( FD_UNLIKELY( !mem ) ) {
      13           3 :     FD_LOG_WARNING(( "NULL mem" ));
      14           3 :     return NULL;
      15           3 :   }
      16             : 
      17          48 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, alignof(fd_txn_account_t) ) ) ) {
      18           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      19           0 :     return NULL;
      20           0 :   }
      21             : 
      22          48 :   if( FD_UNLIKELY( !pubkey ) ) {
      23           3 :     FD_LOG_WARNING(( "NULL pubkey" ));
      24           3 :     return NULL;
      25           3 :   }
      26             : 
      27          45 :   if( FD_UNLIKELY( !meta ) ) {
      28           3 :     FD_LOG_WARNING(( "NULL meta" ));
      29           3 :     return NULL;
      30           3 :   }
      31             : 
      32          42 :   fd_txn_account_t * txn_account = (fd_txn_account_t *)mem;
      33             : 
      34          42 :   fd_memcpy( txn_account->pubkey, pubkey, sizeof(fd_pubkey_t) );
      35             : 
      36          42 :   txn_account->magic = FD_TXN_ACCOUNT_MAGIC;
      37             : 
      38          42 :   uchar * data = (uchar *)meta + sizeof(fd_account_meta_t);
      39             : 
      40          42 :   txn_account->meta_soff = (long)( (ulong)meta - (ulong)mem );
      41             : 
      42          42 :   txn_account->meta       = meta;
      43          42 :   txn_account->data       = data;
      44          42 :   txn_account->is_mutable = is_mutable;
      45             : 
      46          42 :   return mem;
      47          45 : }
      48             : 
      49             : fd_txn_account_t *
      50          48 : fd_txn_account_join( void * mem ) {
      51          48 :   if( FD_UNLIKELY( !mem ) ) {
      52           0 :     FD_LOG_WARNING(( "NULL mem" ));
      53           0 :     return NULL;
      54           0 :   }
      55             : 
      56          48 :   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          48 :   fd_txn_account_t * txn_account = (fd_txn_account_t *)mem;
      62             : 
      63          48 :   if( FD_UNLIKELY( txn_account->magic != FD_TXN_ACCOUNT_MAGIC ) ) {
      64           3 :     FD_LOG_WARNING(( "wrong magic" ));
      65           3 :     return NULL;
      66           3 :   }
      67             : 
      68          45 :   if( FD_UNLIKELY( txn_account->meta_soff==0UL ) ) {
      69           0 :     FD_LOG_CRIT(( "invalid meta_soff" ));
      70           0 :   }
      71             : 
      72          45 :   return txn_account;
      73          45 : }
      74             : 
      75             : void *
      76          15 : fd_txn_account_leave( fd_txn_account_t * acct ) {
      77             : 
      78          15 :   if( FD_UNLIKELY( !acct ) ) {
      79           3 :     FD_LOG_WARNING(( "NULL acct" ));
      80           3 :     return NULL;
      81           3 :   }
      82             : 
      83          12 :   if( FD_UNLIKELY( acct->magic != FD_TXN_ACCOUNT_MAGIC ) ) {
      84           0 :     FD_LOG_WARNING(( "wrong magic" ));
      85           0 :     return NULL;
      86           0 :   }
      87             : 
      88          12 :   acct->meta = NULL;
      89          12 :   acct->data = NULL;
      90             : 
      91          12 :   return acct;
      92          12 : }
      93             : 
      94             : void *
      95           9 : fd_txn_account_delete( void * mem ) {
      96           9 :   if( FD_UNLIKELY( !mem ) ) {
      97           3 :     FD_LOG_WARNING(( "NULL mem" ));
      98           3 :     return NULL;
      99           3 :   }
     100             : 
     101           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, alignof(fd_txn_account_t) ) ) ) {
     102           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     103           0 :     return NULL;
     104           0 :   }
     105             : 
     106           6 :   fd_txn_account_t * txn_account = (fd_txn_account_t *)mem;
     107             : 
     108           6 :   if( FD_UNLIKELY( txn_account->magic != FD_TXN_ACCOUNT_MAGIC ) ) {
     109           0 :     FD_LOG_WARNING(( "wrong magic" ));
     110           0 :     return NULL;
     111           0 :   }
     112             : 
     113           6 :   txn_account->magic = 0UL;
     114             : 
     115           6 :   return mem;
     116           6 : }
     117             : 
     118             : fd_account_meta_t *
     119             : fd_txn_account_init_from_funk_mutable( fd_txn_account_t *        acct,
     120             :                                        fd_pubkey_t const *       pubkey,
     121             :                                        fd_accdb_user_t *         accdb,
     122             :                                        fd_funk_txn_xid_t const * xid,
     123             :                                        int                       do_create,
     124             :                                        ulong                     min_data_sz,
     125          36 :                                        fd_funk_rec_prepare_t *   prepare_out ) {
     126          36 :   memset( prepare_out, 0, sizeof(fd_funk_rec_prepare_t) );
     127             : 
     128          36 :   fd_accdb_rw_t rw[1];
     129          36 :   int flags = do_create ? FD_ACCDB_FLAG_CREATE : 0;
     130          36 :   if( FD_UNLIKELY( !fd_accdb_open_rw( accdb, rw, xid, pubkey->uc, min_data_sz, flags ) ) ) {
     131           0 :     return NULL;
     132           0 :   }
     133             : 
     134          36 :   if( FD_UNLIKELY( !fd_txn_account_join( fd_txn_account_new(
     135          36 :         acct,
     136          36 :         pubkey,
     137          36 :         (fd_account_meta_t *)rw->meta,
     138          36 :         1 ) ) ) ) {
     139           0 :     FD_LOG_CRIT(( "Failed to join txn account" ));
     140           0 :   }
     141             : 
     142             :   /* HACKY: Convert accdb_rw writable reference into txn_account.
     143             :      In the future, use fd_accdb_modify_publish instead */
     144          36 :   accdb->base.rw_active--;
     145          36 :   fd_accdb_user_v1_t * accdb_v1 = fd_type_pun( accdb );
     146          36 :   fd_funk_txn_t * txn = accdb_v1->funk->txn_pool->ele + accdb_v1->tip_txn_idx;
     147          36 :   if( FD_UNLIKELY( !fd_funk_txn_xid_eq( &txn->xid, xid ) ) ) FD_LOG_CRIT(( "accdb_user corrupt: not joined to the expected transaction" ));
     148          36 :   fd_funk_rec_t * rec = (fd_funk_rec_t *)rw->ref->user_data;
     149          36 :   if( !rec->pub ) {
     150          36 :     *prepare_out = (fd_funk_rec_prepare_t) {
     151          36 :       .rec          = rec,
     152          36 :       .rec_head_idx = &txn->rec_head_idx,
     153          36 :       .rec_tail_idx = &txn->rec_tail_idx
     154          36 :     };
     155          36 :   } else {
     156           0 :     memset( prepare_out, 0, sizeof(fd_funk_rec_prepare_t) );
     157           0 :   }
     158             : 
     159          36 :   return rw->meta;
     160          36 : }
     161             : 
     162             : void
     163             : fd_txn_account_mutable_fini( fd_txn_account_t *      acct,
     164             :                              fd_accdb_user_t *       accdb,
     165          36 :                              fd_funk_rec_prepare_t * prepare ) {
     166          36 :   fd_funk_rec_key_t key = fd_funk_acc_key( acct->pubkey );
     167          36 :   fd_funk_t * funk = fd_accdb_user_v1_funk( accdb );
     168             : 
     169             :   /* Check that the prepared record is still valid -
     170             :      if these invariants are broken something is very wrong. */
     171          36 :   if( prepare->rec ) {
     172             :     /* Check that the prepared record is not the Funk null value */
     173          36 :     if( !prepare->rec->val_gaddr ) {
     174           0 :       FD_BASE58_ENCODE_32_BYTES( acct->pubkey->uc, acct_pubkey_b58 );
     175           0 :       FD_LOG_CRIT(( "invalid prepared record for %s: unexpected NULL funk record value. the record might have been modified by another thread",
     176           0 :                     acct_pubkey_b58 ));
     177           0 :     }
     178             : 
     179             :     /* Ensure that the prepared record key still matches our key. */
     180          36 :     if( FD_UNLIKELY( memcmp( prepare->rec->pair.key, &key, sizeof(fd_funk_rec_key_t) )!=0 ) ) {
     181           0 :       FD_BASE58_ENCODE_32_BYTES( acct->pubkey->uc, acct_pubkey_b58 );
     182           0 :       FD_LOG_CRIT(( "invalid prepared record for %s: the record might have been modified by another thread",
     183           0 :                     acct_pubkey_b58 ));
     184           0 :     }
     185             : 
     186             :     /* Crashes the app if this key already exists in funk (conflicting
     187             :        write) */
     188          36 :     fd_funk_rec_publish( funk, prepare );
     189          36 :   }
     190          36 : }
     191             : 
     192             : fd_pubkey_t const *
     193           3 : fd_txn_account_get_owner( fd_txn_account_t const * acct ) {
     194           3 :   if( FD_UNLIKELY( !acct->meta ) ) {
     195           0 :     FD_LOG_CRIT(( "account is not setup" ));
     196           0 :   }
     197           3 :   return (fd_pubkey_t const *)acct->meta->owner;
     198           3 : }
     199             : 
     200             : fd_account_meta_t const *
     201           3 : fd_txn_account_get_meta( fd_txn_account_t const * acct ) {
     202           3 :   return acct->meta;
     203           3 : }
     204             : 
     205             : uchar const *
     206           3 : fd_txn_account_get_data( fd_txn_account_t const * acct ) {
     207           3 :   return acct->data;
     208           3 : }
     209             : 
     210             : uchar *
     211           0 : fd_txn_account_get_data_mut( fd_txn_account_t const * acct ) {
     212           0 :   return acct->data;
     213           0 : }
     214             : 
     215             : ulong
     216           9 : fd_txn_account_get_data_len( fd_txn_account_t const * acct ) {
     217           9 :   if( FD_UNLIKELY( !acct->meta ) ) {
     218           0 :     FD_LOG_CRIT(( "account is not setup" ));
     219           0 :   }
     220           9 :   return acct->meta->dlen;
     221           9 : }
     222             : 
     223             : int
     224           0 : fd_txn_account_is_executable( fd_txn_account_t const * acct ) {
     225           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     226           0 :     FD_LOG_CRIT(( "account is not setup" ));
     227           0 :   }
     228           0 :   return !!acct->meta->executable;
     229           0 : }
     230             : 
     231             : ulong
     232           9 : fd_txn_account_get_lamports( fd_txn_account_t const * acct ) {
     233           9 :   if( FD_UNLIKELY( !acct->meta ) ) {
     234           0 :     FD_LOG_CRIT(( "account is not setup" ));
     235           0 :   }
     236           9 :   return acct->meta->lamports;
     237           9 : }
     238             : 
     239             : void
     240           0 : fd_txn_account_set_meta( fd_txn_account_t * acct, fd_account_meta_t * meta ) {
     241           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     242           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     243           0 :   }
     244           0 :   if( FD_UNLIKELY( !meta ) ) {
     245           0 :     FD_LOG_CRIT(( "account is not setup" ));
     246           0 :   }
     247           0 :   acct->meta = meta;
     248           0 : }
     249             : 
     250             : void
     251          36 : fd_txn_account_set_executable( fd_txn_account_t * acct, int is_executable ) {
     252          36 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     253           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     254           0 :   }
     255          36 :   if( FD_UNLIKELY( !acct->meta ) ) {
     256           0 :     FD_LOG_CRIT(( "account is not setup" ));
     257           0 :   }
     258          36 :   acct->meta->executable = !!is_executable;
     259          36 : }
     260             : 
     261             : void
     262          36 : fd_txn_account_set_owner( fd_txn_account_t * acct, fd_pubkey_t const * owner ) {
     263          36 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     264           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     265           0 :   }
     266          36 :   if( FD_UNLIKELY( !acct->meta ) ) {
     267           0 :     FD_LOG_CRIT(( "account is not setup" ));
     268           0 :   }
     269          36 :   fd_memcpy( acct->meta->owner, owner, sizeof(fd_pubkey_t) );
     270          36 : }
     271             : 
     272             : void
     273          39 : fd_txn_account_set_lamports( fd_txn_account_t * acct, ulong lamports ) {
     274          39 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     275           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     276           0 :   }
     277          39 :   if( FD_UNLIKELY( !acct->meta ) ) {
     278           0 :     FD_LOG_CRIT(( "account is not setup" ));
     279           0 :   }
     280          39 :   acct->meta->lamports = lamports;
     281          39 : }
     282             : 
     283             : int
     284           0 : fd_txn_account_checked_add_lamports( fd_txn_account_t * acct, ulong lamports ) {
     285           0 :   ulong balance_post = 0UL;
     286           0 :   int err = fd_ulong_checked_add( fd_txn_account_get_lamports( acct ), lamports, &balance_post );
     287           0 :   if( FD_UNLIKELY( err ) ) {
     288           0 :     return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
     289           0 :   }
     290             : 
     291           0 :   fd_txn_account_set_lamports( acct, balance_post );
     292           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     293           0 : }
     294             : 
     295             : int
     296           0 : fd_txn_account_checked_sub_lamports( fd_txn_account_t * acct, ulong lamports ) {
     297           0 :   ulong balance_post = 0UL;
     298           0 :   int err = fd_ulong_checked_sub( fd_txn_account_get_lamports( acct ),
     299           0 :                                   lamports,
     300           0 :                                   &balance_post );
     301           0 :   if( FD_UNLIKELY( err ) ) {
     302           0 :     return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
     303           0 :   }
     304             : 
     305           0 :   fd_txn_account_set_lamports( acct, balance_post );
     306           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     307           0 : }
     308             : 
     309             : void
     310             : fd_txn_account_set_data( fd_txn_account_t * acct,
     311             :                          void const *       data,
     312          36 :                          ulong              data_sz ) {
     313          36 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     314           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     315           0 :   }
     316          36 :   if( FD_UNLIKELY( !acct->meta ) ) {
     317           0 :     FD_LOG_CRIT(( "account is not setup" ));
     318           0 :   }
     319          36 :   acct->meta->dlen = (uint)data_sz;
     320          36 :   fd_memcpy( acct->data, data, data_sz );
     321          36 : }
     322             : 
     323             : void
     324           3 : fd_txn_account_set_data_len( fd_txn_account_t * acct, ulong data_len ) {
     325           3 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     326           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     327           0 :   }
     328           3 :   if( FD_UNLIKELY( !acct->meta ) ) {
     329           0 :     FD_LOG_CRIT(( "account is not setup" ));
     330           0 :   }
     331           3 :   acct->meta->dlen = (uint)data_len;
     332           3 : }
     333             : 
     334             : void
     335           0 : fd_txn_account_set_slot( fd_txn_account_t * acct, ulong slot ) {
     336           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     337           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     338           0 :   }
     339           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     340           0 :     FD_LOG_CRIT(( "account is not setup" ));
     341           0 :   }
     342           0 :   acct->meta->slot = slot;
     343           0 : }
     344             : 
     345             : void
     346           0 : fd_txn_account_clear_owner( fd_txn_account_t * acct ) {
     347           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     348           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     349           0 :   }
     350           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     351           0 :     FD_LOG_CRIT(( "account is not setup" ));
     352           0 :   }
     353           0 :   fd_memset( acct->meta->owner, 0, sizeof(fd_pubkey_t) );
     354           0 : }
     355             : 
     356             : void
     357             : fd_txn_account_resize( fd_txn_account_t * acct,
     358           0 :                        ulong              dlen ) {
     359           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     360           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     361           0 :   }
     362           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     363           0 :     FD_LOG_CRIT(( "account is not setup" ));
     364           0 :   }
     365             :   /* Because the memory for an account is preallocated for the transaction
     366             :      up to the max account size, we only need to zero out bytes (for the case
     367             :      where the account grew) and update the account dlen. */
     368           0 :   ulong old_sz    = acct->meta->dlen;
     369           0 :   ulong new_sz    = dlen;
     370           0 :   ulong memset_sz = fd_ulong_sat_sub( new_sz, old_sz );
     371           0 :   fd_memset( acct->data+old_sz, 0, memset_sz );
     372             : 
     373           0 :   acct->meta->dlen = (uint)dlen;
     374           0 : }
     375             : 
     376             : int
     377           6 : fd_txn_account_is_mutable( fd_txn_account_t const * acct ) {
     378             :   /* A txn account is mutable if meta is non NULL */
     379           6 :   return acct->is_mutable;
     380           6 : }
     381             : 
     382             : int
     383           6 : fd_txn_account_is_readonly( fd_txn_account_t const * acct ) {
     384             :   /* A txn account is readonly if only the meta_ field is non NULL */
     385           6 :   return !acct->is_mutable;
     386           6 : }
     387             : 
     388             : void
     389           0 : fd_txn_account_set_readonly( fd_txn_account_t * acct ) {
     390           0 :   acct->is_mutable = 0;
     391           0 : }
     392             : 
     393             : void
     394           0 : fd_txn_account_set_mutable( fd_txn_account_t * acct ) {
     395           0 :   acct->is_mutable = 1;
     396           0 : }

Generated by: LCOV version 1.14