Line data Source code
1 : #include "fd_new_votes.h"
2 :
3 : /* Shared pool backing both the root map and per-fork delta dlists. */
4 :
5 : #define POOL_NAME nv_pool
6 1188 : #define POOL_T fd_new_vote_ele_t
7 120 : #define POOL_NEXT next
8 : #define POOL_IDX_T uint
9 : #define POOL_LAZY 1
10 : #include "../../util/tmpl/fd_pool.c"
11 :
12 : #define MAP_NAME nv_map
13 : #define MAP_KEY_T fd_pubkey_t
14 : #define MAP_ELE_T fd_new_vote_ele_t
15 66 : #define MAP_KEY pubkey
16 60 : #define MAP_KEY_EQ(k0,k1) (fd_pubkey_eq( k0, k1 ))
17 222 : #define MAP_KEY_HASH(key,seed) (fd_hash( seed, key, sizeof(fd_pubkey_t) ))
18 123 : #define MAP_NEXT next
19 4695 : #define MAP_IDX_T uint
20 : #include "../../util/tmpl/fd_map_chain.c"
21 :
22 : #define DLIST_NAME nv_dlist
23 : #define DLIST_ELE_T fd_new_vote_ele_t
24 156 : #define DLIST_PREV prev
25 360 : #define DLIST_NEXT next
26 : #define DLIST_IDX_T uint
27 : #include "../../util/tmpl/fd_dlist.c"
28 :
29 : struct nv_fork_pool_ele { ushort next; };
30 : typedef struct nv_fork_pool_ele nv_fork_pool_ele_t;
31 :
32 : #define POOL_NAME nv_fork_pool
33 1188 : #define POOL_T nv_fork_pool_ele_t
34 : #define POOL_IDX_T ushort
35 : #include "../../util/tmpl/fd_pool.c"
36 :
37 : /* Internal accessors */
38 :
39 : static inline fd_new_vote_ele_t *
40 4599 : get_pool( fd_new_votes_t const * new_votes ) {
41 4599 : return fd_type_pun( (uchar *)new_votes + new_votes->pool_offset );
42 4599 : }
43 :
44 : static inline nv_map_t *
45 4104 : get_map( fd_new_votes_t const * new_votes ) {
46 4104 : return fd_type_pun( (uchar *)new_votes + new_votes->map_offset );
47 4104 : }
48 :
49 : static inline nv_fork_pool_ele_t *
50 7473 : get_fork_pool( fd_new_votes_t const * new_votes ) {
51 7473 : return fd_type_pun( (uchar *)new_votes + new_votes->fork_pool_offset );
52 7473 : }
53 :
54 : static inline nv_dlist_t *
55 : get_dlist( fd_new_votes_t const * new_votes,
56 56772 : ushort fork_idx ) {
57 56772 : return fd_type_pun( (uchar *)new_votes + new_votes->dlist_offsets[ fork_idx ] );
58 56772 : }
59 :
60 : ulong
61 4752 : fd_new_votes_align( void ) {
62 4752 : return FD_NEW_VOTES_ALIGN;
63 4752 : }
64 :
65 : ulong
66 : fd_new_votes_footprint( ulong max_vote_accounts,
67 : ulong expected_vote_accounts,
68 2373 : ulong max_live_forks ) {
69 2373 : ulong map_chain_cnt = nv_map_chain_cnt_est( expected_vote_accounts );
70 :
71 2373 : ulong l = FD_LAYOUT_INIT;
72 2373 : l = FD_LAYOUT_APPEND( l, FD_NEW_VOTES_ALIGN, sizeof(fd_new_votes_t) );
73 2373 : l = FD_LAYOUT_APPEND( l, nv_pool_align(), nv_pool_footprint( max_vote_accounts ) );
74 2373 : l = FD_LAYOUT_APPEND( l, nv_map_align(), nv_map_footprint( map_chain_cnt ) );
75 2373 : l = FD_LAYOUT_APPEND( l, nv_fork_pool_align(), nv_fork_pool_footprint( max_live_forks ) );
76 8217 : for( ulong i=0UL; i<max_live_forks; i++ ) {
77 5844 : l = FD_LAYOUT_APPEND( l, nv_dlist_align(), nv_dlist_footprint() );
78 5844 : }
79 2373 : return FD_LAYOUT_FINI( l, FD_NEW_VOTES_ALIGN );
80 2373 : }
81 :
82 : void *
83 : fd_new_votes_new( void * mem,
84 : ulong seed,
85 : ulong max_vote_accounts,
86 : ulong expected_vote_accounts,
87 594 : ulong max_live_forks ) {
88 594 : if( FD_UNLIKELY( !mem ) ) {
89 0 : FD_LOG_WARNING(( "NULL mem" ));
90 0 : return NULL;
91 0 : }
92 :
93 594 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_new_votes_align() ) ) ) {
94 0 : FD_LOG_WARNING(( "misaligned mem" ));
95 0 : return NULL;
96 0 : }
97 :
98 594 : if( FD_UNLIKELY( !max_vote_accounts ) ) {
99 0 : FD_LOG_WARNING(( "max_vote_accounts is 0" ));
100 0 : return NULL;
101 0 : }
102 :
103 594 : if( FD_UNLIKELY( max_live_forks>FD_NEW_VOTES_FORK_MAX ) ) {
104 0 : FD_LOG_WARNING(( "max_live_forks is too large" ));
105 0 : return NULL;
106 0 : }
107 :
108 594 : ulong map_chain_cnt = nv_map_chain_cnt_est( expected_vote_accounts );
109 :
110 594 : FD_SCRATCH_ALLOC_INIT( l, mem );
111 594 : fd_new_votes_t * new_votes = FD_SCRATCH_ALLOC_APPEND( l, FD_NEW_VOTES_ALIGN, sizeof(fd_new_votes_t) );
112 594 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, nv_pool_align(), nv_pool_footprint( max_vote_accounts ) );
113 594 : void * map_mem = FD_SCRATCH_ALLOC_APPEND( l, nv_map_align(), nv_map_footprint( map_chain_cnt ) );
114 594 : void * fpool_mem = FD_SCRATCH_ALLOC_APPEND( l, nv_fork_pool_align(), nv_fork_pool_footprint( max_live_forks ) );
115 2067 : for( ushort i=0; i<(ushort)max_live_forks; i++ ) {
116 1473 : void * dlist_mem = FD_SCRATCH_ALLOC_APPEND( l, nv_dlist_align(), nv_dlist_footprint() );
117 0 : nv_dlist_t * dlist = nv_dlist_join( nv_dlist_new( dlist_mem ) );
118 1473 : if( FD_UNLIKELY( !dlist ) ) {
119 0 : FD_LOG_WARNING(( "Failed to create new votes fork dlist" ));
120 0 : return NULL;
121 0 : }
122 1473 : new_votes->dlist_offsets[ i ] = (ulong)dlist - (ulong)mem;
123 1473 : }
124 :
125 594 : fd_new_vote_ele_t * pool = nv_pool_join( nv_pool_new( pool_mem, max_vote_accounts ) );
126 594 : if( FD_UNLIKELY( !pool ) ) {
127 0 : FD_LOG_WARNING(( "Failed to create new votes pool" ));
128 0 : return NULL;
129 0 : }
130 :
131 594 : nv_map_t * map = nv_map_join( nv_map_new( map_mem, map_chain_cnt, seed ) );
132 594 : if( FD_UNLIKELY( !map ) ) {
133 0 : FD_LOG_WARNING(( "Failed to create new votes map" ));
134 0 : return NULL;
135 0 : }
136 :
137 594 : nv_fork_pool_ele_t * fork_pool = nv_fork_pool_join( nv_fork_pool_new( fpool_mem, max_live_forks ) );
138 594 : if( FD_UNLIKELY( !fork_pool ) ) {
139 0 : FD_LOG_WARNING(( "Failed to create new votes fork pool" ));
140 0 : return NULL;
141 0 : }
142 :
143 594 : new_votes->max_vote_accounts = max_vote_accounts;
144 594 : new_votes->pool_offset = (ulong)pool - (ulong)mem;
145 594 : new_votes->map_offset = (ulong)map - (ulong)mem;
146 594 : new_votes->fork_pool_offset = (ulong)fork_pool - (ulong)mem;
147 :
148 594 : fd_rwlock_new( &new_votes->lock );
149 :
150 594 : FD_COMPILER_MFENCE();
151 594 : FD_VOLATILE( new_votes->magic ) = FD_NEW_VOTES_MAGIC;
152 594 : FD_COMPILER_MFENCE();
153 :
154 594 : return mem;
155 594 : }
156 :
157 : fd_new_votes_t *
158 600 : fd_new_votes_join( void * mem ) {
159 600 : if( FD_UNLIKELY( !mem ) ) {
160 3 : FD_LOG_WARNING(( "NULL mem" ));
161 3 : return NULL;
162 3 : }
163 :
164 597 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_new_votes_align() ) ) ) {
165 0 : FD_LOG_WARNING(( "misaligned mem" ));
166 0 : return NULL;
167 0 : }
168 :
169 597 : fd_new_votes_t * new_votes = (fd_new_votes_t *)mem;
170 :
171 597 : if( FD_UNLIKELY( new_votes->magic!=FD_NEW_VOTES_MAGIC ) ) {
172 0 : FD_LOG_WARNING(( "bad magic" ));
173 0 : return NULL;
174 0 : }
175 :
176 597 : return new_votes;
177 597 : }
178 :
179 : void
180 3492 : fd_new_votes_reset( fd_new_votes_t * new_votes ) {
181 3492 : fd_rwlock_write( &new_votes->lock );
182 :
183 3492 : fd_new_vote_ele_t * pool = get_pool( new_votes );
184 :
185 3492 : nv_fork_pool_ele_t * fork_pool = get_fork_pool( new_votes );
186 3492 : ulong max_forks = nv_fork_pool_max( fork_pool );
187 59364 : for( ulong i=0UL; i<max_forks; i++ ) {
188 55872 : nv_dlist_remove_all( get_dlist( new_votes, (ushort)i ), pool );
189 55872 : }
190 3492 : nv_fork_pool_reset( fork_pool );
191 3492 : nv_pool_reset( pool );
192 3492 : nv_map_reset( get_map( new_votes ) );
193 :
194 3492 : fd_rwlock_unwrite( &new_votes->lock );
195 3492 : }
196 :
197 : void
198 15 : fd_new_votes_reset_root( fd_new_votes_t * new_votes ) {
199 15 : fd_rwlock_write( &new_votes->lock );
200 :
201 15 : fd_new_vote_ele_t * pool = get_pool( new_votes );
202 15 : nv_map_t * map = get_map( new_votes );
203 :
204 : /* We cannot use nv_pool_reset here because the shared pool also
205 : contains elements that belong to fork dlists. Instead we walk
206 : the map and release each element individually. nv_map_iter_next
207 : is called before nv_pool_ele_release so the iterator has already
208 : read ele->next to advance; the subsequent clobber of ele->next
209 : by the pool free-list push is therefore harmless. */
210 15 : nv_map_iter_t iter = nv_map_iter_init( map, pool );
211 18 : while( !nv_map_iter_done( iter, map, pool ) ) {
212 3 : fd_new_vote_ele_t * ele = nv_map_iter_ele( iter, map, pool );
213 3 : iter = nv_map_iter_next( iter, map, pool );
214 3 : nv_pool_ele_release( pool, ele );
215 3 : }
216 15 : nv_map_reset( map );
217 :
218 15 : fd_rwlock_unwrite( &new_votes->lock );
219 15 : }
220 :
221 : void
222 : fd_new_votes_root_insert( fd_new_votes_t * new_votes,
223 6 : fd_pubkey_t const * pubkey ) {
224 6 : fd_rwlock_write( &new_votes->lock );
225 :
226 6 : fd_new_vote_ele_t * pool = get_pool( new_votes );
227 6 : nv_map_t * map = get_map( new_votes );
228 :
229 6 : if( FD_UNLIKELY( nv_map_ele_query( map, pubkey, NULL, pool ) ) ) {
230 3 : fd_rwlock_unwrite( &new_votes->lock );
231 3 : return;
232 3 : }
233 :
234 3 : FD_CRIT( nv_pool_free( pool ), "no free elements in new votes pool" );
235 3 : fd_new_vote_ele_t * ele = nv_pool_ele_acquire( pool );
236 3 : ele->pubkey = *pubkey;
237 3 : ele->is_tombstone = 0;
238 3 : FD_CRIT( nv_map_ele_insert( map, ele, pool ), "unable to insert new vote into root map" );
239 :
240 3 : FD_BASE58_ENCODE_32_BYTES( pubkey->uc, pubkey_out );
241 3 : FD_LOG_DEBUG(( "root_insert: pubkey=%s", pubkey_out ));
242 3 : fd_rwlock_unwrite( &new_votes->lock );
243 3 : }
244 :
245 : ulong
246 108 : fd_new_votes_cnt( fd_new_votes_t const * new_votes ) {
247 108 : fd_rwlock_t * lock = (fd_rwlock_t *)&new_votes->lock;
248 108 : fd_rwlock_read( lock );
249 108 : ulong cnt = nv_pool_used( get_pool( new_votes ) );
250 108 : fd_rwlock_unread( lock );
251 108 : return cnt;
252 108 : }
253 :
254 : ushort
255 3777 : fd_new_votes_new_fork( fd_new_votes_t * new_votes ) {
256 3777 : fd_rwlock_write( &new_votes->lock );
257 :
258 3777 : nv_fork_pool_ele_t * fork_pool = get_fork_pool( new_votes );
259 3777 : FD_CRIT( nv_fork_pool_free( fork_pool ), "no free forks in new votes fork pool" );
260 3777 : ushort fork_idx = (ushort)nv_fork_pool_idx_acquire( fork_pool );
261 :
262 3777 : fd_rwlock_unwrite( &new_votes->lock );
263 3777 : return fork_idx;
264 3777 : }
265 :
266 : void
267 : fd_new_votes_evict_fork( fd_new_votes_t * new_votes,
268 216 : ushort fork_idx ) {
269 216 : if( fork_idx==USHORT_MAX ) return;
270 :
271 204 : fd_rwlock_write( &new_votes->lock );
272 :
273 204 : fd_new_vote_ele_t * pool = get_pool( new_votes );
274 204 : nv_dlist_t * dlist = get_dlist( new_votes, fork_idx );
275 273 : while( !nv_dlist_is_empty( dlist, pool ) ) {
276 69 : fd_new_vote_ele_t * ele = nv_dlist_ele_pop_head( dlist, pool );
277 69 : nv_pool_ele_release( pool, ele );
278 69 : }
279 :
280 204 : nv_fork_pool_idx_release( get_fork_pool( new_votes ), fork_idx );
281 :
282 204 : fd_rwlock_unwrite( &new_votes->lock );
283 204 : }
284 :
285 : void
286 : fd_new_votes_insert( fd_new_votes_t * new_votes,
287 : ushort fork_idx,
288 129 : fd_pubkey_t const * pubkey ) {
289 129 : fd_rwlock_write( &new_votes->lock );
290 :
291 129 : fd_new_vote_ele_t * pool = get_pool( new_votes );
292 129 : nv_dlist_t * dlist = get_dlist( new_votes, fork_idx );
293 :
294 129 : FD_CRIT( nv_pool_free( pool ), "no free elements in new votes pool" );
295 129 : fd_new_vote_ele_t * ele = nv_pool_ele_acquire( pool );
296 129 : ele->pubkey = *pubkey;
297 129 : ele->is_tombstone = 0;
298 129 : nv_dlist_ele_push_tail( dlist, ele, pool );
299 :
300 129 : FD_BASE58_ENCODE_32_BYTES( pubkey->uc, pubkey_out );
301 129 : FD_LOG_DEBUG(( "insert: pubkey=%s", pubkey_out ));
302 129 : fd_rwlock_unwrite( &new_votes->lock );
303 129 : }
304 :
305 : void
306 : fd_new_votes_remove( fd_new_votes_t * new_votes,
307 : ushort fork_idx,
308 27 : fd_pubkey_t const * pubkey ) {
309 27 : fd_rwlock_write( &new_votes->lock );
310 :
311 27 : fd_new_vote_ele_t * pool = get_pool( new_votes );
312 27 : nv_dlist_t * dlist = get_dlist( new_votes, fork_idx );
313 :
314 27 : FD_CRIT( nv_pool_free( pool ), "no free elements in new votes pool" );
315 27 : fd_new_vote_ele_t * ele = nv_pool_ele_acquire( pool );
316 27 : ele->pubkey = *pubkey;
317 27 : ele->is_tombstone = 1;
318 27 : nv_dlist_ele_push_tail( dlist, ele, pool );
319 :
320 27 : FD_BASE58_ENCODE_32_BYTES( pubkey->uc, pubkey_out );
321 27 : FD_LOG_DEBUG(( "remove: pubkey=%s", pubkey_out ));
322 27 : fd_rwlock_unwrite( &new_votes->lock );
323 27 : }
324 :
325 : void
326 : fd_new_votes_apply_delta( fd_new_votes_t * new_votes,
327 138 : ushort fork_idx ) {
328 138 : if( fork_idx==USHORT_MAX ) return;
329 :
330 135 : fd_rwlock_write( &new_votes->lock );
331 :
332 135 : fd_new_vote_ele_t * pool = get_pool( new_votes );
333 135 : nv_map_t * map = get_map( new_votes );
334 135 : nv_dlist_t * dlist = get_dlist( new_votes, fork_idx );
335 :
336 222 : while( !nv_dlist_is_empty( dlist, pool ) ) {
337 87 : fd_new_vote_ele_t * ele = nv_dlist_ele_pop_head( dlist, pool );
338 87 : if( ele->is_tombstone ) {
339 : /* If the element is a tombstone, remove it from the root map if
340 : it exists and free both the root map element and the tombstone
341 : element. If the element doesn't exist in the root, just free
342 : the tombstone. */
343 18 : if( FD_UNLIKELY( nv_map_ele_query( map, &ele->pubkey, NULL, pool ) ) ) {
344 15 : fd_new_vote_ele_t * root_ele = nv_map_ele_remove( map, &ele->pubkey, NULL, pool );
345 15 : nv_pool_ele_release( pool, root_ele );
346 15 : nv_pool_ele_release( pool, ele );
347 15 : } else {
348 3 : nv_pool_ele_release( pool, ele );
349 3 : }
350 69 : } else {
351 : /* If the element is not a tombstone, insert it into the root map
352 : if it doesn't exist in the root and just transfer pool element
353 : ownership: otherwise, just free the pool_element. */
354 69 : if( FD_UNLIKELY( nv_map_ele_query( map, &ele->pubkey, NULL, pool ) ) ) {
355 6 : nv_pool_ele_release( pool, ele );
356 63 : } else {
357 63 : nv_map_ele_insert( map, ele, pool );
358 63 : }
359 69 : }
360 87 : }
361 135 : fd_rwlock_unwrite( &new_votes->lock );
362 135 : }
363 :
364 : /* Iterator internals. Phase 0 walks the root map; phase 1 walks
365 : each fork dlist in order, skipping pubkeys already in the root map. */
366 :
367 : struct fd_new_votes_iter {
368 : fd_new_votes_t * new_votes;
369 : ushort const * fork_idxs;
370 : ulong fork_idx_cnt;
371 : ulong fork_pos; /* current position in fork_idxs (phase 1) */
372 : nv_map_iter_t map_iter; /* 16 bytes */
373 : nv_dlist_iter_t dlist_iter; /* 8 bytes */
374 : int phase; /* 0 = root map, 1 = fork dlists, 2 done */
375 : };
376 :
377 : FD_STATIC_ASSERT( sizeof(struct fd_new_votes_iter)<=FD_NEW_VOTES_ITER_FOOTPRINT, fd_new_votes_iter_footprint );
378 : FD_STATIC_ASSERT( alignof(struct fd_new_votes_iter)<=FD_NEW_VOTES_ITER_ALIGN, fd_new_votes_iter_align );
379 :
380 : static void
381 183 : iter_advance_dlist( fd_new_votes_iter_t * it ) {
382 183 : fd_new_vote_ele_t * pool = get_pool( it->new_votes );
383 183 : nv_map_t * map = get_map( it->new_votes );
384 :
385 189 : for(;;) {
386 189 : nv_dlist_t * dlist = get_dlist( it->new_votes, it->fork_idxs[ it->fork_pos ] );
387 :
388 210 : while( !nv_dlist_iter_done( it->dlist_iter, dlist, pool ) ) {
389 48 : fd_new_vote_ele_t const * ele = nv_dlist_iter_ele_const( it->dlist_iter, dlist, pool );
390 48 : if( FD_LIKELY( !nv_map_ele_query( map, &ele->pubkey, NULL, pool ) ) ) return;
391 21 : it->dlist_iter = nv_dlist_iter_fwd_next( it->dlist_iter, dlist, pool );
392 21 : }
393 :
394 162 : it->fork_pos++;
395 162 : if( it->fork_pos>=it->fork_idx_cnt ) {
396 156 : it->phase = 2;
397 156 : return;
398 156 : }
399 6 : dlist = get_dlist( it->new_votes, it->fork_idxs[ it->fork_pos ] );
400 6 : it->dlist_iter = nv_dlist_iter_fwd_init( dlist, pool );
401 6 : }
402 183 : }
403 :
404 : fd_new_votes_iter_t *
405 : fd_new_votes_iter_init( fd_new_votes_t * new_votes,
406 : ushort const * fork_idxs,
407 : ulong fork_idx_cnt,
408 174 : uchar * iter_mem ) {
409 174 : fd_new_votes_iter_t * it = (fd_new_votes_iter_t *)iter_mem;
410 :
411 174 : fd_rwlock_read( &new_votes->lock );
412 :
413 174 : it->new_votes = new_votes;
414 174 : it->fork_idxs = fork_idxs;
415 174 : it->fork_idx_cnt = fork_idx_cnt;
416 :
417 174 : fd_new_vote_ele_t * pool = get_pool( new_votes );
418 174 : nv_map_t * map = get_map( new_votes );
419 :
420 174 : it->map_iter = nv_map_iter_init( map, pool );
421 :
422 174 : if( !nv_map_iter_done( it->map_iter, map, pool ) ) {
423 30 : it->phase = 0;
424 30 : return it;
425 30 : }
426 :
427 144 : if( fork_idx_cnt>0UL ) {
428 141 : it->phase = 1;
429 141 : it->fork_pos = 0UL;
430 141 : nv_dlist_t * dlist = get_dlist( new_votes, fork_idxs[0] );
431 141 : it->dlist_iter = nv_dlist_iter_fwd_init( dlist, pool );
432 141 : iter_advance_dlist( it );
433 141 : } else {
434 3 : it->phase = 2;
435 3 : }
436 :
437 144 : return it;
438 174 : }
439 :
440 : int
441 240 : fd_new_votes_iter_done( fd_new_votes_iter_t const * iter ) {
442 240 : return iter->phase==2;
443 240 : }
444 :
445 : void
446 66 : fd_new_votes_iter_next( fd_new_votes_iter_t * it ) {
447 66 : fd_new_vote_ele_t * pool = get_pool( it->new_votes );
448 66 : nv_map_t * map = get_map( it->new_votes );
449 :
450 66 : if( it->phase==0 ) {
451 39 : it->map_iter = nv_map_iter_next( it->map_iter, map, pool );
452 39 : if( !nv_map_iter_done( it->map_iter, map, pool ) ) return;
453 :
454 30 : if( it->fork_idx_cnt>0UL ) {
455 15 : it->phase = 1;
456 15 : it->fork_pos = 0UL;
457 15 : nv_dlist_t * dlist = get_dlist( it->new_votes, it->fork_idxs[0] );
458 15 : it->dlist_iter = nv_dlist_iter_fwd_init( dlist, pool );
459 15 : iter_advance_dlist( it );
460 15 : } else {
461 15 : it->phase = 2;
462 15 : }
463 30 : return;
464 39 : }
465 :
466 27 : if( it->phase==1 ) {
467 27 : nv_dlist_t * dlist = get_dlist( it->new_votes, it->fork_idxs[ it->fork_pos ] );
468 27 : it->dlist_iter = nv_dlist_iter_fwd_next( it->dlist_iter, dlist, pool );
469 27 : iter_advance_dlist( it );
470 27 : }
471 27 : }
472 :
473 : fd_pubkey_t const *
474 : fd_new_votes_iter_ele( fd_new_votes_iter_t const * it,
475 60 : int * is_tombstone ) {
476 60 : fd_new_vote_ele_t * pool = get_pool( it->new_votes );
477 :
478 60 : if( it->phase==0 ) {
479 33 : nv_map_t * map = get_map( it->new_votes );
480 33 : fd_new_vote_ele_t const * ele = nv_map_iter_ele_const( it->map_iter, map, pool );
481 33 : *is_tombstone = 0;
482 33 : return &ele->pubkey;
483 33 : }
484 :
485 27 : nv_dlist_t * dlist = get_dlist( it->new_votes, it->fork_idxs[ it->fork_pos ] );
486 27 : fd_new_vote_ele_t const * ele = nv_dlist_iter_ele_const( it->dlist_iter, dlist, pool );
487 27 : *is_tombstone = ele->is_tombstone;
488 27 : return &ele->pubkey;
489 60 : }
490 :
491 : void
492 174 : fd_new_votes_iter_fini( fd_new_votes_iter_t * it ) {
493 174 : fd_rwlock_unread( &it->new_votes->lock );
494 174 : }
|