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