LCOV - code coverage report
Current view: top level - flamenco/runtime/sysvar - fd_sysvar_cache.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 44 45 97.8 %
Date: 2026-02-01 06:05:50 Functions: 12 1098 1.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, the sysvar cache is used as follows:
       7             : 
       8             :    - Sysvar accounts are written to DB pre-execution (Bank::new)
       9             :    - Sysvar cache is restored from accounts (reads sysvar accounts)
      10             :      (Recreated from scratch using account contents)
      11             :    - Parallel transaction execution (reads from sysvar cache)
      12             :    - Sysvar accounts are written to DB post-execution (Bank::freeze)
      13             : 
      14             :    In other words, sysvars backed by stored accounts are updated before
      15             :    and after transaction execution.  During transaction execution, they
      16             :    are constant.  Firedancer stores a copy of these sysvars in the
      17             :    sysvar cache for performance (raw and typed forms).
      18             : 
      19             :    During the slot boundary (outside of transaction execution), sysvars
      20             :    should be accessed using the accounts directly, and the sysvar cache
      21             :    is considered non-existent. */
      22             : 
      23             : #include "fd_sysvar_base.h"
      24             : #include "../../types/fd_types.h"
      25             : #include "../../accdb/fd_accdb_ref.h"
      26             : 
      27        5622 : #define FD_SYSVAR_CACHE_ENTRY_CNT 9
      28             : 
      29             : /* fd_sysvar_cache_t is the header of a sysvar_cache object.
      30             :    A sysvar_cache object is position-independent and backed entirely by
      31             :    a single memory region.  Each sysvar is stored in serialized/raw form
      32             :    and in a typed form.  fd_sysvar_cache_desc_t points either form.
      33             : 
      34             :    It is safe to relocate a sysvar_cache object, or map it from multiple
      35             :    processes with different address spaces, or clone it via a shallow
      36             :    memcpy. */
      37             : 
      38             : struct fd_sysvar_desc {
      39             :   uint flags;
      40             :   uint data_sz;
      41             : };
      42             : 
      43             : typedef struct fd_sysvar_desc fd_sysvar_desc_t;
      44             : 
      45        2265 : #define FD_SYSVAR_FLAG_VALID (0x1u)
      46             : 
      47             : struct fd_sysvar_cache {
      48             :   ulong magic; /* ==FD_SYSVAR_CACHE_MAGIC */
      49             : 
      50             :   fd_sysvar_desc_t desc[ FD_SYSVAR_CACHE_ENTRY_CNT ];
      51             : 
      52             :   uchar bin_clock             [ FD_SYSVAR_CLOCK_BINCODE_SZ             ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      53             :   uchar obj_clock             [ FD_SYSVAR_CLOCK_FOOTPRINT              ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      54             :   uchar bin_epoch_rewards     [ FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ     ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      55             :   uchar obj_epoch_rewards     [ FD_SYSVAR_EPOCH_REWARDS_FOOTPRINT      ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      56             :   uchar bin_epoch_schedule    [ FD_SYSVAR_EPOCH_SCHEDULE_BINCODE_SZ    ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      57             :   uchar obj_epoch_schedule    [ FD_SYSVAR_EPOCH_SCHEDULE_FOOTPRINT     ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      58             :   uchar bin_last_restart_slot [ FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      59             :   uchar obj_last_restart_slot [ FD_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT  ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      60             :   uchar bin_recent_hashes     [ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ     ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      61             :   uchar obj_recent_hashes     [ FD_SYSVAR_RECENT_HASHES_FOOTPRINT      ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      62             :   uchar bin_rent              [ FD_SYSVAR_RENT_BINCODE_SZ              ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      63             :   uchar obj_rent              [ FD_SYSVAR_RENT_FOOTPRINT               ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      64             :   uchar bin_slot_hashes       [ FD_SYSVAR_SLOT_HASHES_BINCODE_SZ       ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      65             :   uchar obj_slot_hashes       [ FD_SYSVAR_SLOT_HASHES_FOOTPRINT        ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      66             :   uchar bin_slot_history      [ FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ      ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      67             :   uchar obj_slot_history      [ FD_SYSVAR_SLOT_HISTORY_FOOTPRINT       ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      68             :   uchar bin_stake_history     [ FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ     ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      69             :   uchar obj_stake_history     [ FD_SYSVAR_STAKE_HISTORY_FOOTPRINT      ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX)));
      70             : 
      71             :   /* Note that two sysvars are (deliberately) missing:
      72             :      - The 'fees' sysvar was deprecated/demoted.  It is not part of the
      73             :        sysvar cache in Agave.
      74             :      - The 'instructions' sysvar is a virtual account, not a stored
      75             :        account.  It is never written to a database, therefore it does
      76             :        not make sense to cache it. */
      77             : };
      78             : 
      79             : typedef struct fd_sysvar_cache fd_sysvar_cache_t;
      80             : 
      81           9 : #define FD_SYSVAR_clock_IDX               0
      82           3 : #define FD_SYSVAR_epoch_rewards_IDX       1
      83           3 : #define FD_SYSVAR_epoch_schedule_IDX      2
      84           3 : #define FD_SYSVAR_last_restart_slot_IDX   3
      85             : #define FD_SYSVAR_recent_hashes_IDX       4
      86          18 : #define FD_SYSVAR_rent_IDX                5
      87             : #define FD_SYSVAR_slot_hashes_IDX         6
      88             : #define FD_SYSVAR_slot_history_IDX        7
      89             : #define FD_SYSVAR_stake_history_IDX       8
      90             : 
      91             : FD_PROTOTYPES_BEGIN
      92             : 
      93             : /* Constructor API */
      94             : 
      95             : /* fd_sysvar_cache_new formats a memory region allocated according to
      96             :    fd_sysvar_cache_{align,footprint} for use as a sysvar_cache object. */
      97             : 
      98             : void *
      99             : fd_sysvar_cache_new( void * mem );
     100             : 
     101             : /* fd_sysvar_cache_join joins the caller to a sysvar_cache object as
     102             :    writable mode.  fd_sysvar_cache_join_const is the read-only version. */
     103             : 
     104             : fd_sysvar_cache_t *
     105             : fd_sysvar_cache_join( void * mem );
     106             : 
     107             : fd_sysvar_cache_t const *
     108             : fd_sysvar_cache_join_const( void const * mem );
     109             : 
     110             : /* fd_sysvar_cache_leave undoes a join to a sysvar_cache object. */
     111             : 
     112             : void *
     113             : fd_sysvar_cache_leave( fd_sysvar_cache_t * sysvar_cache );
     114             : 
     115             : void const *
     116             : fd_sysvar_cache_leave_const( fd_sysvar_cache_t const * sysvar_cache );
     117             : 
     118             : /* fd_sysvar_cache_delete releases the sysvar cache object's backing
     119             :    memory region back to the caller. */
     120             : 
     121             : void *
     122             : fd_sysvar_cache_delete( void * mem );
     123             : 
     124             : /* fd_sysvar_cache_restore rebuilds the sysvar cache from the account
     125             :    database.  Does blocking account database queries.  Returns 1 on
     126             :    success, or 0 on failure (logs warnings).  Reasons for failure
     127             :    include unexpected database error or sysvar deserialize failure. */
     128             : 
     129             : int
     130             : fd_sysvar_cache_restore( fd_bank_t *               bank,
     131             :                          fd_accdb_user_t *         accdb,
     132             :                          fd_funk_txn_xid_t const * xid );
     133             : 
     134             : /* fd_sysvar_cache_restore_fuzz is a weaker version of the above for use
     135             :    with solfuzz/protosol conformance tooling.  This version works around
     136             :    bugs in that tooling that create invalid sysvars and suppresses noisy
     137             :    log warning. */
     138             : 
     139             : void
     140             : fd_sysvar_cache_restore_fuzz( fd_bank_t *               bank,
     141             :                               fd_accdb_user_t *         accdb,
     142             :                               fd_funk_txn_xid_t const * xid );
     143             : 
     144             : void
     145             : fd_sysvar_cache_restore_from_ref( fd_sysvar_cache_t *   cache,
     146             :                                   fd_accdb_ro_t const * ro );
     147             : 
     148             : /* Generic accessors for serialized sysvar account data. */
     149             : 
     150             : /* fd_sysvar_cache_data_query returns a pointer to raw/serialized sysvar
     151             :    account data.  address points to the address of the sysvar account.
     152             :    *psz is set to the serialized data size (or 0 on failure).
     153             :    The returned pointer is valid until the next API call that takes a
     154             :    non-const pointer to sysvar_cache.  Note there are technically three
     155             :    outcomes (retval is the return value):
     156             :    - retval!=NULL && *psz!=0  sysvar is valid
     157             :    - retval==NULL && *psz==0  no sysvar with this address or sysvar
     158             :                               or sysvar contains invalid data
     159             :    - retval!=NULL && *psz==0  sysvar is valid, but empty (impossible
     160             :                               with current sysvars) */
     161             : 
     162             : uchar const *
     163             : fd_sysvar_cache_data_query(
     164             :     fd_sysvar_cache_t const * sysvar_cache,
     165             :     void const *              address, /* 32 bytes */
     166             :     ulong *                   psz
     167             : );
     168             : 
     169             : #define FD_SYSVAR_IS_VALID( sysvar_cache, sysvar ) \
     170         129 :   ( ( FD_VOLATILE_CONST( sysvar_cache->desc[ FD_SYSVAR_##sysvar##_IDX ].flags ) \
     171         129 :       & ( FD_SYSVAR_FLAG_VALID ) ) \
     172         129 :     == FD_SYSVAR_FLAG_VALID )
     173             : 
     174             : /* Accessors for small POD sysvars.  These do a copy on read.
     175             : 
     176             :    fd_sysvar_clock_is_valid returns 1 if the cached sysvar is valid
     177             :    (read, read_nofail, join_const are then guaranteed to succeed).
     178             :    Returns 0 otherwise.
     179             : 
     180             :    fd_sysvar_clock_read attempts to copy sysvar data from cache into the
     181             :    out argument.  Returns out on success, or NULL if the sysvar account
     182             :    does not exist or contains data that failed deserialization.
     183             : 
     184             :    fd_sysvar_clock_read_nofail returns a copy of the sysvar data.  If
     185             :    the sysvar does not exist or failed to deserialize, aborts the app
     186             :    with FD_LOG_ERR.
     187             : 
     188             :    Accessors for the other sysvars in this section are analogous. */
     189             : 
     190             : static inline int
     191          12 : fd_sysvar_cache_clock_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     192          12 :   return FD_SYSVAR_IS_VALID( sysvar_cache, clock );
     193          12 : }
     194             : 
     195             : fd_sol_sysvar_clock_t *
     196             : fd_sysvar_cache_clock_read(
     197             :     fd_sysvar_cache_t const * sysvar_cache,
     198             :     fd_sol_sysvar_clock_t *   out
     199             : );
     200             : 
     201             : /* Macro to improve FD_LOG_ERR line number accuracy */
     202             : 
     203             : #define SIMPLE_SYSVAR_READ_NOFAIL( cache, name, typet )                \
     204           3 :   __extension__({                                                      \
     205           3 :     typet out;                                                         \
     206           3 :     if( FD_UNLIKELY( !fd_sysvar_cache_##name##_read( (cache), &out ) ) )\
     207           3 :       FD_LOG_ERR(( "fd_sysvar_" #name "_read_nofail failed: sysvar not valid" )); \
     208           3 :     out;                                                               \
     209           3 :   })
     210             : 
     211             : #define fd_sysvar_cache_clock_read_nofail( cache ) \
     212           3 :   SIMPLE_SYSVAR_READ_NOFAIL( cache, clock, fd_sol_sysvar_clock_t )
     213             : 
     214             : static inline int
     215           3 : fd_sysvar_cache_epoch_rewards_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     216           3 :   return FD_SYSVAR_IS_VALID( sysvar_cache, epoch_rewards );
     217           3 : }
     218             : 
     219             : fd_sysvar_epoch_rewards_t *
     220             : fd_sysvar_cache_epoch_rewards_read(
     221             :     fd_sysvar_cache_t const *   sysvar_cache,
     222             :     fd_sysvar_epoch_rewards_t * out
     223             : );
     224             : 
     225             : static inline int
     226           3 : fd_sysvar_cache_epoch_schedule_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     227           3 :   return FD_SYSVAR_IS_VALID( sysvar_cache, epoch_schedule );
     228           3 : }
     229             : 
     230             : fd_epoch_schedule_t *
     231             : fd_sysvar_cache_epoch_schedule_read(
     232             :     fd_sysvar_cache_t const * sysvar_cache,
     233             :     fd_epoch_schedule_t *     out
     234             : );
     235             : 
     236             : #define fd_sysvar_cache_epoch_schedule_read_nofail( cache ) \
     237             :   SIMPLE_SYSVAR_READ_NOFAIL( cache, epoch_schedule, fd_epoch_schedule_t )
     238             : 
     239             : static inline int
     240           3 : fd_sysvar_cache_last_restart_slot_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     241           3 :   return FD_SYSVAR_IS_VALID( sysvar_cache, last_restart_slot );
     242           3 : }
     243             : 
     244             : fd_sol_sysvar_last_restart_slot_t *
     245             : fd_sysvar_cache_last_restart_slot_read(
     246             :     fd_sysvar_cache_t const *           sysvar_cache,
     247             :     fd_sol_sysvar_last_restart_slot_t * out
     248             : );
     249             : 
     250             : static inline int
     251           3 : fd_sysvar_cache_rent_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     252           3 :   return FD_SYSVAR_IS_VALID( sysvar_cache, rent );
     253           3 : }
     254             : 
     255             : fd_rent_t *
     256             : fd_sysvar_cache_rent_read(
     257             :     fd_sysvar_cache_t const * sysvar_cache,
     258             :     fd_rent_t *               out
     259             : );
     260             : 
     261             : #define fd_sysvar_cache_rent_read_nofail( cache ) \
     262           0 :   SIMPLE_SYSVAR_READ_NOFAIL( cache, rent, fd_rent_t )
     263             : 
     264             : /* Accessors for large sysvars. */
     265             : 
     266             : static inline int
     267          18 : fd_sysvar_cache_recent_hashes_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     268          18 :   return FD_SYSVAR_IS_VALID( sysvar_cache, recent_hashes );
     269          18 : }
     270             : 
     271             : fd_block_block_hash_entry_t const * /* deque */
     272             : fd_sysvar_cache_recent_hashes_join_const(
     273             :     fd_sysvar_cache_t const * sysvar_cache
     274             : );
     275             : 
     276             : void
     277             : fd_sysvar_cache_recent_hashes_leave_const(
     278             :     fd_sysvar_cache_t const *           sysvar_cache,
     279             :     fd_block_block_hash_entry_t const * hashes_deque
     280             : );
     281             : 
     282             : /* fd_sysvar_cache_slot_hashes_{join,leave}_const {attach,detach} the
     283             :    caller {from,to} the slot hashes deque contained in the slot hashes
     284             :    sysvar.
     285             : 
     286             :    The join API returns a pointer into the sysvar cache.  If the sysvar
     287             :    account is in an invalid state (non-existent, failed to deserialize),
     288             :    join returns NULL. */
     289             : 
     290             : static inline int
     291          66 : fd_sysvar_cache_slot_hashes_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     292          66 :   return FD_SYSVAR_IS_VALID( sysvar_cache, slot_hashes );
     293          66 : }
     294             : 
     295             : fd_slot_hash_t const *
     296             : fd_sysvar_cache_slot_hashes_join_const(
     297             :     fd_sysvar_cache_t const * sysvar_cache
     298             : );
     299             : 
     300             : void
     301             : fd_sysvar_cache_slot_hashes_leave_const(
     302             :     fd_sysvar_cache_t const * sysvar_cache,
     303             :     fd_slot_hash_t const *    slot_hashes
     304             : );
     305             : 
     306             : /* fd_sysvar_cache_slot_history_{join,leave}_const {attach,detach} the
     307             :    caller {from,to} the "slot history" sysvar.  Behavior analogous to
     308             :    above accessors. */
     309             : 
     310             : static inline int
     311           6 : fd_sysvar_cache_slot_history_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     312           6 :   return FD_SYSVAR_IS_VALID( sysvar_cache, slot_history );
     313           6 : }
     314             : 
     315             : fd_slot_history_global_t const *
     316             : fd_sysvar_cache_slot_history_join_const(
     317             :     fd_sysvar_cache_t const * sysvar_cache
     318             : );
     319             : 
     320             : void
     321             : fd_sysvar_cache_slot_history_leave_const(
     322             :     fd_sysvar_cache_t const *        sysvar_cache,
     323             :     fd_slot_history_global_t const * slot_history
     324             : );
     325             : 
     326             : /* fd_sysvar_cache_stake_history_{join,leave}_const {attach,detach} the
     327             :    caller {from,to} the "stake history" sysvar.  Behavior analogous to
     328             :    above accessors. */
     329             : 
     330             : static inline int
     331          15 : fd_sysvar_cache_stake_history_is_valid( fd_sysvar_cache_t const * sysvar_cache ) {
     332          15 :   return FD_SYSVAR_IS_VALID( sysvar_cache, stake_history );
     333          15 : }
     334             : 
     335             : fd_stake_history_t const *
     336             : fd_sysvar_cache_stake_history_join_const(
     337             :     fd_sysvar_cache_t const * sysvar_cache
     338             : );
     339             : 
     340             : void
     341             : fd_sysvar_cache_stake_history_leave_const(
     342             :     fd_sysvar_cache_t const *  sysvar_cache,
     343             :     fd_stake_history_t const * stake_history
     344             : );
     345             : 
     346             : FD_PROTOTYPES_END
     347             : 
     348             : #endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h */

Generated by: LCOV version 1.14