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