Line data Source code
1 : #include "fd_vote_stakes.h"
2 : #include "../fd_rwlock.h"
3 : #include "../accdb/fd_accdb.h"
4 : #include "../fd_flamenco_base.h"
5 : #include "../runtime/fd_runtime_const.h"
6 : #include "../runtime/program/vote/fd_vote_state_versioned.h"
7 : #include "../../util/bits/fd_bits.h"
8 : #include "../../util/log/fd_log.h"
9 : #include "../../ballet/bls/fd_bls12_381.h"
10 :
11 : #include <errno.h>
12 : #include <unistd.h>
13 :
14 12 : #define FD_VOTE_STAKES_MAGIC (0xF17EDA2CE7601E70UL) /* FIREDANCER VOTE STAKES V0 */
15 84291 : #define FD_VOTE_STAKES_EPOCH_CACHE_CNT (5UL) /* t-2..t-5 sets plus one so crossing into t+1 evicts t-6 */
16 :
17 : struct vacc {
18 : fd_pubkey_t pubkey;
19 : fd_pubkey_t node_account;
20 : ulong stake;
21 : ushort commission; /* inflation rewards, basis points */
22 : ushort block_revenue_commission_bps; /* SIMD-0123 */
23 : ulong pending_delegator_rewards; /* SIMD-0123, as of the set's epoch boundary */
24 : fd_pubkey_t inflation_collector; /* SIMD-0232, defaults to pubkey */
25 : fd_pubkey_t block_collector; /* SIMD-0232, defaults to node_account */
26 : ushort rank;
27 : uchar bls_key[ FD_BLS_PUBKEY_COMPRESSED_SZ ]; /* zero if unregistered */
28 : uchar bls_key_uncompressed[ FD_BLS_PUBKEY_UNCOMPRESSED_SZ ]; /* decompressed by finalize, valid iff rank!=NULL */
29 : uint left;
30 : uint right;
31 : uint next;
32 : };
33 : typedef struct vacc vacc_t;
34 :
35 : struct vacc_rank {
36 : vacc_t * vacc;
37 : ulong drop;
38 : };
39 : typedef struct vacc_rank vacc_rank_t;
40 :
41 : #define SORT_NAME vacc_rank_sort
42 0 : #define SORT_KEY_T vacc_rank_t
43 0 : #define SORT_BEFORE(a,b) (((a).vacc->stake>(b).vacc->stake) | ((a).vacc->stake==(b).vacc->stake && \
44 0 : memcmp( (a).vacc->bls_key, (b).vacc->bls_key, FD_BLS_PUBKEY_COMPRESSED_SZ )<0 ))
45 : #include "../../util/tmpl/fd_sort.c"
46 :
47 : #define SORT_NAME vacc_rank_bls_sort
48 0 : #define SORT_KEY_T vacc_rank_t
49 0 : #define SORT_BEFORE(a,b) (memcmp( (a).vacc->bls_key, (b).vacc->bls_key, FD_BLS_PUBKEY_COMPRESSED_SZ )<0)
50 : #include "../../util/tmpl/fd_sort.c"
51 :
52 : #define SORT_NAME vacc_rank_identity_sort
53 0 : #define SORT_KEY_T vacc_rank_t
54 0 : #define SORT_BEFORE(a,b) (memcmp( &(a).vacc->node_account, &(b).vacc->node_account, sizeof(fd_pubkey_t) )<0)
55 : #include "../../util/tmpl/fd_sort.c"
56 :
57 : #define HEAP_NAME vacc_heap
58 104 : #define HEAP_IDX_T uint
59 : #define HEAP_T vacc_t
60 137 : #define HEAP_LT(e0,e1) ( ((e0)->stake < (e1)->stake) | \
61 137 : (((e0)->stake==(e1)->stake) & \
62 137 : (memcmp( &(e0)->pubkey, &(e1)->pubkey, sizeof(fd_pubkey_t) )<0 ) ) )
63 : #include "../../util/tmpl/fd_heap.c"
64 :
65 : #define POOL_NAME vacc_pool
66 168 : #define POOL_T vacc_t
67 : #define POOL_IDX_T uint
68 : #define POOL_LAZY 1
69 : #include "../../util/tmpl/fd_pool.c"
70 :
71 : #define MAP_NAME vacc_map
72 : #define MAP_KEY_T fd_pubkey_t
73 : #define MAP_ELE_T vacc_t
74 2470 : #define MAP_KEY pubkey
75 3182 : #define MAP_KEY_EQ(k0,k1) (!memcmp( k0, k1, sizeof(fd_pubkey_t) ))
76 5729 : #define MAP_KEY_HASH(key,seed) (fd_hash32( key->uc, seed ))
77 80391 : #define MAP_IDX_T uint
78 : #include "../../util/tmpl/fd_map_chain.c"
79 :
80 : struct vacc_fork {
81 : uint ref_cnt;
82 : uint next;
83 : uint cache_idx; /* UINT_MAX if the t-1 set is not cached */
84 : };
85 : typedef struct vacc_fork vacc_fork_t;
86 :
87 : #define POOL_NAME vacc_fork_pool
88 24 : #define POOL_T vacc_fork_t
89 : #define POOL_IDX_T uint
90 : #define POOL_LAZY 1
91 : #include "../../util/tmpl/fd_pool.c"
92 :
93 : struct vacc_states {
94 : struct {
95 : ulong last_vote_slot;
96 : long last_vote_ts;
97 : uchar is_valid;
98 : } states[ FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ];
99 : uint next;
100 : };
101 : typedef struct vacc_states vacc_states_t;
102 :
103 : #define POOL_NAME vacc_state_pool
104 24 : #define POOL_T vacc_states_t
105 : #define POOL_IDX_T uint
106 : #define POOL_LAZY 1
107 : #include "../../util/tmpl/fd_pool.c"
108 :
109 : struct t_1_cache_ent {
110 : ulong set_idx; /* ULONG_MAX if the entry is empty */
111 : ulong lru;
112 : };
113 : typedef struct t_1_cache_ent t_1_cache_ent_t;
114 :
115 : struct fd_vote_stakes {
116 : ulong magic;
117 : ulong cache_cnt;
118 : ulong max_live_slots;
119 : ulong min_stake_wmark;
120 : int disk_fd;
121 : ulong lru;
122 : fd_rwlock_t lock;
123 :
124 : /* (pubkey, stake) pairs for the t-2 epoch. These are shared across
125 : forks/banks. */
126 : ulong t_2_epoch[ FD_VOTE_STAKES_EPOCH_CACHE_CNT ];
127 : ulong t_2_vacc_pool_off[ FD_VOTE_STAKES_EPOCH_CACHE_CNT ];
128 : ulong t_2_vacc_map_off [ FD_VOTE_STAKES_EPOCH_CACHE_CNT ];
129 :
130 : /* (pubkey, stake) pairs for the t-1 epoch. These can be different
131 : for every fork across the epoch boundary. Up to max_live_slots
132 : sets exist, keyed by set idx; cache_cnt of them are held in memory
133 : and the rest are spilled to disk_fd. */
134 : ulong vacc_fork_pool_off;
135 : ulong t_1_cache_off;
136 : ulong t_1_vacc_pools_mem_off;
137 : ulong t_1_vacc_pools_off;
138 : ulong t_1_vacc_maps_off;
139 : ulong vacc_heap_off;
140 :
141 : /* Per-bank state about the t-2 vote state. Each per-bank state will
142 : be an array sized to length max_live_slots which is a system-wide
143 : bound. Keyed by bank idx. */
144 : ulong vacc_states_pool_off;
145 : };
146 : typedef struct fd_vote_stakes fd_vote_stakes_t;
147 :
148 : static inline vacc_t *
149 : t_2_vacc_pool( fd_vote_stakes_t const * vote_stakes,
150 17211 : ulong idx ) {
151 17211 : return fd_type_pun( (uchar *)vote_stakes + vote_stakes->t_2_vacc_pool_off[ idx ] );
152 17211 : }
153 :
154 : static inline vacc_map_t *
155 : t_2_vacc_map( fd_vote_stakes_t const * vote_stakes,
156 16597 : ulong idx ) {
157 16597 : return fd_type_pun( (uchar *)vote_stakes + vote_stakes->t_2_vacc_map_off[ idx ] );
158 16597 : }
159 :
160 : static inline vacc_fork_t *
161 265255 : vacc_fork_pool( fd_vote_stakes_t const * vote_stakes ) {
162 265255 : return fd_type_pun( (uchar *)vote_stakes + vote_stakes->vacc_fork_pool_off );
163 265255 : }
164 :
165 : static inline t_1_cache_ent_t *
166 132137 : t_1_cache( fd_vote_stakes_t const * vote_stakes ) {
167 132137 : return fd_type_pun( (uchar *)vote_stakes + vote_stakes->t_1_cache_off );
168 132137 : }
169 :
170 : static inline vacc_t *
171 : t_1_cache_pool( fd_vote_stakes_t const * vote_stakes,
172 69985 : ulong cache_idx ) {
173 69985 : ulong off = vote_stakes->t_1_vacc_pools_off + cache_idx*vacc_pool_footprint( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS );
174 69985 : return fd_type_pun( (uchar *)vote_stakes + off );
175 69985 : }
176 :
177 : static inline vacc_map_t *
178 : t_1_cache_map( fd_vote_stakes_t const * vote_stakes,
179 69985 : ulong cache_idx ) {
180 69985 : ulong chain_cnt = vacc_map_chain_cnt_est( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS );
181 69985 : ulong off = vote_stakes->t_1_vacc_maps_off + cache_idx*vacc_map_footprint( chain_cnt );
182 69985 : return fd_type_pun( (uchar *)vote_stakes + off );
183 69985 : }
184 :
185 : static void
186 : t_1_disk_io( fd_vote_stakes_t * vote_stakes,
187 : ulong cache_idx,
188 : ulong set_idx,
189 0 : int write ) {
190 0 : ulong pool_sz = vacc_pool_footprint( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS );
191 0 : ulong map_sz = vacc_map_footprint( vacc_map_chain_cnt_est( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ) );
192 0 : uchar * bufs[2] = { (uchar *)vote_stakes + vote_stakes->t_1_vacc_pools_mem_off + cache_idx*pool_sz,
193 0 : (uchar *)t_1_cache_map( vote_stakes, cache_idx ) };
194 0 : ulong szs [2] = { pool_sz, map_sz };
195 0 : ulong off = set_idx*(pool_sz+map_sz);
196 0 : for( ulong b=0UL; b<2UL; b++ ) {
197 0 : ulong done = 0UL;
198 0 : while( done<szs[b] ) {
199 0 : long n = write ? pwrite( vote_stakes->disk_fd, bufs[b]+done, szs[b]-done, (long)(off+done) )
200 0 : : pread ( vote_stakes->disk_fd, bufs[b]+done, szs[b]-done, (long)(off+done) );
201 0 : if( FD_UNLIKELY( n<0L ) ) {
202 0 : if( FD_LIKELY( errno==EINTR ) ) continue;
203 0 : FD_LOG_CRIT(( "%s(vote stakes spill file, fd=%d) failed (%i-%s)", write ? "pwrite" : "pread", vote_stakes->disk_fd, errno, fd_io_strerror( errno ) ));
204 0 : }
205 0 : if( FD_UNLIKELY( !n ) ) FD_LOG_CRIT(( "%s(vote stakes spill file, fd=%d) returned 0 at offset %lu (set=%lu)",
206 0 : write ? "pwrite" : "pread", vote_stakes->disk_fd, off+done, set_idx ));
207 0 : done += (ulong)n;
208 0 : }
209 0 : off += szs[b];
210 0 : }
211 0 : }
212 :
213 : static ulong
214 : t_1_evict( fd_vote_stakes_t * vote_stakes,
215 65765 : ulong set_idx ) {
216 65765 : t_1_cache_ent_t * ent = t_1_cache( vote_stakes );
217 65765 : t_1_cache_ent_t * victim = ent;
218 131523 : for( ulong i=1UL; i<vote_stakes->cache_cnt; i++ ) if( ent[i].lru<victim->lru ) victim = ent+i;
219 :
220 65765 : ulong cache_idx = (ulong)(victim-ent);
221 65765 : vacc_fork_t * fork_pool = vacc_fork_pool( vote_stakes );
222 65765 : if( victim->set_idx!=ULONG_MAX ) {
223 0 : t_1_disk_io( vote_stakes, cache_idx, victim->set_idx, 1 );
224 0 : vacc_fork_pool_ele( fork_pool, victim->set_idx )->cache_idx = UINT_MAX;
225 0 : }
226 65765 : victim->set_idx = set_idx;
227 65765 : victim->lru = ++vote_stakes->lru;
228 65765 : vacc_fork_pool_ele( fork_pool, set_idx )->cache_idx = (uint)cache_idx;
229 65765 : return cache_idx;
230 65765 : }
231 :
232 : static ulong
233 : t_1_lock( fd_vote_stakes_t * vote_stakes,
234 : ulong set_idx,
235 2966 : int write ) {
236 2966 : if( FD_LIKELY( !write ) ) {
237 1743 : fd_rwlock_read( &vote_stakes->lock );
238 1743 : ulong cache_idx = vacc_fork_pool_ele_const( vacc_fork_pool( vote_stakes ), set_idx )->cache_idx;
239 1743 : if( FD_LIKELY( cache_idx!=UINT_MAX ) ) return cache_idx;
240 0 : fd_rwlock_unread( &vote_stakes->lock );
241 0 : }
242 1223 : fd_rwlock_write( &vote_stakes->lock );
243 1223 : ulong cache_idx = vacc_fork_pool_ele_const( vacc_fork_pool( vote_stakes ), set_idx )->cache_idx;
244 1223 : if( FD_UNLIKELY( cache_idx==UINT_MAX ) ) {
245 0 : cache_idx = t_1_evict( vote_stakes, set_idx );
246 0 : t_1_disk_io( vote_stakes, cache_idx, set_idx, 0 );
247 1223 : } else {
248 1223 : t_1_cache( vote_stakes )[ cache_idx ].lru = ++vote_stakes->lru;
249 1223 : }
250 1223 : if( FD_LIKELY( !write ) ) fd_rwlock_demote( &vote_stakes->lock );
251 1223 : return cache_idx;
252 2966 : }
253 :
254 : static void
255 : t_1_unlock( fd_vote_stakes_t * vote_stakes,
256 2966 : int write ) {
257 2966 : if( FD_UNLIKELY( write ) ) fd_rwlock_unwrite( &vote_stakes->lock );
258 1743 : else fd_rwlock_unread ( &vote_stakes->lock );
259 2966 : }
260 :
261 : static ushort
262 65760 : t_1_acquire( fd_vote_stakes_t * vote_stakes ) {
263 65760 : vacc_fork_t * fork_pool = vacc_fork_pool( vote_stakes );
264 65760 : FD_CHECK_CRIT( vacc_fork_pool_free( fork_pool ), "vote stakes t-1 set pool exhausted" );
265 65760 : ulong set_idx = vacc_fork_pool_idx_acquire( fork_pool );
266 65760 : vacc_fork_pool_ele( fork_pool, set_idx )->ref_cnt = 1U;
267 65760 : fd_rwlock_write( &vote_stakes->lock );
268 65760 : ulong cache_idx = t_1_evict( vote_stakes, set_idx );
269 65760 : vacc_map_reset ( t_1_cache_map ( vote_stakes, cache_idx ) );
270 65760 : vacc_pool_reset( t_1_cache_pool( vote_stakes, cache_idx ) );
271 65760 : fd_rwlock_unwrite( &vote_stakes->lock );
272 65760 : return (ushort)set_idx;
273 65760 : }
274 :
275 : static void
276 : t_1_release( fd_vote_stakes_t * vote_stakes,
277 64526 : ulong set_idx ) {
278 64526 : vacc_fork_t * fork_pool = vacc_fork_pool( vote_stakes );
279 64526 : vacc_fork_t * fork = vacc_fork_pool_ele( fork_pool, set_idx );
280 64526 : fd_rwlock_write( &vote_stakes->lock );
281 64542 : if( fork->cache_idx!=UINT_MAX ) {
282 64542 : t_1_cache_ent_t * ent = t_1_cache( vote_stakes ) + fork->cache_idx;
283 64542 : ent->set_idx = ULONG_MAX;
284 64542 : ent->lru = 0UL;
285 64542 : fork->cache_idx = UINT_MAX;
286 64542 : }
287 64526 : fd_rwlock_unwrite( &vote_stakes->lock );
288 64526 : vacc_fork_pool_idx_release( fork_pool, set_idx );
289 64526 : }
290 :
291 : static inline vacc_heap_t *
292 763 : vacc_heap( fd_vote_stakes_t const * vote_stakes ) {
293 763 : return fd_type_pun( (uchar *)vote_stakes + vote_stakes->vacc_heap_off );
294 763 : }
295 :
296 : static inline vacc_states_t *
297 137133 : vacc_states_pool( fd_vote_stakes_t const * vote_stakes ) {
298 137133 : return fd_type_pun( (uchar *)vote_stakes + vote_stakes->vacc_states_pool_off );
299 137133 : }
300 :
301 : /* The fork id is a compound of the epoch, t-1 set idx, and bank idx. */
302 :
303 : static inline ushort
304 70781 : fork_id_bank_id( ulong fork_id ) {
305 70781 : return (ushort)(fork_id & (ulong)USHORT_MAX);
306 70781 : }
307 :
308 : static inline ushort
309 68725 : fork_id_t_1_idx( ulong fork_id ) {
310 68725 : return (ushort)((fork_id>>16UL) & (ulong)USHORT_MAX);
311 68725 : }
312 :
313 : static inline ushort
314 15458 : fork_id_epoch( ulong fork_id ) {
315 15458 : return (ushort)((fork_id>>32UL) & (ulong)USHORT_MAX);
316 15458 : }
317 :
318 : static inline void
319 : fork_id_set_bank_id( ulong * fork_id,
320 66409 : ushort bank_id ) {
321 66409 : *fork_id = (*fork_id & ~(ulong)USHORT_MAX) | (ulong)bank_id;
322 66409 : }
323 :
324 : static inline void
325 : fork_id_set_t_1_idx( ulong * fork_id,
326 66400 : ushort t_1_idx ) {
327 66400 : *fork_id = (*fork_id & ~((ulong)USHORT_MAX<<16UL)) | ((ulong)t_1_idx<<16UL);
328 66400 : }
329 :
330 : static inline void
331 : fork_id_set_epoch( ulong * fork_id,
332 66400 : ushort epoch ) {
333 66400 : *fork_id = (*fork_id & ~((ulong)USHORT_MAX<<32UL)) | ((ulong)epoch<<32UL);
334 66400 : }
335 :
336 : ulong
337 360 : fd_vote_stakes_align( void ) {
338 360 : return FD_VOTE_STAKES_ALIGN;
339 360 : }
340 :
341 : ulong
342 : fd_vote_stakes_footprint( ulong max_live_slots,
343 60 : ulong cache_cnt ) {
344 60 : if( FD_UNLIKELY( !max_live_slots || max_live_slots>USHORT_MAX ) ) return 0UL;
345 60 : if( FD_UNLIKELY( !cache_cnt ) ) return 0UL;
346 60 : cache_cnt = fd_ulong_min( cache_cnt, max_live_slots );
347 :
348 60 : ulong map_chain_cnt = vacc_map_chain_cnt_est( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS );
349 60 : ulong pool_footprint = vacc_pool_footprint( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS );
350 60 : ulong map_footprint = vacc_map_footprint( map_chain_cnt );
351 :
352 60 : ulong l = FD_LAYOUT_INIT;
353 60 : l = FD_LAYOUT_APPEND( l, fd_vote_stakes_align(), sizeof(fd_vote_stakes_t) );
354 360 : for( ulong i=0UL; i<FD_VOTE_STAKES_EPOCH_CACHE_CNT; i++ ) {
355 300 : l = FD_LAYOUT_APPEND( l, vacc_pool_align(), pool_footprint );
356 300 : l = FD_LAYOUT_APPEND( l, vacc_map_align(), map_footprint );
357 300 : }
358 60 : l = FD_LAYOUT_APPEND( l, vacc_fork_pool_align(), vacc_fork_pool_footprint( max_live_slots ) );
359 60 : l = FD_LAYOUT_APPEND( l, alignof(t_1_cache_ent_t), cache_cnt*sizeof(t_1_cache_ent_t) );
360 60 : l = FD_LAYOUT_APPEND( l, vacc_pool_align(), cache_cnt*pool_footprint );
361 60 : l = FD_LAYOUT_APPEND( l, vacc_map_align(), cache_cnt*map_footprint );
362 60 : l = FD_LAYOUT_APPEND( l, vacc_heap_align(), vacc_heap_footprint( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ) );
363 60 : l = FD_LAYOUT_APPEND( l, vacc_state_pool_align(), vacc_state_pool_footprint( max_live_slots ) );
364 60 : return FD_LAYOUT_FINI( l, fd_vote_stakes_align() );
365 60 : }
366 :
367 : void *
368 : fd_vote_stakes_new( void * mem,
369 : int disk_fd,
370 : ulong max_live_slots,
371 : ulong cache_cnt,
372 12 : ulong seed ) {
373 12 : if( FD_UNLIKELY( !mem ) ) {
374 0 : FD_LOG_WARNING(( "NULL mem" ));
375 0 : return NULL;
376 0 : }
377 :
378 12 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_vote_stakes_align() ) ) ) {
379 0 : FD_LOG_WARNING(( "misaligned mem" ));
380 0 : return NULL;
381 0 : }
382 :
383 12 : if( FD_UNLIKELY( !max_live_slots || max_live_slots>USHORT_MAX ) ) {
384 0 : FD_LOG_WARNING(( "invalid max_live_slots" ));
385 0 : return NULL;
386 0 : }
387 :
388 12 : if( FD_UNLIKELY( !cache_cnt ) ) {
389 0 : FD_LOG_WARNING(( "invalid cache_cnt" ));
390 0 : return NULL;
391 0 : }
392 :
393 12 : if( FD_UNLIKELY( disk_fd<0 ) ) {
394 0 : FD_LOG_WARNING(( "invalid disk_fd %d", disk_fd ));
395 0 : return NULL;
396 0 : }
397 :
398 12 : ulong footprint = fd_vote_stakes_footprint( max_live_slots, cache_cnt );
399 12 : cache_cnt = fd_ulong_min( cache_cnt, max_live_slots );
400 :
401 12 : ulong map_chain_cnt = vacc_map_chain_cnt_est( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS );
402 12 : ulong pool_footprint = vacc_pool_footprint( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS );
403 12 : ulong map_footprint = vacc_map_footprint( map_chain_cnt );
404 :
405 12 : FD_SCRATCH_ALLOC_INIT( l, mem );
406 12 : fd_vote_stakes_t * vote_stakes = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_stakes_align(), sizeof(fd_vote_stakes_t) );
407 0 : void * t_2_pool_mem[ FD_VOTE_STAKES_EPOCH_CACHE_CNT ];
408 12 : void * t_2_map_mem [ FD_VOTE_STAKES_EPOCH_CACHE_CNT ];
409 72 : for( ulong i=0UL; i<FD_VOTE_STAKES_EPOCH_CACHE_CNT; i++ ) {
410 60 : t_2_pool_mem[ i ] = FD_SCRATCH_ALLOC_APPEND( l, vacc_pool_align(), pool_footprint );
411 60 : t_2_map_mem [ i ] = FD_SCRATCH_ALLOC_APPEND( l, vacc_map_align(), map_footprint );
412 60 : }
413 12 : void * vacc_fork_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, vacc_fork_pool_align(), vacc_fork_pool_footprint( max_live_slots ) );
414 12 : void * t_1_cache_mem = FD_SCRATCH_ALLOC_APPEND( l, alignof(t_1_cache_ent_t), cache_cnt*sizeof(t_1_cache_ent_t) );
415 12 : void * t_1_vacc_pools_mem = FD_SCRATCH_ALLOC_APPEND( l, vacc_pool_align(), cache_cnt*pool_footprint );
416 12 : void * t_1_vacc_maps_mem = FD_SCRATCH_ALLOC_APPEND( l, vacc_map_align(), cache_cnt*map_footprint );
417 12 : void * vacc_heap_mem = FD_SCRATCH_ALLOC_APPEND( l, vacc_heap_align(), vacc_heap_footprint( FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ) );
418 12 : void * vacc_states_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, vacc_state_pool_align(), vacc_state_pool_footprint( max_live_slots ) );
419 :
420 12 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_vote_stakes_align() )!=(ulong)mem+footprint ) ) {
421 0 : FD_LOG_WARNING(( "fd_vote_stakes_new: bad layout" ));
422 0 : return NULL;
423 0 : }
424 :
425 72 : for( ulong i=0UL; i<FD_VOTE_STAKES_EPOCH_CACHE_CNT; i++ ) {
426 60 : vacc_t * t_2_pool = vacc_pool_join( vacc_pool_new( t_2_pool_mem[ i ], FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ) );
427 60 : if( FD_UNLIKELY( !t_2_pool ) ) {
428 0 : FD_LOG_WARNING(( "Failed to create t-2 vote account pool" ));
429 0 : return NULL;
430 0 : }
431 :
432 60 : vacc_map_t * t_2_map = vacc_map_join( vacc_map_new( t_2_map_mem[ i ], map_chain_cnt, seed ) );
433 60 : if( FD_UNLIKELY( !t_2_map ) ) {
434 0 : FD_LOG_WARNING(( "Failed to create t-2 vote account map" ));
435 0 : return NULL;
436 0 : }
437 :
438 60 : vote_stakes->t_2_vacc_pool_off[ i ] = (ulong)t_2_pool - (ulong)mem;
439 60 : vote_stakes->t_2_vacc_map_off [ i ] = (ulong)t_2_map - (ulong)mem;
440 60 : }
441 :
442 12 : vacc_fork_t * fork_pool = vacc_fork_pool_join( vacc_fork_pool_new( vacc_fork_pool_mem, max_live_slots ) );
443 12 : if( FD_UNLIKELY( !fork_pool ) ) {
444 0 : FD_LOG_WARNING(( "Failed to create vote account fork pool" ));
445 0 : return NULL;
446 0 : }
447 12 : vote_stakes->vacc_fork_pool_off = (ulong)fork_pool - (ulong)mem;
448 :
449 12 : t_1_cache_ent_t * t_1_cache_ents = t_1_cache_mem;
450 36 : for( ulong i=0UL; i<cache_cnt; i++ ) t_1_cache_ents[ i ] = (t_1_cache_ent_t){ .set_idx = ULONG_MAX };
451 12 : vote_stakes->t_1_cache_off = (ulong)t_1_cache_mem - (ulong)mem;
452 12 : vote_stakes->t_1_vacc_pools_mem_off = (ulong)t_1_vacc_pools_mem - (ulong)mem;
453 :
454 36 : for( ulong i=0UL; i<cache_cnt; i++ ) {
455 24 : void * pool_mem = (uchar *)t_1_vacc_pools_mem + i*pool_footprint;
456 24 : vacc_t * pool = vacc_pool_join( vacc_pool_new( pool_mem, FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ) );
457 24 : if( FD_UNLIKELY( !pool ) ) {
458 0 : FD_LOG_WARNING(( "Failed to create t-1 vote account pool" ));
459 0 : return NULL;
460 0 : }
461 24 : if( FD_UNLIKELY( !i ) ) vote_stakes->t_1_vacc_pools_off = (ulong)pool - (ulong)mem;
462 :
463 24 : void * map_mem = (uchar *)t_1_vacc_maps_mem + i*map_footprint;
464 24 : vacc_map_t * map = vacc_map_join( vacc_map_new( map_mem, map_chain_cnt, seed ) );
465 24 : if( FD_UNLIKELY( !map ) ) {
466 0 : FD_LOG_WARNING(( "Failed to create t-1 vote account map" ));
467 0 : return NULL;
468 0 : }
469 24 : }
470 12 : vote_stakes->t_1_vacc_maps_off = (ulong)t_1_vacc_maps_mem - (ulong)mem;
471 :
472 12 : vacc_heap_t * heap = vacc_heap_join( vacc_heap_new( vacc_heap_mem, FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ) );
473 12 : if( FD_UNLIKELY( !heap ) ) {
474 0 : FD_LOG_WARNING(( "Failed to create vote account heap" ));
475 0 : return NULL;
476 0 : }
477 :
478 12 : vacc_states_t * vacc_states_pool = vacc_state_pool_join( vacc_state_pool_new( vacc_states_pool_mem, max_live_slots ) );
479 12 : if( FD_UNLIKELY( !vacc_states_pool ) ) {
480 0 : FD_LOG_WARNING(( "Failed to create vote account state pool" ));
481 0 : return NULL;
482 0 : }
483 :
484 12 : vote_stakes->max_live_slots = max_live_slots;
485 12 : vote_stakes->cache_cnt = cache_cnt;
486 12 : vote_stakes->disk_fd = disk_fd;
487 12 : vote_stakes->lru = 0UL;
488 12 : vote_stakes->min_stake_wmark = 0UL;
489 12 : vote_stakes->vacc_heap_off = (ulong)heap - (ulong)mem;
490 12 : vote_stakes->vacc_states_pool_off = (ulong)vacc_states_pool - (ulong)mem;
491 12 : fd_rwlock_new( &vote_stakes->lock );
492 72 : for( ulong i=0UL; i<FD_VOTE_STAKES_EPOCH_CACHE_CNT; i++ ) vote_stakes->t_2_epoch[ i ] = ULONG_MAX;
493 :
494 12 : FD_COMPILER_MFENCE();
495 12 : FD_VOLATILE( vote_stakes->magic ) = FD_VOTE_STAKES_MAGIC;
496 12 : FD_COMPILER_MFENCE();
497 :
498 12 : return vote_stakes;
499 12 : }
500 :
501 : fd_vote_stakes_t *
502 : fd_vote_stakes_join( void * mem,
503 24 : int disk_fd ) {
504 24 : fd_vote_stakes_t * vote_stakes = (fd_vote_stakes_t *)mem;
505 :
506 24 : if( FD_UNLIKELY( !vote_stakes ) ) {
507 0 : FD_LOG_WARNING(( "NULL vote stakes" ));
508 0 : return NULL;
509 0 : }
510 :
511 24 : if( FD_UNLIKELY( vote_stakes->magic!=FD_VOTE_STAKES_MAGIC ) ) {
512 0 : FD_LOG_WARNING(( "Invalid vote stakes magic" ));
513 0 : return NULL;
514 0 : }
515 :
516 24 : if( FD_UNLIKELY( vote_stakes->disk_fd!=disk_fd ) ) {
517 0 : FD_LOG_WARNING(( "disk_fd mismatch (vote_stakes=%d join=%d)", vote_stakes->disk_fd, disk_fd ));
518 0 : return NULL;
519 0 : }
520 :
521 24 : return vote_stakes;
522 24 : }
523 :
524 : ulong
525 615 : fd_vote_stakes_fork_epoch( ulong fork_id ) {
526 615 : return (ulong)fork_id_epoch( fork_id );
527 615 : }
528 :
529 : ulong
530 : fd_vote_stakes_init( fd_vote_stakes_t * vote_stakes,
531 65734 : ulong epoch ) {
532 : /* Acquire t-1 key set idx */
533 65734 : ushort t_1_idx = t_1_acquire( vote_stakes );
534 :
535 : /* Acquire t-2 state bank idx */
536 65734 : vacc_states_t * states_pool = vacc_states_pool( vote_stakes );
537 65734 : FD_CHECK_CRIT( vacc_state_pool_free( states_pool ), "vote stakes state pool exhausted" );
538 65734 : ushort bank_idx = (ushort)vacc_state_pool_idx_acquire( states_pool );
539 65734 : vacc_states_t * states = vacc_state_pool_ele( states_pool, bank_idx );
540 65734 : memset( states->states, 0, sizeof(states->states) );
541 65734 : vote_stakes->t_2_epoch[ epoch % FD_VOTE_STAKES_EPOCH_CACHE_CNT ] = epoch;
542 :
543 : /* Construct the fork id */
544 65734 : ulong fork_id = 0UL;
545 65734 : fork_id_set_bank_id( &fork_id, bank_idx );
546 65734 : fork_id_set_t_1_idx( &fork_id, t_1_idx );
547 65734 : fork_id_set_epoch( &fork_id, (ushort)epoch );
548 65734 : return fork_id;
549 65734 : }
550 :
551 : void
552 627 : fd_vote_stakes_reset( fd_vote_stakes_t * vote_stakes ) {
553 3762 : for( ulong i=0UL; i<FD_VOTE_STAKES_EPOCH_CACHE_CNT; i++ ) {
554 3135 : vacc_map_reset( t_2_vacc_map( vote_stakes, i ) );
555 3135 : vacc_pool_reset( t_2_vacc_pool( vote_stakes, i ) );
556 3135 : vote_stakes->t_2_epoch[ i ] = ULONG_MAX;
557 3135 : }
558 :
559 627 : t_1_cache_ent_t * t_1_cache_ents = t_1_cache( vote_stakes );
560 1881 : for( ulong i=0UL; i<vote_stakes->cache_cnt; i++ ) {
561 1254 : t_1_cache_ents[ i ] = (t_1_cache_ent_t){ .set_idx = ULONG_MAX };
562 1254 : vacc_map_reset ( t_1_cache_map ( vote_stakes, i ) );
563 1254 : vacc_pool_reset( t_1_cache_pool( vote_stakes, i ) );
564 1254 : }
565 627 : vote_stakes->lru = 0UL;
566 :
567 627 : vacc_fork_pool_reset( vacc_fork_pool( vote_stakes ) );
568 627 : vacc_state_pool_reset( vacc_states_pool( vote_stakes ) );
569 627 : FD_TEST( vacc_heap_new( vacc_heap( vote_stakes ), FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ) );
570 627 : vote_stakes->min_stake_wmark = 0UL;
571 627 : }
572 :
573 : static void
574 : vacc_init( vacc_t * vacc,
575 : fd_pubkey_t const * pubkey,
576 : fd_pubkey_t const * node_account,
577 : ulong stake,
578 : ushort commission,
579 : uchar const bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
580 : ushort block_revenue_commission_bps,
581 : ulong pending_delegator_rewards,
582 : fd_pubkey_t const * inflation_collector_opt,
583 2243 : fd_pubkey_t const * block_collector_opt ) {
584 2243 : vacc->pubkey = *pubkey;
585 2243 : vacc->node_account = *node_account;
586 2243 : vacc->stake = stake;
587 2243 : vacc->commission = commission;
588 2243 : vacc->block_revenue_commission_bps = block_revenue_commission_bps;
589 2243 : vacc->pending_delegator_rewards = pending_delegator_rewards;
590 2243 : vacc->inflation_collector = inflation_collector_opt ? *inflation_collector_opt : *pubkey;
591 2243 : vacc->block_collector = block_collector_opt ? *block_collector_opt : *node_account;
592 2243 : vacc->rank = FD_VOTE_STAKES_ALPENGLOW_RANK_NULL;
593 2243 : memcpy( vacc->bls_key, bls_key, FD_BLS_PUBKEY_COMPRESSED_SZ );
594 2243 : }
595 :
596 : void
597 : fd_vote_stakes_snap_insert_t_1( fd_vote_stakes_t * vote_stakes,
598 : ulong fork_id,
599 : fd_pubkey_t const * pubkey,
600 : fd_pubkey_t const * node_account,
601 : ulong stake,
602 : ushort commission,
603 : uchar const bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
604 : ushort block_revenue_commission_bps,
605 : ulong pending_delegator_rewards,
606 : fd_pubkey_t const * inflation_collector_opt,
607 1087 : fd_pubkey_t const * block_collector_opt ) {
608 1087 : if( FD_UNLIKELY( !stake ) ) return;
609 :
610 1087 : ulong cache_idx = t_1_lock( vote_stakes, fork_id_t_1_idx( fork_id ), 1 );
611 1087 : vacc_t * pool = t_1_cache_pool( vote_stakes, cache_idx );
612 1087 : vacc_map_t * map = t_1_cache_map ( vote_stakes, cache_idx );
613 :
614 1087 : vacc_t * vacc = vacc_pool_ele_acquire( pool );
615 1087 : vacc_init( vacc, pubkey, node_account, stake, commission, bls_key,
616 1087 : block_revenue_commission_bps, pending_delegator_rewards, inflation_collector_opt, block_collector_opt );
617 1087 : FD_TEST( vacc_map_ele_insert( map, vacc, pool ) );
618 1087 : t_1_unlock( vote_stakes, 1 );
619 1087 : }
620 :
621 : void
622 : fd_vote_stakes_snap_insert_t_2( fd_vote_stakes_t * vote_stakes,
623 : ulong fork_id,
624 : fd_pubkey_t const * pubkey,
625 : fd_pubkey_t const * node_account,
626 : ulong stake,
627 : ushort commission,
628 : uchar const bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
629 : ushort block_revenue_commission_bps,
630 : ulong pending_delegator_rewards,
631 : fd_pubkey_t const * inflation_collector_opt,
632 1052 : fd_pubkey_t const * block_collector_opt ) {
633 1052 : if( FD_UNLIKELY( !stake ) ) return;
634 :
635 1052 : ulong epoch_idx = (ulong)fork_id_epoch( fork_id ) % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
636 1052 : vacc_t * pool = t_2_vacc_pool( vote_stakes, epoch_idx );
637 1052 : vacc_map_t * map = t_2_vacc_map ( vote_stakes, epoch_idx );
638 :
639 1052 : vacc_t * vacc = vacc_pool_ele_acquire( pool );
640 1052 : vacc_init( vacc, pubkey, node_account, stake, commission, bls_key,
641 1052 : block_revenue_commission_bps, pending_delegator_rewards, inflation_collector_opt, block_collector_opt );
642 1052 : FD_TEST( vacc_map_ele_insert( map, vacc, pool ) );
643 1052 : }
644 :
645 : void
646 : fd_vote_stakes_snap_insert_t_n( fd_vote_stakes_t * vote_stakes,
647 : ulong fork_id,
648 : ulong n,
649 : fd_pubkey_t const * pubkey,
650 : fd_pubkey_t const * node_account,
651 : ulong stake,
652 : ushort commission,
653 : uchar const bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
654 : ushort block_revenue_commission_bps,
655 : ulong pending_delegator_rewards,
656 : fd_pubkey_t const * inflation_collector_opt,
657 0 : fd_pubkey_t const * block_collector_opt ) {
658 0 : ulong epoch = (ulong)fork_id_epoch( fork_id );
659 0 : ulong back = n-2UL;
660 0 : if( FD_UNLIKELY( epoch<back || !stake ) ) return;
661 :
662 0 : ulong t_n_epoch = epoch - back;
663 0 : ulong t_n_idx = t_n_epoch % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
664 0 : vacc_t * pool = t_2_vacc_pool( vote_stakes, t_n_idx );
665 0 : vacc_map_t * map = t_2_vacc_map ( vote_stakes, t_n_idx );
666 :
667 0 : vacc_t * vacc = vacc_pool_ele_acquire( pool );
668 0 : vacc_init( vacc, pubkey, node_account, stake, commission, bls_key,
669 0 : block_revenue_commission_bps, pending_delegator_rewards, inflation_collector_opt, block_collector_opt );
670 0 : FD_TEST( vacc_map_ele_insert( map, vacc, pool ) );
671 0 : vote_stakes->t_2_epoch[ t_n_idx ] = t_n_epoch;
672 0 : }
673 :
674 : static void
675 : t_1_insert( fd_vote_stakes_t * vote_stakes,
676 : vacc_t * pool,
677 : vacc_map_t * map,
678 : fd_pubkey_t const * pubkey,
679 : fd_pubkey_t const * node_account,
680 : ulong stake,
681 : ushort commission,
682 : uchar const bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
683 : ushort block_revenue_commission_bps,
684 : ulong pending_delegator_rewards,
685 : fd_pubkey_t const * inflation_collector_opt,
686 104 : fd_pubkey_t const * block_collector_opt ) {
687 104 : vacc_heap_t * heap = vacc_heap( vote_stakes );
688 :
689 104 : if( FD_UNLIKELY( stake==0UL || stake<=vote_stakes->min_stake_wmark ) ) return;
690 :
691 104 : if( FD_UNLIKELY( vacc_heap_ele_cnt( heap )==vacc_heap_ele_max( heap ) ) ) {
692 0 : vacc_t * ele = vacc_heap_ele_peek_min( heap, pool );
693 0 : ulong min_stake = ele->stake;
694 0 : if( stake<min_stake ) return;
695 :
696 0 : vote_stakes->min_stake_wmark = min_stake;
697 0 : while( (ele=vacc_heap_ele_peek_min( heap, pool )) && min_stake==ele->stake ) {
698 0 : vacc_heap_ele_remove_min( heap, pool );
699 0 : vacc_map_ele_remove( map, &ele->pubkey, NULL, pool );
700 0 : vacc_pool_ele_release( pool, ele );
701 0 : }
702 0 : if( FD_UNLIKELY( stake==min_stake ) ) return;
703 0 : }
704 :
705 104 : vacc_t * vacc = vacc_pool_ele_acquire( pool );
706 104 : vacc_init( vacc, pubkey, node_account, stake, commission, bls_key,
707 104 : block_revenue_commission_bps, pending_delegator_rewards, inflation_collector_opt, block_collector_opt );
708 104 : vacc_heap_ele_insert( heap, vacc, pool );
709 104 : FD_TEST( vacc_map_ele_insert( map, vacc, pool ) );
710 104 : }
711 :
712 : void
713 : fd_vote_stakes_insert( fd_vote_stakes_t * vote_stakes,
714 : ulong fork_id,
715 : fd_pubkey_t const * pubkey,
716 : fd_pubkey_t const * node_account,
717 : ulong stake,
718 : ushort commission,
719 : uchar const bls_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
720 : ushort block_revenue_commission_bps,
721 : ulong pending_delegator_rewards,
722 : fd_pubkey_t const * inflation_collector_opt,
723 104 : fd_pubkey_t const * block_collector_opt ) {
724 104 : ulong cache_idx = t_1_lock( vote_stakes, fork_id_t_1_idx( fork_id ), 1 );
725 104 : t_1_insert( vote_stakes, t_1_cache_pool( vote_stakes, cache_idx ), t_1_cache_map( vote_stakes, cache_idx ),
726 104 : pubkey, node_account, stake, commission, bls_key,
727 104 : block_revenue_commission_bps, pending_delegator_rewards, inflation_collector_opt, block_collector_opt );
728 104 : t_1_unlock( vote_stakes, 1 );
729 104 : }
730 :
731 : void
732 : fd_vote_stakes_finalize( fd_vote_stakes_t * vote_stakes,
733 : ulong fork_id,
734 32 : int iter_kind ) {
735 32 : vacc_t * pool;
736 32 : vacc_map_t * map;
737 32 : ulong cache_idx = ULONG_MAX;
738 32 : if( FD_LIKELY( iter_kind==FD_VOTE_STAKES_ITER_T_1 ) ) {
739 32 : cache_idx = t_1_lock( vote_stakes, fork_id_t_1_idx( fork_id ), 1 );
740 32 : pool = t_1_cache_pool( vote_stakes, cache_idx );
741 32 : map = t_1_cache_map ( vote_stakes, cache_idx );
742 32 : } else {
743 0 : FD_TEST( iter_kind>=FD_VOTE_STAKES_ITER_T_2 && iter_kind<=FD_VOTE_STAKES_ITER_T_5 );
744 0 : ulong fork_epoch = (ulong)fork_id_epoch( fork_id );
745 0 : ulong back = (ulong)(iter_kind-FD_VOTE_STAKES_ITER_T_2);
746 0 : if( FD_UNLIKELY( fork_epoch<back ) ) return;
747 :
748 0 : ulong epoch = fork_epoch-back;
749 0 : ulong epoch_idx = epoch % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
750 0 : if( FD_UNLIKELY( vote_stakes->t_2_epoch[ epoch_idx ]!=epoch ) ) return;
751 0 : pool = t_2_vacc_pool( vote_stakes, epoch_idx );
752 0 : map = t_2_vacc_map ( vote_stakes, epoch_idx );
753 0 : }
754 :
755 32 : vacc_rank_t rank[ FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ];
756 32 : ulong rank_cnt = 0UL;
757 32 : for( vacc_map_iter_t iter = vacc_map_iter_init( map, pool );
758 136 : !vacc_map_iter_done( iter, map, pool );
759 104 : iter = vacc_map_iter_next( iter, map, pool ) ) {
760 104 : vacc_t * vacc = vacc_map_iter_ele( iter, map, pool );
761 104 : vacc->rank = FD_VOTE_STAKES_ALPENGLOW_RANK_NULL;
762 104 : if( FD_UNLIKELY( !vacc->stake ) ) continue;
763 104 : if( FD_UNLIKELY( fd_bls12_381_g1_decompress_syscall( vacc->bls_key_uncompressed, vacc->bls_key, 1 ) ) ) continue;
764 0 : if( FD_UNLIKELY( vacc->bls_key[0]&0x40 ) ) continue; /* infinity: agave's rank map rejects the identity point */
765 0 : FD_TEST( rank_cnt<FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS );
766 0 : rank[ rank_cnt++ ] = (vacc_rank_t){ .vacc=vacc, .drop=0UL };
767 0 : }
768 :
769 32 : vacc_rank_bls_sort_inplace( rank, rank_cnt );
770 32 : for( ulong i=1UL; i<rank_cnt; i++ ) {
771 0 : if( FD_UNLIKELY( !memcmp( rank[i].vacc->bls_key, rank[i-1UL].vacc->bls_key, FD_BLS_PUBKEY_COMPRESSED_SZ ) ) ) {
772 0 : rank[i].drop = rank[i-1UL].drop = 1UL;
773 0 : }
774 0 : }
775 :
776 32 : vacc_rank_identity_sort_inplace( rank, rank_cnt );
777 32 : for( ulong i=1UL; i<rank_cnt; i++ ) {
778 0 : if( FD_UNLIKELY( fd_pubkey_eq( &rank[i].vacc->node_account, &rank[i-1UL].vacc->node_account ) ) ) {
779 0 : rank[i].drop = rank[i-1UL].drop = 1UL;
780 0 : }
781 0 : }
782 :
783 32 : ulong survivor_cnt = 0UL;
784 32 : for( ulong i=0UL; i<rank_cnt; i++ ) {
785 0 : if( FD_LIKELY( !rank[i].drop ) ) rank[ survivor_cnt++ ] = rank[i];
786 0 : }
787 32 : vacc_rank_sort_inplace( rank, survivor_cnt );
788 :
789 32 : for( ulong i=0UL; i<survivor_cnt; i++ ) rank[i].vacc->rank = (ushort)i;
790 32 : if( cache_idx!=ULONG_MAX ) t_1_unlock( vote_stakes, 1 );
791 32 : }
792 :
793 : void
794 : fd_vote_stakes_purge_fork( fd_vote_stakes_t * vote_stakes,
795 65132 : ulong fork_id ) {
796 65132 : ushort bank_id = fork_id_bank_id( fork_id );
797 65132 : ushort t_1_idx = fork_id_t_1_idx( fork_id );
798 :
799 65132 : vacc_state_pool_idx_release( vacc_states_pool( vote_stakes ), bank_id );
800 :
801 65132 : vacc_fork_t * fork = vacc_fork_pool_ele( vacc_fork_pool( vote_stakes ), t_1_idx );
802 65132 : FD_TEST( fork->ref_cnt );
803 65132 : if( !--fork->ref_cnt ) t_1_release( vote_stakes, t_1_idx );
804 65132 : }
805 :
806 : ulong
807 : fd_vote_stakes_new_fork( fd_vote_stakes_t * vote_stakes,
808 : ulong parent_fork_id,
809 659 : ulong epoch ) {
810 659 : FD_TEST( epoch<=USHORT_MAX );
811 :
812 659 : vacc_states_t * states_pool = vacc_states_pool( vote_stakes );
813 659 : FD_CHECK_CRIT( vacc_state_pool_free( states_pool ), "vote stakes state pool exhausted" );
814 659 : ushort parent_bank_id = fork_id_bank_id( parent_fork_id );
815 659 : ushort bank_id = (ushort)vacc_state_pool_idx_acquire( states_pool );
816 659 : ushort parent_epoch = fork_id_epoch( parent_fork_id );
817 659 : ushort t_1_idx;
818 :
819 659 : vacc_states_t * child_state = vacc_state_pool_ele( states_pool, bank_id );
820 659 : if( FD_LIKELY( epoch==(ulong)parent_epoch ) ) {
821 : /* Standard case: just inherit the parent's t-1 set (and increment
822 : the ref count) and copy over the t-2 state. */
823 627 : t_1_idx = fork_id_t_1_idx( parent_fork_id );
824 627 : vacc_fork_pool_ele( vacc_fork_pool( vote_stakes ), t_1_idx )->ref_cnt++;
825 :
826 627 : vacc_states_t const * parent_state = vacc_state_pool_ele_const( states_pool, parent_bank_id );
827 627 : memcpy( child_state->states, parent_state->states, sizeof(child_state->states) );
828 627 : } else {
829 : /* Epoch boundary: copy the parent's t-1 set into the t-2 set and
830 : acquire new t-1 and t-2 state. */
831 :
832 : /* Copy the t-1 set, ranks included, iff it's the first time
833 : crossing into a new epoch boundary. */
834 32 : ulong t_2_idx = epoch % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
835 32 : if( vote_stakes->t_2_epoch[ t_2_idx ]!=epoch ) {
836 32 : ulong t_1_cache_idx = t_1_lock( vote_stakes, fork_id_t_1_idx( parent_fork_id ), 0 );
837 32 : vacc_t * t_1_pool = t_1_cache_pool( vote_stakes, t_1_cache_idx );
838 32 : vacc_map_t * t_1_map = t_1_cache_map ( vote_stakes, t_1_cache_idx );
839 32 : vacc_t * t_2_pool = t_2_vacc_pool( vote_stakes, t_2_idx );
840 32 : vacc_map_t * t_2_map = t_2_vacc_map ( vote_stakes, t_2_idx );
841 :
842 32 : vacc_map_reset( t_2_map );
843 32 : vacc_pool_reset( t_2_pool );
844 32 : for( vacc_map_iter_t iter = vacc_map_iter_init( t_1_map, t_1_pool );
845 259 : !vacc_map_iter_done( iter, t_1_map, t_1_pool );
846 227 : iter = vacc_map_iter_next( iter, t_1_map, t_1_pool ) ) {
847 227 : vacc_t const * src = vacc_map_iter_ele_const( iter, t_1_map, t_1_pool );
848 227 : vacc_t * dst = vacc_pool_ele_acquire( t_2_pool );
849 227 : dst->pubkey = src->pubkey;
850 227 : dst->node_account = src->node_account;
851 227 : dst->stake = src->stake;
852 227 : dst->commission = src->commission;
853 227 : dst->block_revenue_commission_bps = src->block_revenue_commission_bps;
854 227 : dst->pending_delegator_rewards = src->pending_delegator_rewards;
855 227 : dst->inflation_collector = src->inflation_collector;
856 227 : dst->block_collector = src->block_collector;
857 227 : dst->rank = src->rank;
858 227 : memcpy( dst->bls_key, src->bls_key, FD_BLS_PUBKEY_COMPRESSED_SZ );
859 227 : memcpy( dst->bls_key_uncompressed, src->bls_key_uncompressed, FD_BLS_PUBKEY_UNCOMPRESSED_SZ );
860 227 : FD_TEST( vacc_map_ele_insert( t_2_map, dst, t_2_pool ) );
861 227 : }
862 32 : t_1_unlock( vote_stakes, 0 );
863 32 : vote_stakes->t_2_epoch[ t_2_idx ] = epoch;
864 32 : }
865 :
866 : /* Reset the t-2 states for the new fork and prepare the heap for
867 : insertion into the new t-1 set. */
868 32 : t_1_idx = t_1_acquire( vote_stakes );
869 32 : memset( child_state->states, 0, sizeof(child_state->states) );
870 :
871 32 : FD_TEST( vacc_heap_new( vacc_heap( vote_stakes ), FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS ) );
872 32 : vote_stakes->min_stake_wmark = 0UL;
873 32 : }
874 :
875 659 : ulong fork_id = 0UL;
876 659 : fork_id_set_bank_id( &fork_id, bank_id );
877 659 : fork_id_set_t_1_idx( &fork_id, t_1_idx );
878 659 : fork_id_set_epoch( &fork_id, (ushort)epoch );
879 659 : return fork_id;
880 659 : }
881 :
882 : void
883 : fd_vote_stakes_update_state( fd_vote_stakes_t * vote_stakes,
884 : ulong fork_id,
885 : fd_pubkey_t const * pubkey,
886 : ulong last_vote_slot,
887 : long last_vote_ts,
888 1580 : uchar is_valid ) {
889 1580 : ulong epoch_idx = (ulong)fork_id_epoch( fork_id ) % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
890 1580 : vacc_t * pool = t_2_vacc_pool( vote_stakes, epoch_idx );
891 1580 : vacc_map_t * map = t_2_vacc_map ( vote_stakes, epoch_idx );
892 :
893 1580 : vacc_t const * vacc = vacc_map_ele_query_const( map, pubkey, NULL, pool );
894 1580 : if( FD_UNLIKELY( !vacc ) ) return;
895 :
896 1580 : ulong vacc_idx = vacc_pool_idx( pool, vacc );
897 1580 : vacc_states_t * states = vacc_state_pool_ele( vacc_states_pool( vote_stakes ), fork_id_bank_id( fork_id ) );
898 1580 : states->states[ vacc_idx ].is_valid = (uchar)!!is_valid;
899 1580 : if( is_valid ) {
900 1542 : states->states[ vacc_idx ].last_vote_slot = last_vote_slot;
901 1542 : states->states[ vacc_idx ].last_vote_ts = last_vote_ts;
902 1542 : }
903 1580 : }
904 :
905 : void
906 : fd_vote_stakes_refresh( fd_vote_stakes_t * vote_stakes,
907 : ulong fork_id,
908 : fd_accdb_t * accdb,
909 647 : fd_accdb_fork_id_t accdb_fork_id ) {
910 647 : uchar __attribute__((aligned(FD_VOTE_STAKES_ITER_ALIGN))) iter_mem[ FD_VOTE_STAKES_ITER_FOOTPRINT ];
911 :
912 647 : for( fd_vote_stakes_iter_t * iter = fd_vote_stakes_iter_init( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_2, iter_mem );
913 1926 : !fd_vote_stakes_iter_done( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_2, iter );
914 1279 : fd_vote_stakes_iter_next( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_2, iter ) ) {
915 1279 : fd_vote_stakes_ele_t ele[1];
916 1279 : fd_vote_stakes_iter_ele( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_2, iter, ele );
917 1279 : fd_pubkey_t const * pubkey = &ele->pubkey;
918 :
919 1279 : fd_acc_t acc = fd_accdb_read_one( accdb, accdb_fork_id, pubkey->uc );
920 1279 : if( FD_UNLIKELY( !acc.lamports || !fd_vsv_is_correct_size_owner_and_init( acc.owner, acc.data, acc.data_len ) ) ) {
921 38 : fd_accdb_unread_one( accdb, &acc );
922 38 : fd_vote_stakes_update_state( vote_stakes, fork_id, pubkey, 0UL, 0L, 0 );
923 38 : continue;
924 38 : }
925 :
926 1241 : fd_vote_block_timestamp_t last_vote;
927 1241 : FD_TEST( !fd_vote_account_last_timestamp( acc.data, acc.data_len, &last_vote ) );
928 1241 : fd_vote_stakes_update_state( vote_stakes, fork_id, pubkey, last_vote.slot, last_vote.timestamp, 1 );
929 1241 : fd_accdb_unread_one( accdb, &acc );
930 1241 : }
931 647 : }
932 :
933 : /* t_1_vacc_query_const looks up pubkey in the fork's t-1 set under
934 : the shared t-1 lock, which the caller must release with
935 : t_1_unlock( vote_stakes, 0 ). */
936 :
937 : static vacc_t const *
938 : t_1_vacc_query_const( fd_vote_stakes_t * vote_stakes,
939 : ulong fork_id,
940 1324 : fd_pubkey_t const * pubkey ) {
941 1324 : ulong cache_idx = t_1_lock( vote_stakes, fork_id_t_1_idx( fork_id ), 0 );
942 1324 : return vacc_map_ele_query_const( t_1_cache_map( vote_stakes, cache_idx ), pubkey, NULL, t_1_cache_pool( vote_stakes, cache_idx ) );
943 1324 : }
944 :
945 : /* t_n_vacc_query looks up pubkey in the fork's t-n set, n in 2..5,
946 : and sets *pool to the set's pool. Returns NULL if the set is not
947 : resident or pubkey is not in it. The query does not reorder the
948 : map, which other tiles may be iterating. */
949 : static vacc_t const *
950 : t_n_vacc_query( fd_vote_stakes_t const * vote_stakes,
951 : ulong fork_id,
952 : ulong n,
953 : fd_pubkey_t const * pubkey,
954 495 : vacc_t const ** pool ) {
955 495 : ulong epoch = (ulong)fork_id_epoch( fork_id );
956 495 : ulong back = n-2UL;
957 495 : if( FD_UNLIKELY( epoch<back ) ) return NULL;
958 495 : ulong epoch_idx = (epoch-back) % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
959 495 : if( FD_UNLIKELY( vote_stakes->t_2_epoch[ epoch_idx ]!=epoch-back ) ) return NULL;
960 356 : *pool = t_2_vacc_pool( vote_stakes, epoch_idx );
961 356 : return vacc_map_ele_query_const( t_2_vacc_map( vote_stakes, epoch_idx ), pubkey, NULL, *pool );
962 495 : }
963 :
964 : /* vacc_ele copies vacc to ele_out. vacc_ele_state adds the fork's
965 : vote state for vacc, which must be in the t-2 pool. */
966 :
967 : static void
968 : vacc_ele( vacc_t const * vacc,
969 3229 : fd_vote_stakes_ele_t * ele_out ) {
970 3229 : *ele_out = (fd_vote_stakes_ele_t){
971 3229 : .pubkey = vacc->pubkey,
972 3229 : .node_account = vacc->node_account,
973 3229 : .stake = vacc->stake,
974 3229 : .commission = vacc->commission,
975 3229 : .block_revenue_commission_bps = vacc->block_revenue_commission_bps,
976 3229 : .pending_delegator_rewards = vacc->pending_delegator_rewards,
977 3229 : .inflation_collector = vacc->inflation_collector,
978 3229 : .block_collector = vacc->block_collector,
979 3229 : .rank = vacc->rank,
980 3229 : };
981 3229 : memcpy( ele_out->bls_key, vacc->bls_key, FD_BLS_PUBKEY_COMPRESSED_SZ );
982 3229 : memcpy( ele_out->bls_key_uncompressed, vacc->bls_key_uncompressed, FD_BLS_PUBKEY_UNCOMPRESSED_SZ );
983 3229 : }
984 :
985 : static void
986 : vacc_ele_state( fd_vote_stakes_t const * vote_stakes,
987 : ulong fork_id,
988 : vacc_t const * pool,
989 : vacc_t const * vacc,
990 2801 : fd_vote_stakes_ele_t * ele_out ) {
991 2801 : ulong vacc_idx = vacc_pool_idx( pool, vacc );
992 2801 : vacc_states_t const * states = vacc_state_pool_ele_const( vacc_states_pool( vote_stakes ), fork_id_bank_id( fork_id ) );
993 2801 : ele_out->last_vote_slot = states->states[ vacc_idx ].last_vote_slot;
994 2801 : ele_out->last_vote_ts = states->states[ vacc_idx ].last_vote_ts;
995 2801 : ele_out->is_valid = states->states[ vacc_idx ].is_valid;
996 2801 : }
997 :
998 : int
999 : fd_vote_stakes_query_t_1( fd_vote_stakes_t * vote_stakes,
1000 : ulong fork_id,
1001 : fd_pubkey_t const * pubkey,
1002 1324 : fd_vote_stakes_ele_t * ele_out_opt ) {
1003 1324 : vacc_t const * vacc = t_1_vacc_query_const( vote_stakes, fork_id, pubkey );
1004 1324 : if( FD_LIKELY( vacc && ele_out_opt ) ) vacc_ele( vacc, ele_out_opt );
1005 1324 : t_1_unlock( vote_stakes, 0 );
1006 1324 : return !!vacc;
1007 1324 : }
1008 :
1009 : int
1010 : fd_vote_stakes_query_t_2( fd_vote_stakes_t const * vote_stakes,
1011 : ulong fork_id,
1012 : fd_pubkey_t const * pubkey,
1013 252 : fd_vote_stakes_ele_t * ele_out_opt ) {
1014 252 : vacc_t const * pool;
1015 252 : vacc_t const * vacc = t_n_vacc_query( vote_stakes, fork_id, 2UL, pubkey, &pool );
1016 252 : if( FD_UNLIKELY( !vacc ) ) return 0;
1017 243 : if( ele_out_opt ) {
1018 243 : vacc_ele( vacc, ele_out_opt );
1019 243 : vacc_ele_state( vote_stakes, fork_id, pool, vacc, ele_out_opt );
1020 243 : }
1021 243 : return 1;
1022 252 : }
1023 :
1024 : int
1025 : fd_vote_stakes_query_t_3( fd_vote_stakes_t const * vote_stakes,
1026 : ulong fork_id,
1027 : fd_pubkey_t const * pubkey,
1028 243 : fd_vote_stakes_ele_t * ele_out_opt ) {
1029 243 : vacc_t const * pool;
1030 243 : vacc_t const * vacc = t_n_vacc_query( vote_stakes, fork_id, 3UL, pubkey, &pool );
1031 243 : if( FD_UNLIKELY( !vacc ) ) return 0;
1032 87 : if( ele_out_opt ) vacc_ele( vacc, ele_out_opt );
1033 87 : return 1;
1034 243 : }
1035 :
1036 : ulong
1037 : fd_vote_stakes_cnt_t_1( fd_vote_stakes_t * vote_stakes,
1038 0 : ulong fork_id ) {
1039 0 : ulong cache_idx = t_1_lock( vote_stakes, fork_id_t_1_idx( fork_id ), 0 );
1040 0 : ulong cnt = vacc_pool_used( t_1_cache_pool( vote_stakes, cache_idx ) );
1041 0 : t_1_unlock( vote_stakes, 0 );
1042 0 : return cnt;
1043 0 : }
1044 :
1045 : ulong
1046 : fd_vote_stakes_cnt_t_2( fd_vote_stakes_t const * vote_stakes,
1047 0 : ulong fork_id ) {
1048 0 : return vacc_pool_used( t_2_vacc_pool( vote_stakes, (ulong)fork_id_epoch( fork_id ) % FD_VOTE_STAKES_EPOCH_CACHE_CNT ) );
1049 0 : }
1050 :
1051 : ulong
1052 : fd_vote_stakes_t_2_votes( fd_vote_stakes_t const * vote_stakes,
1053 : ulong fork_id,
1054 : ulong * stake,
1055 : ulong * last_vote_slot,
1056 614 : long * last_vote_ts ) {
1057 614 : ulong epoch = (ulong)fork_id_epoch( fork_id );
1058 614 : ulong epoch_idx = epoch % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
1059 614 : if( FD_UNLIKELY( vote_stakes->t_2_epoch[ epoch_idx ]!=epoch ) ) return 0UL;
1060 :
1061 : /* t-2 pools are only ever reset and refilled, so [0,used) is dense. */
1062 614 : vacc_t const * pool = t_2_vacc_pool( vote_stakes, epoch_idx );
1063 614 : vacc_states_t const * states = vacc_state_pool_ele_const( vacc_states_pool( vote_stakes ), fork_id_bank_id( fork_id ) );
1064 614 : ulong used = vacc_pool_used( pool );
1065 614 : ulong cnt = 0UL;
1066 1695 : for( ulong i=0UL; i<used; i++ ) {
1067 1081 : if( !states->states[ i ].is_valid ) continue;
1068 1044 : stake [ cnt ] = pool[ i ].stake;
1069 1044 : last_vote_slot[ cnt ] = states->states[ i ].last_vote_slot;
1070 1044 : last_vote_ts [ cnt ] = states->states[ i ].last_vote_ts;
1071 1044 : cnt++;
1072 1044 : }
1073 614 : return cnt;
1074 614 : }
1075 :
1076 : ulong
1077 : fd_vote_stakes_total_stake( fd_vote_stakes_t const * vote_stakes,
1078 0 : ulong epoch ) {
1079 0 : ulong idx = epoch % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
1080 0 : if( FD_UNLIKELY( vote_stakes->t_2_epoch[ idx ]!=epoch ) ) return 0UL;
1081 :
1082 0 : vacc_t * pool = t_2_vacc_pool( vote_stakes, idx );
1083 0 : vacc_map_t * map = t_2_vacc_map ( vote_stakes, idx );
1084 :
1085 0 : ulong total = 0UL;
1086 0 : for( vacc_map_iter_t iter = vacc_map_iter_init( map, pool );
1087 0 : !vacc_map_iter_done( iter, map, pool );
1088 0 : iter = vacc_map_iter_next( iter, map, pool ) ) {
1089 0 : total += vacc_map_iter_ele_const( iter, map, pool )->stake;
1090 0 : }
1091 0 : return total;
1092 0 : }
1093 :
1094 : FD_STATIC_ASSERT( FD_VOTE_STAKES_ITER_FOOTPRINT == sizeof(vacc_map_iter_t), iter_footprint );
1095 : FD_STATIC_ASSERT( FD_VOTE_STAKES_ITER_ALIGN == alignof(vacc_map_iter_t), iter_align );
1096 :
1097 : fd_vote_stakes_iter_t *
1098 : fd_vote_stakes_iter_init( fd_vote_stakes_t * vote_stakes,
1099 : ulong fork_id,
1100 : int iter_kind,
1101 1334 : uchar iter_mem[ static FD_VOTE_STAKES_ITER_FOOTPRINT ] ) {
1102 1334 : vacc_map_iter_t iter = {0};
1103 1334 : if( FD_LIKELY( iter_kind==FD_VOTE_STAKES_ITER_T_1 ) ) {
1104 36 : ulong cache_idx = t_1_lock( vote_stakes, fork_id_t_1_idx( fork_id ), 0 );
1105 36 : iter = vacc_map_iter_init( t_1_cache_map( vote_stakes, cache_idx ), t_1_cache_pool( vote_stakes, cache_idx ) );
1106 36 : t_1_unlock( vote_stakes, 0 );
1107 1298 : } else {
1108 1298 : FD_TEST( iter_kind>=FD_VOTE_STAKES_ITER_T_2 && iter_kind<=FD_VOTE_STAKES_ITER_T_5 );
1109 1298 : ulong fork_epoch = (ulong)fork_id_epoch( fork_id );
1110 1298 : ulong back = (ulong)(iter_kind-FD_VOTE_STAKES_ITER_T_2);
1111 1298 : if( FD_LIKELY( fork_epoch>=back ) ) {
1112 1298 : ulong epoch = fork_epoch-back;
1113 1298 : ulong epoch_idx = epoch % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
1114 1298 : if( FD_LIKELY( vote_stakes->t_2_epoch[ epoch_idx ]==epoch ) ) {
1115 1298 : vacc_t * pool = t_2_vacc_pool( vote_stakes, epoch_idx );
1116 1298 : vacc_map_t * map = t_2_vacc_map ( vote_stakes, epoch_idx );
1117 1298 : iter = vacc_map_iter_init( map, pool );
1118 1298 : }
1119 1298 : }
1120 1298 : }
1121 1334 : memcpy( iter_mem, &iter, sizeof(iter) );
1122 1334 : return (fd_vote_stakes_iter_t *)iter_mem;
1123 1334 : }
1124 :
1125 : int
1126 : fd_vote_stakes_iter_done( fd_vote_stakes_t * vote_stakes,
1127 : ulong fork_id,
1128 : int iter_kind,
1129 4055 : fd_vote_stakes_iter_t * iter ) {
1130 4055 : if( FD_LIKELY( iter_kind==FD_VOTE_STAKES_ITER_T_1 ) ) {
1131 141 : ulong cache_idx = t_1_lock( vote_stakes, fork_id_t_1_idx( fork_id ), 0 );
1132 141 : int done = vacc_map_iter_done( *(vacc_map_iter_t *)iter, t_1_cache_map( vote_stakes, cache_idx ), t_1_cache_pool( vote_stakes, cache_idx ) );
1133 141 : t_1_unlock( vote_stakes, 0 );
1134 141 : return done;
1135 141 : }
1136 :
1137 3914 : FD_TEST( iter_kind>=FD_VOTE_STAKES_ITER_T_2 && iter_kind<=FD_VOTE_STAKES_ITER_T_5 );
1138 3914 : ulong fork_epoch = (ulong)fork_id_epoch( fork_id );
1139 3914 : ulong back = (ulong)(iter_kind-FD_VOTE_STAKES_ITER_T_2);
1140 3914 : if( FD_UNLIKELY( fork_epoch<back ) ) return 1;
1141 :
1142 3914 : ulong epoch = fork_epoch-back;
1143 3914 : ulong epoch_idx = epoch % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
1144 3914 : if( FD_UNLIKELY( vote_stakes->t_2_epoch[ epoch_idx ]!=epoch ) ) return 1;
1145 :
1146 3914 : vacc_t * pool = t_2_vacc_pool( vote_stakes, epoch_idx );
1147 3914 : vacc_map_t * map = t_2_vacc_map ( vote_stakes, epoch_idx );
1148 3914 : return vacc_map_iter_done( *(vacc_map_iter_t *)iter, map, pool );
1149 3914 : }
1150 :
1151 : static ulong
1152 : iter_set( fd_vote_stakes_t * vote_stakes,
1153 : ulong fork_id,
1154 : int iter_kind,
1155 : vacc_t ** pool,
1156 5444 : vacc_map_t ** map ) {
1157 5444 : if( FD_LIKELY( iter_kind==FD_VOTE_STAKES_ITER_T_1 ) ) {
1158 210 : ulong cache_idx = t_1_lock( vote_stakes, fork_id_t_1_idx( fork_id ), 0 );
1159 210 : *pool = t_1_cache_pool( vote_stakes, cache_idx );
1160 210 : *map = t_1_cache_map ( vote_stakes, cache_idx );
1161 210 : return cache_idx;
1162 210 : }
1163 5234 : FD_TEST( iter_kind>=FD_VOTE_STAKES_ITER_T_2 && iter_kind<=FD_VOTE_STAKES_ITER_T_5 );
1164 5234 : ulong epoch_idx = ((ulong)fork_id_epoch( fork_id )-(ulong)(iter_kind-FD_VOTE_STAKES_ITER_T_2)) % FD_VOTE_STAKES_EPOCH_CACHE_CNT;
1165 5234 : *pool = t_2_vacc_pool( vote_stakes, epoch_idx );
1166 5234 : *map = t_2_vacc_map ( vote_stakes, epoch_idx );
1167 5234 : return ULONG_MAX;
1168 5234 : }
1169 :
1170 : void
1171 : fd_vote_stakes_iter_next( fd_vote_stakes_t * vote_stakes,
1172 : ulong fork_id,
1173 : int iter_kind,
1174 2722 : fd_vote_stakes_iter_t * iter ) {
1175 2722 : vacc_t * pool;
1176 2722 : vacc_map_t * map;
1177 2722 : ulong cache_idx = iter_set( vote_stakes, fork_id, iter_kind, &pool, &map );
1178 2722 : *(vacc_map_iter_t *)iter = vacc_map_iter_next( *(vacc_map_iter_t *)iter, map, pool );
1179 2722 : if( cache_idx!=ULONG_MAX ) t_1_unlock( vote_stakes, 0 );
1180 2722 : }
1181 :
1182 : void
1183 : fd_vote_stakes_iter_ele( fd_vote_stakes_t * vote_stakes,
1184 : ulong fork_id,
1185 : int iter_kind,
1186 : fd_vote_stakes_iter_t * iter,
1187 2722 : fd_vote_stakes_ele_t * ele_out ) {
1188 2722 : vacc_t * pool;
1189 2722 : vacc_map_t * map;
1190 2722 : ulong cache_idx = iter_set( vote_stakes, fork_id, iter_kind, &pool, &map );
1191 2722 : vacc_t const * vacc = vacc_map_iter_ele_const( *(vacc_map_iter_t *)iter, map, pool );
1192 2722 : vacc_ele( vacc, ele_out );
1193 2722 : if( iter_kind==FD_VOTE_STAKES_ITER_T_2 ) vacc_ele_state( vote_stakes, fork_id, pool, vacc, ele_out );
1194 2722 : if( cache_idx!=ULONG_MAX ) t_1_unlock( vote_stakes, 0 );
1195 2722 : }
|