Line data Source code
1 : #include "fd_vote_states.h"
2 : #include "../types/fd_types.h"
3 :
4 : #define POOL_NAME fd_vote_state_pool
5 69 : #define POOL_T fd_vote_state_ele_t
6 39 : #define POOL_NEXT next_
7 : #include "../../util/tmpl/fd_pool.c"
8 :
9 : #define MAP_NAME fd_vote_state_map
10 : #define MAP_KEY_T fd_pubkey_t
11 : #define MAP_ELE_T fd_vote_state_ele_t
12 6 : #define MAP_KEY vote_account
13 27 : #define MAP_KEY_EQ(k0,k1) (fd_pubkey_eq( k0, k1 ))
14 42 : #define MAP_KEY_HASH(key,seed) (fd_hash( seed, key, sizeof(fd_pubkey_t) ))
15 15 : #define MAP_NEXT next_
16 : #include "../../util/tmpl/fd_map_chain.c"
17 :
18 : static fd_vote_state_ele_t *
19 60 : fd_vote_states_get_pool( fd_vote_states_t const * vote_states ) {
20 60 : return fd_vote_state_pool_join( (uchar *)vote_states + vote_states->pool_offset_ );
21 60 : }
22 :
23 : static fd_vote_state_map_t *
24 36 : fd_vote_states_get_map( fd_vote_states_t const * vote_states ) {
25 36 : return fd_vote_state_map_join( (uchar *)vote_states + vote_states->map_offset_ );
26 36 : }
27 :
28 : ulong
29 90 : fd_vote_states_align( void ) {
30 : /* The align of the struct should be the max of the align of the data
31 : structures that it contains. In this case, this is the map, the
32 : pool, and the struct itself. */
33 90 : return fd_ulong_max( fd_ulong_max( fd_vote_state_map_align(),
34 90 : fd_vote_state_pool_align() ), alignof(fd_vote_states_t) );
35 90 : }
36 :
37 : ulong
38 12 : fd_vote_states_footprint( ulong max_vote_accounts ) {
39 :
40 12 : ulong map_chain_cnt = fd_vote_state_map_chain_cnt_est( max_vote_accounts );
41 :
42 12 : ulong l = FD_LAYOUT_INIT;
43 12 : l = FD_LAYOUT_APPEND( l, fd_vote_states_align(), sizeof(fd_vote_states_t) );
44 12 : l = FD_LAYOUT_APPEND( l, fd_vote_state_pool_align(), fd_vote_state_pool_footprint( max_vote_accounts ) );
45 12 : l = FD_LAYOUT_APPEND( l, fd_vote_state_map_align(), fd_vote_state_map_footprint( map_chain_cnt ) );
46 12 : return FD_LAYOUT_FINI( l, fd_vote_states_align() );
47 12 : }
48 :
49 : void *
50 : fd_vote_states_new( void * mem,
51 : ulong max_vote_accounts,
52 9 : ulong seed ) {
53 9 : if( FD_UNLIKELY( !mem ) ) {
54 3 : FD_LOG_WARNING(( "NULL mem" ));
55 3 : return NULL;
56 3 : }
57 :
58 6 : if( FD_UNLIKELY( !max_vote_accounts ) ) {
59 3 : FD_LOG_WARNING(( "max_vote_accounts is 0" ));
60 3 : return NULL;
61 3 : }
62 :
63 3 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_vote_states_align() ) ) ) {
64 0 : FD_LOG_WARNING(( "misaligned mem" ));
65 0 : return NULL;
66 0 : }
67 :
68 3 : ulong map_chain_cnt = fd_vote_state_map_chain_cnt_est( max_vote_accounts );
69 :
70 3 : FD_SCRATCH_ALLOC_INIT( l, mem );
71 3 : fd_vote_states_t * vote_states = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_states_align(), sizeof(fd_vote_states_t) );
72 3 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_state_pool_align(), fd_vote_state_pool_footprint( max_vote_accounts ) );
73 3 : void * map_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_state_map_align(), fd_vote_state_map_footprint( map_chain_cnt ) );
74 :
75 3 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_vote_states_align() )!=(ulong)mem+fd_vote_states_footprint( max_vote_accounts ) ) ) {
76 0 : FD_LOG_WARNING(( "fd_vote_states_new: bad layout" ));
77 0 : return NULL;
78 0 : }
79 :
80 3 : vote_states->max_vote_accounts_ = max_vote_accounts;
81 3 : vote_states->pool_offset_ = (ulong)pool_mem - (ulong)mem;
82 3 : vote_states->map_offset_ = (ulong)map_mem - (ulong)mem;
83 :
84 3 : if( FD_UNLIKELY( !fd_vote_state_pool_join( fd_vote_state_pool_new( pool_mem, max_vote_accounts ) ) ) ) {
85 0 : FD_LOG_WARNING(( "Failed to create vote states pool" ));
86 0 : return NULL;
87 0 : }
88 :
89 3 : if( FD_UNLIKELY( !fd_vote_state_map_join( fd_vote_state_map_new( map_mem, map_chain_cnt, seed ) ) ) ) {
90 0 : FD_LOG_WARNING(( "Failed to create vote states map" ));
91 0 : return NULL;
92 0 : }
93 :
94 3 : FD_COMPILER_MFENCE();
95 3 : FD_VOLATILE( vote_states->magic ) = FD_VOTE_STATES_MAGIC;
96 3 : FD_COMPILER_MFENCE();
97 :
98 3 : return mem;
99 3 : }
100 :
101 : fd_vote_states_t *
102 9 : fd_vote_states_join( void * mem ) {
103 9 : if( FD_UNLIKELY( !mem ) ) {
104 3 : FD_LOG_WARNING(( "NULL mem" ));
105 3 : return NULL;
106 3 : }
107 :
108 6 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_vote_states_align() ) ) ) {
109 0 : FD_LOG_WARNING(( "misaligned mem" ));
110 0 : return NULL;
111 0 : }
112 :
113 6 : fd_vote_states_t * vote_states = (fd_vote_states_t *)mem;
114 :
115 6 : if( FD_UNLIKELY( vote_states->magic != FD_VOTE_STATES_MAGIC ) ) {
116 3 : FD_LOG_WARNING(( "Invalid vote states magic" ));
117 3 : return NULL;
118 3 : }
119 :
120 3 : ulong map_chain_cnt = fd_vote_state_map_chain_cnt_est( vote_states->max_vote_accounts_ );
121 3 : FD_SCRATCH_ALLOC_INIT( l, vote_states );
122 3 : vote_states = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_states_align(), sizeof(fd_vote_states_t) );
123 3 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_state_pool_align(), fd_vote_state_pool_footprint( vote_states->max_vote_accounts_ ) );
124 3 : void * map_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_state_map_align(), fd_vote_state_map_footprint( map_chain_cnt ) );
125 :
126 3 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_vote_states_align() )!=(ulong)mem+fd_vote_states_footprint( vote_states->max_vote_accounts_ ) ) ) {
127 0 : FD_LOG_WARNING(( "fd_vote_states_join: bad layout" ));
128 0 : return NULL;
129 0 : }
130 :
131 3 : if( FD_UNLIKELY( !fd_vote_state_pool_join( pool_mem ) ) ) {
132 0 : FD_LOG_WARNING(( "Failed to join vote states pool" ));
133 0 : return NULL;
134 0 : }
135 :
136 3 : if( FD_UNLIKELY( !fd_vote_state_map_join( map_mem ) ) ) {
137 0 : FD_LOG_WARNING(( "Failed to join vote states map" ));
138 0 : return NULL;
139 0 : }
140 :
141 3 : return vote_states;
142 3 : }
143 :
144 : void
145 : fd_vote_states_update( fd_vote_states_t * vote_states,
146 : fd_pubkey_t const * vote_account,
147 : fd_pubkey_t const * node_account,
148 : uchar commission,
149 : long last_vote_timestamp,
150 : ulong last_vote_slot,
151 : ulong credits_cnt,
152 : ushort * epoch,
153 : ulong * credits,
154 6 : ulong * prev_credits ) {
155 6 : fd_vote_state_ele_t * vote_state_pool = fd_vote_states_get_pool( vote_states );
156 6 : fd_vote_state_map_t * vote_state_map = fd_vote_states_get_map( vote_states );
157 :
158 6 : if( FD_UNLIKELY( !vote_state_pool ) ) {
159 0 : FD_LOG_CRIT(( "unable to retrieve join to vote state pool" ));
160 0 : }
161 6 : if( FD_UNLIKELY( !vote_state_map ) ) {
162 0 : FD_LOG_CRIT(( "unable to retrieve join to vote state map" ));
163 0 : }
164 :
165 : /* First, handle the case where the vote state already exists
166 : and we just need to update the entry. The reason we do a const idx
167 : query is to allow fd_vote_states_update to be called while
168 : iterating over the map. It is unsafe to call
169 : fd_vote_state_map_ele_query() during iteration, but we only
170 : need to change fields which are not used for pool/map management. */
171 :
172 6 : ulong idx = fd_vote_state_map_idx_query_const(
173 6 : vote_state_map,
174 6 : vote_account,
175 6 : ULONG_MAX,
176 6 : vote_state_pool );
177 :
178 6 : if( idx!=ULONG_MAX ) {
179 :
180 0 : fd_vote_state_ele_t * vote_state = fd_vote_state_pool_ele( vote_state_pool, idx );
181 0 : if( FD_UNLIKELY( !vote_state ) ) {
182 0 : FD_LOG_CRIT(( "unable to retrieve vote state" ));
183 0 : }
184 :
185 : /* TODO: can do something smarter where we only update the
186 : comission and the credits coresponding to the new epoch. */
187 0 : vote_state->commission = commission;
188 0 : vote_state->credits_cnt = credits_cnt;
189 0 : vote_state->last_vote_timestamp = last_vote_timestamp;
190 0 : vote_state->last_vote_slot = last_vote_slot;
191 0 : vote_state->node_account = *node_account;
192 0 : for( ulong i=0UL; i<credits_cnt; i++ ) {
193 0 : vote_state->epoch[i] = epoch[i];
194 0 : vote_state->credits[i] = credits[i];
195 0 : vote_state->prev_credits[i] = prev_credits[i];
196 0 : }
197 0 : return;
198 0 : }
199 :
200 : /* If the vote state does not exist, we need to create a new entry. */
201 : /* Otherwise, try to acquire a new node and populate it. */
202 6 : if( FD_UNLIKELY( !fd_vote_state_pool_free( vote_state_pool ) ) ) {
203 0 : FD_LOG_CRIT(( "no free vote states in pool" ));
204 0 : }
205 :
206 6 : fd_vote_state_ele_t * vote_state = fd_vote_state_pool_ele_acquire( vote_state_pool );
207 6 : if( FD_UNLIKELY( !vote_state ) ) {
208 0 : FD_LOG_CRIT(( "unable to acquire vote state" ));
209 0 : }
210 :
211 6 : vote_state->vote_account = *vote_account;
212 6 : vote_state->node_account = *node_account;
213 6 : vote_state->commission = commission;
214 6 : vote_state->last_vote_timestamp = last_vote_timestamp;
215 6 : vote_state->last_vote_slot = last_vote_slot;
216 6 : vote_state->credits_cnt = credits_cnt;
217 9 : for( ulong i=0UL; i<credits_cnt; i++ ) {
218 3 : vote_state->epoch[i] = epoch[i];
219 3 : vote_state->credits[i] = credits[i];
220 3 : vote_state->prev_credits[i] = prev_credits[i];
221 3 : }
222 :
223 6 : if( FD_UNLIKELY( !fd_vote_state_map_ele_insert(
224 6 : vote_state_map,
225 6 : vote_state,
226 6 : vote_state_pool ) ) ) {
227 0 : FD_LOG_CRIT(( "unable to insert stake delegation into map" ));
228 0 : }
229 6 : }
230 :
231 : void
232 : fd_vote_states_remove( fd_vote_states_t * vote_states,
233 3 : fd_pubkey_t const * vote_account ) {
234 3 : fd_vote_state_ele_t * vote_state_pool = fd_vote_states_get_pool( vote_states );
235 3 : fd_vote_state_map_t * vote_state_map = fd_vote_states_get_map( vote_states );
236 3 : if( FD_UNLIKELY( !vote_state_pool ) ) {
237 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation pool" ));
238 0 : }
239 3 : if( FD_UNLIKELY( !vote_state_map ) ) {
240 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation map" ));
241 0 : }
242 :
243 3 : ulong vote_state_idx = fd_vote_state_map_idx_query_const(
244 3 : vote_state_map,
245 3 : vote_account,
246 3 : ULONG_MAX,
247 3 : vote_state_pool );
248 3 : if( FD_UNLIKELY( vote_state_idx == ULONG_MAX ) ) {
249 : /* The vote state was not found, nothing to do. */
250 0 : return;
251 0 : }
252 :
253 3 : fd_vote_state_ele_t * vote_state = fd_vote_state_pool_ele( vote_state_pool, vote_state_idx );
254 3 : if( FD_UNLIKELY( !vote_state ) ) {
255 0 : FD_LOG_CRIT(( "unable to retrieve vote state" ));
256 0 : }
257 :
258 3 : ulong idx = fd_vote_state_map_idx_remove( vote_state_map, vote_account, ULONG_MAX, vote_state_pool );
259 3 : if( FD_UNLIKELY( idx==ULONG_MAX ) ) {
260 0 : FD_LOG_CRIT(( "unable to remove vote state" ));
261 0 : }
262 :
263 : /* Set vote state's next_ pointer to the null idx. */
264 3 : vote_state->next_ = fd_vote_state_pool_idx_null( vote_state_pool );
265 :
266 3 : fd_vote_state_pool_idx_release( vote_state_pool, vote_state_idx );
267 3 : }
268 :
269 : void
270 : fd_vote_states_update_from_account( fd_vote_states_t * vote_states,
271 : fd_pubkey_t const * vote_account,
272 : uchar const * account_data,
273 0 : ulong account_data_len ) {
274 :
275 : /* TODO: Instead of doing this messy + unbounded decode, it should be
276 : replaced with a more efficient decode that just reads the fields
277 : we need directly. */
278 :
279 0 : fd_bincode_decode_ctx_t ctx = {
280 0 : .data = account_data,
281 0 : .dataend = account_data + account_data_len,
282 0 : };
283 :
284 0 : ulong total_sz = 0UL;
285 0 : int err = fd_vote_state_versioned_decode_footprint( &ctx, &total_sz );
286 0 : if( FD_UNLIKELY( err ) ) {
287 0 : FD_LOG_CRIT(( "unable to decode vote state versioned" ));
288 0 : }
289 :
290 0 : uchar vote_state_versioned[total_sz];
291 :
292 0 : fd_vote_state_versioned_t * vsv = fd_vote_state_versioned_decode( vote_state_versioned, &ctx );
293 0 : if( FD_UNLIKELY( vsv==NULL ) ) {
294 0 : FD_LOG_CRIT(( "unable to decode vote state versioned" ));
295 0 : }
296 :
297 0 : fd_pubkey_t node_account;
298 0 : uchar commission;
299 0 : long last_vote_timestamp;
300 0 : ulong last_vote_slot;
301 0 : ulong credits_cnt = 0UL;
302 0 : ushort epoch[EPOCH_CREDITS_MAX];
303 0 : ulong credits[EPOCH_CREDITS_MAX];
304 0 : ulong prev_credits[EPOCH_CREDITS_MAX];
305 :
306 0 : fd_vote_epoch_credits_t * epoch_credits = NULL;
307 :
308 0 : switch( vsv->discriminant ) {
309 0 : case fd_vote_state_versioned_enum_v0_23_5:
310 0 : node_account = vsv->inner.v0_23_5.node_pubkey;
311 0 : commission = vsv->inner.v0_23_5.commission;
312 0 : last_vote_timestamp = vsv->inner.v0_23_5.last_timestamp.timestamp;
313 0 : last_vote_slot = vsv->inner.v0_23_5.last_timestamp.slot;
314 0 : epoch_credits = vsv->inner.v0_23_5.epoch_credits;
315 :
316 0 : for( deq_fd_vote_epoch_credits_t_iter_t iter = deq_fd_vote_epoch_credits_t_iter_init( epoch_credits );
317 0 : !deq_fd_vote_epoch_credits_t_iter_done( epoch_credits, iter );
318 0 : iter = deq_fd_vote_epoch_credits_t_iter_next( epoch_credits, iter ) ) {
319 :
320 0 : fd_vote_epoch_credits_t * ele = deq_fd_vote_epoch_credits_t_iter_ele( epoch_credits, iter );
321 :
322 0 : epoch[credits_cnt] = (ushort)ele->epoch;
323 0 : credits[credits_cnt] = ele->credits;
324 0 : prev_credits[credits_cnt] = ele->prev_credits;
325 0 : credits_cnt++;
326 0 : }
327 :
328 0 : break;
329 0 : case fd_vote_state_versioned_enum_v1_14_11:
330 0 : node_account = vsv->inner.v1_14_11.node_pubkey;
331 0 : commission = vsv->inner.v1_14_11.commission;
332 0 : last_vote_timestamp = vsv->inner.v1_14_11.last_timestamp.timestamp;
333 0 : last_vote_slot = vsv->inner.v1_14_11.last_timestamp.slot;
334 0 : epoch_credits = vsv->inner.v1_14_11.epoch_credits;
335 :
336 0 : for( deq_fd_vote_epoch_credits_t_iter_t iter = deq_fd_vote_epoch_credits_t_iter_init( epoch_credits );
337 0 : !deq_fd_vote_epoch_credits_t_iter_done( epoch_credits, iter );
338 0 : iter = deq_fd_vote_epoch_credits_t_iter_next( epoch_credits, iter ) ) {
339 :
340 0 : fd_vote_epoch_credits_t * ele = deq_fd_vote_epoch_credits_t_iter_ele( epoch_credits, iter );
341 :
342 0 : epoch[credits_cnt] = (ushort)ele->epoch;
343 0 : credits[credits_cnt] = ele->credits;
344 0 : prev_credits[credits_cnt] = ele->prev_credits;
345 0 : credits_cnt++;
346 0 : }
347 0 : break;
348 0 : case fd_vote_state_versioned_enum_current:
349 0 : node_account = vsv->inner.current.node_pubkey;
350 0 : commission = vsv->inner.current.commission;
351 0 : last_vote_timestamp = vsv->inner.current.last_timestamp.timestamp;
352 0 : last_vote_slot = vsv->inner.current.last_timestamp.slot;
353 0 : epoch_credits = vsv->inner.current.epoch_credits;
354 :
355 0 : for( deq_fd_vote_epoch_credits_t_iter_t iter = deq_fd_vote_epoch_credits_t_iter_init( epoch_credits );
356 0 : !deq_fd_vote_epoch_credits_t_iter_done( epoch_credits, iter );
357 0 : iter = deq_fd_vote_epoch_credits_t_iter_next( epoch_credits, iter ) ) {
358 :
359 0 : fd_vote_epoch_credits_t * ele = deq_fd_vote_epoch_credits_t_iter_ele( epoch_credits, iter );
360 :
361 0 : epoch[credits_cnt] = (ushort)ele->epoch;
362 0 : credits[credits_cnt] = ele->credits;
363 0 : prev_credits[credits_cnt] = ele->prev_credits;
364 0 : credits_cnt++;
365 0 : }
366 0 : break;
367 0 : default:
368 0 : __builtin_unreachable();
369 0 : }
370 :
371 0 : fd_vote_states_update(
372 0 : vote_states,
373 0 : vote_account,
374 0 : &node_account,
375 0 : commission,
376 0 : last_vote_timestamp,
377 0 : last_vote_slot,
378 0 : credits_cnt,
379 0 : epoch,
380 0 : credits,
381 0 : prev_credits );
382 0 : }
383 :
384 : void
385 3 : fd_vote_states_reset_stakes( fd_vote_states_t * vote_states ) {
386 3 : fd_vote_state_ele_t * vote_state_pool = fd_vote_states_get_pool( vote_states );
387 3 : fd_vote_state_map_t * vote_state_map = fd_vote_states_get_map( vote_states );
388 3 : if( FD_UNLIKELY( !vote_state_pool ) ) {
389 0 : FD_LOG_CRIT(( "unable to retrieve join to vote state pool" ));
390 0 : }
391 3 : if( FD_UNLIKELY( !vote_state_map ) ) {
392 0 : FD_LOG_CRIT(( "unable to retrieve join to vote state map" ));
393 0 : }
394 :
395 3 : for( fd_vote_state_map_iter_t iter = fd_vote_state_map_iter_init( vote_state_map, vote_state_pool );
396 9 : !fd_vote_state_map_iter_done( iter, vote_state_map, vote_state_pool );
397 6 : iter = fd_vote_state_map_iter_next( iter, vote_state_map, vote_state_pool ) ) {
398 6 : ulong idx = fd_vote_state_map_iter_idx( iter, vote_state_map, vote_state_pool );
399 :
400 6 : fd_vote_state_ele_t * vote_state = fd_vote_state_pool_ele( vote_state_pool, idx );
401 6 : if( FD_UNLIKELY( !vote_state ) ) {
402 0 : FD_LOG_CRIT(( "unable to retrieve vote state" ));
403 0 : }
404 :
405 6 : vote_state->stake = 0UL;
406 6 : }
407 3 : }
408 :
409 : void
410 : fd_vote_states_update_stake( fd_vote_states_t * vote_states,
411 : fd_pubkey_t const * vote_account,
412 6 : ulong stake ) {
413 6 : fd_vote_state_map_t * vote_state_map = fd_vote_states_get_map( vote_states );
414 6 : fd_vote_state_ele_t * vote_state_pool = fd_vote_states_get_pool( vote_states );
415 :
416 6 : fd_vote_state_ele_t * vote_state = fd_vote_state_map_ele_query(
417 6 : vote_state_map,
418 6 : vote_account,
419 6 : NULL,
420 6 : vote_state_pool );
421 6 : if( FD_UNLIKELY( !vote_state ) ) {
422 0 : FD_LOG_WARNING(( "unable to retrieve vote state" ));
423 0 : return;
424 0 : }
425 :
426 6 : vote_state->stake = stake;
427 6 : }
428 :
429 : fd_vote_state_ele_t *
430 : fd_vote_states_query( fd_vote_states_t const * vote_states,
431 18 : fd_pubkey_t const * vote_account ) {
432 :
433 : /* map_chain's _ele_query function isn't safe for concurrent access.
434 : The solution is to use the idx_query_const function, which is safe
435 : for concurrent access. The caller is still responsible for
436 : synchronizing concurrent writers to the fd_vote_state_ele_t. */
437 18 : ulong idx = fd_vote_state_map_idx_query_const(
438 18 : fd_vote_states_get_map( vote_states ),
439 18 : vote_account,
440 18 : ULONG_MAX,
441 18 : fd_vote_states_get_pool( vote_states ) );
442 18 : if( FD_UNLIKELY( idx==ULONG_MAX ) ) {
443 3 : return NULL;
444 3 : }
445 :
446 15 : fd_vote_state_ele_t * vote_state = fd_vote_state_pool_ele( fd_vote_states_get_pool( vote_states ), idx );
447 15 : if( FD_UNLIKELY( !vote_state ) ) {
448 0 : FD_LOG_CRIT(( "unable to retrieve vote state" ));
449 0 : }
450 :
451 15 : return vote_state;
452 15 : }
453 :
454 : /* fd_vote_states_query_const is the same as fd_vote_states but instead
455 : returns a const pointer. */
456 :
457 : fd_vote_state_ele_t const *
458 : fd_vote_states_query_const( fd_vote_states_t const * vote_states,
459 0 : fd_pubkey_t const * vote_account ) {
460 0 : return fd_vote_state_map_ele_query_const(
461 0 : fd_vote_states_get_map( vote_states ),
462 0 : vote_account,
463 0 : NULL,
464 0 : fd_vote_states_get_pool( vote_states ) );
465 0 : }
466 :
467 : ulong
468 0 : fd_vote_states_max( fd_vote_states_t const * vote_states ) {
469 0 : return vote_states->max_vote_accounts_;
470 0 : }
471 :
472 : ulong
473 9 : fd_vote_states_cnt( fd_vote_states_t const * vote_states ) {
474 9 : return fd_vote_state_pool_used( fd_vote_states_get_pool( vote_states ) );
475 9 : }
476 :
477 : fd_vote_state_ele_t *
478 0 : fd_vote_states_iter_ele( fd_vote_states_iter_t * iter ) {
479 0 : ulong idx = fd_vote_state_map_iter_idx( iter->iter, iter->map, iter->pool );
480 0 : return fd_vote_state_pool_ele( iter->pool, idx );
481 0 : }
482 :
483 : fd_vote_states_iter_t *
484 : fd_vote_states_iter_init( fd_vote_states_iter_t * iter,
485 0 : fd_vote_states_t const * vote_states ) {
486 0 : if( FD_UNLIKELY( !iter ) ) {
487 0 : FD_LOG_CRIT(( "NULL iter_mem" ));
488 0 : }
489 0 : if( FD_UNLIKELY( !vote_states ) ) {
490 0 : FD_LOG_CRIT(( "NULL vote_states" ));
491 0 : }
492 :
493 0 : iter->map = fd_vote_states_get_map( vote_states );
494 0 : iter->pool = fd_vote_states_get_pool( vote_states );
495 0 : iter->iter = fd_vote_state_map_iter_init( iter->map, iter->pool );
496 :
497 0 : return iter;
498 0 : }
499 :
500 : int
501 0 : fd_vote_states_iter_done( fd_vote_states_iter_t * iter ) {
502 0 : return fd_vote_state_map_iter_done( iter->iter, iter->map, iter->pool );
503 0 : }
504 :
505 : void
506 0 : fd_vote_states_iter_next( fd_vote_states_iter_t * iter ) {
507 0 : iter->iter = fd_vote_state_map_iter_next( iter->iter, iter->map, iter->pool );
508 0 : }
|