LCOV - code coverage report
Current view: top level - flamenco/stakes - fd_new_votes.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 287 317 90.5 %
Date: 2026-08-04 05:20:02 Functions: 23 23 100.0 %

          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         228 : #define POOL_T     fd_new_vote_ele_t
       7         132 : #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          78 : #define MAP_KEY                pubkey
      16          66 : #define MAP_KEY_EQ(k0,k1)      (fd_pubkey_eq( k0, k1 ))
      17         252 : #define MAP_KEY_HASH(key,seed) (fd_hash( seed, key, sizeof(fd_pubkey_t) ))
      18         144 : #define MAP_NEXT               next
      19        4974 : #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         183 : #define DLIST_PREV  prev
      25         396 : #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         228 : #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        6510 : get_pool( fd_new_votes_t const * new_votes ) {
      41        6510 :   return fd_type_pun( (uchar *)new_votes + new_votes->pool_offset );
      42        6510 : }
      43             : 
      44             : static inline nv_map_t *
      45        5421 : get_map( fd_new_votes_t const * new_votes ) {
      46        5421 :   return fd_type_pun( (uchar *)new_votes + new_votes->map_offset );
      47        5421 : }
      48             : 
      49             : static inline nv_fork_pool_ele_t *
      50        9522 : get_fork_pool( fd_new_votes_t const * new_votes ) {
      51        9522 :   return fd_type_pun( (uchar *)new_votes + new_votes->fork_pool_offset );
      52        9522 : }
      53             : 
      54             : static inline nv_dlist_t *
      55             : get_dlist( fd_new_votes_t const * new_votes,
      56       65307 :            ushort                 fork_idx ) {
      57       65307 :   return fd_type_pun( (uchar *)new_votes + new_votes->dlist_offsets[ fork_idx ] );
      58       65307 : }
      59             : 
      60             : ulong
      61         942 : fd_new_votes_align( void ) {
      62         942 :   return FD_NEW_VOTES_ALIGN;
      63         942 : }
      64             : 
      65             : ulong
      66             : fd_new_votes_footprint( ulong max_vote_accounts,
      67             :                         ulong expected_vote_accounts,
      68         468 :                         ulong max_live_forks ) {
      69         468 :   ulong map_chain_cnt = nv_map_chain_cnt_est( expected_vote_accounts );
      70             : 
      71         468 :   ulong l = FD_LAYOUT_INIT;
      72         468 :   l = FD_LAYOUT_APPEND( l, FD_NEW_VOTES_ALIGN,    sizeof(fd_new_votes_t) );
      73         468 :   l = FD_LAYOUT_APPEND( l, nv_pool_align(),        nv_pool_footprint( max_vote_accounts ) );
      74         468 :   l = FD_LAYOUT_APPEND( l, nv_map_align(),         nv_map_footprint( map_chain_cnt ) );
      75         468 :   l = FD_LAYOUT_APPEND( l, nv_fork_pool_align(),   nv_fork_pool_footprint( max_live_forks ) );
      76        7836 :   for( ulong i=0UL; i<max_live_forks; i++ ) {
      77        7368 :     l = FD_LAYOUT_APPEND( l, nv_dlist_align(), nv_dlist_footprint() );
      78        7368 :   }
      79         468 :   return FD_LAYOUT_FINI( l, FD_NEW_VOTES_ALIGN );
      80         468 : }
      81             : 
      82             : void *
      83             : fd_new_votes_new( void * mem,
      84             :                   ulong  seed,
      85             :                   ulong  max_vote_accounts,
      86             :                   ulong  expected_vote_accounts,
      87         114 :                   ulong  max_live_forks ) {
      88         114 :   if( FD_UNLIKELY( !mem ) ) {
      89           0 :     FD_LOG_WARNING(( "NULL mem" ));
      90           0 :     return NULL;
      91           0 :   }
      92             : 
      93         114 :   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         114 :   if( FD_UNLIKELY( !max_vote_accounts ) ) {
      99           0 :     FD_LOG_WARNING(( "max_vote_accounts is 0" ));
     100           0 :     return NULL;
     101           0 :   }
     102             : 
     103         114 :   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         114 :   ulong map_chain_cnt = nv_map_chain_cnt_est( expected_vote_accounts );
     109             : 
     110         114 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     111         114 :   fd_new_votes_t * new_votes = FD_SCRATCH_ALLOC_APPEND( l, FD_NEW_VOTES_ALIGN,    sizeof(fd_new_votes_t) );
     112         114 :   void *           pool_mem  = FD_SCRATCH_ALLOC_APPEND( l, nv_pool_align(),        nv_pool_footprint( max_vote_accounts ) );
     113         114 :   void *           map_mem   = FD_SCRATCH_ALLOC_APPEND( l, nv_map_align(),         nv_map_footprint( map_chain_cnt ) );
     114         114 :   void *           fpool_mem = FD_SCRATCH_ALLOC_APPEND( l, nv_fork_pool_align(),   nv_fork_pool_footprint( max_live_forks ) );
     115        1863 :   for( ushort i=0; i<(ushort)max_live_forks; i++ ) {
     116        1749 :     void *       dlist_mem = FD_SCRATCH_ALLOC_APPEND( l, nv_dlist_align(), nv_dlist_footprint() );
     117        1749 :     nv_dlist_t * dlist     = nv_dlist_join( nv_dlist_new( dlist_mem ) );
     118        1749 :     if( FD_UNLIKELY( !dlist ) ) {
     119           0 :       FD_LOG_WARNING(( "Failed to create new votes fork dlist" ));
     120           0 :       return NULL;
     121           0 :     }
     122        1749 :     new_votes->dlist_offsets[ i ] = (ulong)dlist - (ulong)mem;
     123        1749 :   }
     124             : 
     125         114 :   fd_new_vote_ele_t * pool = nv_pool_join( nv_pool_new( pool_mem, max_vote_accounts ) );
     126         114 :   if( FD_UNLIKELY( !pool ) ) {
     127           0 :     FD_LOG_WARNING(( "Failed to create new votes pool" ));
     128           0 :     return NULL;
     129           0 :   }
     130             : 
     131         114 :   nv_map_t * map = nv_map_join( nv_map_new( map_mem, map_chain_cnt, seed ) );
     132         114 :   if( FD_UNLIKELY( !map ) ) {
     133           0 :     FD_LOG_WARNING(( "Failed to create new votes map" ));
     134           0 :     return NULL;
     135           0 :   }
     136             : 
     137         114 :   nv_fork_pool_ele_t * fork_pool = nv_fork_pool_join( nv_fork_pool_new( fpool_mem, max_live_forks ) );
     138         114 :   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         114 :   new_votes->max_vote_accounts = max_vote_accounts;
     144         114 :   new_votes->pool_offset       = (ulong)pool      - (ulong)mem;
     145         114 :   new_votes->map_offset        = (ulong)map       - (ulong)mem;
     146         114 :   new_votes->fork_pool_offset  = (ulong)fork_pool - (ulong)mem;
     147             : 
     148         114 :   fd_rwlock_new( &new_votes->lock );
     149             : 
     150         114 :   FD_COMPILER_MFENCE();
     151         114 :   FD_VOLATILE( new_votes->magic ) = FD_NEW_VOTES_MAGIC;
     152         114 :   FD_COMPILER_MFENCE();
     153             : 
     154         114 :   return mem;
     155         114 : }
     156             : 
     157             : fd_new_votes_t *
     158         120 : fd_new_votes_join( void * mem ) {
     159         120 :   if( FD_UNLIKELY( !mem ) ) {
     160           3 :     FD_LOG_WARNING(( "NULL mem" ));
     161           3 :     return NULL;
     162           3 :   }
     163             : 
     164         117 :   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         117 :   fd_new_votes_t * new_votes = (fd_new_votes_t *)mem;
     170             : 
     171         117 :   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         117 :   return new_votes;
     177         117 : }
     178             : 
     179             : void
     180        3942 : fd_new_votes_reset( fd_new_votes_t * new_votes ) {
     181        3942 :   fd_rwlock_write( &new_votes->lock );
     182             : 
     183        3942 :   fd_new_vote_ele_t * pool = get_pool( new_votes );
     184             : 
     185        3942 :   nv_fork_pool_ele_t * fork_pool = get_fork_pool( new_votes );
     186        3942 :   ulong max_forks = nv_fork_pool_max( fork_pool );
     187       66978 :   for( ulong i=0UL; i<max_forks; i++ ) {
     188       63036 :     nv_dlist_remove_all( get_dlist( new_votes, (ushort)i ), pool );
     189       63036 :   }
     190        3942 :   nv_fork_pool_reset( fork_pool );
     191        3942 :   nv_pool_reset( pool );
     192        3942 :   nv_map_reset( get_map( new_votes ) );
     193             : 
     194        3942 :   fd_rwlock_unwrite( &new_votes->lock );
     195        3942 : }
     196             : 
     197             : void
     198          81 : fd_new_votes_reset_root( fd_new_votes_t * new_votes ) {
     199          81 :   fd_rwlock_write( &new_votes->lock );
     200             : 
     201          81 :   fd_new_vote_ele_t * pool = get_pool( new_votes );
     202          81 :   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          81 :   nv_map_iter_t iter = nv_map_iter_init( map, pool );
     211          87 :   while( !nv_map_iter_done( iter, map, pool ) ) {
     212           6 :     fd_new_vote_ele_t * ele = nv_map_iter_ele( iter, map, pool );
     213           6 :     iter = nv_map_iter_next( iter, map, pool );
     214           6 :     nv_pool_ele_release( pool, ele );
     215           6 :   }
     216          81 :   nv_map_reset( map );
     217             : 
     218          81 :   fd_rwlock_unwrite( &new_votes->lock );
     219          81 : }
     220             : 
     221             : void
     222             : fd_new_votes_root_insert( fd_new_votes_t *    new_votes,
     223          12 :                           fd_pubkey_t const * pubkey ) {
     224          12 :   fd_rwlock_write( &new_votes->lock );
     225             : 
     226          12 :   fd_new_vote_ele_t * pool = get_pool( new_votes );
     227          12 :   nv_map_t *          map  = get_map( new_votes );
     228             : 
     229          12 :   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           9 :   FD_CHECK_CRIT( nv_pool_free( pool ), "no free elements in new votes pool" );
     235           9 :   fd_new_vote_ele_t * ele = nv_pool_ele_acquire( pool );
     236           9 :   ele->pubkey       = *pubkey;
     237           9 :   ele->is_tombstone = 0;
     238           9 :   FD_CHECK_CRIT( nv_map_ele_insert( map, ele, pool ), "unable to insert new vote into root map" );
     239             : 
     240           9 :   FD_BASE58_ENCODE_32_BYTES( pubkey->uc, pubkey_out );
     241           9 :   FD_LOG_DEBUG(( "root_insert: pubkey=%s", pubkey_out ));
     242           9 :   fd_rwlock_unwrite( &new_votes->lock );
     243           9 : }
     244             : 
     245             : ulong
     246         114 : fd_new_votes_cnt( fd_new_votes_t const * new_votes ) {
     247         114 :   fd_rwlock_t * lock = (fd_rwlock_t *)&new_votes->lock;
     248         114 :   fd_rwlock_read( lock );
     249         114 :   ulong cnt = nv_pool_used( get_pool( new_votes ) );
     250         114 :   fd_rwlock_unread( lock );
     251         114 :   return cnt;
     252         114 : }
     253             : 
     254             : ushort
     255        4815 : fd_new_votes_new_fork( fd_new_votes_t * new_votes ) {
     256        4815 :   fd_rwlock_write( &new_votes->lock );
     257             : 
     258        4815 :   nv_fork_pool_ele_t * fork_pool = get_fork_pool( new_votes );
     259        4815 :   FD_CHECK_CRIT( nv_fork_pool_free( fork_pool ), "no free forks in new votes fork pool" );
     260        4815 :   ushort fork_idx = (ushort)nv_fork_pool_idx_acquire( fork_pool );
     261             : 
     262        4815 :   fd_rwlock_unwrite( &new_votes->lock );
     263        4815 :   return fork_idx;
     264        4815 : }
     265             : 
     266             : void
     267             : fd_new_votes_evict_fork( fd_new_votes_t * new_votes,
     268         777 :                          ushort           fork_idx ) {
     269         777 :   if( fork_idx==USHORT_MAX ) return;
     270             : 
     271         765 :   fd_rwlock_write( &new_votes->lock );
     272             : 
     273         765 :   fd_new_vote_ele_t * pool  = get_pool( new_votes );
     274         765 :   nv_dlist_t *        dlist = get_dlist( new_votes, fork_idx );
     275         834 :   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         765 :   nv_fork_pool_idx_release( get_fork_pool( new_votes ), fork_idx );
     281             : 
     282         765 :   fd_rwlock_unwrite( &new_votes->lock );
     283         765 : }
     284             : 
     285             : void
     286             : fd_new_votes_insert( fd_new_votes_t *    new_votes,
     287             :                      ushort              fork_idx,
     288         153 :                      fd_pubkey_t const * pubkey ) {
     289         153 :   fd_rwlock_write( &new_votes->lock );
     290             : 
     291         153 :   fd_new_vote_ele_t * pool  = get_pool( new_votes );
     292         153 :   nv_dlist_t *        dlist = get_dlist( new_votes, fork_idx );
     293             : 
     294         153 :   FD_CHECK_CRIT( nv_pool_free( pool ), "no free elements in new votes pool" );
     295         153 :   fd_new_vote_ele_t * ele = nv_pool_ele_acquire( pool );
     296         153 :   ele->pubkey       = *pubkey;
     297         153 :   ele->is_tombstone = 0;
     298         153 :   nv_dlist_ele_push_tail( dlist, ele, pool );
     299             : 
     300         153 :   FD_BASE58_ENCODE_32_BYTES( pubkey->uc, pubkey_out );
     301         153 :   FD_LOG_DEBUG(( "insert: pubkey=%s", pubkey_out ));
     302         153 :   fd_rwlock_unwrite( &new_votes->lock );
     303         153 : }
     304             : 
     305             : void
     306             : fd_new_votes_remove( fd_new_votes_t *    new_votes,
     307             :                      ushort              fork_idx,
     308          30 :                      fd_pubkey_t const * pubkey ) {
     309          30 :   fd_rwlock_write( &new_votes->lock );
     310             : 
     311          30 :   fd_new_vote_ele_t * pool  = get_pool( new_votes );
     312          30 :   nv_dlist_t *        dlist = get_dlist( new_votes, fork_idx );
     313             : 
     314          30 :   FD_CHECK_CRIT( nv_pool_free( pool ), "no free elements in new votes pool" );
     315          30 :   fd_new_vote_ele_t * ele = nv_pool_ele_acquire( pool );
     316          30 :   ele->pubkey       = *pubkey;
     317          30 :   ele->is_tombstone = 1;
     318          30 :   nv_dlist_ele_push_tail( dlist, ele, pool );
     319             : 
     320          30 :   FD_BASE58_ENCODE_32_BYTES( pubkey->uc, pubkey_out );
     321          30 :   FD_LOG_DEBUG(( "remove: pubkey=%s", pubkey_out ));
     322          30 :   fd_rwlock_unwrite( &new_votes->lock );
     323          30 : }
     324             : 
     325             : void
     326             : fd_new_votes_apply_delta( fd_new_votes_t * new_votes,
     327         684 :                           ushort           fork_idx ) {
     328         684 :   if( fork_idx==USHORT_MAX ) return;
     329             : 
     330         678 :   fd_rwlock_write( &new_votes->lock );
     331             : 
     332         678 :   fd_new_vote_ele_t * pool  = get_pool( new_votes );
     333         678 :   nv_map_t *          map   = get_map( new_votes );
     334         678 :   nv_dlist_t *        dlist = get_dlist( new_votes, fork_idx );
     335             : 
     336         774 :   while( !nv_dlist_is_empty( dlist, pool ) ) {
     337          96 :     fd_new_vote_ele_t * ele = nv_dlist_ele_pop_head( dlist, pool );
     338          96 :     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          21 :       if( FD_UNLIKELY( nv_map_ele_query( map, &ele->pubkey, NULL, pool ) ) ) {
     344          18 :         fd_new_vote_ele_t * root_ele = nv_map_ele_remove( map, &ele->pubkey, NULL, pool );
     345          18 :         nv_pool_ele_release( pool, root_ele );
     346          18 :         nv_pool_ele_release( pool, ele );
     347          18 :       } else {
     348           3 :         nv_pool_ele_release( pool, ele );
     349           3 :       }
     350          75 :     } 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          75 :       if( FD_UNLIKELY( nv_map_ele_query( map, &ele->pubkey, NULL, pool ) ) ) {
     355           6 :         nv_pool_ele_release( pool, ele );
     356          69 :       } else {
     357          69 :         nv_map_ele_insert( map, ele, pool );
     358          69 :       }
     359          75 :     }
     360          96 :   }
     361         678 :   fd_rwlock_unwrite( &new_votes->lock );
     362         678 : }
     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         300 : iter_advance_dlist( fd_new_votes_iter_t * it ) {
     382         300 :   fd_new_vote_ele_t * pool = get_pool( it->new_votes );
     383         300 :   nv_map_t *          map  = get_map( it->new_votes );
     384             : 
     385         309 :   for(;;) {
     386         309 :     nv_dlist_t * dlist = get_dlist( it->new_votes, it->fork_idxs[ it->fork_pos ] );
     387             : 
     388         330 :     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         282 :     it->fork_pos++;
     395         282 :     if( it->fork_pos>=it->fork_idx_cnt ) {
     396         273 :       it->phase = 2;
     397         273 :       return;
     398         273 :     }
     399           9 :     dlist = get_dlist( it->new_votes, it->fork_idxs[ it->fork_pos ] );
     400           9 :     it->dlist_iter = nv_dlist_iter_fwd_init( dlist, pool );
     401           9 :   }
     402         300 : }
     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         300 :                         uchar *          iter_mem ) {
     409         300 :   fd_new_votes_iter_t * it = (fd_new_votes_iter_t *)iter_mem;
     410             : 
     411         300 :   fd_rwlock_read( &new_votes->lock );
     412             : 
     413         300 :   it->new_votes    = new_votes;
     414         300 :   it->fork_idxs    = fork_idxs;
     415         300 :   it->fork_idx_cnt = fork_idx_cnt;
     416             : 
     417         300 :   fd_new_vote_ele_t * pool = get_pool( new_votes );
     418         300 :   nv_map_t *          map  = get_map( new_votes );
     419             : 
     420         300 :   it->map_iter = nv_map_iter_init( map, pool );
     421             : 
     422         300 :   if( !nv_map_iter_done( it->map_iter, map, pool ) ) {
     423          36 :     it->phase = 0;
     424          36 :     return it;
     425          36 :   }
     426             : 
     427         264 :   if( fork_idx_cnt>0UL ) {
     428         258 :     it->phase      = 1;
     429         258 :     it->fork_pos   = 0UL;
     430         258 :     nv_dlist_t * dlist = get_dlist( new_votes, fork_idxs[0] );
     431         258 :     it->dlist_iter = nv_dlist_iter_fwd_init( dlist, pool );
     432         258 :     iter_advance_dlist( it );
     433         258 :   } else {
     434           6 :     it->phase = 2;
     435           6 :   }
     436             : 
     437         264 :   return it;
     438         300 : }
     439             : 
     440             : int
     441         369 : fd_new_votes_iter_done( fd_new_votes_iter_t const * iter ) {
     442         369 :   return iter->phase==2;
     443         369 : }
     444             : 
     445             : void
     446          69 : fd_new_votes_iter_next( fd_new_votes_iter_t * it ) {
     447          69 :   fd_new_vote_ele_t * pool = get_pool( it->new_votes );
     448          69 :   nv_map_t *          map  = get_map( it->new_votes );
     449             : 
     450          69 :   if( it->phase==0 ) {
     451          42 :     it->map_iter = nv_map_iter_next( it->map_iter, map, pool );
     452          42 :     if( !nv_map_iter_done( it->map_iter, map, pool ) ) return;
     453             : 
     454          33 :     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          18 :     } else {
     461          18 :       it->phase = 2;
     462          18 :     }
     463          33 :     return;
     464          42 :   }
     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          66 :                        int *                       is_tombstone ) {
     476          66 :   fd_new_vote_ele_t * pool = get_pool( it->new_votes );
     477             : 
     478          66 :   if( it->phase==0 ) {
     479          39 :     nv_map_t * map = get_map( it->new_votes );
     480          39 :     fd_new_vote_ele_t const * ele = nv_map_iter_ele_const( it->map_iter, map, pool );
     481          39 :     *is_tombstone = 0;
     482          39 :     return &ele->pubkey;
     483          39 :   }
     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          66 : }
     490             : 
     491             : void
     492         300 : fd_new_votes_iter_fini( fd_new_votes_iter_t * it ) {
     493         300 :   fd_rwlock_unread( &it->new_votes->lock );
     494         300 : }

Generated by: LCOV version 1.14