LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_txn_account.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 162 292 55.5 %
Date: 2025-12-18 05:07:35 Functions: 20 29 69.0 %

          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        1026 :                     int                 is_mutable ) {
      12        1026 :   if( FD_UNLIKELY( !mem ) ) {
      13           3 :     FD_LOG_WARNING(( "NULL mem" ));
      14           3 :     return NULL;
      15           3 :   }
      16             : 
      17        1023 :   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        1023 :   if( FD_UNLIKELY( !pubkey ) ) {
      23           3 :     FD_LOG_WARNING(( "NULL pubkey" ));
      24           3 :     return NULL;
      25           3 :   }
      26             : 
      27        1020 :   if( FD_UNLIKELY( !meta ) ) {
      28           3 :     FD_LOG_WARNING(( "NULL meta" ));
      29           3 :     return NULL;
      30           3 :   }
      31             : 
      32        1017 :   fd_txn_account_t * txn_account = (fd_txn_account_t *)mem;
      33             : 
      34        1017 :   fd_memcpy( txn_account->pubkey, pubkey, sizeof(fd_pubkey_t) );
      35             : 
      36        1017 :   txn_account->magic = FD_TXN_ACCOUNT_MAGIC;
      37             : 
      38        1017 :   uchar * data = (uchar *)meta + sizeof(fd_account_meta_t);
      39             : 
      40        1017 :   txn_account->meta_soff = (long)( (ulong)meta - (ulong)mem );
      41             : 
      42        1017 :   txn_account->meta       = meta;
      43        1017 :   txn_account->data       = data;
      44        1017 :   txn_account->is_mutable = is_mutable;
      45             : 
      46        1017 :   return mem;
      47        1020 : }
      48             : 
      49             : fd_txn_account_t *
      50         558 : fd_txn_account_join( void * mem ) {
      51         558 :   if( FD_UNLIKELY( !mem ) ) {
      52           0 :     FD_LOG_WARNING(( "NULL mem" ));
      53           0 :     return NULL;
      54           0 :   }
      55             : 
      56         558 :   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         558 :   fd_txn_account_t * txn_account = (fd_txn_account_t *)mem;
      62             : 
      63         558 :   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         555 :   if( FD_UNLIKELY( txn_account->meta_soff==0UL ) ) {
      69           0 :     FD_LOG_CRIT(( "invalid meta_soff" ));
      70           0 :   }
      71             : 
      72         555 :   return txn_account;
      73         555 : }
      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             : /* Factory constructors from funk */
     119             : 
     120             : int
     121             : fd_txn_account_init_from_funk_readonly( fd_txn_account_t *        acct,
     122             :                                         fd_pubkey_t const *       pubkey,
     123             :                                         fd_funk_t const *         funk,
     124        4137 :                                         fd_funk_txn_xid_t const * xid ) {
     125        4137 :   fd_accdb_user_t accdb[1];
     126        4137 :   fd_accdb_user_v1_init( accdb, funk->shmem );
     127             : 
     128        4137 :   fd_accdb_ro_t ro[1];
     129        4137 :   if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, ro, xid, pubkey ) ) ) {
     130        3672 :     fd_accdb_user_fini( accdb );
     131        3672 :     return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     132        3672 :   }
     133             : 
     134             :   /* HACKY: Convert accdb_rw writable reference into txn_account.
     135             :      In the future, use fd_accdb_modify_publish instead */
     136         465 :   accdb->base.ro_active--;
     137         465 :   if( FD_UNLIKELY( !fd_txn_account_new(
     138         465 :         acct,
     139         465 :         pubkey,
     140         465 :         (fd_account_meta_t *)ro->meta,
     141         465 :         0 ) ) ) {
     142           0 :     FD_LOG_CRIT(( "Failed to join txn account" ));
     143           0 :   }
     144         465 :   fd_accdb_user_fini( accdb );
     145             : 
     146         465 :   return FD_ACC_MGR_SUCCESS;
     147         465 : }
     148             : 
     149             : fd_account_meta_t *
     150             : fd_txn_account_init_from_funk_mutable( fd_txn_account_t *        acct,
     151             :                                        fd_pubkey_t const *       pubkey,
     152             :                                        fd_accdb_user_t *         accdb,
     153             :                                        fd_funk_txn_xid_t const * xid,
     154             :                                        int                       do_create,
     155             :                                        ulong                     min_data_sz,
     156         498 :                                        fd_funk_rec_prepare_t *   prepare_out ) {
     157         498 :   memset( prepare_out, 0, sizeof(fd_funk_rec_prepare_t) );
     158             : 
     159         498 :   fd_accdb_rw_t rw[1];
     160         498 :   int flags = do_create ? FD_ACCDB_FLAG_CREATE : 0;
     161         498 :   if( FD_UNLIKELY( !fd_accdb_open_rw( accdb, rw, xid, pubkey->uc, min_data_sz, flags ) ) ) {
     162           0 :     return NULL;
     163           0 :   }
     164             : 
     165         498 :   if( FD_UNLIKELY( !fd_txn_account_join( fd_txn_account_new(
     166         498 :         acct,
     167         498 :         pubkey,
     168         498 :         (fd_account_meta_t *)rw->meta,
     169         498 :         1 ) ) ) ) {
     170           0 :     FD_LOG_CRIT(( "Failed to join txn account" ));
     171           0 :   }
     172             : 
     173             :   /* HACKY: Convert accdb_rw writable reference into txn_account.
     174             :      In the future, use fd_accdb_modify_publish instead */
     175         498 :   accdb->base.rw_active--;
     176         498 :   fd_accdb_user_v1_t * accdb_v1 = fd_type_pun( accdb );
     177         498 :   fd_funk_txn_t * txn = accdb_v1->funk->txn_pool->ele + accdb_v1->tip_txn_idx;
     178         498 :   if( FD_UNLIKELY( !fd_funk_txn_xid_eq( &txn->xid, xid ) ) ) FD_LOG_CRIT(( "accdb_user corrupt: not joined to the expected transaction" ));
     179         498 :   if( !rw->published ) {
     180          45 :     *prepare_out = (fd_funk_rec_prepare_t) {
     181          45 :       .rec          = rw->rec,
     182          45 :       .rec_head_idx = &txn->rec_head_idx,
     183          45 :       .rec_tail_idx = &txn->rec_tail_idx
     184          45 :     };
     185         453 :   } else {
     186         453 :     memset( prepare_out, 0, sizeof(fd_funk_rec_prepare_t) );
     187         453 :   }
     188             : 
     189         498 :   return rw->meta;
     190         498 : }
     191             : 
     192             : void
     193             : fd_txn_account_mutable_fini( fd_txn_account_t *      acct,
     194             :                              fd_accdb_user_t *       accdb,
     195         498 :                              fd_funk_rec_prepare_t * prepare ) {
     196         498 :   fd_funk_rec_key_t key = fd_funk_acc_key( acct->pubkey );
     197         498 :   fd_funk_t * funk = fd_accdb_user_v1_funk( accdb );
     198             : 
     199             :   /* Check that the prepared record is still valid -
     200             :      if these invariants are broken something is very wrong. */
     201         498 :   if( prepare->rec ) {
     202             :     /* Check that the prepared record is not the Funk null value */
     203          45 :     if( !prepare->rec->val_gaddr ) {
     204           0 :       FD_BASE58_ENCODE_32_BYTES( acct->pubkey->uc, acct_pubkey_b58 );
     205           0 :       FD_LOG_CRIT(( "invalid prepared record for %s: unexpected NULL funk record value. the record might have been modified by another thread",
     206           0 :                     acct_pubkey_b58 ));
     207           0 :     }
     208             : 
     209             :     /* Ensure that the prepared record key still matches our key. */
     210          45 :     if( FD_UNLIKELY( memcmp( prepare->rec->pair.key, &key, sizeof(fd_funk_rec_key_t) )!=0 ) ) {
     211           0 :       FD_BASE58_ENCODE_32_BYTES( acct->pubkey->uc, acct_pubkey_b58 );
     212           0 :       FD_LOG_CRIT(( "invalid prepared record for %s: the record might have been modified by another thread",
     213           0 :                     acct_pubkey_b58 ));
     214           0 :     }
     215             : 
     216             :     /* Crashes the app if this key already exists in funk (conflicting
     217             :        write) */
     218          45 :     fd_funk_rec_publish( funk, prepare );
     219          45 :   }
     220         498 : }
     221             : 
     222             : fd_pubkey_t const *
     223          51 : fd_txn_account_get_owner( fd_txn_account_t const * acct ) {
     224          51 :   if( FD_UNLIKELY( !acct->meta ) ) {
     225           0 :     FD_LOG_CRIT(( "account is not setup" ));
     226           0 :   }
     227          51 :   return (fd_pubkey_t const *)acct->meta->owner;
     228          51 : }
     229             : 
     230             : fd_account_meta_t const *
     231         465 : fd_txn_account_get_meta( fd_txn_account_t const * acct ) {
     232         465 :   return acct->meta;
     233         465 : }
     234             : 
     235             : uchar const *
     236         975 : fd_txn_account_get_data( fd_txn_account_t const * acct ) {
     237         975 :   return acct->data;
     238         975 : }
     239             : 
     240             : uchar *
     241           0 : fd_txn_account_get_data_mut( fd_txn_account_t const * acct ) {
     242           0 :   return acct->data;
     243           0 : }
     244             : 
     245             : ulong
     246         519 : fd_txn_account_get_data_len( fd_txn_account_t const * acct ) {
     247         519 :   if( FD_UNLIKELY( !acct->meta ) ) {
     248           0 :     FD_LOG_CRIT(( "account is not setup" ));
     249           0 :   }
     250         519 :   return acct->meta->dlen;
     251         519 : }
     252             : 
     253             : int
     254           0 : fd_txn_account_is_executable( fd_txn_account_t const * acct ) {
     255           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     256           0 :     FD_LOG_CRIT(( "account is not setup" ));
     257           0 :   }
     258           0 :   return !!acct->meta->executable;
     259           0 : }
     260             : 
     261             : ulong
     262         936 : fd_txn_account_get_lamports( fd_txn_account_t const * acct ) {
     263         936 :   if( FD_UNLIKELY( !acct->meta ) ) {
     264           0 :     FD_LOG_CRIT(( "account is not setup" ));
     265           0 :   }
     266         936 :   return acct->meta->lamports;
     267         936 : }
     268             : 
     269             : void
     270           0 : fd_txn_account_set_meta( fd_txn_account_t * acct, fd_account_meta_t * meta ) {
     271           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     272           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     273           0 :   }
     274           0 :   if( FD_UNLIKELY( !meta ) ) {
     275           0 :     FD_LOG_CRIT(( "account is not setup" ));
     276           0 :   }
     277           0 :   acct->meta = meta;
     278           0 : }
     279             : 
     280             : void
     281          36 : fd_txn_account_set_executable( fd_txn_account_t * acct, int is_executable ) {
     282          36 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     283           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     284           0 :   }
     285          36 :   if( FD_UNLIKELY( !acct->meta ) ) {
     286           0 :     FD_LOG_CRIT(( "account is not setup" ));
     287           0 :   }
     288          36 :   acct->meta->executable = !!is_executable;
     289          36 : }
     290             : 
     291             : void
     292         498 : fd_txn_account_set_owner( fd_txn_account_t * acct, fd_pubkey_t const * owner ) {
     293         498 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     294           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     295           0 :   }
     296         498 :   if( FD_UNLIKELY( !acct->meta ) ) {
     297           0 :     FD_LOG_CRIT(( "account is not setup" ));
     298           0 :   }
     299         498 :   fd_memcpy( acct->meta->owner, owner, sizeof(fd_pubkey_t) );
     300         498 : }
     301             : 
     302             : void
     303         501 : fd_txn_account_set_lamports( fd_txn_account_t * acct, ulong lamports ) {
     304         501 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     305           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     306           0 :   }
     307         501 :   if( FD_UNLIKELY( !acct->meta ) ) {
     308           0 :     FD_LOG_CRIT(( "account is not setup" ));
     309           0 :   }
     310         501 :   acct->meta->lamports = lamports;
     311         501 : }
     312             : 
     313             : int
     314           0 : fd_txn_account_checked_add_lamports( fd_txn_account_t * acct, ulong lamports ) {
     315           0 :   ulong balance_post = 0UL;
     316           0 :   int err = fd_ulong_checked_add( fd_txn_account_get_lamports( acct ), lamports, &balance_post );
     317           0 :   if( FD_UNLIKELY( err ) ) {
     318           0 :     return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
     319           0 :   }
     320             : 
     321           0 :   fd_txn_account_set_lamports( acct, balance_post );
     322           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     323           0 : }
     324             : 
     325             : int
     326           0 : fd_txn_account_checked_sub_lamports( fd_txn_account_t * acct, ulong lamports ) {
     327           0 :   ulong balance_post = 0UL;
     328           0 :   int err = fd_ulong_checked_sub( fd_txn_account_get_lamports( acct ),
     329           0 :                                   lamports,
     330           0 :                                   &balance_post );
     331           0 :   if( FD_UNLIKELY( err ) ) {
     332           0 :     return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
     333           0 :   }
     334             : 
     335           0 :   fd_txn_account_set_lamports( acct, balance_post );
     336           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     337           0 : }
     338             : 
     339             : void
     340             : fd_txn_account_set_data( fd_txn_account_t * acct,
     341             :                          void const *       data,
     342         498 :                          ulong              data_sz ) {
     343         498 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     344           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     345           0 :   }
     346         498 :   if( FD_UNLIKELY( !acct->meta ) ) {
     347           0 :     FD_LOG_CRIT(( "account is not setup" ));
     348           0 :   }
     349         498 :   acct->meta->dlen = (uint)data_sz;
     350         498 :   fd_memcpy( acct->data, data, data_sz );
     351         498 : }
     352             : 
     353             : void
     354           3 : fd_txn_account_set_data_len( fd_txn_account_t * acct, ulong data_len ) {
     355           3 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     356           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     357           0 :   }
     358           3 :   if( FD_UNLIKELY( !acct->meta ) ) {
     359           0 :     FD_LOG_CRIT(( "account is not setup" ));
     360           0 :   }
     361           3 :   acct->meta->dlen = (uint)data_len;
     362           3 : }
     363             : 
     364             : void
     365         462 : fd_txn_account_set_slot( fd_txn_account_t * acct, ulong slot ) {
     366         462 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     367           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     368           0 :   }
     369         462 :   if( FD_UNLIKELY( !acct->meta ) ) {
     370           0 :     FD_LOG_CRIT(( "account is not setup" ));
     371           0 :   }
     372         462 :   acct->meta->slot = slot;
     373         462 : }
     374             : 
     375             : void
     376           0 : fd_txn_account_clear_owner( fd_txn_account_t * acct ) {
     377           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     378           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     379           0 :   }
     380           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     381           0 :     FD_LOG_CRIT(( "account is not setup" ));
     382           0 :   }
     383           0 :   fd_memset( acct->meta->owner, 0, sizeof(fd_pubkey_t) );
     384           0 : }
     385             : 
     386             : void
     387             : fd_txn_account_resize( fd_txn_account_t * acct,
     388           0 :                        ulong              dlen ) {
     389           0 :   if( FD_UNLIKELY( !acct->is_mutable ) ) {
     390           0 :     FD_LOG_CRIT(( "account is not mutable" ));
     391           0 :   }
     392           0 :   if( FD_UNLIKELY( !acct->meta ) ) {
     393           0 :     FD_LOG_CRIT(( "account is not setup" ));
     394           0 :   }
     395             :   /* Because the memory for an account is preallocated for the transaction
     396             :      up to the max account size, we only need to zero out bytes (for the case
     397             :      where the account grew) and update the account dlen. */
     398           0 :   ulong old_sz    = acct->meta->dlen;
     399           0 :   ulong new_sz    = dlen;
     400           0 :   ulong memset_sz = fd_ulong_sat_sub( new_sz, old_sz );
     401           0 :   fd_memset( acct->data+old_sz, 0, memset_sz );
     402             : 
     403           0 :   acct->meta->dlen = (uint)dlen;
     404           0 : }
     405             : 
     406             : int
     407           6 : fd_txn_account_is_mutable( fd_txn_account_t const * acct ) {
     408             :   /* A txn account is mutable if meta is non NULL */
     409           6 :   return acct->is_mutable;
     410           6 : }
     411             : 
     412             : int
     413           6 : fd_txn_account_is_readonly( fd_txn_account_t const * acct ) {
     414             :   /* A txn account is readonly if only the meta_ field is non NULL */
     415           6 :   return !acct->is_mutable;
     416           6 : }
     417             : 
     418             : void
     419           0 : fd_txn_account_set_readonly( fd_txn_account_t * acct ) {
     420           0 :   acct->is_mutable = 0;
     421           0 : }
     422             : 
     423             : void
     424           0 : fd_txn_account_set_mutable( fd_txn_account_t * acct ) {
     425           0 :   acct->is_mutable = 1;
     426           0 : }

Generated by: LCOV version 1.14