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 */