LCOV - code coverage report
Current view: top level - flamenco/accdb - fd_accdb_impl_v0.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 271 0.0 %
Date: 2026-01-25 05:14:44 Functions: 0 22 0.0 %

          Line data    Source code
       1             : #include "fd_accdb_impl_v0.h"
       2             : 
       3             : fd_account_meta_t const fd_accdb_meta_empty = {0};
       4             : 
       5             : FD_FN_CONST ulong
       6           0 : fd_accdb_v0_align( void ) {
       7           0 :   return alignof(fd_accdb_v0_t);
       8           0 : }
       9             : 
      10             : ulong
      11           0 : fd_accdb_v0_footprint( ulong rec_cnt ) {
      12           0 :   ulong rec_sz;
      13           0 :   if( FD_UNLIKELY( __builtin_umull_overflow( rec_cnt, sizeof(fd_accdb_v0_rec_t), &rec_sz ) ) ) return 0UL;
      14           0 :   ulong sz;
      15           0 :   if( FD_UNLIKELY( __builtin_uaddl_overflow( sizeof(fd_accdb_v0_t), rec_sz, &sz ) ) ) return 0UL;
      16           0 :   return sz;
      17           0 : }
      18             : 
      19             : void *
      20             : fd_accdb_v0_new( void * shmem,
      21           0 :                  ulong  rec_cnt ) {
      22             : 
      23           0 :   if( FD_UNLIKELY( !fd_accdb_v0_footprint( rec_cnt ) ) ) {
      24           0 :     FD_LOG_WARNING(( "invalid rec_cnt" ));
      25           0 :     return NULL;
      26           0 :   }
      27             : 
      28           0 :   fd_accdb_v0_t * v0 = (fd_accdb_v0_t *)shmem;
      29           0 :   memset( v0, 0, sizeof(fd_accdb_v0_t) );
      30           0 :   v0->rec_cnt = 0UL;
      31           0 :   v0->rec_max = rec_cnt;
      32           0 :   fd_rwlock_new( &v0->lock );
      33             : 
      34           0 :   FD_COMPILER_MFENCE();
      35           0 :   v0->magic = FD_ACCDB_V0_MAGIC;
      36           0 :   FD_COMPILER_MFENCE();
      37             : 
      38           0 :   return v0;
      39           0 : }
      40             : 
      41             : fd_accdb_v0_t *
      42           0 : fd_accdb_v0_join( void * mem ) {
      43             : 
      44           0 :   if( FD_UNLIKELY( !mem ) ) {
      45           0 :     FD_LOG_WARNING(( "NULL accdb_v0" ));
      46           0 :     return NULL;
      47           0 :   }
      48           0 :   fd_accdb_v0_t * v0 = (fd_accdb_v0_t *)mem;
      49           0 :   if( FD_UNLIKELY( v0->magic!=FD_ACCDB_V0_MAGIC ) ) {
      50           0 :     FD_LOG_WARNING(( "bad magic" ));
      51           0 :     return NULL;
      52           0 :   }
      53             : 
      54           0 :   return v0;
      55           0 : }
      56             : 
      57             : void *
      58           0 : fd_accdb_v0_leave( fd_accdb_v0_t * v0 ) {
      59           0 :   return v0;
      60           0 : }
      61             : 
      62             : void *
      63           0 : fd_accdb_v0_delete( void * mem ) {
      64             : 
      65           0 :   if( FD_UNLIKELY( !mem ) ) {
      66           0 :     FD_LOG_WARNING(( "NULL accdb_v0" ));
      67           0 :     return NULL;
      68           0 :   }
      69           0 :   fd_accdb_v0_t * v0 = (fd_accdb_v0_t *)mem;
      70           0 :   if( FD_UNLIKELY( v0->magic!=FD_ACCDB_V0_MAGIC ) ) {
      71           0 :     FD_LOG_WARNING(( "bad magic" ));
      72           0 :     return NULL;
      73           0 :   }
      74           0 :   v0->magic = 0UL;
      75             : 
      76           0 :   fd_rwlock_write( &v0->lock );
      77           0 :   for( ulong i=0UL; i<v0->rec_cnt; i++ ) {
      78           0 :     if( FD_UNLIKELY( (!!v0->rec[ i ].writer_cnt) |
      79           0 :                      (!!v0->rec[ i ].reader_cnt) ) ) {
      80           0 :       FD_LOG_CRIT(( "attempted to delete accdb_v0 with active users, aborting" ));
      81           0 :     }
      82           0 :   }
      83           0 :   fd_rwlock_unwrite( &v0->lock );
      84             : 
      85           0 :   memset( v0, 0, fd_accdb_v0_footprint( v0->rec_cnt ) );
      86           0 :   return v0;
      87           0 : }
      88             : 
      89             : fd_accdb_user_t *
      90             : fd_accdb_user_v0_init( fd_accdb_user_t * accdb_,
      91           0 :                        fd_accdb_v0_t *   v0 ) {
      92             : 
      93           0 :   if( FD_UNLIKELY( !v0 || v0->magic!=FD_ACCDB_V0_MAGIC ) ) {
      94           0 :     FD_LOG_WARNING(( "invalid accdb_v0" ));
      95           0 :     return NULL;
      96           0 :   }
      97             : 
      98           0 :   fd_accdb_user_v0_t * accdb = fd_type_pun( accdb_ );
      99           0 :   memset( accdb, 0, sizeof(fd_accdb_user_v0_t) );
     100           0 :   accdb->base.accdb_type = FD_ACCDB_TYPE_V0;
     101           0 :   accdb->base.vt         = &fd_accdb_user_v0_vt;
     102           0 :   accdb->v0              = v0;
     103           0 :   return accdb_;
     104           0 : }
     105             : 
     106             : void
     107           0 : fd_accdb_user_v0_fini( fd_accdb_user_t * accdb ) {
     108           0 :   (void)accdb;
     109             :   /* FIXME consider asserting that the v0 reference count is zero */
     110           0 :   return;
     111           0 : }
     112             : 
     113             : static long
     114             : find_key( fd_accdb_v0_t const * v0,
     115           0 :           void const *          address ) {
     116           0 :   for( ulong i=0UL; i<v0->rec_cnt; i++ ) {
     117           0 :     if( 0==memcmp( &v0->rec[ i ].key, address, sizeof(fd_pubkey_t) ) ) {
     118           0 :       return (long)i;
     119           0 :     }
     120           0 :   }
     121           0 :   return -1L;
     122           0 : }
     123             : 
     124             : static void
     125             : remove_rec( fd_accdb_v0_t * v0,
     126           0 :             long            idx ) {
     127           0 :   if( v0->rec_cnt ) {
     128           0 :     ulong last_idx = v0->rec_cnt-1UL;
     129           0 :     v0->rec[ idx ] = v0->rec[ last_idx ];
     130           0 :   }
     131           0 :   v0->rec_cnt--;
     132           0 : }
     133             : 
     134             : static long
     135             : push_rec( fd_accdb_v0_t * v0,
     136           0 :           void const *    address ) {
     137           0 :   if( FD_UNLIKELY( v0->rec_cnt >= v0->rec_max ) ) return -1L;
     138           0 :   long idx = (long)v0->rec_cnt;
     139           0 :   fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
     140           0 :   memset( rec,       0,       sizeof(fd_accdb_v0_rec_t) );
     141           0 :   memcpy( &rec->key, address, sizeof(fd_pubkey_t)       );
     142           0 :   v0->rec_cnt++;
     143           0 :   return idx;
     144           0 : }
     145             : 
     146             : static ulong
     147           0 : fd_accdb_user_v0_batch_max( fd_accdb_user_t * accdb ) {
     148           0 :   (void)accdb;
     149           0 :   return 1UL;
     150           0 : }
     151             : 
     152             : static fd_accdb_ro_t *
     153             : fd_accdb_user_v0_open_ro( fd_accdb_user_t *         accdb_,
     154             :                           fd_accdb_ro_t *           ro,
     155             :                           fd_funk_txn_xid_t const * xid,
     156           0 :                           void const *              address ) {
     157           0 :   (void)xid;
     158           0 :   fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
     159           0 :   fd_accdb_v0_t *      v0    = accdb->v0;
     160             : 
     161           0 :   long idx = find_key( v0, address );
     162           0 :   fd_accdb_ro_t * found = NULL;
     163           0 :   if( idx>=0L ) {
     164           0 :     fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
     165           0 :     if( FD_UNLIKELY( rec->writer_cnt ) ) {
     166           0 :       FD_BASE58_ENCODE_32_BYTES( address, address_b58 );
     167           0 :       FD_LOG_CRIT(( "accdb_user_v0_open_ro failed: account %s is currently in use", address_b58 ));
     168           0 :     }
     169           0 :     rec->reader_cnt++;
     170             : 
     171           0 :     *ro = (fd_accdb_ro_t) {0};
     172           0 :     FD_STORE( fd_pubkey_t, ro->ref->address, rec->key );
     173           0 :     ro->ref->accdb_type = FD_ACCDB_TYPE_V0;
     174           0 :     ro->ref->ref_type   = FD_ACCDB_REF_RO;
     175           0 :     ro->ref->user_data  = 0UL;
     176           0 :     ro->meta            = &rec->meta;
     177             : 
     178           0 :     accdb->base.ro_active++;
     179           0 :     found = ro;
     180           0 :   }
     181             : 
     182           0 :   return found;
     183           0 : }
     184             : 
     185             : void
     186             : fd_accdb_user_v0_open_ro_multi( fd_accdb_user_t *         accdb_,
     187             :                                 fd_accdb_ro_t *           ro,
     188             :                                 fd_funk_txn_xid_t const * xid,
     189             :                                 void const *              address,
     190           0 :                                 ulong                     cnt ) {
     191           0 :   fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
     192           0 :   fd_accdb_v0_t *      v0    = accdb->v0;
     193           0 :   fd_rwlock_write( &v0->lock );
     194           0 :   ulong addr_laddr = (ulong)address;
     195           0 :   for( ulong i=0UL; i<cnt; i++ ) {
     196           0 :     void const *    addr_i = (void const *)( (ulong)addr_laddr + i*32UL );
     197           0 :     fd_accdb_ro_t * ro_i   = fd_accdb_user_v0_open_ro( accdb_, &ro[i], xid, addr_i );
     198           0 :     if( !ro_i ) fd_accdb_ro_init_empty( &ro[i], addr_i );
     199           0 :   }
     200           0 :   fd_rwlock_unwrite( &v0->lock );
     201           0 : }
     202             : 
     203             : static void
     204             : fd_accdb_user_v0_close_ro( fd_accdb_user_t * accdb,
     205           0 :                            fd_accdb_ro_t *   ro ) {
     206           0 :   fd_accdb_user_v0_t * user = (fd_accdb_user_v0_t *)accdb;
     207           0 :   fd_accdb_v0_t *      v0   = user->v0;
     208             : 
     209           0 :   long idx = find_key( v0, ro->ref->address );
     210           0 :   if( FD_UNLIKELY( idx<0L ) ) {
     211           0 :     FD_BASE58_ENCODE_32_BYTES( ro->ref->address, address_b58 );
     212           0 :     FD_LOG_CRIT(( "accdb_user_v0_close_ro failed: account %s not found", address_b58 ));
     213           0 :   }
     214           0 :   fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
     215             : 
     216           0 :   if( FD_UNLIKELY( !rec->reader_cnt ||
     217           0 :                    !user->base.ro_active ) ) {
     218           0 :     FD_LOG_CRIT(( "accdb_user_v0_close_ro failed: ref count underflow" ));
     219           0 :   }
     220           0 :   rec->reader_cnt--;
     221           0 :   user->base.ro_active--;
     222           0 : }
     223             : 
     224             : static fd_accdb_rw_t *
     225             : fd_accdb_user_v0_open_rw( fd_accdb_user_t *         accdb_,
     226             :                           fd_accdb_rw_t *           rw_,
     227             :                           fd_funk_txn_xid_t const * xid,
     228             :                           void const *              address,
     229             :                           ulong                     data_max,
     230           0 :                           int                       flags ) {
     231           0 :   fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
     232           0 :   fd_accdb_v0_t *      v0    = accdb->v0;
     233           0 :   (void)xid;
     234             : 
     235           0 :   fd_accdb_rw_t * rw = NULL;
     236             : 
     237           0 :   int const flag_create   = !!( flags & FD_ACCDB_FLAG_CREATE   );
     238           0 :   int const flag_truncate = !!( flags & FD_ACCDB_FLAG_TRUNCATE );
     239           0 :   if( FD_UNLIKELY( flags & ~(FD_ACCDB_FLAG_CREATE|FD_ACCDB_FLAG_TRUNCATE) ) ) {
     240           0 :     FD_LOG_CRIT(( "invalid flags for open_rw: %#02x", (uint)flags ));
     241           0 :   }
     242             : 
     243           0 :   if( FD_UNLIKELY( data_max > FD_RUNTIME_ACC_SZ_MAX ) ) {
     244           0 :     FD_LOG_CRIT(( "invalid data_max %lu", data_max ));
     245           0 :   }
     246             : 
     247           0 :   long idx = find_key( v0, address );
     248           0 :   if( idx<0L ) {
     249           0 :     if( !flag_create ) return NULL;
     250           0 :     idx = push_rec( v0, address );
     251           0 :     if( FD_UNLIKELY( idx<0L ) ) FD_LOG_CRIT(( "accdb_user_v0_open_rw failed: cannot create account, out of memory" ));
     252           0 :   }
     253           0 :   rw = rw_;
     254             : 
     255           0 :   fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
     256           0 :   if( flag_truncate ) rec->meta.dlen = 0;
     257           0 :   accdb->base.rw_active++;
     258           0 :   rec->writer_cnt = 1;
     259           0 :   rec->reader_cnt = 0;
     260             : 
     261           0 :   *rw = (fd_accdb_rw_t) {0};
     262           0 :   memcpy( rw->ref->address, address, sizeof(fd_pubkey_t) );
     263           0 :   rw->ref->accdb_type = FD_ACCDB_TYPE_V0;
     264           0 :   rw->ref->ref_type   = FD_ACCDB_REF_RW;
     265           0 :   rw->ref->user_data  = 0UL;
     266           0 :   rw->meta            = &rec->meta;
     267             : 
     268           0 :   return rw;
     269           0 : }
     270             : 
     271             : void
     272             : fd_accdb_user_v0_open_rw_multi( fd_accdb_user_t *         accdb_,
     273             :                                 fd_accdb_rw_t *           rw,
     274             :                                 fd_funk_txn_xid_t const * xid,
     275             :                                 void const *              address,
     276             :                                 ulong const *             data_max,
     277             :                                 int                       flags,
     278           0 :                                 ulong                     cnt ) {
     279           0 :   fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
     280           0 :   fd_accdb_v0_t *      v0    = accdb->v0;
     281           0 :   fd_rwlock_write( &v0->lock );
     282           0 :   ulong addr_laddr = (ulong)address;
     283           0 :   for( ulong i=0UL; i<cnt; i++ ) {
     284           0 :     void const *    addr_i = (void const *)( (ulong)addr_laddr + i*32UL );
     285           0 :     ulong           dmax_i = data_max[i];
     286           0 :     fd_accdb_rw_t * rw_i   = fd_accdb_user_v0_open_rw( accdb_, &rw[i], xid, addr_i, dmax_i, flags );
     287           0 :     if( !rw_i ) memset( &rw[i], 0, sizeof(fd_accdb_rw_t) );
     288           0 :   }
     289           0 :   fd_rwlock_unwrite( &v0->lock );
     290           0 : }
     291             : 
     292             : static void
     293             : fd_accdb_user_v0_close_rw( fd_accdb_user_t * accdb,
     294           0 :                            fd_accdb_rw_t *   rw ) {
     295           0 :   fd_accdb_user_v0_t * user = (fd_accdb_user_v0_t *)accdb;
     296           0 :   fd_accdb_v0_t *      v0   = user->v0;
     297             : 
     298           0 :   long idx = find_key( v0, rw->ref->address );
     299           0 :   if( FD_UNLIKELY( idx<0L ) ) {
     300           0 :     FD_BASE58_ENCODE_32_BYTES( rw->ref->address, address_b58 );
     301           0 :     FD_LOG_CRIT(( "accdb_user_v0_close_rw failed: account %s not found", address_b58 ));
     302           0 :   }
     303           0 :   fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
     304             : 
     305           0 :   if( FD_UNLIKELY( !rec->writer_cnt ||
     306           0 :                    !user->base.rw_active ||
     307           0 :                    user->base.ro_active ) ) {
     308           0 :     FD_LOG_CRIT(( "accdb_user_v0_close_rw failed: invalid ref count detected" ));
     309           0 :   }
     310           0 :   rec->writer_cnt--;
     311           0 :   user->base.rw_active--;
     312             : 
     313           0 :   if( rec->meta.lamports==0UL ) remove_rec( v0, idx );
     314           0 : }
     315             : 
     316             : static void
     317             : fd_accdb_user_v0_close_ref( fd_accdb_user_t * accdb,
     318           0 :                             fd_accdb_ref_t *  ref ) {
     319           0 :   if( ref->accdb_type==FD_ACCDB_TYPE_NONE ) return;
     320           0 :   switch( ref->ref_type ) {
     321           0 :   case FD_ACCDB_REF_RO:
     322           0 :     fd_accdb_user_v0_close_ro( accdb, (fd_accdb_ro_t *)ref );
     323           0 :     break;
     324           0 :   case FD_ACCDB_REF_RW:
     325           0 :     fd_accdb_user_v0_close_rw( accdb, (fd_accdb_rw_t *)ref );
     326           0 :     break;
     327           0 :   default:
     328           0 :     FD_LOG_CRIT(( "invalid ref_type %u in fd_accdb_user_v0_close_ref", (uint)ref->ref_type ));
     329           0 :   }
     330           0 : }
     331             : 
     332             : void
     333             : fd_accdb_user_v0_close_ref_multi( fd_accdb_user_t * accdb_,
     334             :                                   fd_accdb_ref_t *  ref,
     335           0 :                                   ulong             cnt ) {
     336           0 :   fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
     337           0 :   fd_accdb_v0_t *      v0    = accdb->v0;
     338           0 :   fd_rwlock_write( &v0->lock );
     339           0 :   for( ulong i=0UL; i<cnt; i++ ) {
     340           0 :     fd_accdb_ref_t * ref_i = &ref[i];
     341           0 :     fd_accdb_user_v0_close_ref( accdb_, ref_i );
     342           0 :   }
     343           0 :   fd_rwlock_unwrite( &v0->lock );
     344           0 : }
     345             : 
     346             : ulong
     347             : fd_accdb_user_v0_rw_data_max( fd_accdb_user_t *     accdb,
     348           0 :                               fd_accdb_rw_t const * rw ) {
     349           0 :   (void)accdb;
     350           0 :   if( rw->ref->accdb_type==FD_ACCDB_TYPE_NONE ) {
     351           0 :     return rw->ref->user_data; /* data_max */
     352           0 :   }
     353           0 :   return FD_RUNTIME_ACC_SZ_MAX;
     354           0 : }
     355             : 
     356             : void
     357             : fd_accdb_user_v0_rw_data_sz_set( fd_accdb_user_t * accdb,
     358             :                                  fd_accdb_rw_t *   rw,
     359             :                                  ulong             data_sz,
     360           0 :                                  int               flags ) {
     361           0 :   (void)accdb;
     362           0 :   int flag_dontzero = !!( flags & FD_ACCDB_FLAG_DONTZERO );
     363           0 :   if( FD_UNLIKELY( flags & ~(FD_ACCDB_FLAG_DONTZERO) ) ) {
     364           0 :     FD_LOG_CRIT(( "invalid flags for rw_data_sz_set: %#02x", (uint)flags ));
     365           0 :   }
     366             : 
     367           0 :   ulong prev_sz = rw->meta->dlen;
     368           0 :   if( data_sz>prev_sz ) {
     369           0 :     if( FD_UNLIKELY( data_sz>FD_RUNTIME_ACC_SZ_MAX ) ) {
     370           0 :       FD_LOG_CRIT(( "attempted to write %lu bytes into a rec with only %lu bytes of data space",
     371           0 :                     data_sz, FD_RUNTIME_ACC_SZ_MAX ));
     372           0 :     }
     373           0 :     if( !flag_dontzero ) {
     374           0 :       void * tail = (uchar *)fd_accdb_ref_data( rw ) + prev_sz;
     375           0 :       fd_memset( tail, 0, data_sz-prev_sz );
     376           0 :     }
     377           0 :   }
     378           0 :   rw->meta->dlen = (uint)data_sz;
     379           0 : }
     380             : 
     381             : fd_accdb_user_vt_t const fd_accdb_user_v0_vt = {
     382             :   .fini            = fd_accdb_user_v0_fini,
     383             :   .batch_max       = fd_accdb_user_v0_batch_max,
     384             :   .open_ro_multi   = fd_accdb_user_v0_open_ro_multi,
     385             :   .open_rw_multi   = fd_accdb_user_v0_open_rw_multi,
     386             :   .close_ref_multi = fd_accdb_user_v0_close_ref_multi,
     387             :   .rw_data_max     = fd_accdb_user_v0_rw_data_max,
     388             :   .rw_data_sz_set  = fd_accdb_user_v0_rw_data_sz_set
     389             : };

Generated by: LCOV version 1.14