LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_acc_mgr.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 29 35 82.9 %
Date: 2024-11-13 11:58:15 Functions: 9 560 1.6 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_fd_acc_mgr_h
       2             : #define HEADER_fd_src_flamenco_runtime_fd_acc_mgr_h
       3             : 
       4             : /* fd_acc_mgr provides APIs for the Solana account database. */
       5             : 
       6             : #include "../fd_flamenco_base.h"
       7             : #include "../../ballet/txn/fd_txn.h"
       8             : #include "../../funk/fd_funk.h"
       9             : #include "fd_borrowed_account.h"
      10             : 
      11             : /* FD_ACC_MGR_{SUCCESS,ERR{...}} are fd_acc_mgr_t specific error codes.
      12             :    To be stored in an int. */
      13             : 
      14    10369437 : #define FD_ACC_MGR_SUCCESS             (0)
      15     3304998 : #define FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT (-1)
      16           0 : #define FD_ACC_MGR_ERR_WRITE_FAILED    (-2)
      17           0 : #define FD_ACC_MGR_ERR_READ_FAILED     (-3)
      18           0 : #define FD_ACC_MGR_ERR_WRONG_MAGIC     (-4)
      19             : 
      20             : /* FD_ACC_SZ_MAX is the hardcoded size limit of a Solana account. */
      21             : 
      22     1192815 : #define FD_ACC_SZ_MAX (10UL<<20) /* 10MiB */
      23             : 
      24             : /* FD_ACC_TOT_SZ_MAX is the size limit of a Solana account in the firedancer
      25             :    client. This means that it includes the max size of the account (10MiB)
      26             :    and the associated metadata. */
      27             : 
      28     1192767 : #define FD_ACC_TOT_SZ_MAX (FD_ACC_SZ_MAX + FD_ACCOUNT_META_FOOTPRINT)
      29             : 
      30             : /* fd_acc_mgr_t translates between the runtime account DB abstraction
      31             :    and the actual funk database.  Also manages rent collection.
      32             :    fd_acc_mgr_t cannot be relocated to another address space.
      33             : 
      34             :    ### Translation
      35             : 
      36             :    Each runtime account is backed by a funk record.  However, not all
      37             :    funk records contain an account.  Funk records may temporarily hold
      38             :    "deleted accounts".
      39             : 
      40             :    The memory layout of the acc_mgr funk record data is
      41             :    (fd_account_meta_t, padding, account data). */
      42             : 
      43             : struct __attribute__((aligned(16UL))) fd_acc_mgr {
      44             :   fd_funk_t * funk;
      45             : 
      46             :   ulong slots_per_epoch;  /* see epoch schedule.  do not update directly */
      47             : 
      48             :   /* part_width is the width of rent partition.  Each partition is a
      49             :      contiguous sub-range of [0,2^256) where each element is an
      50             :      account address. */
      51             : 
      52             :   ulong part_width;
      53             : 
      54             :   /* skip_rent_rewrites is a feature flag controlling rent collection
      55             :      behavior during eager rent collection passes. */
      56             : 
      57             :   uchar skip_rent_rewrites : 1;
      58             : 
      59             :   uint is_locked;
      60             : };
      61             : 
      62             : /* FD_ACC_MGR_{ALIGN,FOOTPRINT} specify the parameters for the memory
      63             :    region backing an fd_acc_mgr_t. */
      64             : 
      65      108789 : #define FD_ACC_MGR_ALIGN     (alignof(fd_acc_mgr_t))
      66      326367 : #define FD_ACC_MGR_FOOTPRINT ( sizeof(fd_acc_mgr_t))
      67             : 
      68             : FD_PROTOTYPES_BEGIN
      69             : 
      70             : /* Management API *****************************************************/
      71             : 
      72             : /* fd_acc_mgr_new formats a memory region suitable to hold an
      73             :    fd_acc_mgr_t.  Binds newly created object to global and returns
      74             :    cast. */
      75             : 
      76             : fd_acc_mgr_t *
      77             : fd_acc_mgr_new( void *      mem,
      78             :                 fd_funk_t * funk );
      79             : 
      80             : /* fd_acc_mgr_delete releases the memory region used by an fd_acc_mgr_t
      81             :    and returns it to the caller. */
      82             : 
      83             : void *
      84             : fd_acc_mgr_delete( fd_acc_mgr_t * acc_mgr );
      85             : 
      86             : /* Funk key handling **************************************************/
      87             : 
      88             : /* fd_acc_funk_key returns a fd_funk database key given an account
      89             :    address. */
      90             : 
      91             : FD_FN_PURE static inline fd_funk_rec_key_t
      92     5913021 : fd_acc_funk_key( fd_pubkey_t const * pubkey ) {
      93     5913021 :   fd_funk_rec_key_t key = {0};
      94     5913021 :   fd_memcpy( key.c, pubkey, sizeof(fd_pubkey_t) );
      95     5913021 :   key.c[ FD_FUNK_REC_KEY_FOOTPRINT - 1 ] = FD_FUNK_KEY_TYPE_ACC;
      96     5913021 :   return key;
      97     5913021 : }
      98             : 
      99             : /* fd_funk_key_is_acc returns 1 if given fd_funk key is an account
     100             :    managed by fd_acc_mgr_t, and 0 otherwise. */
     101             : 
     102             : FD_FN_PURE static inline int
     103     1239099 : fd_funk_key_is_acc( fd_funk_rec_key_t const * id ) {
     104     1239099 :   return id->c[ FD_FUNK_REC_KEY_FOOTPRINT - 1 ] == FD_FUNK_KEY_TYPE_ACC;
     105     1239099 : }
     106             : 
     107             : /* fd_funk_key_to_acc reinterprets a funk rec key as an account address.
     108             :    Safe assuming fd_funk_key_is_acc( id )==1. */
     109             : 
     110             : FD_FN_CONST static inline fd_pubkey_t const *
     111           0 : fd_funk_key_to_acc( fd_funk_rec_key_t const * id ) {
     112           0 :   return (fd_pubkey_t const *)fd_type_pun_const( id->c );
     113           0 : }
     114             : 
     115             : 
     116             : /* Account Access API *************************************************/
     117             : 
     118             : static inline void
     119     1310805 : fd_account_meta_init( fd_account_meta_t * m ) {
     120     1310805 :   fd_memset( m, 0, sizeof(fd_account_meta_t) );
     121     1310805 :   m->magic = FD_ACCOUNT_META_MAGIC;
     122     1310805 :   m->hlen  = sizeof(fd_account_meta_t);
     123     1310805 : }
     124             : 
     125             : /* fd_acc_exists checks if the account in a funk record exists or was
     126             :    deleted.  Handles NULL input safely.  Returns 0 if the account was
     127             :    deleted (zero lamports, empty data, zero owner).  Otherwise, returns
     128             :    1. */
     129             : 
     130             : static inline int
     131     2816976 : fd_acc_exists( fd_account_meta_t const * m ) {
     132             : 
     133     2816976 :   if( !m ) return 0;
     134             : 
     135     1778577 : # if FD_HAS_AVX
     136     1778577 :   wl_t o = wl_ldu( m->info.owner );
     137     1778577 :   int has_owner = !_mm256_testz_si256( o, o );
     138             : # else
     139             :   int has_owner = 0;
     140             :   for( ulong i=0UL; i<32UL; i++ )
     141             :     has_owner |= m->info.owner[i];
     142             :   has_owner = !!has_owner;
     143             : # endif
     144             : 
     145     1778577 :   return ( ( m->info.lamports > 0 ) |
     146     1778577 :            ( m->dlen          > 0 ) |
     147     1778577 :            ( has_owner            ) );
     148             : 
     149     2816976 : }
     150             : 
     151             : /* fd_acc_mgr_view_raw requests a read-only handle to account data.
     152             :    acc_mgr is the global account manager object.  txn is the database
     153             :    transaction to query.  pubkey is the account key to query.
     154             : 
     155             :    On success:
     156             :    - loads the account data into in-memory cache
     157             :    - returns a pointer to it in the caller's local address space
     158             :    - if out_rec!=NULL, sets *out_rec to a pointer to the funk rec.
     159             :      This handle is suitable as opt_con_rec for fd_acc_mgr_modify_raw.
     160             :    - notably, leaves *opt_err untouched, even if opt_err!=NULL
     161             : 
     162             :    First byte of returned pointer is first byte of fd_account_meta_t.
     163             :    To find data region of account, add (fd_account_meta_t)->hlen.
     164             : 
     165             :    Lifetime of returned fd_funk_rec_t and account record pointers ends
     166             :    when user calls modify_data for same account, or tranasction ends.
     167             : 
     168             :    On failure, returns NULL, and sets *opt_err if opt_err!=NULL.
     169             :    Reasons for error include
     170             :    - account not found
     171             :    - internal database or user error (out of memory, attempting to view
     172             :      record which has an active modify_data handle, etc.)
     173             : 
     174             :    It is always wrong to cast return value to a non-const pointer.
     175             :    Instead, use fd_acc_mgr_modify_raw to acquire a mutable handle.
     176             : 
     177             :    if txn_out is supplied (non-null), the txn the key was found in
     178             :    is returned. If *txn_out == NULL, the key was found in the root
     179             :    context */
     180             : 
     181             : fd_account_meta_t const *
     182             : fd_acc_mgr_view_raw( fd_acc_mgr_t *         acc_mgr,
     183             :                      fd_funk_txn_t const *  txn,
     184             :                      fd_pubkey_t const *    pubkey,
     185             :                      fd_funk_rec_t const ** opt_out_rec,
     186             :                      int *                  opt_err,
     187             :                      fd_funk_txn_t const ** txn_out   );
     188             : 
     189             : int
     190             : fd_acc_mgr_view( fd_acc_mgr_t *          acc_mgr,
     191             :                  fd_funk_txn_t const *   txn,
     192             :                  fd_pubkey_t const *     pubkey,
     193             :                  fd_borrowed_account_t * account );
     194             : 
     195             : /* fd_acc_mgr_modify_raw requests a writable handle to an account.
     196             :    Follows interface of fd_acc_mgr_modify_raw with the following
     197             :    changes:
     198             : 
     199             :    - do_create controls behavior if account does not exist.  If set to
     200             :      0, returns error.  If set to 1, creates account with given size
     201             :      and zero-initializes metadata.  Caller must initialize metadata of
     202             :      returned handle in this case.
     203             :    - min_data_sz is the minimum writable data size that the caller will
     204             :      accept.  This parameter will never shrink an existing account.  If
     205             :      do_create, specifies the new account's size.  Otherwise, increases
     206             :      record size if necessary.
     207             :    - When resizing or creating an account, the caller should also always
     208             :      set the account meta's size field.  This is not done automatically.
     209             :    - If caller already has a read-only handle to the requested account,
     210             :      opt_con_rec can be used to skip query by pubkey.
     211             :    - In most cases, account is copied to "dirty cache".
     212             : 
     213             :    On success:
     214             :    - If opt_out_rec!=NULL, sets *opt_out_rec to a pointer to writable
     215             :      funk rec.  Suitable as rec parameter to fd_acc_mgr_commit_raw.
     216             :    - Returns pointer to mutable account metadata and data analogous to
     217             :      fd_acc_mgr_view_raw.
     218             :    - IMPORTANT:  Return value may point to the same memory region as a
     219             :      previous calls to fd_acc_mgr_view_raw or fd_acc_mgr_modify_raw do,
     220             :      for the same funk rec (account/txn pair).  fd_acc_mgr only promises
     221             :      that account handles requested for different funk txns will not
     222             :      alias. Generally, for each funk txn, the user should only ever
     223             :      access the latest handle returned by view/modify.
     224             : 
     225             :    Caller must eventually commit funk record.  During replay, this is
     226             :    done automatically by slot freeze. */
     227             : 
     228             : fd_account_meta_t *
     229             : fd_acc_mgr_modify_raw( fd_acc_mgr_t *        acc_mgr,
     230             :                        fd_funk_txn_t *       txn,
     231             :                        fd_pubkey_t const *   pubkey,
     232             :                        int                   do_create,
     233             :                        ulong                 min_data_sz,
     234             :                        fd_funk_rec_t const * opt_con_rec,
     235             :                        fd_funk_rec_t **      opt_out_rec,
     236             :                        int *                 opt_err );
     237             : 
     238             : int
     239             : fd_acc_mgr_modify( fd_acc_mgr_t *          acc_mgr,
     240             :                    fd_funk_txn_t *         txn,
     241             :                    fd_pubkey_t const *     pubkey,
     242             :                    int                     do_create,
     243             :                    ulong                   min_data_sz,
     244             :                    fd_borrowed_account_t * account );
     245             : 
     246             : int
     247             : fd_acc_mgr_save( fd_acc_mgr_t *          acc_mgr,
     248             :                  fd_borrowed_account_t * account );
     249             : 
     250             : /* This version of save is for old code written before tpool integration */
     251             : 
     252             : int
     253             : fd_acc_mgr_save_non_tpool( fd_acc_mgr_t *          acc_mgr,
     254             :                            fd_funk_txn_t *         txn,
     255             :                            fd_borrowed_account_t * account );
     256             : 
     257             : int
     258             : fd_acc_mgr_save_many_tpool( fd_acc_mgr_t *           acc_mgr,
     259             :                             fd_funk_txn_t *          txn,
     260             :                             fd_borrowed_account_t ** accounts,
     261             :                             ulong                    accounts_cnt,
     262             :                             fd_tpool_t *             tpool );
     263             : 
     264             : void
     265             : fd_acc_mgr_lock( fd_acc_mgr_t * acc_mgr );
     266             : 
     267             : void
     268             : fd_acc_mgr_unlock( fd_acc_mgr_t * acc_mgr );
     269             : 
     270             : /* fd_acc_mgr_set_slots_per_epoch updates the slots_per_epoch setting
     271             :    and rebalances rent partitions.  No-op unless 'skip_rent_rewrites'
     272             :    feature is activated or 'slots_per_epoch' changes. */
     273             : 
     274             : void
     275             : fd_acc_mgr_set_slots_per_epoch( fd_exec_slot_ctx_t * slot_ctx,
     276             :                                 ulong                slots_per_epoch );
     277             : 
     278             : /* fd_acc_mgr_strerror converts an fd_acc_mgr error code into a human
     279             :    readable cstr.  The lifetime of the returned pointer is infinite and
     280             :    the call itself is thread safe.  The returned pointer is always to a
     281             :    non-NULL cstr. */
     282             : 
     283             : FD_FN_CONST char const *
     284             : fd_acc_mgr_strerror( int err );
     285             : 
     286             : FD_PROTOTYPES_END
     287             : 
     288             : #endif /* HEADER_fd_src_flamenco_runtime_fd_acc_mgr_h */

Generated by: LCOV version 1.14