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 0 : X( fd_sol_sysvar_clock, clock ) \ 40 0 : X( fd_epoch_schedule, epoch_schedule ) \ 41 0 : X( fd_sysvar_epoch_rewards, epoch_rewards ) \ 42 0 : X( fd_sysvar_fees, fees ) \ 43 0 : X( fd_rent, rent ) \ 44 0 : X( fd_slot_hashes, slot_hashes ) \ 45 0 : X( fd_recent_block_hashes, recent_block_hashes ) \ 46 0 : X( fd_stake_history, stake_history ) \ 47 0 : 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 : 61 : /* Declare the val_{...} values */ 62 : # define X( type, name ) \ 63 : type##_global_t val_##name[1]; 64 : FD_SYSVAR_CACHE_ITER(X) 65 : # undef X 66 : 67 : /* Declare the has_{...} bits */ 68 : # define X( _type, name ) \ 69 : ulong has_##name : 1; 70 : FD_SYSVAR_CACHE_ITER(X) 71 : # undef X 72 : }; 73 : 74 : struct fd_sysvar_cache_private; 75 : typedef struct fd_sysvar_cache_private fd_sysvar_cache_t; 76 : 77 : FD_PROTOTYPES_BEGIN 78 : 79 : /* fd_sysvar_cache_{align,footprint} return the memory region params of 80 : an fd_sysvar_cache_t. */ 81 : 82 : ulong 83 : fd_sysvar_cache_align( void ); 84 : 85 : ulong 86 : fd_sysvar_cache_footprint( void ); 87 : 88 : /* fd_sysvar_cache_new creates a new sysvar cache object. mem is the 89 : memory region that will back the fd_sysvar_cache_t. Attaches to the 90 : given valloc for use as a heap allocator for sysvar data. Returns 91 : object (in mem) on success and NULL on failure. Logs reasons for 92 : failure. */ 93 : 94 : fd_sysvar_cache_t * 95 : fd_sysvar_cache_new( void * mem ); 96 : 97 : /* fd_sysvar_cache_delete destroys a given sysvar cache object and any 98 : heap allocations made. Detaches from the valloc provided in 99 : fd_sysvar_cache_new. Returns the memory region that previously 100 : backed cache back to the caller. */ 101 : 102 : void * 103 : fd_sysvar_cache_delete( fd_sysvar_cache_t * cache ); 104 : 105 : /* fd_sysvar_cache_restore restores all sysvars from the given slot 106 : context. 107 : 108 : Roughly compatible with Agave's 109 : solana_program_runtime::sysvar_cache::SysvarCache::fill_missing_entries 110 : https://github.com/solana-labs/solana/blob/v1.17.23/program-runtime/src/sysvar_cache.rs#L137-L208 */ 111 : 112 : void 113 : fd_sysvar_cache_restore( fd_sysvar_cache_t * cache, 114 : fd_acc_mgr_t * acc_mgr, 115 : fd_funk_txn_t * funk_txn, 116 : fd_spad_t * runtime_spad, 117 : fd_wksp_t * wksp ); 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_spad_t * runtime_spad, \ 127 : fd_wksp_t * wksp ); 128 : FD_SYSVAR_CACHE_ITER(X) 129 : # undef X 130 : 131 : /* Accessors for sysvars. May return NULL. */ 132 : 133 : FD_FN_PURE fd_sol_sysvar_clock_global_t const * fd_sysvar_cache_clock ( fd_sysvar_cache_t const * cache ); 134 : FD_FN_PURE fd_epoch_schedule_global_t const * fd_sysvar_cache_epoch_schedule ( fd_sysvar_cache_t const * cache ); 135 : FD_FN_PURE fd_sysvar_epoch_rewards_global_t const * fd_sysvar_cache_epoch_rewards ( fd_sysvar_cache_t const * cache ); 136 : FD_FN_PURE fd_sysvar_fees_global_t const * fd_sysvar_cache_fees ( fd_sysvar_cache_t const * cache ); 137 : FD_FN_PURE fd_rent_global_t const * fd_sysvar_cache_rent ( fd_sysvar_cache_t const * cache ); 138 : FD_FN_PURE fd_slot_hashes_global_t const * fd_sysvar_cache_slot_hashes ( fd_sysvar_cache_t const * cache ); 139 : FD_FN_PURE fd_recent_block_hashes_global_t const * fd_sysvar_cache_recent_block_hashes( fd_sysvar_cache_t const * cache ); 140 : FD_FN_PURE fd_stake_history_global_t const * fd_sysvar_cache_stake_history ( fd_sysvar_cache_t const * cache ); 141 : FD_FN_PURE fd_sol_sysvar_last_restart_slot_global_t const * fd_sysvar_cache_last_restart_slot ( fd_sysvar_cache_t const * cache ); 142 : 143 : /* fd_sysvar_from_instr_acct_{...} pretends to read a sysvar from an 144 : instruction account. Checks that a given instruction account has 145 : an address matching the sysvar. Returns the sysvar from the sysvar 146 : cache. On return, *err is in FD_EXECUTOR_INSTR_{SUCCESS,ERR_{...}}. 147 : 148 : Matches Agave's 149 : solana_program_runtime::sysvar_cache::get_sysvar_with_account_check 150 : https://github.com/solana-labs/solana/blob/v1.18.8/program-runtime/src/sysvar_cache.rs#L215-L314 151 : 152 : Equivalent to: 153 : 154 : fd_sysvar_FOO_t const * 155 : fd_sysvar_from_instr_acct_FOO( fd_exec_instr_ctx_t const * ctx, 156 : ulong acct_idx ) { 157 : if( FD_UNLIKELY( idx >= ctx->instr->acct_cnt ) ) { 158 : *err = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; 159 : return NULL; 160 : } 161 : if( ctx->instr->acct_pubkeys[ acct_idx ] != FOO_addr ) { 162 : *err = FD_EXECUTOR_INSTR_ERR_INVALID_ARG; 163 : return NULL; 164 : } 165 : FOO_t const * value = fd_sysvar_cache_FOO( ctx->slot_ctx->sysvar_cache ); 166 : *err = value ? 0 : FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; 167 : return value; 168 : } */ 169 : 170 : fd_sol_sysvar_clock_global_t const * fd_sysvar_from_instr_acct_clock ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 171 : fd_epoch_schedule_global_t const * fd_sysvar_from_instr_acct_epoch_schedule ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 172 : fd_sysvar_epoch_rewards_global_t const * fd_sysvar_from_instr_acct_epoch_rewards ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 173 : fd_sysvar_fees_global_t const * fd_sysvar_from_instr_acct_fees ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 174 : fd_rent_global_t const * fd_sysvar_from_instr_acct_rent ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 175 : fd_slot_hashes_global_t const * fd_sysvar_from_instr_acct_slot_hashes ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 176 : fd_recent_block_hashes_global_t const * fd_sysvar_from_instr_acct_recent_block_hashes( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 177 : fd_stake_history_global_t const * fd_sysvar_from_instr_acct_stake_history ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 178 : fd_sol_sysvar_last_restart_slot_global_t const * fd_sysvar_from_instr_acct_last_restart_slot ( fd_exec_instr_ctx_t const * ctx, ulong acct_idx, int * err ); 179 : 180 : /* fd_check_sysvar_account does a check on if an instruction account index 181 : matches the expected pubkey of a specific sysvar. */ 182 : 183 : int 184 : fd_check_sysvar_account( fd_exec_instr_ctx_t const * ctx, 185 : ulong insn_acc_idx, 186 : fd_pubkey_t const * expected_id ); 187 : 188 : FD_PROTOTYPES_END 189 : 190 : #endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h */