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 46 95.7 %
Date: 2025-10-13 04:42:14 Functions: 12 945 1.3 %

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

Generated by: LCOV version 1.14