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