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 reproduces the behavior of 5 : solana_program_runtime::sysvar_cache::SysvarCache. 6 : 7 : Firedancer provides this sysvar cache to be compatible with the Agave 8 : validator. Otherwise, it serves no purpose other than to make the 9 : runtime more complicated. The sysvar cache keeps a copy of various 10 : sysvar accounts. It is part of the implicit state of the runtime. 11 : 12 : Note that not all sysvars are in this cache. 13 : 14 : ### Cache state 15 : 16 : The sysvar cache is not a pure cache. For every supported sysvar, it 17 : may store NULL or a parsed version of the sysvar account. It is 18 : populated from the accounts DB. After parsing, the contents of the 19 : cache are not identical to the original account content anymore. If 20 : a sysvar account fails to parse, the corresponding cache entry will 21 : be NULL. 22 : 23 : ### Write back 24 : 25 : The sysvar cache can be modified directly by native programs. There 26 : is no standard pattern to how these changes get written back to the 27 : accounts DB. Currently, the write back happens at arbitrary stages 28 : in the slot boundary logic and is different for every sysvar. 29 : 30 : ### Memory Management 31 : 32 : fd_sysvar_cache_t is contained by a continuous memory region and 33 : embeds a heap allocator. */ 34 : 35 : #include "../fd_acc_mgr.h" 36 : 37 : /* Reuse this table to avoid code duplication */ 38 : #define FD_SYSVAR_CACHE_ITER(X) \ 39 228942 : X( fd_sol_sysvar_clock, clock ) \ 40 228942 : X( fd_epoch_schedule, epoch_schedule ) \ 41 228942 : X( fd_sysvar_epoch_rewards, epoch_rewards ) \ 42 228942 : X( fd_sysvar_fees, fees ) \ 43 228942 : X( fd_rent, rent ) \ 44 228942 : X( fd_slot_hashes, slot_hashes ) \ 45 228942 : X( fd_recent_block_hashes, recent_block_hashes ) \ 46 228942 : X( fd_stake_history, stake_history ) \ 47 228942 : X( fd_sol_sysvar_last_restart_slot, last_restart_slot ) 48 : 49 : /* The memory of fd_sysvar_cache_t fits as much sysvar information into 50 : the struct as possible. Unfortunately some parts of the sysvar 51 : spill out onto the heap due to how the type generator works. 52 : 53 : The has_{...} bits specify whether a sysvar logically exists. 54 : The val_{...} structs contain the top-level struct of each sysvar. 55 : If has_{...}==0 then any heap pointers in val_{...} are NULL, 56 : allowing for safe idempotent calls to fd_sol_sysvar_{...}_destroy() */ 57 : 58 : struct __attribute__((aligned(16UL))) fd_sysvar_cache_private { 59 : ulong magic; /* ==FD_SYSVAR_CACHE_MAGIC */ 60 : fd_valloc_t valloc; 61 : 62 : /* Declare the val_{...} values */ 63 : # define X( type, name ) \ 64 : type##_t val_##name[1]; 65 : FD_SYSVAR_CACHE_ITER(X) 66 : # undef X 67 : 68 : /* Declare the has_{...} bits */ 69 : # define X( _type, name ) \ 70 : ulong has_##name : 1; 71 : FD_SYSVAR_CACHE_ITER(X) 72 : # undef X 73 : }; 74 : 75 : struct fd_sysvar_cache_private; 76 : typedef struct fd_sysvar_cache_private fd_sysvar_cache_t; 77 : 78 : FD_PROTOTYPES_BEGIN 79 : 80 : /* fd_sysvar_cache_{align,footprint} return the memory region params of 81 : an fd_sysvar_cache_t. */ 82 : 83 : ulong 84 : fd_sysvar_cache_align( void ); 85 : 86 : ulong 87 : fd_sysvar_cache_footprint( void ); 88 : 89 : /* fd_sysvar_cache_new creates a new sysvar cache object. mem is the 90 : memory region that will back the fd_sysvar_cache_t. Attaches to the 91 : given valloc for use as a heap allocator for sysvar data. Returns 92 : object (in mem) on success and NULL on failure. Logs reasons for 93 : failure. */ 94 : 95 : fd_sysvar_cache_t * 96 : fd_sysvar_cache_new( void * mem, 97 : fd_valloc_t valloc ); 98 : 99 : /* fd_sysvar_cache_delete destroys a given sysvar cache object and any 100 : heap allocations made. Detaches from the valloc provided in 101 : fd_sysvar_cache_new. Returns the memory region that previously 102 : backed cache back to the caller. */ 103 : 104 : void * 105 : fd_sysvar_cache_delete( fd_sysvar_cache_t * cache ); 106 : 107 : /* fd_sysvar_cache_restore restores all sysvars from the given slot 108 : context. 109 : 110 : Roughly compatible with Agave's 111 : solana_program_runtime::sysvar_cache::SysvarCache::fill_missing_entries 112 : https://github.com/solana-labs/solana/blob/v1.17.23/program-runtime/src/sysvar_cache.rs#L137-L208 */ 113 : 114 : void 115 : fd_sysvar_cache_restore( fd_sysvar_cache_t * cache, 116 : fd_acc_mgr_t * acc_mgr, 117 : fd_funk_txn_t * funk_txn ); 118 : 119 : /* fd_sysvar_cache_restore_{name} restores only the given sysvar object from the given slot context */ 120 : 121 : # define X( type, name ) \ 122 : void \ 123 : fd_sysvar_cache_restore_##name( fd_sysvar_cache_t * cache, \ 124 : fd_acc_mgr_t * acc_mgr, \ 125 : fd_funk_txn_t * funk_txn ); 126 : FD_SYSVAR_CACHE_ITER(X) 127 : # undef X 128 : 129 : /* Accessors for sysvars. May return NULL. */ 130 : 131 : FD_FN_PURE fd_sol_sysvar_clock_t const * fd_sysvar_cache_clock ( fd_sysvar_cache_t const * cache ); 132 : FD_FN_PURE fd_epoch_schedule_t const * fd_sysvar_cache_epoch_schedule ( fd_sysvar_cache_t const * cache ); 133 : FD_FN_PURE fd_sysvar_epoch_rewards_t const * fd_sysvar_cache_epoch_rewards ( fd_sysvar_cache_t const * cache ); 134 : FD_FN_PURE fd_sysvar_fees_t const * fd_sysvar_cache_fees ( fd_sysvar_cache_t const * cache ); 135 : FD_FN_PURE fd_rent_t const * fd_sysvar_cache_rent ( fd_sysvar_cache_t const * cache ); 136 : FD_FN_PURE fd_slot_hashes_t const * fd_sysvar_cache_slot_hashes ( fd_sysvar_cache_t const * cache ); 137 : FD_FN_PURE fd_recent_block_hashes_t const * fd_sysvar_cache_recent_block_hashes( fd_sysvar_cache_t const * cache ); 138 : FD_FN_PURE fd_stake_history_t const * fd_sysvar_cache_stake_history ( fd_sysvar_cache_t const * cache ); 139 : FD_FN_PURE fd_sol_sysvar_last_restart_slot_t const * fd_sysvar_cache_last_restart_slot ( fd_sysvar_cache_t const * cache ); 140 : 141 : /* fd_sysvar_from_instr_acct_{...} pretends to read a sysvar from an 142 : instruction account. Checks that a given instruction account has 143 : an address matching the sysvar. Returns the sysvar from the sysvar 144 : cache. On return, *err is in FD_EXECUTOR_INSTR_{SUCCESS,ERR_{...}}. 145 : 146 : Matches Agave's 147 : solana_program_runtime::sysvar_cache::get_sysvar_with_account_check 148 : https://github.com/solana-labs/solana/blob/v1.18.8/program-runtime/src/sysvar_cache.rs#L215-L314 149 : 150 : Equivalent to: 151 : 152 : fd_sysvar_FOO_t const * 153 : fd_sysvar_from_instr_acct_FOO( fd_exec_instr_ctx_t const * ctx, 154 : ulong acct_idx ) { 155 : if( FD_UNLIKELY( idx >= ctx->instr->acct_cnt ) ) { 156 : *err = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; 157 : return NULL; 158 : } 159 : if( ctx->instr->acct_pubkeys[ acct_idx ] != FOO_addr ) { 160 : *err = FD_EXECUTOR_INSTR_ERR_INVALID_ARG; 161 : return NULL; 162 : } 163 : FOO_t const * value = fd_sysvar_cache_FOO( ctx->slot_ctx->sysvar_cache ); 164 : *err = value ? 0 : FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; 165 : return value; 166 : } */ 167 : 168 : fd_sol_sysvar_clock_t const * fd_sysvar_from_instr_acct_clock ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 169 : fd_epoch_schedule_t const * fd_sysvar_from_instr_acct_epoch_schedule ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 170 : fd_sysvar_epoch_rewards_t const * fd_sysvar_from_instr_acct_epoch_rewards ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 171 : fd_sysvar_fees_t const * fd_sysvar_from_instr_acct_fees ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 172 : fd_rent_t const * fd_sysvar_from_instr_acct_rent ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 173 : fd_slot_hashes_t const * fd_sysvar_from_instr_acct_slot_hashes ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 174 : fd_recent_block_hashes_t const * fd_sysvar_from_instr_acct_recent_block_hashes( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 175 : fd_stake_history_t const * fd_sysvar_from_instr_acct_stake_history ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 176 : fd_sol_sysvar_last_restart_slot_t const * fd_sysvar_from_instr_acct_last_restart_slot ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 177 : 178 : /* fd_check_sysvar_account does a check on if an instruction account index 179 : matches the expected pubkey of a specific sysvar. */ 180 : 181 : int 182 : fd_check_sysvar_account( fd_exec_instr_ctx_t const * ctx, 183 : ulong insn_acc_idx, 184 : fd_pubkey_t const * expected_id ); 185 : 186 : FD_PROTOTYPES_END 187 : 188 : #endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h */