LCOV - code coverage report
Current view: top level - flamenco/stakes - fd_new_votes.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 286 317 90.2 %
Date: 2026-05-15 07:18:56 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        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 : }

Generated by: LCOV version 1.14