LCOV - code coverage report
Current view: top level - flamenco/runtime/sysvar - fd_sysvar_cache.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 26 45 57.8 %
Date: 2026-11-11 12:40:43 Functions: 2 1352 0.1 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h
       2             : #define HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h
       3             : 
       4             : /* fd_sysvar_cache.h is a read-only cache of sysvar accounts.
       5             : 
       6             :    Each block, sysvars are used as follows:
       7             : 
       8             :    - Sysvar accounts are written to DB pre-execution (Bank::new)
       9             :    - Replay validates the sysvar accounts (fd_sysvar_cache_validate)
      10             :    - Parallel transaction execution (reads from sysvar cache)
      11             :    - Sysvar accounts are written to DB post-execution (Bank::freeze)
      12             : 
      13             :    In other words, sysvars backed by stored accounts are updated before
      14             :    and after transaction execution.  During transaction execution, they
      15             :    are constant.  Each executor (fd_runtime_t) keeps a local copy of
      16             :    these sysvars for the bank it is executing (in serialized form).
      17             : 
      18             :    During the slot boundary (outside of transaction execution), sysvars
      19             :    should be accessed using the accounts directly. */
      20             : 
      21             : #include "fd_sysvar_base.h"
      22             : #include "../../accdb/fd_accdb.h"
      23             : 
      24     3829428 : #define FD_SYSVAR_CACHE_ENTRY_CNT 8
      25             : 
      26             : /* fd_sysvar_cache_t is the header of a sysvar_cache object.
      27             :    A sysvar_cache object is position-independent and backed entirely by
      28             :    a single memory region.  Each sysvar is stored in serialized/raw form
      29             :    only.  fd_sysvar_desc_t records the size and validity of each entry.
      30             : 
      31             :    It is safe to relocate a sysvar_cache object, or map it from multiple
      32             :    processes with different address spaces, or clone it via a shallow
      33             :    memcpy. */
      34             : 
      35             : struct fd_sysvar_desc {
      36             :   uint flags;
      37             :   uint data_sz;
      38             : };
      39             : 
      40             : typedef struct fd_sysvar_desc fd_sysvar_desc_t;
      41             : 
      42      655837 : #define FD_SYSVAR_FLAG_VALID (0x1u)
      43             : 
      44             : struct fd_sysvar_cache {
      45             :   ulong magic; /* ==FD_SYSVAR_CACHE_MAGIC */
      46             : 
      47             :   fd_sysvar_desc_t desc[ FD_SYSVAR_CACHE_ENTRY_CNT ];
      48             : 
      49             :   uchar bin_clock             [ FD_SYSVAR_CLOCK_BINCODE_SZ             ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      50             :   uchar bin_epoch_rewards     [ FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ     ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      51             :   uchar bin_epoch_schedule    [ FD_SYSVAR_EPOCH_SCHEDULE_BINCODE_SZ    ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      52             :   uchar bin_last_restart_slot [ FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      53             :   uchar bin_recent_hashes     [ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ     ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      54             :   uchar bin_rent              [ FD_SYSVAR_RENT_BINCODE_SZ              ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      55             :   uchar bin_slot_hashes       [ FD_SYSVAR_SLOT_HASHES_BINCODE_SZ       ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      56             :   uchar bin_stake_history     [ FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ     ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      57             : 
      58             :   /* Note that three sysvars are (deliberately) missing:
      59             :      - The 'fees' sysvar was deprecated/demoted.  It is not part of the
      60             :        sysvar cache in Agave.
      61             :      - The 'instructions' sysvar is a virtual account, not a stored
      62             :        account.  It is never written to a database, therefore it does
      63             :        not make sense to cache it.
      64             :      - The 'slot history' sysvar is large and not readable by programs.
      65             :        Its users read it from the account database directly. */
      66             : };
      67             : 
      68             : typedef struct fd_sysvar_cache fd_sysvar_cache_t;
      69             : 
      70       60329 : #define FD_SYSVAR_clock_IDX               0
      71          64 : #define FD_SYSVAR_epoch_rewards_IDX       1
      72       64602 : #define FD_SYSVAR_epoch_schedule_IDX      2
      73          90 : #define FD_SYSVAR_last_restart_slot_IDX   3
      74       56610 : #define FD_SYSVAR_recent_hashes_IDX       4
      75       66441 : #define FD_SYSVAR_rent_IDX                5
      76        9085 : #define FD_SYSVAR_slot_hashes_IDX         6
      77           0 : #define FD_SYSVAR_stake_history_IDX       7
      78             : 
      79             : FD_PROTOTYPES_BEGIN
      80             : 
      81             : /* Constructor API */
      82             : 
      83             : /* fd_sysvar_cache_new formats a memory region of size
      84             :    sizeof(fd_sysvar_cache_t) and alignment alignof(fd_sysvar_cache_t)
      85             :    for use as a sysvar_cache object. */
      86             : 
      87             : void *
      88             : fd_sysvar_cache_new( void * mem );
      89             : 
      90             : /* fd_sysvar_cache_join joins the caller to a sysvar_cache object as
      91             :    writable mode.  fd_sysvar_cache_join_const is the read-only version. */
      92             : 
      93             : fd_sysvar_cache_t *
      94             : fd_sysvar_cache_join( void * mem );
      95             : 
      96             : fd_sysvar_cache_t const *
      97             : fd_sysvar_cache_join_const( void const * mem );
      98             : 
      99             : /* fd_sysvar_cache_leave undoes a join to a sysvar_cache object. */
     100             : 
     101             : void *
     102             : fd_sysvar_cache_leave( fd_sysvar_cache_t * sysvar_cache );
     103             : 
     104             : void const *
     105             : fd_sysvar_cache_leave_const( fd_sysvar_cache_t const * sysvar_cache );
     106             : 
     107             : /* fd_sysvar_cache_delete releases the sysvar cache object's backing
     108             :    memory region back to the caller. */
     109             : 
     110             : void *
     111             : fd_sysvar_cache_delete( void * mem );
     112             : 
     113             : /* fd_sysvar_cache_restore rebuilds the sysvar cache from the account
     114             :    database as of fork_id.  Does blocking account database queries.
     115             :    Must not be called while an accdb acquire is open.  Returns 1 on
     116             :    success (missing sysvars fine), or 0 if any present sysvar account
     117             :    fails validation (logs details at DEBUG level). */
     118             : 
     119             : int
     120             : fd_sysvar_cache_restore( fd_sysvar_cache_t * cache,
     121             :                          fd_accdb_t *        accdb,
     122             :                          fd_accdb_fork_id_t  fork_id );
     123             : 
     124             : /* fd_sysvar_cache_restore_fuzz is a weaker version of the above for use
     125             :    with solfuzz/protosol conformance tooling.  This version works around
     126             :    bugs in that tooling that create invalid sysvars and suppresses
     127             :    missing-sysvar logs. */
     128             : 
     129             : void
     130             : fd_sysvar_cache_restore_fuzz( fd_sysvar_cache_t * cache,
     131             :                               fd_accdb_t *        accdb,
     132             :                               fd_accdb_fork_id_t  fork_id );
     133             : 
     134             : /* fd_sysvar_cache_validate checks that every present sysvar account
     135             :    of the bank decodes, without keeping a copy.  Same return value as
     136             :    fd_sysvar_cache_restore. */
     137             : 
     138             : int
     139             : fd_sysvar_cache_validate( fd_bank_t const * bank,
     140             :                           fd_accdb_t *      accdb );
     141             : 
     142             : /* fd_sysvar_cache_restore_one restores a single sysvar cache entry from
     143             :    raw account fields (as opposed to a full fd_acc_t).  If pubkey is not
     144             :    a sysvar or lamports is zero, this is a no-op. */
     145             : 
     146             : void
     147             : fd_sysvar_cache_restore_one( fd_sysvar_cache_t * cache,
     148             :                              fd_pubkey_t const * pubkey,
     149             :                              ulong               lamports,
     150             :                              uchar const *       acc_data,
     151             :                              ulong               acc_data_len );
     152             : 
     153             : /* Generic accessors for serialized sysvar account data. */
     154             : 
     155             : /* fd_sysvar_cache_data_query returns a pointer to raw/serialized sysvar
     156             :    account data.  address points to the address of the sysvar account.
     157             :    *psz is set to the serialized data size (or 0 on failure).
     158             :    The returned pointer is valid until the next API call that takes a
     159             :    non-const pointer to sysvar_cache.  Note there are technically three
     160             :    outcomes (retval is the return value):
     161             :    - retval!=NULL && *psz!=0  sysvar is valid
     162             :    - retval==NULL && *psz==0  no sysvar with this address or sysvar
     163             :                               or sysvar contains invalid data
     164             :    - retval!=NULL && *psz==0  sysvar is valid, but empty (impossible
     165             :                               with current sysvars) */
     166             : 
     167             : uchar const *
     168             : fd_sysvar_cache_data_query(
     169             :     fd_sysvar_cache_t const * sysvar_cache,
     170             :     void const *              address, /* 32 bytes */
     171             :     ulong *                   psz
     172             : );
     173             : 
     174             : #define FD_SYSVAR_IS_VALID( sysvar_cache, sysvar ) \
     175        3378 :   ( ( FD_VOLATILE_CONST( sysvar_cache->desc[ FD_SYSVAR_##sysvar##_IDX ].flags ) \
     176        3378 :       & ( FD_SYSVAR_FLAG_VALID ) ) \
     177        3378 :     == FD_SYSVAR_FLAG_VALID )
     178             : 
     179             : /* Accessors for small POD sysvars.  These do a copy on read.
     180             : 
     181             :    fd_sysvar_cache_clock_is_valid returns 1 if the cached sysvar is valid
     182             :    (read and read_nofail are then guaranteed to succeed).
     183             :    Returns 0 otherwise.
     184             : 
     185             :    fd_sysvar_cache_clock_read copies sysvar data from cache into out.
     186             :    Returns out on success, or NULL if the sysvar account
     187             :    does not exist or contains data that failed deserialization.
     188             : 
     189             :    fd_sysvar_cache_clock_read_nofail returns a copy of the sysvar data.  If
     190             :    the sysvar does not exist or failed to deserialize, aborts the app
     191             :    with FD_LOG_ERR.
     192             : 
     193             :    Accessors for the other sysvars in this section are analogous. */
     194             : 
     195             : static inline int
     196           0 : fd_sysvar_cache_clock_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     197           0 :   return FD_SYSVAR_IS_VALID( sysvar_cache, clock );
     198           0 : }
     199             : 
     200             : fd_sol_sysvar_clock_t *
     201             : fd_sysvar_cache_clock_read(
     202             :     fd_sysvar_cache_t const * sysvar_cache,
     203             :     fd_sol_sysvar_clock_t *   out
     204             : );
     205             : 
     206             : /* Macro to improve FD_LOG_ERR line number accuracy */
     207             : 
     208             : #define SIMPLE_SYSVAR_READ_NOFAIL( cache, name, typet )                \
     209         290 :   __extension__({                                                      \
     210         290 :     typet out;                                                         \
     211         290 :     if( FD_UNLIKELY( !fd_sysvar_cache_##name##_read( (cache), &out ) ) )\
     212         290 :       FD_LOG_ERR(( "fd_sysvar_" #name "_read_nofail failed: sysvar not valid" )); \
     213         290 :     out;                                                               \
     214         290 :   })
     215             : 
     216             : #define fd_sysvar_cache_clock_read_nofail( cache ) \
     217         143 :   SIMPLE_SYSVAR_READ_NOFAIL( cache, clock, fd_sol_sysvar_clock_t )
     218             : 
     219             : static inline int
     220           0 : fd_sysvar_cache_epoch_rewards_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     221           0 :   return FD_SYSVAR_IS_VALID( sysvar_cache, epoch_rewards );
     222           0 : }
     223             : 
     224             : fd_sysvar_epoch_rewards_t *
     225             : fd_sysvar_cache_epoch_rewards_read(
     226             :     fd_sysvar_cache_t const *   sysvar_cache,
     227             :     fd_sysvar_epoch_rewards_t * out
     228             : );
     229             : 
     230             : static inline int
     231           0 : fd_sysvar_cache_epoch_schedule_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     232           0 :   return FD_SYSVAR_IS_VALID( sysvar_cache, epoch_schedule );
     233           0 : }
     234             : 
     235             : fd_epoch_schedule_t *
     236             : fd_sysvar_cache_epoch_schedule_read(
     237             :     fd_sysvar_cache_t const * sysvar_cache,
     238             :     fd_epoch_schedule_t *     out
     239             : );
     240             : 
     241             : static inline int
     242           0 : fd_sysvar_cache_last_restart_slot_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     243           0 :   return FD_SYSVAR_IS_VALID( sysvar_cache, last_restart_slot );
     244           0 : }
     245             : 
     246             : ulong const *
     247             : fd_sysvar_cache_last_restart_slot_read( fd_sysvar_cache_t const * sysvar_cache );
     248             : 
     249             : static inline int
     250           0 : fd_sysvar_cache_rent_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     251           0 :   return FD_SYSVAR_IS_VALID( sysvar_cache, rent );
     252           0 : }
     253             : 
     254             : fd_rent_t *
     255             : fd_sysvar_cache_rent_read(
     256             :     fd_sysvar_cache_t const * sysvar_cache,
     257             :     fd_rent_t *               out
     258             : );
     259             : 
     260             : #define fd_sysvar_cache_rent_read_nofail( cache ) \
     261         147 :   SIMPLE_SYSVAR_READ_NOFAIL( cache, rent, fd_rent_t )
     262             : 
     263             : /* Accessors for large sysvars. */
     264             : 
     265             : static inline int
     266        1638 : fd_sysvar_cache_recent_hashes_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     267        1638 :   return FD_SYSVAR_IS_VALID( sysvar_cache, recent_hashes );
     268        1638 : }
     269             : 
     270             : /* fd_sysvar_cache_recent_hashes_is_empty returns 0 if there is at least
     271             :    one valid blockhash queue entry in the 'recent blockhashes' sysvar,
     272             :    1 otherwise (invalid sysvar or empty queue). */
     273             : 
     274             : int
     275             : fd_sysvar_cache_recent_hashes_is_empty( fd_sysvar_cache_t const * sysvar_cache );
     276             : 
     277             : static inline int
     278        1740 : fd_sysvar_cache_slot_hashes_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     279        1740 :   return FD_SYSVAR_IS_VALID( sysvar_cache, slot_hashes );
     280        1740 : }
     281             : 
     282             : static inline int
     283           0 : fd_sysvar_cache_stake_history_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     284           0 :   return FD_SYSVAR_IS_VALID( sysvar_cache, stake_history );
     285           0 : }
     286             : 
     287             : /* View convenience wrappers.  These combine fd_sysvar_cache_data_query
     288             :    with the corresponding fd_sysvar_*_view function.  Returns view on
     289             :    success or NULL if the sysvar is invalid. */
     290             : 
     291             : fd_stake_history_t *
     292             : fd_sysvar_cache_stake_history_view( fd_sysvar_cache_t const * cache,
     293             :                                     fd_stake_history_t *      view );
     294             : 
     295             : fd_slot_hashes_t *
     296             : fd_sysvar_cache_slot_hashes_view( fd_sysvar_cache_t const * cache,
     297             :                                   fd_slot_hashes_t *        view );
     298             : 
     299             : FD_PROTOTYPES_END
     300             : 
     301             : #endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h */

Generated by: LCOV version 1.14