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_stake_history.h"
6 :
7 : #include <errno.h>
8 :
9 : void *
10 1164 : fd_sysvar_cache_new( void * mem ) {
11 :
12 1164 : if( FD_UNLIKELY( !mem ) ) {
13 3 : FD_LOG_WARNING(( "NULL mem" ));
14 3 : return NULL;
15 3 : }
16 1161 : 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 1158 : fd_sysvar_cache_t * sysvar_cache = mem;
22 1158 : sysvar_cache->magic = 0UL;
23 1158 : memset( sysvar_cache->desc, 0, FD_SYSVAR_CACHE_ENTRY_CNT*sizeof(fd_sysvar_desc_t) );
24 :
25 1158 : FD_COMPILER_MFENCE();
26 1158 : sysvar_cache->magic = FD_SYSVAR_CACHE_MAGIC;
27 1158 : FD_COMPILER_MFENCE();
28 :
29 1158 : return sysvar_cache;
30 1161 : }
31 :
32 : fd_sysvar_cache_t *
33 1170 : fd_sysvar_cache_join( void * mem ) {
34 : /* FIXME This is a good place to ref-count writable joins */
35 1170 : return (fd_sysvar_cache_t *)fd_sysvar_cache_join_const( mem );
36 1170 : }
37 :
38 : fd_sysvar_cache_t const *
39 1179 : fd_sysvar_cache_join_const( void const * mem ) {
40 :
41 1179 : if( FD_UNLIKELY( !mem ) ) {
42 6 : FD_LOG_WARNING(( "NULL mem" ));
43 6 : return NULL;
44 6 : }
45 1173 : 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 1167 : fd_sysvar_cache_t const * sysvar_cache = mem;
50 1167 : 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 1161 : return sysvar_cache;
56 1167 : }
57 :
58 : void *
59 966 : fd_sysvar_cache_leave( fd_sysvar_cache_t * sysvar_cache ) {
60 966 : return sysvar_cache;
61 966 : }
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 78 : fd_sysvar_cache_delete( void * mem ) {
70 :
71 78 : if( FD_UNLIKELY( !mem ) ) {
72 3 : FD_LOG_WARNING(( "NULL mem" ));
73 3 : return NULL;
74 3 : }
75 75 : fd_sysvar_cache_t * sysvar_cache = mem;
76 75 : 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 72 : memset( sysvar_cache, 0, sizeof(fd_sysvar_cache_t) );
82 :
83 72 : return mem;
84 75 : }
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 1755 : ) {
92 1755 : *psz = 0UL;
93 1755 : fd_pubkey_t const pubkey = FD_LOAD( fd_pubkey_t, address );
94 1755 : sysvar_tbl_t const * entry = sysvar_map_query( &pubkey, NULL );
95 1755 : if( FD_UNLIKELY( !entry ) ) return NULL; /* address is not a sysvar */
96 1752 : fd_sysvar_desc_t const * desc = &sysvar_cache->desc[ entry->desc_idx ];
97 1752 : fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl [ entry->desc_idx ];
98 1752 : if( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) return NULL; /* sysvar data invalid */
99 1701 : *psz = desc->data_sz;
100 1701 : return (uchar const *)sysvar_cache + pos->data_off;
101 1752 : }
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 564 : typet * out ) { \
109 564 : ulong const idx = FD_SYSVAR_##name##_IDX; \
110 564 : fd_sysvar_desc_t const * desc = &cache->desc[ idx ]; \
111 564 : fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ idx ]; \
112 564 : if( FD_UNLIKELY( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) ) return NULL; \
113 564 : memcpy( out, (uchar *)cache+pos->data_off, pos->data_max ); \
114 543 : return out; \
115 564 : }
116 :
117 : #define SIMPLE_SYSVAR( name, name2, type ) \
118 : SIMPLE_SYSVAR_READ( name, name2, fd_##type##_t )
119 21 : FD_SYSVAR_SIMPLE_ITER( SIMPLE_SYSVAR )
120 21 : #undef SIMPLE_SYSVAR
121 21 : #undef SIMPLE_SYSVAR_READ
122 21 :
123 21 : ulong const *
124 21 : 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 15 : fd_sysvar_cache_recent_hashes_is_empty( fd_sysvar_cache_t const * sysvar_cache ) {
134 15 : fd_sysvar_desc_t const * desc = &sysvar_cache->desc[ FD_SYSVAR_recent_hashes_IDX ];
135 15 : if( FD_UNLIKELY( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) ) return 1;
136 15 : FD_TEST( desc->data_sz >= sizeof(ulong) );
137 15 : ulong len = FD_LOAD( ulong, sysvar_cache->bin_recent_hashes );
138 15 : return len == 0UL;
139 15 : }
140 :
141 : int
142 : fd_sysvar_obj_restore( fd_sysvar_cache_t * cache,
143 : fd_sysvar_desc_t * desc,
144 4635 : fd_sysvar_pos_t const * pos ) {
145 4635 : desc->flags &= ~FD_SYSVAR_FLAG_VALID;
146 :
147 4635 : uchar const * data = (uchar const *)cache + pos->data_off;
148 4635 : ulong const data_sz = desc->data_sz;
149 :
150 4635 : if( FD_UNLIKELY( !pos->validate( data, data_sz ) ) ) {
151 36 : FD_LOG_DEBUG(( "Failed to validate sysvar %s with data_sz=%lu",
152 36 : pos->name, data_sz ));
153 36 : return EINVAL;
154 36 : }
155 4599 : desc->flags |= FD_SYSVAR_FLAG_VALID;
156 4599 : return 0;
157 4635 : }
158 :
159 : static int
160 12876 : fd_sysvar_validate_clock( uchar const * data, ulong data_sz ) {
161 12876 : (void)data;
162 12876 : return data_sz >= sizeof(fd_sol_sysvar_clock_t );
163 12876 : }
164 :
165 : static int
166 12825 : fd_sysvar_validate_rent( uchar const * data, ulong data_sz ) {
167 12825 : (void)data;
168 12825 : return data_sz >= sizeof(fd_rent_t );
169 12825 : }
170 :
171 : static int
172 12840 : fd_sysvar_validate_last_restart_slot( uchar const * data, ulong data_sz ) {
173 12840 : (void)data;
174 12840 : return data_sz >= sizeof(ulong);
175 12840 : }
176 :
177 : static int
178 1053 : fd_sysvar_validate_epoch_rewards( uchar const * data, ulong data_sz ) {
179 1053 : if( FD_UNLIKELY( data_sz < sizeof(fd_sysvar_epoch_rewards_t) ) ) return 0;
180 1050 : fd_sysvar_epoch_rewards_t ew = FD_LOAD( fd_sysvar_epoch_rewards_t, data );
181 1050 : uchar active = ew.active;
182 1050 : if( FD_UNLIKELY( active!=0 && active!=1 ) ) return 0;
183 1047 : return 1;
184 1050 : }
185 :
186 : static int
187 12858 : fd_sysvar_validate_epoch_schedule( uchar const * data, ulong data_sz ) {
188 12858 : if( FD_UNLIKELY( data_sz < sizeof(fd_epoch_schedule_t) ) ) return 0;
189 12855 : fd_epoch_schedule_t es = FD_LOAD( fd_epoch_schedule_t, data );
190 12855 : uchar warmup = es.warmup;
191 12855 : if( FD_UNLIKELY( warmup!=0 && warmup!=1 ) ) return 0;
192 12849 : return 1;
193 12855 : }
194 :
195 : fd_sysvar_pos_t const fd_sysvar_pos_tbl[ FD_SYSVAR_CACHE_ENTRY_CNT ] = {
196 : [FD_SYSVAR_clock_IDX] =
197 : { .name="clock",
198 : .data_off=offsetof(fd_sysvar_cache_t, bin_clock ), .data_max=FD_SYSVAR_CLOCK_BINCODE_SZ,
199 : .validate=fd_sysvar_validate_clock },
200 : [FD_SYSVAR_epoch_rewards_IDX] =
201 : { .name="epoch rewards",
202 : .data_off=offsetof(fd_sysvar_cache_t, bin_epoch_rewards ), .data_max=FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ,
203 : .validate=fd_sysvar_validate_epoch_rewards },
204 : [FD_SYSVAR_epoch_schedule_IDX] =
205 : { .name="epoch schedule",
206 : .data_off=offsetof(fd_sysvar_cache_t, bin_epoch_schedule ), .data_max=FD_SYSVAR_EPOCH_SCHEDULE_BINCODE_SZ,
207 : .validate=fd_sysvar_validate_epoch_schedule },
208 : [FD_SYSVAR_last_restart_slot_IDX] =
209 : { .name="last restart slot",
210 : .data_off=offsetof(fd_sysvar_cache_t, bin_last_restart_slot), .data_max=FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ,
211 : .validate=fd_sysvar_validate_last_restart_slot },
212 : [FD_SYSVAR_recent_hashes_IDX] =
213 : { .name="recent blockhashes",
214 : .data_off=offsetof(fd_sysvar_cache_t, bin_recent_hashes ), .data_max=FD_SYSVAR_RECENT_HASHES_BINCODE_SZ,
215 : .validate=fd_sysvar_recent_hashes_validate },
216 : [FD_SYSVAR_rent_IDX] =
217 : { .name="rent",
218 : .data_off=offsetof(fd_sysvar_cache_t, bin_rent ), .data_max=FD_SYSVAR_RENT_BINCODE_SZ,
219 : .validate=fd_sysvar_validate_rent },
220 : [FD_SYSVAR_slot_hashes_IDX] =
221 : { .name="slot hashes",
222 : .data_off=offsetof(fd_sysvar_cache_t, bin_slot_hashes ), .data_max=FD_SYSVAR_SLOT_HASHES_BINCODE_SZ,
223 : .validate=fd_sysvar_slot_hashes_validate },
224 : [FD_SYSVAR_stake_history_IDX] =
225 : { .name="stake history",
226 : .data_off=offsetof(fd_sysvar_cache_t, bin_stake_history ), .data_max=FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ,
227 : .validate=fd_sysvar_stake_history_validate },
228 : };
229 :
230 : fd_slot_hashes_t *
231 : fd_sysvar_cache_slot_hashes_view( fd_sysvar_cache_t const * cache,
232 288 : fd_slot_hashes_t * view ) {
233 288 : fd_sysvar_desc_t const * desc = &cache->desc[ FD_SYSVAR_slot_hashes_IDX ];
234 288 : if( FD_UNLIKELY( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) ) return NULL;
235 288 : return fd_sysvar_slot_hashes_view( view, cache->bin_slot_hashes, desc->data_sz );
236 288 : }
237 :
238 : fd_stake_history_t *
239 : fd_sysvar_cache_stake_history_view( fd_sysvar_cache_t const * cache,
240 6 : fd_stake_history_t * view ) {
241 6 : fd_sysvar_desc_t const * desc = &cache->desc[ FD_SYSVAR_stake_history_IDX ];
242 6 : if( FD_UNLIKELY( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) ) return NULL;
243 6 : return fd_sysvar_stake_history_view( view, cache->bin_stake_history, desc->data_sz );
244 6 : }
|