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
|