LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_acc_mgr.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 24 37 64.9 %
Date: 2025-03-20 12:08:36 Functions: 3 585 0.5 %

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

Generated by: LCOV version 1.14