Line data Source code
1 : #include "fd_vote_stakes.h"
2 : #include "fd_vote_stakes_private.h"
3 :
4 : ulong
5 14247 : fd_vote_stakes_align( void ) {
6 14247 : return FD_VOTE_STAKES_ALIGN;
7 14247 : }
8 :
9 : ulong
10 : fd_vote_stakes_footprint( ulong max_vote_accounts,
11 : ulong expected_vote_accounts,
12 2373 : ulong max_fork_width ) {
13 2373 : ulong map_chain_cnt = index_map_chain_cnt_est( expected_vote_accounts );
14 :
15 2373 : ulong l = FD_LAYOUT_INIT;
16 2373 : l = FD_LAYOUT_APPEND( l, fd_vote_stakes_align(), sizeof(fd_vote_stakes_t) );
17 2373 : l = FD_LAYOUT_APPEND( l, index_pool_align(), index_pool_footprint( max_vote_accounts * 2UL ) );
18 2373 : l = FD_LAYOUT_APPEND( l, index_map_align(), index_map_footprint( map_chain_cnt ) );
19 2373 : l = FD_LAYOUT_APPEND( l, index_map_multi_align(), index_map_multi_footprint( map_chain_cnt ) );
20 2373 : l = FD_LAYOUT_APPEND( l, fork_pool_align(), fork_pool_footprint( max_fork_width ) );
21 2373 : l = FD_LAYOUT_APPEND( l, fork_dlist_align(), fork_dlist_footprint() );
22 5589 : for( ulong i=0; i<max_fork_width; i++ ) {
23 3216 : l = FD_LAYOUT_APPEND( l, stakes_pool_align(), stakes_pool_footprint( max_vote_accounts ) );
24 3216 : l = FD_LAYOUT_APPEND( l, stakes_map_align(), stakes_map_footprint( map_chain_cnt ) );
25 3216 : }
26 2373 : return FD_LAYOUT_FINI( l, fd_vote_stakes_align() );
27 2373 : }
28 :
29 : void *
30 : fd_vote_stakes_new( void * shmem,
31 : ulong max_vote_accounts,
32 : ulong expected_vote_accounts,
33 : ulong max_fork_width,
34 597 : ulong seed ) {
35 597 : if( FD_UNLIKELY( !shmem ) ) {
36 0 : FD_LOG_WARNING(( "NULL mem" ));
37 0 : return NULL;
38 0 : }
39 :
40 597 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vote_stakes_align() ) ) ) {
41 0 : FD_LOG_WARNING(( "misaligned mem" ));
42 0 : return NULL;
43 0 : }
44 :
45 597 : if( FD_UNLIKELY( max_fork_width>MAX_FORK_WIDTH ) ) {
46 0 : FD_LOG_WARNING(( "max_fork_width is too large" ));
47 0 : return NULL;
48 0 : }
49 :
50 597 : ulong map_chain_cnt = index_map_chain_cnt_est( expected_vote_accounts );
51 :
52 597 : FD_SCRATCH_ALLOC_INIT( l, shmem );
53 597 : fd_vote_stakes_t * vote_stakes = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_stakes_align(), sizeof(fd_vote_stakes_t) );
54 597 : void * index_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, index_pool_align(), index_pool_footprint( max_vote_accounts * 2UL ) );
55 597 : void * index_map_mem = FD_SCRATCH_ALLOC_APPEND( l, index_map_align(), index_map_footprint( map_chain_cnt ) );
56 597 : void * index_map_multi_mem = FD_SCRATCH_ALLOC_APPEND( l, index_map_multi_align(), index_map_multi_footprint( map_chain_cnt ) );
57 597 : void * fork_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fork_pool_align(), fork_pool_footprint( max_fork_width ) );
58 597 : void * fork_dlist_mem = FD_SCRATCH_ALLOC_APPEND( l, fork_dlist_align(), fork_dlist_footprint() );
59 1446 : for( ulong i=0; i<max_fork_width; i++ ) {
60 849 : void * stakes_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, stakes_pool_align(), stakes_pool_footprint( max_vote_accounts ) );
61 0 : stake_t * stakes_pool = stakes_pool_join( stakes_pool_new( stakes_pool_mem, max_vote_accounts ) );
62 849 : if( FD_UNLIKELY( !stakes_pool ) ) {
63 0 : FD_LOG_WARNING(( "Failed to create vote stakes ele pool" ));
64 0 : return NULL;
65 0 : }
66 849 : vote_stakes->stakes_pool_off[ i ] = (ulong)stakes_pool - (ulong)shmem;
67 :
68 849 : void * stakes_map_mem = FD_SCRATCH_ALLOC_APPEND( l, stakes_map_align(), stakes_map_footprint( map_chain_cnt ) );
69 0 : stakes_map_t * stakes_map = stakes_map_join( stakes_map_new( stakes_map_mem, map_chain_cnt, seed ) );
70 849 : if( FD_UNLIKELY( !stakes_map ) ) {
71 0 : FD_LOG_WARNING(( "Failed to create vote stakes ele map" ));
72 0 : return NULL;
73 0 : }
74 849 : vote_stakes->stakes_map_off[ i ] = (ulong)stakes_map - (ulong)shmem;
75 849 : }
76 :
77 597 : index_ele_t * index_pool = index_pool_join( index_pool_new( index_pool_mem, max_vote_accounts * 2UL ) );
78 597 : if( FD_UNLIKELY( !index_pool ) ) {
79 0 : FD_LOG_WARNING(( "Failed to create vote stakes index pool" ));
80 0 : return NULL;
81 0 : }
82 :
83 597 : index_map_t * index_map = index_map_join( index_map_new( index_map_mem, map_chain_cnt, seed ) );
84 597 : if( FD_UNLIKELY( !index_map ) ) {
85 0 : FD_LOG_WARNING(( "Failed to create vote stakes index map" ));
86 0 : return NULL;
87 0 : }
88 :
89 597 : index_map_multi_t * index_map_multi = index_map_multi_join( index_map_multi_new( index_map_multi_mem, map_chain_cnt, seed ) );
90 597 : if( FD_UNLIKELY( !index_map_multi ) ) {
91 0 : FD_LOG_WARNING(( "Failed to create vote stakes index map multi" ));
92 0 : return NULL;
93 0 : }
94 :
95 597 : fork_t * fork_pool = fork_pool_join( fork_pool_new( fork_pool_mem, max_fork_width ) );
96 597 : if( FD_UNLIKELY( !fork_pool ) ) {
97 0 : FD_LOG_WARNING(( "Failed to create vote stakes fork pool" ));
98 0 : return NULL;
99 0 : }
100 :
101 597 : fork_dlist_t * fork_dlist = fork_dlist_join( fork_dlist_new( fork_dlist_mem ) );
102 597 : if( FD_UNLIKELY( !fork_dlist ) ) {
103 0 : FD_LOG_WARNING(( "Failed to create vote stakes fork dlist" ));
104 0 : return NULL;
105 0 : }
106 :
107 597 : if( FD_UNLIKELY( max_fork_width>USHORT_MAX ) ) {
108 0 : FD_LOG_WARNING(( "max_fork_width is too large" ));
109 0 : return NULL;
110 0 : }
111 :
112 597 : vote_stakes->max_fork_width = (ushort)max_fork_width;
113 597 : vote_stakes->index_pool_off = (ulong)index_pool - (ulong)shmem;
114 597 : vote_stakes->index_map_off = (ulong)index_map - (ulong)shmem;
115 597 : vote_stakes->index_map_multi_off = (ulong)index_map_multi - (ulong)shmem;
116 597 : vote_stakes->fork_pool_off = (ulong)fork_pool - (ulong)shmem;
117 597 : vote_stakes->fork_dlist_off = (ulong)fork_dlist - (ulong)shmem;
118 597 : vote_stakes->root_idx = (ushort)fork_pool_idx_acquire( fork_pool );
119 597 : fork_dlist_idx_push_tail( fork_dlist, vote_stakes->root_idx, fork_pool );
120 :
121 597 : fd_rwlock_new( &vote_stakes->lock );
122 :
123 597 : FD_COMPILER_MFENCE();
124 597 : FD_VOLATILE( vote_stakes->magic ) = FD_VOTE_STAKES_MAGIC;
125 597 : FD_COMPILER_MFENCE();
126 :
127 597 : return vote_stakes;
128 597 : }
129 :
130 : fd_vote_stakes_t *
131 1185 : fd_vote_stakes_join( void * shmem ) {
132 1185 : fd_vote_stakes_t * vote_stakes = (fd_vote_stakes_t *)shmem;
133 :
134 1185 : if( FD_UNLIKELY( !vote_stakes ) ) {
135 0 : FD_LOG_WARNING(( "NULL vote stakes" ));
136 0 : return NULL;
137 0 : }
138 :
139 1185 : if( FD_UNLIKELY( vote_stakes->magic != FD_VOTE_STAKES_MAGIC ) ) {
140 0 : FD_LOG_WARNING(( "Invalid vote stakes magic" ));
141 0 : return NULL;
142 0 : }
143 :
144 1185 : return vote_stakes;
145 1185 : }
146 :
147 : void
148 : fd_vote_stakes_root_insert_key( fd_vote_stakes_t * vote_stakes,
149 : fd_pubkey_t const * pubkey,
150 : fd_pubkey_t const * node_account_t_1,
151 : ulong stake_t_1,
152 : uchar commission_t_1,
153 3447 : ulong epoch ) {
154 3447 : fd_rwlock_write( &vote_stakes->lock );
155 :
156 3447 : index_ele_t * index_pool = get_index_pool( vote_stakes );
157 3447 : index_map_t * index_map = get_index_map( vote_stakes );
158 3447 : index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
159 :
160 3447 : index_ele_t * ele = index_pool_ele_acquire( index_pool );
161 3447 : ele->pubkey = *pubkey;
162 3447 : ele->refcnt = 1;
163 3447 : ele->stake_t_1 = (stake_t_1 & 0x7FFFFFFFFFFFFFFFUL);
164 3447 : ele->commission_t_1 = commission_t_1;
165 3447 : ele->node_account_t_1 = *node_account_t_1;
166 3447 : ele->stake_t_2 = 0UL;
167 3447 : ele->node_account_t_2 = (fd_pubkey_t){0};
168 3447 : ele->commission_t_2 = 0U;
169 3447 : ele->epoch = epoch % 2;
170 3447 : ele->exists_t_1 = 1;
171 3447 : ele->exists_t_2 = 0;
172 : /* It is fine to leave node account t_2 uninitalized because it will
173 : only be used if stake_t_2 is non-zero. */
174 :
175 3447 : FD_TEST( index_map_ele_insert( index_map, ele, index_pool ) );
176 3447 : FD_TEST( index_map_multi_ele_insert( index_map_multi, ele, index_pool ) );
177 :
178 3447 : stake_t * stakes_pool = get_stakes_pool( vote_stakes, vote_stakes->root_idx );
179 3447 : stakes_map_t * stakes_map = get_stakes_map( vote_stakes, vote_stakes->root_idx );
180 :
181 3447 : uint pubkey_idx = (uint)index_pool_idx( index_pool, ele );
182 3447 : stake_t * new_stake = stakes_pool_ele_acquire( stakes_pool );
183 3447 : new_stake->idx = pubkey_idx;
184 3447 : FD_TEST( stakes_map_ele_insert( stakes_map, new_stake, stakes_pool ) );
185 :
186 3447 : fd_rwlock_unwrite( &vote_stakes->lock );
187 3447 : }
188 :
189 : void
190 : fd_vote_stakes_root_update_meta( fd_vote_stakes_t * vote_stakes,
191 : fd_pubkey_t const * pubkey,
192 : fd_pubkey_t const * node_account_t_2,
193 : ulong stake_t_2,
194 : uchar commission_t_2,
195 3450 : ulong epoch ) {
196 3450 : fd_rwlock_write( &vote_stakes->lock );
197 :
198 3450 : index_ele_t * index_pool = get_index_pool( vote_stakes );
199 3450 : index_map_t * index_map = get_index_map( vote_stakes );
200 3450 : index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
201 3450 : index_ele_t * ele = index_map_multi_ele_query( index_map_multi, pubkey, NULL, index_pool );
202 3450 : if( FD_UNLIKELY( !ele ) ) {
203 3 : ele = index_pool_ele_acquire( index_pool );
204 3 : ele->pubkey = *pubkey;
205 3 : ele->refcnt = 1;
206 3 : ele->stake_t_1 = 0UL;
207 3 : ele->node_account_t_1 = (fd_pubkey_t){0};
208 3 : ele->epoch = epoch % 2;
209 3 : ele->commission_t_1 = 0U;
210 3 : ele->exists_t_1 = 0;
211 :
212 3 : FD_TEST( index_map_ele_insert( index_map, ele, index_pool ) );
213 3 : FD_TEST( index_map_multi_ele_insert( index_map_multi, ele, index_pool ) );
214 :
215 3 : stake_t * stakes_pool = get_stakes_pool( vote_stakes, vote_stakes->root_idx );
216 3 : stakes_map_t * stakes_map = get_stakes_map( vote_stakes, vote_stakes->root_idx );
217 :
218 3 : uint pubkey_idx = (uint)index_pool_idx( index_pool, ele );
219 3 : stake_t * new_stake = stakes_pool_ele_acquire( stakes_pool );
220 3 : new_stake->idx = pubkey_idx;
221 3 : FD_TEST( stakes_map_ele_insert( stakes_map, new_stake, stakes_pool ) );
222 3 : }
223 :
224 3450 : ele->commission_t_2 = commission_t_2;
225 3450 : ele->node_account_t_2 = *node_account_t_2;
226 3450 : ele->stake_t_2 = stake_t_2;
227 3450 : ele->exists_t_2 = 1;
228 :
229 3450 : fd_rwlock_unwrite( &vote_stakes->lock );
230 3450 : }
231 :
232 : void
233 : fd_vote_stakes_root_purge_key( fd_vote_stakes_t * vote_stakes,
234 0 : fd_pubkey_t const * pubkey ) {
235 0 : fd_rwlock_write( &vote_stakes->lock );
236 :
237 0 : index_ele_t * index_pool = get_index_pool( vote_stakes );
238 0 : index_map_t * index_map = get_index_map( vote_stakes );
239 0 : index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
240 :
241 0 : uint ele_idx = (uint)index_map_multi_idx_query( index_map_multi, pubkey, UINT_MAX, index_pool );
242 0 : FD_TEST( ele_idx!=UINT_MAX );
243 :
244 0 : index_ele_t * ele = index_pool_ele( index_pool, ele_idx );
245 :
246 0 : FD_TEST( index_map_multi_ele_remove_fast( index_map_multi, ele, index_pool ) );
247 0 : FD_TEST( index_map_ele_remove( index_map, &ele->index_key, NULL, index_pool ) );
248 :
249 0 : stake_t * stakes_pool = get_stakes_pool( vote_stakes, vote_stakes->root_idx );
250 0 : stakes_map_t * stakes_map = get_stakes_map( vote_stakes, vote_stakes->root_idx );
251 :
252 0 : stake_t * stake_ele = stakes_map_ele_remove( stakes_map, &ele_idx, NULL, stakes_pool );
253 0 : stakes_pool_ele_release( stakes_pool, stake_ele );
254 :
255 0 : index_pool_ele_release( index_pool, ele );
256 :
257 0 : fd_rwlock_unwrite( &vote_stakes->lock );
258 0 : }
259 :
260 : void
261 : fd_vote_stakes_insert( fd_vote_stakes_t * vote_stakes,
262 : ushort fork_idx,
263 : fd_pubkey_t const * pubkey,
264 : fd_pubkey_t const * node_account_t_1,
265 : fd_pubkey_t const * node_account_t_2,
266 : ulong stake_t_1,
267 : ulong stake_t_2,
268 : uchar commission_t_1,
269 : uchar commission_t_2,
270 : uchar exists_t_1,
271 : uchar exists_t_2,
272 189 : ulong epoch ) {
273 189 : fd_rwlock_write( &vote_stakes->lock );
274 :
275 189 : index_ele_t * index_pool = get_index_pool( vote_stakes );
276 189 : index_map_t * index_map = get_index_map( vote_stakes );
277 189 : index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
278 189 : stake_t * stakes_pool = get_stakes_pool( vote_stakes, fork_idx );
279 189 : stakes_map_t * stakes_map = get_stakes_map( vote_stakes, fork_idx );
280 :
281 189 : index_key_t index_key = {
282 189 : .pubkey = *pubkey,
283 189 : .node_account_t_1 = *node_account_t_1,
284 189 : .stake_t_1 = stake_t_1 & 0x7FFFFFFFFFFFFFFFUL,
285 189 : .epoch = epoch % 2,
286 189 : .commission_t_1 = commission_t_1,
287 189 : .exists_t_1 = exists_t_1,
288 189 : };
289 189 : index_ele_t * index_ele = index_map_ele_query( index_map, &index_key, NULL, index_pool );
290 189 : if( FD_LIKELY( !index_ele ) ) {
291 186 : index_ele = index_pool_ele_acquire( index_pool );
292 186 : index_ele->index_key = index_key;
293 186 : index_ele->epoch = epoch % 2;
294 186 : index_ele->refcnt = 1;
295 186 : index_ele->node_account_t_2 = *node_account_t_2;
296 186 : index_ele->commission_t_2 = commission_t_2;
297 186 : index_ele->stake_t_2 = stake_t_2;
298 186 : index_ele->exists_t_2 = exists_t_2;
299 186 : FD_TEST( index_map_multi_ele_insert( index_map_multi, index_ele, index_pool ) );
300 186 : FD_TEST( index_map_ele_insert( index_map, index_ele, index_pool ) );
301 186 : } else {
302 3 : index_ele->refcnt++;
303 3 : }
304 :
305 189 : stake_t * stake = stakes_pool_ele_acquire( stakes_pool );
306 189 : stake->idx = (uint)index_pool_idx( index_pool, index_ele );
307 189 : FD_TEST( stakes_map_ele_insert( stakes_map, stake, stakes_pool ) );
308 :
309 189 : fd_rwlock_unwrite( &vote_stakes->lock );
310 189 : }
311 :
312 : void
313 3417 : fd_vote_stakes_genesis_fini( fd_vote_stakes_t * vote_stakes ) {
314 3417 : fd_rwlock_write( &vote_stakes->lock );
315 :
316 3417 : index_ele_t * index_pool = get_index_pool( vote_stakes );
317 3417 : index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
318 :
319 3417 : for( index_map_multi_iter_t iter = index_map_multi_iter_init( index_map_multi, index_pool );
320 6840 : !index_map_multi_iter_done( iter, index_map_multi, index_pool );
321 3423 : iter = index_map_multi_iter_next( iter, index_map_multi, index_pool ) ) {
322 3423 : index_ele_t * ele = index_map_multi_iter_ele( iter, index_map_multi, index_pool );
323 3423 : ele->node_account_t_2 = ele->node_account_t_1;
324 3423 : ele->stake_t_2 = ele->stake_t_1;
325 3423 : }
326 :
327 3417 : fd_rwlock_unwrite( &vote_stakes->lock );
328 3417 : }
329 :
330 : ushort
331 144 : fd_vote_stakes_new_child( fd_vote_stakes_t * vote_stakes ) {
332 144 : fd_rwlock_write( &vote_stakes->lock );
333 :
334 144 : fork_t * fork_pool = get_fork_pool( vote_stakes );
335 144 : fork_dlist_t * fork_dlist = get_fork_dlist( vote_stakes );
336 :
337 144 : if( FD_UNLIKELY( !fork_pool_free( fork_pool ) ) ) {
338 0 : FD_LOG_CRIT(( "no free forks in pool" ));
339 0 : }
340 :
341 144 : ushort idx = (ushort)fork_pool_idx_acquire( fork_pool );
342 :
343 144 : fork_dlist_idx_push_tail( fork_dlist, idx, fork_pool );
344 :
345 144 : fd_rwlock_unwrite( &vote_stakes->lock );
346 144 : return idx;
347 144 : }
348 :
349 : void
350 : fd_vote_stakes_advance_root( fd_vote_stakes_t * vote_stakes,
351 90 : ushort root_idx ) {
352 90 : fd_rwlock_write( &vote_stakes->lock );
353 :
354 : /* Only expect the vote stakes to update once an epoch. */
355 90 : if( FD_LIKELY( root_idx==vote_stakes->root_idx ) ) {
356 78 : fd_rwlock_unwrite( &vote_stakes->lock );
357 78 : return;
358 78 : }
359 :
360 12 : fork_t * fork_pool = get_fork_pool( vote_stakes );
361 12 : fork_dlist_t * fork_dlist = get_fork_dlist( vote_stakes );
362 :
363 12 : index_ele_t * index_pool = get_index_pool( vote_stakes );
364 12 : index_map_t * index_map = get_index_map( vote_stakes );
365 12 : index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
366 : /* For every outstanding fork that is not the new candidate root,
367 : remove all stakes refcnts from the index. If the index has no
368 : outstanding references, remove the index entry. */
369 42 : while( !fork_dlist_is_empty( fork_dlist, fork_pool ) ) {
370 30 : ushort fork_idx = (ushort)fork_dlist_idx_pop_head( fork_dlist, fork_pool );
371 30 : if( fork_idx==root_idx ) continue;
372 :
373 18 : stake_t * stakes_pool = get_stakes_pool( vote_stakes, fork_idx );
374 18 : stakes_map_t * stakes_map = get_stakes_map( vote_stakes, fork_idx );
375 18 : for( stakes_map_iter_t iter = stakes_map_iter_init( stakes_map, stakes_pool );
376 75 : !stakes_map_iter_done( iter, stakes_map, stakes_pool );
377 57 : iter = stakes_map_iter_next( iter, stakes_map, stakes_pool ) ) {
378 57 : stake_t * stake = stakes_map_iter_ele( iter, stakes_map, stakes_pool );
379 57 : index_ele_t * ele = index_pool_ele( index_pool, stake->idx );
380 57 : ele->refcnt--;
381 :
382 57 : if( FD_UNLIKELY( ele->refcnt==0U ) ) {
383 57 : FD_TEST( index_map_ele_remove( index_map, &ele->index_key, NULL, index_pool ) );
384 57 : FD_TEST( index_map_multi_ele_remove_fast( index_map_multi, ele, index_pool ) );
385 57 : index_pool_ele_release( index_pool, ele );
386 57 : }
387 57 : }
388 18 : fork_pool_idx_release( fork_pool, fork_idx );
389 18 : stakes_map_reset( get_stakes_map( vote_stakes, fork_idx ) );
390 18 : stakes_pool_reset( get_stakes_pool( vote_stakes, fork_idx ) );
391 18 : }
392 : /* TODO: There's probably a way to do a more efficient reset here. */
393 :
394 12 : fork_dlist_idx_push_head( fork_dlist, root_idx, fork_pool );
395 12 : vote_stakes->root_idx = root_idx;
396 :
397 12 : fd_rwlock_unwrite( &vote_stakes->lock );
398 12 : }
399 :
400 : static int
401 : fd_vote_stakes_query_private( fd_vote_stakes_t * vote_stakes,
402 : ushort fork_idx,
403 : fd_pubkey_t const * pubkey,
404 : ulong * stake_t_1_out_opt,
405 : ulong * stake_t_2_out_opt,
406 : fd_pubkey_t * node_account_t_1_out_opt,
407 : fd_pubkey_t * node_account_t_2_out_opt,
408 : uchar * commission_t_1_out_opt,
409 : uchar * commission_t_2_out_opt,
410 : uchar * exists_t_1_out_opt,
411 351 : uchar * exists_t_2_out_opt ) {
412 :
413 351 : index_ele_t * index_pool = get_index_pool( vote_stakes );
414 351 : index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
415 :
416 351 : stake_t * stakes_pool = get_stakes_pool( vote_stakes, fork_idx );
417 351 : stakes_map_t * stakes_map = get_stakes_map( vote_stakes, fork_idx );
418 :
419 : /* The index may have multiple entries for the same pubkey, so every
420 : single matching index entry must be checked to see if the index
421 : exists in the given fork's stakes map. If it does, return the
422 : t_2 stake value.*/
423 351 : uint ele_idx = (uint)index_map_multi_idx_query_const( index_map_multi, pubkey, UINT_MAX, index_pool );
424 351 : if( FD_UNLIKELY( ele_idx==UINT_MAX ) ) {
425 0 : return 0;
426 0 : }
427 :
428 351 : while( !stakes_map_ele_query_const( stakes_map, &ele_idx, NULL, stakes_pool ) ) {
429 0 : ele_idx = (uint)index_map_multi_idx_next_const( ele_idx, UINT_MAX, index_pool );
430 0 : if( FD_UNLIKELY( ele_idx==UINT_MAX ) ) {
431 0 : return 0;
432 0 : }
433 0 : }
434 :
435 351 : index_ele_t * index_ele = index_pool_ele( index_pool, ele_idx );
436 351 : if( stake_t_1_out_opt ) *stake_t_1_out_opt = index_ele->stake_t_1;
437 351 : if( stake_t_2_out_opt ) *stake_t_2_out_opt = index_ele->stake_t_2;
438 351 : if( node_account_t_1_out_opt ) *node_account_t_1_out_opt = index_ele->node_account_t_1;
439 351 : if( node_account_t_2_out_opt ) *node_account_t_2_out_opt = index_ele->node_account_t_2;
440 351 : if( commission_t_1_out_opt ) *commission_t_1_out_opt = (uchar)index_ele->commission_t_1;
441 351 : if( commission_t_2_out_opt ) *commission_t_2_out_opt = (uchar)index_ele->commission_t_2;
442 351 : if( exists_t_1_out_opt ) *exists_t_1_out_opt = (uchar)index_ele->exists_t_1;
443 351 : if( exists_t_2_out_opt ) *exists_t_2_out_opt = index_ele->exists_t_2;
444 351 : return 1;
445 351 : }
446 :
447 : int
448 : fd_vote_stakes_query( fd_vote_stakes_t * vote_stakes,
449 : ushort fork_idx,
450 : fd_pubkey_t const * pubkey,
451 : ulong * stake_t_1_out_opt,
452 : ulong * stake_t_2_out_opt,
453 : fd_pubkey_t * node_account_t_1_out_opt,
454 : fd_pubkey_t * node_account_t_2_out_opt,
455 : uchar * commission_t_1_out_opt,
456 : uchar * commission_t_2_out_opt,
457 : uchar * exists_t_1_out_opt,
458 69 : uchar * exists_t_2_out_opt ) {
459 69 : fd_rwlock_read( &vote_stakes->lock );
460 69 : int result = fd_vote_stakes_query_private( vote_stakes,
461 69 : fork_idx,
462 69 : pubkey,
463 69 : stake_t_1_out_opt,
464 69 : stake_t_2_out_opt,
465 69 : node_account_t_1_out_opt,
466 69 : node_account_t_2_out_opt,
467 69 : commission_t_1_out_opt,
468 69 : commission_t_2_out_opt,
469 69 : exists_t_1_out_opt,
470 69 : exists_t_2_out_opt );
471 69 : fd_rwlock_unread( &vote_stakes->lock );
472 69 : return result;
473 69 : }
474 :
475 : int
476 : fd_vote_stakes_query_t_1( fd_vote_stakes_t * vote_stakes,
477 : ushort fork_idx,
478 : fd_pubkey_t const * pubkey,
479 : ulong * stake_out,
480 : fd_pubkey_t * node_account_out,
481 141 : uchar * commission_out ) {
482 141 : fd_rwlock_read( &vote_stakes->lock );
483 141 : uchar exists_t_1 = 0;
484 141 : int found = fd_vote_stakes_query_private( vote_stakes, fork_idx, pubkey, stake_out, NULL, node_account_out, NULL, commission_out, NULL, &exists_t_1, 0 );
485 141 : fd_rwlock_unread( &vote_stakes->lock );
486 141 : return found && exists_t_1;
487 141 : }
488 :
489 : int
490 : fd_vote_stakes_query_t_2( fd_vote_stakes_t * vote_stakes,
491 : ushort fork_idx,
492 : fd_pubkey_t const * pubkey,
493 : ulong * stake_out,
494 : fd_pubkey_t * node_account_out,
495 141 : uchar * commission_out ) {
496 141 : fd_rwlock_read( &vote_stakes->lock );
497 141 : uchar exists_t_2 = 0;
498 141 : int found = fd_vote_stakes_query_private( vote_stakes, fork_idx, pubkey, NULL, stake_out, NULL, node_account_out, NULL, commission_out, NULL, &exists_t_2 );
499 141 : fd_rwlock_unread( &vote_stakes->lock );
500 141 : return found && exists_t_2;
501 141 : }
502 :
503 : void
504 6864 : fd_vote_stakes_reset( fd_vote_stakes_t * vote_stakes ) {
505 6864 : fd_rwlock_write( &vote_stakes->lock );
506 :
507 : /* Pop the fork dlist */
508 6864 : fork_t * fork_pool = get_fork_pool( vote_stakes );
509 6864 : fork_dlist_t * fork_dlist = get_fork_dlist( vote_stakes );
510 6864 : fork_dlist_remove_all( fork_dlist, fork_pool );
511 :
512 6864 : fork_pool_reset( fork_pool );
513 :
514 : /* For each fork, reset the stakes map and pool */
515 34392 : for( ushort i=0; i<vote_stakes->max_fork_width; i++ ) {
516 27528 : stakes_map_reset( get_stakes_map( vote_stakes, i ) );
517 27528 : stakes_pool_reset( get_stakes_pool( vote_stakes, i ) );
518 27528 : }
519 :
520 : /* Reset the index map and multi map */
521 6864 : index_map_reset( get_index_map( vote_stakes ) );
522 6864 : index_map_multi_reset( get_index_map_multi( vote_stakes ) );
523 :
524 : /* Reset the index pool */
525 6864 : index_pool_reset( get_index_pool( vote_stakes ) );
526 :
527 : /* Setup the pool again */
528 6864 : vote_stakes->root_idx = (ushort)fork_pool_idx_acquire( fork_pool );
529 6864 : fork_dlist_idx_push_tail( fork_dlist, vote_stakes->root_idx, fork_pool );
530 :
531 6864 : fd_rwlock_unwrite( &vote_stakes->lock );
532 6864 : }
533 :
534 : uint
535 : fd_vote_stakes_ele_cnt( fd_vote_stakes_t * vote_stakes,
536 21 : ushort fork_idx ) {
537 21 : fd_rwlock_read( &vote_stakes->lock );
538 21 : stake_t * stakes_pool = get_stakes_pool( vote_stakes, fork_idx );
539 21 : uint cnt = (uint)stakes_pool_used( stakes_pool );
540 21 : fd_rwlock_unread( &vote_stakes->lock );
541 21 : return cnt;
542 21 : }
543 :
544 : ushort
545 4008 : fd_vote_stakes_get_root_idx( fd_vote_stakes_t * vote_stakes ) {
546 4008 : fd_rwlock_read( &vote_stakes->lock );
547 4008 : ushort idx = vote_stakes->root_idx;
548 4008 : fd_rwlock_unread( &vote_stakes->lock );
549 4008 : return idx;
550 4008 : }
551 :
552 : fd_vote_stakes_iter_t *
553 : fd_vote_stakes_fork_iter_init( fd_vote_stakes_t * vote_stakes,
554 : ushort fork_idx,
555 3777 : uchar iter_mem[ static FD_VOTE_STAKES_ITER_FOOTPRINT ] ) {
556 3777 : fd_rwlock_write( &vote_stakes->lock );
557 :
558 3777 : stakes_map_iter_t iter = stakes_map_iter_init( get_stakes_map( vote_stakes, fork_idx ), get_stakes_pool( vote_stakes, fork_idx ) );
559 3777 : memcpy( iter_mem, &iter, sizeof(stakes_map_iter_t) );
560 3777 : return (fd_vote_stakes_iter_t *)iter_mem;
561 3777 : }
562 :
563 : void
564 3777 : fd_vote_stakes_fork_iter_fini( fd_vote_stakes_t * vote_stakes ) {
565 3777 : fd_rwlock_unwrite( &vote_stakes->lock );
566 3777 : }
567 :
568 : int
569 : fd_vote_stakes_fork_iter_done( fd_vote_stakes_t * vote_stakes,
570 : ushort fork_idx,
571 7581 : fd_vote_stakes_iter_t * iter ) {
572 7581 : stakes_map_iter_t * stakes_map_iter = (stakes_map_iter_t *)iter;
573 7581 : return stakes_map_iter_done( *stakes_map_iter, get_stakes_map( vote_stakes, fork_idx ), get_stakes_pool( vote_stakes, fork_idx ) );
574 7581 : }
575 :
576 : void
577 : fd_vote_stakes_fork_iter_next( fd_vote_stakes_t * vote_stakes,
578 : ushort fork_idx,
579 3804 : fd_vote_stakes_iter_t * iter ) {
580 3804 : stakes_map_iter_t * stakes_map_iter = (stakes_map_iter_t *)iter;
581 3804 : *stakes_map_iter = stakes_map_iter_next( *stakes_map_iter, get_stakes_map( vote_stakes, fork_idx ), get_stakes_pool( vote_stakes, fork_idx ) );
582 3804 : }
583 :
584 : void
585 : fd_vote_stakes_fork_iter_ele( fd_vote_stakes_t * vote_stakes,
586 : ushort fork_idx,
587 : fd_vote_stakes_iter_t * iter,
588 : fd_pubkey_t * pubkey_out,
589 : ulong * stake_t_1_out_opt,
590 : ulong * stake_t_2_out_opt,
591 : fd_pubkey_t * node_account_t_1_out_opt,
592 : fd_pubkey_t * node_account_t_2_out_opt,
593 : uchar * commission_t_1_out_opt,
594 3804 : uchar * commission_t_2_out_opt ) {
595 3804 : stakes_map_iter_t * stakes_map_iter = (stakes_map_iter_t *)iter;
596 3804 : stake_t * stake = stakes_map_iter_ele( *stakes_map_iter, get_stakes_map( vote_stakes, fork_idx ), get_stakes_pool( vote_stakes, fork_idx ) );
597 :
598 3804 : index_ele_t * index_pool = get_index_pool( vote_stakes );
599 3804 : index_ele_t * index_ele = index_pool_ele( index_pool, stake->idx );
600 :
601 3804 : *pubkey_out = index_ele->index_key.pubkey;
602 :
603 3804 : if( stake_t_1_out_opt ) *stake_t_1_out_opt = index_ele->index_key.stake_t_1;
604 3804 : if( stake_t_2_out_opt ) *stake_t_2_out_opt = index_ele->stake_t_2;
605 3804 : if( node_account_t_1_out_opt ) *node_account_t_1_out_opt = index_ele->node_account_t_1;
606 3804 : if( node_account_t_2_out_opt ) *node_account_t_2_out_opt = index_ele->node_account_t_2;
607 3804 : if( commission_t_1_out_opt ) *commission_t_1_out_opt = (uchar)index_ele->commission_t_1;
608 3804 : if( commission_t_2_out_opt ) *commission_t_2_out_opt = (uchar)index_ele->commission_t_2;
609 3804 : }
|