LCOV - code coverage report
Current view: top level - flamenco/runtime/sysvar - fd_sysvar_cache.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 155 167 92.8 %
Date: 2026-04-29 06:59:03 Functions: 22 23 95.7 %

          Line data    Source code
       1             : #include "fd_sysvar_cache.h"
       2             : #include "fd_sysvar_cache_private.h"
       3             : #include "fd_sysvar_recent_hashes.h"
       4             : #include "fd_sysvar_slot_history.h"
       5             : #include <errno.h>
       6             : 
       7             : void *
       8        4230 : fd_sysvar_cache_new( void * mem ) {
       9             : 
      10        4230 :   if( FD_UNLIKELY( !mem ) ) {
      11           3 :     FD_LOG_WARNING(( "NULL mem" ));
      12           3 :     return NULL;
      13           3 :   }
      14        4227 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, alignof(fd_sysvar_cache_t) ) ) ) {
      15           3 :     FD_LOG_WARNING(( "misaligned mem" ));
      16           3 :     return NULL;
      17           3 :   }
      18             : 
      19        4224 :   fd_sysvar_cache_t * sysvar_cache = mem;
      20        4224 :   sysvar_cache->magic = 0UL;
      21        4224 :   memset( sysvar_cache->desc, 0, FD_SYSVAR_CACHE_ENTRY_CNT*sizeof(fd_sysvar_desc_t) );
      22             : 
      23        4224 :   FD_COMPILER_MFENCE();
      24        4224 :   sysvar_cache->magic = FD_SYSVAR_CACHE_MAGIC;
      25        4224 :   FD_COMPILER_MFENCE();
      26             : 
      27        4224 :   return sysvar_cache;
      28        4227 : }
      29             : 
      30             : fd_sysvar_cache_t *
      31        4236 : fd_sysvar_cache_join( void * mem ) {
      32             :   /* FIXME This is a good place to ref-count writable joins */
      33        4236 :   return (fd_sysvar_cache_t *)fd_sysvar_cache_join_const( mem );
      34        4236 : }
      35             : 
      36             : fd_sysvar_cache_t const *
      37        4245 : fd_sysvar_cache_join_const( void const * mem ) {
      38             : 
      39        4245 :   if( FD_UNLIKELY( !mem ) ) {
      40           6 :     FD_LOG_WARNING(( "NULL mem" ));
      41           6 :     return NULL;
      42           6 :   }
      43        4239 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, alignof(fd_sysvar_cache_t) ) ) ) {
      44           6 :     FD_LOG_WARNING(( "misaligned mem" ));
      45           6 :     return NULL;
      46           6 :   }
      47        4233 :   fd_sysvar_cache_t const * sysvar_cache = mem;
      48        4233 :   if( FD_UNLIKELY( sysvar_cache->magic != FD_SYSVAR_CACHE_MAGIC ) ) {
      49           6 :     FD_LOG_WARNING(( "bad magic" ));
      50           6 :     return NULL;
      51           6 :   }
      52             : 
      53        4227 :   return sysvar_cache;
      54        4233 : }
      55             : 
      56             : void *
      57        4224 : fd_sysvar_cache_leave( fd_sysvar_cache_t * sysvar_cache ) {
      58        4224 :   return sysvar_cache;
      59        4224 : }
      60             : 
      61             : void const *
      62           3 : fd_sysvar_cache_leave_const( fd_sysvar_cache_t const * sysvar_cache ) {
      63           3 :   return sysvar_cache;
      64           3 : }
      65             : 
      66             : void *
      67          39 : fd_sysvar_cache_delete( void * mem ) {
      68             : 
      69          39 :   if( FD_UNLIKELY( !mem ) ) {
      70           3 :     FD_LOG_WARNING(( "NULL mem" ));
      71           3 :     return NULL;
      72           3 :   }
      73          36 :   fd_sysvar_cache_t * sysvar_cache = mem;
      74          36 :   if( FD_UNLIKELY( sysvar_cache->magic != FD_SYSVAR_CACHE_MAGIC ) ) {
      75           3 :     FD_LOG_WARNING(( "bad magic" ));
      76           3 :     return NULL;
      77           3 :   }
      78             : 
      79          33 :   memset( sysvar_cache, 0, sizeof(fd_sysvar_cache_t) );
      80             : 
      81          33 :   return mem;
      82          36 : }
      83             : 
      84             : uchar const *
      85             : fd_sysvar_cache_data_query(
      86             :     fd_sysvar_cache_t const * sysvar_cache,
      87             :     void const *              address, /* 32 bytes */
      88             :     ulong *                   psz
      89         504 : ) {
      90         504 :   *psz = 0UL;
      91         504 :   fd_pubkey_t const pubkey = FD_LOAD( fd_pubkey_t, address );
      92         504 :   sysvar_tbl_t const * entry = sysvar_map_query( &pubkey, NULL );
      93         504 :   if( FD_UNLIKELY( !entry ) ) return NULL; /* address is not a sysvar */
      94         501 :   fd_sysvar_desc_t const * desc = &sysvar_cache->desc[ entry->desc_idx ];
      95         501 :   fd_sysvar_pos_t const *  pos  = &fd_sysvar_pos_tbl [ entry->desc_idx ];
      96         501 :   if( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) return NULL; /* sysvar data invalid */
      97         474 :   *psz = desc->data_sz;
      98         474 :   return (uchar const *)sysvar_cache + pos->data_off;
      99         501 : }
     100             : 
     101             : /* Generate accessors for sysvars that are backed by POD structs. */
     102             : 
     103             : #define SIMPLE_SYSVAR_READ( name, name2, typet )                       \
     104             :   typet *                                                              \
     105             :   fd_sysvar_cache_##name##_read( fd_sysvar_cache_t const * cache,      \
     106          45 :                                  typet *                   out ) {     \
     107          45 :     ulong const idx = FD_SYSVAR_##name##_IDX;                          \
     108          45 :     fd_sysvar_desc_t const * desc = &cache->desc[ idx ];               \
     109          45 :     fd_sysvar_pos_t const *  pos  = &fd_sysvar_pos_tbl[ idx ];         \
     110          45 :     if( FD_UNLIKELY( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) ) return NULL; \
     111          45 :     if( !pos->obj_max ) memcpy( out, (uchar *)cache+pos->data_off, pos->data_max ); \
     112          27 :     else                memcpy( out, (uchar *)cache+pos->obj_off,  pos->obj_max  ); \
     113          27 :     return out;                                                        \
     114          45 :   }
     115             : 
     116             : #define SIMPLE_SYSVAR( name, name2, type ) \
     117             :   SIMPLE_SYSVAR_READ( name, name2, fd_##type##_t )
     118          18 : FD_SYSVAR_SIMPLE_ITER( SIMPLE_SYSVAR )
     119          18 : #undef SIMPLE_SYSVAR
     120          18 : #undef SIMPLE_SYSVAR_READ
     121          18 : 
     122          18 : ulong const *
     123          18 : fd_sysvar_cache_last_restart_slot_read( fd_sysvar_cache_t const * cache ) {
     124           3 :   ulong const idx = FD_SYSVAR_last_restart_slot_IDX;
     125           3 :   fd_sysvar_desc_t const * desc = &cache->desc[ idx ];
     126           3 :   fd_sysvar_pos_t const *  pos  = &fd_sysvar_pos_tbl[ idx ];
     127           3 :   if( FD_UNLIKELY( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) ) return NULL;
     128           0 :   return fd_type_pun_const( (uchar const *)cache + pos->data_off );
     129           3 : }
     130             : 
     131             : int
     132           9 : fd_sysvar_cache_recent_hashes_is_empty( fd_sysvar_cache_t const * sysvar_cache ) {
     133           9 :   fd_sysvar_desc_t const * desc = &sysvar_cache->desc[ FD_SYSVAR_recent_hashes_IDX ];
     134           9 :   if( FD_UNLIKELY( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) ) return 1;
     135           9 :   FD_TEST( desc->data_sz >= sizeof(ulong) );
     136           9 :   ulong len = FD_LOAD( ulong, sysvar_cache->bin_recent_hashes );
     137           9 :   return len == 0UL;
     138           9 : }
     139             : 
     140             : fd_slot_hash_t const *
     141             : fd_sysvar_cache_slot_hashes_join_const(
     142             :     fd_sysvar_cache_t const * cache
     143         105 : ) {
     144         105 :   if( FD_UNLIKELY( !fd_sysvar_cache_slot_hashes_is_valid( cache ) ) ) return NULL;
     145         102 :   fd_slot_hashes_global_t * var = (void *)cache->obj_slot_hashes;
     146         102 :   fd_slot_hash_t * deq = deq_fd_slot_hash_t_join( (uchar *)var+var->hashes_offset );
     147             :   /* If the above is_valid check is passed, then join is guaranteed to succeed */
     148         102 :   if( FD_UNLIKELY( !deq ) ) FD_LOG_CRIT(( "slot hashes sysvar corruption detected" ));
     149         102 :   return deq; /* demote to const ptr */
     150         102 : }
     151             : 
     152             : void
     153             : fd_sysvar_cache_slot_hashes_leave_const(
     154             :     fd_sysvar_cache_t const * sysvar_cache,
     155             :     fd_slot_hash_t const *    slot_hashes
     156         102 : ) {
     157         102 :   (void)sysvar_cache; (void)slot_hashes;
     158         102 : }
     159             : 
     160             : fd_stake_history_t const *
     161             : fd_sysvar_cache_stake_history_join_const(
     162             :     fd_sysvar_cache_t const * cache
     163         417 : ) {
     164         417 :   if( FD_UNLIKELY( !fd_sysvar_cache_stake_history_is_valid( cache ) ) ) return NULL;
     165         318 :   return (void const *)cache->obj_stake_history;
     166         417 : }
     167             : 
     168             : void
     169             : fd_sysvar_cache_stake_history_leave_const(
     170             :     fd_sysvar_cache_t const *  sysvar_cache,
     171             :     fd_stake_history_t const * stake_history
     172           0 : ) {
     173           0 :   (void)sysvar_cache; (void)stake_history;
     174           0 : }
     175             : 
     176             : int
     177             : fd_sysvar_obj_restore( fd_sysvar_cache_t *     cache,
     178             :                        fd_sysvar_desc_t *      desc,
     179       30267 :                        fd_sysvar_pos_t const * pos ) {
     180       30267 :   desc->flags &= ~FD_SYSVAR_FLAG_VALID;
     181             : 
     182       30267 :   uchar const * data    = (uchar const *)cache + pos->data_off;
     183       30267 :   ulong const   data_sz = desc->data_sz;
     184             : 
     185       30267 :   if( FD_UNLIKELY( !pos->decode ) ) {
     186       22833 :     if( FD_UNLIKELY( !pos->validate( data, data_sz ) ) ) {
     187           9 :       FD_LOG_DEBUG(( "Failed to validate sysvar %s with data_sz=%lu",
     188           9 :                      pos->name, data_sz ));
     189           9 :       return EINVAL;
     190           9 :     }
     191       22824 :     desc->flags |= FD_SYSVAR_FLAG_VALID;
     192       22824 :     return 0;
     193       22833 :   }
     194             : 
     195        7434 :   fd_bincode_decode_ctx_t ctx = { .data=data, .dataend=data+data_sz };
     196        7434 :   ulong obj_sz = 0UL;
     197        7434 :   if( FD_UNLIKELY( pos->decode_footprint( &ctx, &obj_sz )!=FD_BINCODE_SUCCESS ) ) {
     198           0 :     FD_LOG_DEBUG(( "Failed to decode sysvar %s with data_sz=%lu: decode failed",
     199           0 :                    pos->name, data_sz ));
     200           0 :     return EINVAL;
     201           0 :   }
     202        7434 :   if( FD_UNLIKELY( obj_sz > pos->obj_max ) ) {
     203           0 :     FD_LOG_WARNING(( "Failed to restore sysvar %s: obj_sz=%lu exceeds max=%u",
     204           0 :                      pos->name, obj_sz, pos->obj_max ));
     205           0 :     return ENOMEM;
     206           0 :   }
     207             : 
     208        7434 :   fd_memset( (uchar *)cache+pos->obj_off, 0, pos->obj_max );
     209        7434 :   pos->decode( (uchar *)cache+pos->obj_off, &ctx );
     210        7434 :   desc->flags |= FD_SYSVAR_FLAG_VALID;
     211             : 
     212        7434 :   return 0;
     213        7434 : }
     214             : 
     215             : #define TYPES_CALLBACKS( name, suf )                                   \
     216             :   .decode_footprint = fd_##name##_decode_footprint,                    \
     217             :   .decode           = (__typeof__(((fd_sysvar_pos_t *)NULL)->decode))(ulong)fd_##name##_decode##suf
     218             : 
     219             : static int
     220        3720 : fd_sysvar_validate_clock( uchar const * data, ulong data_sz ) {
     221        3720 :   (void)data;
     222        3720 :   return data_sz >= sizeof(fd_sol_sysvar_clock_t );
     223        3720 : }
     224             : 
     225             : static int
     226        3714 : fd_sysvar_validate_rent( uchar const * data, ulong data_sz ) {
     227        3714 :   (void)data;
     228        3714 :   return data_sz >= sizeof(fd_rent_t );
     229        3714 : }
     230             : 
     231             : static int
     232        3684 : fd_sysvar_validate_last_restart_slot( uchar const * data, ulong data_sz ) {
     233        3684 :   (void)data;
     234        3684 :   return data_sz >= sizeof(ulong);
     235        3684 : }
     236             : 
     237             : static int
     238         183 : fd_sysvar_validate_epoch_rewards( uchar const * data, ulong data_sz ) {
     239         183 :   if( FD_UNLIKELY( data_sz < sizeof(fd_sysvar_epoch_rewards_t) ) ) return 0;
     240         183 :   fd_sysvar_epoch_rewards_t ew = FD_LOAD( fd_sysvar_epoch_rewards_t, data );
     241         183 :   uchar active = ew.active;
     242         183 :   if( FD_UNLIKELY( active!=0 && active!=1 ) ) return 0;
     243         180 :   return 1;
     244         183 : }
     245             : 
     246             : static int
     247        3717 : fd_sysvar_validate_epoch_schedule( uchar const * data, ulong data_sz ) {
     248        3717 :   if( FD_UNLIKELY( data_sz < sizeof(fd_epoch_schedule_t) ) ) return 0;
     249        3717 :   fd_epoch_schedule_t es = FD_LOAD( fd_epoch_schedule_t, data );
     250        3717 :   uchar warmup = es.warmup;
     251        3717 :   if( FD_UNLIKELY( warmup!=0 && warmup!=1 ) ) return 0;
     252        3714 :   return 1;
     253        3717 : }
     254             : 
     255             : fd_sysvar_pos_t const fd_sysvar_pos_tbl[ FD_SYSVAR_CACHE_ENTRY_CNT ] = {
     256             :   [FD_SYSVAR_clock_IDX] =
     257             :     { .name="clock",
     258             :       .data_off=offsetof(fd_sysvar_cache_t, bin_clock            ), .data_max=FD_SYSVAR_CLOCK_BINCODE_SZ,
     259             :       .validate=fd_sysvar_validate_clock },
     260             :   [FD_SYSVAR_epoch_rewards_IDX] =
     261             :     { .name="epoch rewards",
     262             :       .data_off=offsetof(fd_sysvar_cache_t, bin_epoch_rewards    ), .data_max=FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ,
     263             :       .validate=fd_sysvar_validate_epoch_rewards },
     264             :   [FD_SYSVAR_epoch_schedule_IDX] =
     265             :     { .name="epoch schedule",
     266             :       .data_off=offsetof(fd_sysvar_cache_t, bin_epoch_schedule   ), .data_max=FD_SYSVAR_EPOCH_SCHEDULE_BINCODE_SZ,
     267             :       .validate=fd_sysvar_validate_epoch_schedule },
     268             :   [FD_SYSVAR_last_restart_slot_IDX] =
     269             :     { .name="last restart slot",
     270             :       .data_off=offsetof(fd_sysvar_cache_t, bin_last_restart_slot), .data_max=FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ,
     271             :       .validate=fd_sysvar_validate_last_restart_slot },
     272             :   [FD_SYSVAR_recent_hashes_IDX] =
     273             :     { .name="recent blockhashes",
     274             :       .data_off=offsetof(fd_sysvar_cache_t, bin_recent_hashes    ), .data_max=FD_SYSVAR_RECENT_HASHES_BINCODE_SZ,
     275             :       .validate=fd_sysvar_recent_hashes_validate },
     276             :   [FD_SYSVAR_rent_IDX] =
     277             :     { .name="rent",
     278             :       .data_off=offsetof(fd_sysvar_cache_t, bin_rent             ), .data_max=FD_SYSVAR_RENT_BINCODE_SZ,
     279             :       .validate=fd_sysvar_validate_rent },
     280             :   [FD_SYSVAR_slot_hashes_IDX] =
     281             :     { .name="slot hashes",
     282             :       .data_off=offsetof(fd_sysvar_cache_t, bin_slot_hashes      ), .data_max=FD_SYSVAR_SLOT_HASHES_BINCODE_SZ,
     283             :       .obj_off =offsetof(fd_sysvar_cache_t, obj_slot_hashes      ), .obj_max =FD_SYSVAR_SLOT_HASHES_FOOTPRINT,
     284             :       TYPES_CALLBACKS( slot_hashes, _global ) },
     285             :   [FD_SYSVAR_slot_history_IDX] =
     286             :     { .name="slot history",
     287             :       .data_off=offsetof(fd_sysvar_cache_t, bin_slot_history     ), .data_max=FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ,
     288             :       .validate=fd_sysvar_slot_history_validate },
     289             :   [FD_SYSVAR_stake_history_IDX] =
     290             :     { .name="stake history",
     291             :       .data_off=offsetof(fd_sysvar_cache_t, bin_stake_history    ), .data_max=FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ,
     292             :       .obj_off =offsetof(fd_sysvar_cache_t, obj_stake_history    ), .obj_max =FD_SYSVAR_STAKE_HISTORY_FOOTPRINT,
     293             :       TYPES_CALLBACKS( stake_history, ) },
     294             : };
     295             : 
     296             : #undef TYPES_CALLBACKS

Generated by: LCOV version 1.14