LCOV - code coverage report
Current view: top level - flamenco/stakes - fd_vote_stakes.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 329 396 83.1 %
Date: 2026-05-15 07:18:56 Functions: 22 23 95.7 %

          Line data    Source code
       1             : #include "fd_vote_stakes.h"
       2             : #include "fd_vote_stakes_private.h"
       3             : 
       4             : ulong
       5       14247 : fd_vote_stakes_align( void ) {
       6       14247 :   return FD_VOTE_STAKES_ALIGN;
       7       14247 : }
       8             : 
       9             : ulong
      10             : fd_vote_stakes_footprint( ulong max_vote_accounts,
      11             :                           ulong expected_vote_accounts,
      12        2373 :                           ulong max_fork_width ) {
      13        2373 :   ulong map_chain_cnt = index_map_chain_cnt_est( expected_vote_accounts );
      14             : 
      15        2373 :   ulong l = FD_LAYOUT_INIT;
      16        2373 :   l = FD_LAYOUT_APPEND( l, fd_vote_stakes_align(),  sizeof(fd_vote_stakes_t) );
      17        2373 :   l = FD_LAYOUT_APPEND( l, index_pool_align(),      index_pool_footprint( max_vote_accounts * 2UL ) );
      18        2373 :   l = FD_LAYOUT_APPEND( l, index_map_align(),       index_map_footprint( map_chain_cnt ) );
      19        2373 :   l = FD_LAYOUT_APPEND( l, index_map_multi_align(), index_map_multi_footprint( map_chain_cnt ) );
      20        2373 :   l = FD_LAYOUT_APPEND( l, fork_pool_align(),       fork_pool_footprint( max_fork_width ) );
      21        2373 :   l = FD_LAYOUT_APPEND( l, fork_dlist_align(),      fork_dlist_footprint() );
      22        5589 :   for( ulong i=0; i<max_fork_width; i++ ) {
      23        3216 :     l = FD_LAYOUT_APPEND( l, stakes_pool_align(), stakes_pool_footprint( max_vote_accounts ) );
      24        3216 :     l = FD_LAYOUT_APPEND( l, stakes_map_align(),  stakes_map_footprint( map_chain_cnt ) );
      25        3216 :   }
      26        2373 :   return FD_LAYOUT_FINI( l, fd_vote_stakes_align() );
      27        2373 : }
      28             : 
      29             : void *
      30             : fd_vote_stakes_new( void * shmem,
      31             :                     ulong  max_vote_accounts,
      32             :                     ulong  expected_vote_accounts,
      33             :                     ulong  max_fork_width,
      34         597 :                     ulong  seed ) {
      35         597 :   if( FD_UNLIKELY( !shmem ) ) {
      36           0 :     FD_LOG_WARNING(( "NULL mem" ));
      37           0 :     return NULL;
      38           0 :   }
      39             : 
      40         597 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_vote_stakes_align() ) ) ) {
      41           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      42           0 :     return NULL;
      43           0 :   }
      44             : 
      45         597 :   if( FD_UNLIKELY( max_fork_width>MAX_FORK_WIDTH ) ) {
      46           0 :     FD_LOG_WARNING(( "max_fork_width is too large" ));
      47           0 :     return NULL;
      48           0 :   }
      49             : 
      50         597 :   ulong map_chain_cnt = index_map_chain_cnt_est( expected_vote_accounts );
      51             : 
      52         597 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      53         597 :   fd_vote_stakes_t * vote_stakes         = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_stakes_align(),  sizeof(fd_vote_stakes_t) );
      54         597 :   void *             index_pool_mem      = FD_SCRATCH_ALLOC_APPEND( l, index_pool_align(),      index_pool_footprint( max_vote_accounts * 2UL ) );
      55         597 :   void *             index_map_mem       = FD_SCRATCH_ALLOC_APPEND( l, index_map_align(),       index_map_footprint( map_chain_cnt ) );
      56         597 :   void *             index_map_multi_mem = FD_SCRATCH_ALLOC_APPEND( l, index_map_multi_align(), index_map_multi_footprint( map_chain_cnt ) );
      57         597 :   void *             fork_pool_mem       = FD_SCRATCH_ALLOC_APPEND( l, fork_pool_align(),       fork_pool_footprint( max_fork_width ) );
      58         597 :   void *             fork_dlist_mem      = FD_SCRATCH_ALLOC_APPEND( l, fork_dlist_align(),      fork_dlist_footprint() );
      59        1446 :   for( ulong i=0; i<max_fork_width; i++ ) {
      60         849 :     void *    stakes_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, stakes_pool_align(), stakes_pool_footprint( max_vote_accounts ) );
      61           0 :     stake_t * stakes_pool     = stakes_pool_join( stakes_pool_new( stakes_pool_mem, max_vote_accounts ) );
      62         849 :     if( FD_UNLIKELY( !stakes_pool ) ) {
      63           0 :       FD_LOG_WARNING(( "Failed to create vote stakes ele pool" ));
      64           0 :       return NULL;
      65           0 :     }
      66         849 :     vote_stakes->stakes_pool_off[ i ] = (ulong)stakes_pool - (ulong)shmem;
      67             : 
      68         849 :     void * stakes_map_mem = FD_SCRATCH_ALLOC_APPEND( l, stakes_map_align(), stakes_map_footprint( map_chain_cnt ) );
      69           0 :     stakes_map_t * stakes_map = stakes_map_join( stakes_map_new( stakes_map_mem, map_chain_cnt, seed ) );
      70         849 :     if( FD_UNLIKELY( !stakes_map ) ) {
      71           0 :       FD_LOG_WARNING(( "Failed to create vote stakes ele map" ));
      72           0 :       return NULL;
      73           0 :     }
      74         849 :     vote_stakes->stakes_map_off[ i ] = (ulong)stakes_map - (ulong)shmem;
      75         849 :   }
      76             : 
      77         597 :   index_ele_t * index_pool = index_pool_join( index_pool_new( index_pool_mem, max_vote_accounts * 2UL ) );
      78         597 :   if( FD_UNLIKELY( !index_pool ) ) {
      79           0 :     FD_LOG_WARNING(( "Failed to create vote stakes index pool" ));
      80           0 :     return NULL;
      81           0 :   }
      82             : 
      83         597 :   index_map_t * index_map = index_map_join( index_map_new( index_map_mem, map_chain_cnt, seed ) );
      84         597 :   if( FD_UNLIKELY( !index_map ) ) {
      85           0 :     FD_LOG_WARNING(( "Failed to create vote stakes index map" ));
      86           0 :     return NULL;
      87           0 :   }
      88             : 
      89         597 :   index_map_multi_t * index_map_multi = index_map_multi_join( index_map_multi_new( index_map_multi_mem, map_chain_cnt, seed ) );
      90         597 :   if( FD_UNLIKELY( !index_map_multi ) ) {
      91           0 :     FD_LOG_WARNING(( "Failed to create vote stakes index map multi" ));
      92           0 :     return NULL;
      93           0 :   }
      94             : 
      95         597 :   fork_t * fork_pool = fork_pool_join( fork_pool_new( fork_pool_mem, max_fork_width ) );
      96         597 :   if( FD_UNLIKELY( !fork_pool ) ) {
      97           0 :     FD_LOG_WARNING(( "Failed to create vote stakes fork pool" ));
      98           0 :     return NULL;
      99           0 :   }
     100             : 
     101         597 :   fork_dlist_t * fork_dlist = fork_dlist_join( fork_dlist_new( fork_dlist_mem ) );
     102         597 :   if( FD_UNLIKELY( !fork_dlist ) ) {
     103           0 :     FD_LOG_WARNING(( "Failed to create vote stakes fork dlist" ));
     104           0 :     return NULL;
     105           0 :   }
     106             : 
     107         597 :   if( FD_UNLIKELY( max_fork_width>USHORT_MAX ) ) {
     108           0 :     FD_LOG_WARNING(( "max_fork_width is too large" ));
     109           0 :     return NULL;
     110           0 :   }
     111             : 
     112         597 :   vote_stakes->max_fork_width      = (ushort)max_fork_width;
     113         597 :   vote_stakes->index_pool_off      = (ulong)index_pool - (ulong)shmem;
     114         597 :   vote_stakes->index_map_off       = (ulong)index_map - (ulong)shmem;
     115         597 :   vote_stakes->index_map_multi_off = (ulong)index_map_multi - (ulong)shmem;
     116         597 :   vote_stakes->fork_pool_off       = (ulong)fork_pool - (ulong)shmem;
     117         597 :   vote_stakes->fork_dlist_off      = (ulong)fork_dlist - (ulong)shmem;
     118         597 :   vote_stakes->root_idx            = (ushort)fork_pool_idx_acquire( fork_pool );
     119         597 :   fork_dlist_idx_push_tail( fork_dlist, vote_stakes->root_idx, fork_pool );
     120             : 
     121         597 :   fd_rwlock_new( &vote_stakes->lock );
     122             : 
     123         597 :   FD_COMPILER_MFENCE();
     124         597 :   FD_VOLATILE( vote_stakes->magic ) = FD_VOTE_STAKES_MAGIC;
     125         597 :   FD_COMPILER_MFENCE();
     126             : 
     127         597 :   return vote_stakes;
     128         597 : }
     129             : 
     130             : fd_vote_stakes_t *
     131        1185 : fd_vote_stakes_join( void * shmem ) {
     132        1185 :   fd_vote_stakes_t * vote_stakes = (fd_vote_stakes_t *)shmem;
     133             : 
     134        1185 :   if( FD_UNLIKELY( !vote_stakes ) ) {
     135           0 :     FD_LOG_WARNING(( "NULL vote stakes" ));
     136           0 :     return NULL;
     137           0 :   }
     138             : 
     139        1185 :   if( FD_UNLIKELY( vote_stakes->magic != FD_VOTE_STAKES_MAGIC ) ) {
     140           0 :     FD_LOG_WARNING(( "Invalid vote stakes magic" ));
     141           0 :     return NULL;
     142           0 :   }
     143             : 
     144        1185 :   return vote_stakes;
     145        1185 : }
     146             : 
     147             : void
     148             : fd_vote_stakes_root_insert_key( fd_vote_stakes_t *  vote_stakes,
     149             :                                 fd_pubkey_t const * pubkey,
     150             :                                 fd_pubkey_t const * node_account_t_1,
     151             :                                 ulong               stake_t_1,
     152             :                                 uchar               commission_t_1,
     153        3447 :                                 ulong               epoch ) {
     154        3447 :   fd_rwlock_write( &vote_stakes->lock );
     155             : 
     156        3447 :   index_ele_t *       index_pool      = get_index_pool( vote_stakes );
     157        3447 :   index_map_t *       index_map       = get_index_map( vote_stakes );
     158        3447 :   index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
     159             : 
     160        3447 :   index_ele_t * ele     = index_pool_ele_acquire( index_pool );
     161        3447 :   ele->pubkey           = *pubkey;
     162        3447 :   ele->refcnt           = 1;
     163        3447 :   ele->stake_t_1        = (stake_t_1 & 0x7FFFFFFFFFFFFFFFUL);
     164        3447 :   ele->commission_t_1   = commission_t_1;
     165        3447 :   ele->node_account_t_1 = *node_account_t_1;
     166        3447 :   ele->stake_t_2        = 0UL;
     167        3447 :   ele->node_account_t_2 = (fd_pubkey_t){0};
     168        3447 :   ele->commission_t_2   = 0U;
     169        3447 :   ele->epoch            = epoch % 2;
     170        3447 :   ele->exists_t_1       = 1;
     171        3447 :   ele->exists_t_2       = 0;
     172             :   /* It is fine to leave node account t_2 uninitalized because it will
     173             :      only be used if stake_t_2 is non-zero. */
     174             : 
     175        3447 :   FD_TEST( index_map_ele_insert( index_map, ele, index_pool ) );
     176        3447 :   FD_TEST( index_map_multi_ele_insert( index_map_multi, ele, index_pool ) );
     177             : 
     178        3447 :   stake_t *      stakes_pool = get_stakes_pool( vote_stakes, vote_stakes->root_idx );
     179        3447 :   stakes_map_t * stakes_map  = get_stakes_map( vote_stakes, vote_stakes->root_idx );
     180             : 
     181        3447 :   uint      pubkey_idx = (uint)index_pool_idx( index_pool, ele );
     182        3447 :   stake_t * new_stake = stakes_pool_ele_acquire( stakes_pool );
     183        3447 :   new_stake->idx = pubkey_idx;
     184        3447 :   FD_TEST( stakes_map_ele_insert( stakes_map, new_stake, stakes_pool ) );
     185             : 
     186        3447 :   fd_rwlock_unwrite( &vote_stakes->lock );
     187        3447 : }
     188             : 
     189             : void
     190             : fd_vote_stakes_root_update_meta( fd_vote_stakes_t *  vote_stakes,
     191             :                                  fd_pubkey_t const * pubkey,
     192             :                                  fd_pubkey_t const * node_account_t_2,
     193             :                                  ulong               stake_t_2,
     194             :                                  uchar               commission_t_2,
     195        3450 :                                  ulong               epoch ) {
     196        3450 :   fd_rwlock_write( &vote_stakes->lock );
     197             : 
     198        3450 :   index_ele_t *       index_pool      = get_index_pool( vote_stakes );
     199        3450 :   index_map_t *       index_map       = get_index_map( vote_stakes );
     200        3450 :   index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
     201        3450 :   index_ele_t *       ele             = index_map_multi_ele_query( index_map_multi, pubkey, NULL, index_pool );
     202        3450 :   if( FD_UNLIKELY( !ele ) ) {
     203           3 :     ele                   = index_pool_ele_acquire( index_pool );
     204           3 :     ele->pubkey           = *pubkey;
     205           3 :     ele->refcnt           = 1;
     206           3 :     ele->stake_t_1        = 0UL;
     207           3 :     ele->node_account_t_1 = (fd_pubkey_t){0};
     208           3 :     ele->epoch            = epoch % 2;
     209           3 :     ele->commission_t_1   = 0U;
     210           3 :     ele->exists_t_1       = 0;
     211             : 
     212           3 :     FD_TEST( index_map_ele_insert( index_map, ele, index_pool ) );
     213           3 :     FD_TEST( index_map_multi_ele_insert( index_map_multi, ele, index_pool ) );
     214             : 
     215           3 :     stake_t *      stakes_pool = get_stakes_pool( vote_stakes, vote_stakes->root_idx );
     216           3 :     stakes_map_t * stakes_map  = get_stakes_map( vote_stakes, vote_stakes->root_idx );
     217             : 
     218           3 :     uint      pubkey_idx = (uint)index_pool_idx( index_pool, ele );
     219           3 :     stake_t * new_stake = stakes_pool_ele_acquire( stakes_pool );
     220           3 :     new_stake->idx = pubkey_idx;
     221           3 :     FD_TEST( stakes_map_ele_insert( stakes_map, new_stake, stakes_pool ) );
     222           3 :   }
     223             : 
     224        3450 :   ele->commission_t_2   = commission_t_2;
     225        3450 :   ele->node_account_t_2 = *node_account_t_2;
     226        3450 :   ele->stake_t_2        = stake_t_2;
     227        3450 :   ele->exists_t_2       = 1;
     228             : 
     229        3450 :   fd_rwlock_unwrite( &vote_stakes->lock );
     230        3450 : }
     231             : 
     232             : void
     233             : fd_vote_stakes_root_purge_key( fd_vote_stakes_t *  vote_stakes,
     234           0 :                                fd_pubkey_t const * pubkey ) {
     235           0 :   fd_rwlock_write( &vote_stakes->lock );
     236             : 
     237           0 :   index_ele_t *       index_pool      = get_index_pool( vote_stakes );
     238           0 :   index_map_t *       index_map       = get_index_map( vote_stakes );
     239           0 :   index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
     240             : 
     241           0 :   uint ele_idx = (uint)index_map_multi_idx_query( index_map_multi, pubkey, UINT_MAX, index_pool );
     242           0 :   FD_TEST( ele_idx!=UINT_MAX );
     243             : 
     244           0 :   index_ele_t * ele = index_pool_ele( index_pool, ele_idx );
     245             : 
     246           0 :   FD_TEST( index_map_multi_ele_remove_fast( index_map_multi, ele, index_pool ) );
     247           0 :   FD_TEST( index_map_ele_remove( index_map, &ele->index_key, NULL, index_pool ) );
     248             : 
     249           0 :   stake_t *      stakes_pool = get_stakes_pool( vote_stakes, vote_stakes->root_idx );
     250           0 :   stakes_map_t * stakes_map  = get_stakes_map( vote_stakes, vote_stakes->root_idx );
     251             : 
     252           0 :   stake_t * stake_ele = stakes_map_ele_remove( stakes_map, &ele_idx, NULL, stakes_pool );
     253           0 :   stakes_pool_ele_release( stakes_pool, stake_ele );
     254             : 
     255           0 :   index_pool_ele_release( index_pool, ele );
     256             : 
     257           0 :   fd_rwlock_unwrite( &vote_stakes->lock );
     258           0 : }
     259             : 
     260             : void
     261             : fd_vote_stakes_insert( fd_vote_stakes_t *  vote_stakes,
     262             :                        ushort              fork_idx,
     263             :                        fd_pubkey_t const * pubkey,
     264             :                        fd_pubkey_t const * node_account_t_1,
     265             :                        fd_pubkey_t const * node_account_t_2,
     266             :                        ulong               stake_t_1,
     267             :                        ulong               stake_t_2,
     268             :                        uchar               commission_t_1,
     269             :                        uchar               commission_t_2,
     270             :                        uchar               exists_t_1,
     271             :                        uchar               exists_t_2,
     272         189 :                        ulong               epoch ) {
     273         189 :   fd_rwlock_write( &vote_stakes->lock );
     274             : 
     275         189 :   index_ele_t *       index_pool      = get_index_pool( vote_stakes );
     276         189 :   index_map_t *       index_map       = get_index_map( vote_stakes );
     277         189 :   index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
     278         189 :   stake_t *           stakes_pool     = get_stakes_pool( vote_stakes, fork_idx );
     279         189 :   stakes_map_t *      stakes_map      = get_stakes_map( vote_stakes, fork_idx );
     280             : 
     281         189 :   index_key_t index_key = {
     282         189 :     .pubkey           = *pubkey,
     283         189 :     .node_account_t_1 = *node_account_t_1,
     284         189 :     .stake_t_1        = stake_t_1 & 0x7FFFFFFFFFFFFFFFUL,
     285         189 :     .epoch            = epoch % 2,
     286         189 :     .commission_t_1   = commission_t_1,
     287         189 :     .exists_t_1       = exists_t_1,
     288         189 :   };
     289         189 :   index_ele_t * index_ele = index_map_ele_query( index_map, &index_key, NULL, index_pool );
     290         189 :   if( FD_LIKELY( !index_ele ) ) {
     291         186 :     index_ele                   = index_pool_ele_acquire( index_pool );
     292         186 :     index_ele->index_key        = index_key;
     293         186 :     index_ele->epoch            = epoch % 2;
     294         186 :     index_ele->refcnt           = 1;
     295         186 :     index_ele->node_account_t_2 = *node_account_t_2;
     296         186 :     index_ele->commission_t_2   = commission_t_2;
     297         186 :     index_ele->stake_t_2        = stake_t_2;
     298         186 :     index_ele->exists_t_2       = exists_t_2;
     299         186 :     FD_TEST( index_map_multi_ele_insert( index_map_multi, index_ele, index_pool ) );
     300         186 :     FD_TEST( index_map_ele_insert( index_map, index_ele, index_pool ) );
     301         186 :   } else {
     302           3 :     index_ele->refcnt++;
     303           3 :   }
     304             : 
     305         189 :   stake_t * stake = stakes_pool_ele_acquire( stakes_pool );
     306         189 :   stake->idx = (uint)index_pool_idx( index_pool, index_ele );
     307         189 :   FD_TEST( stakes_map_ele_insert( stakes_map, stake, stakes_pool ) );
     308             : 
     309         189 :   fd_rwlock_unwrite( &vote_stakes->lock );
     310         189 : }
     311             : 
     312             : void
     313        3417 : fd_vote_stakes_genesis_fini( fd_vote_stakes_t * vote_stakes ) {
     314        3417 :   fd_rwlock_write( &vote_stakes->lock );
     315             : 
     316        3417 :   index_ele_t *       index_pool      = get_index_pool( vote_stakes );
     317        3417 :   index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
     318             : 
     319        3417 :   for( index_map_multi_iter_t iter = index_map_multi_iter_init( index_map_multi, index_pool );
     320        6840 :        !index_map_multi_iter_done( iter, index_map_multi, index_pool );
     321        3423 :        iter = index_map_multi_iter_next( iter, index_map_multi, index_pool ) ) {
     322        3423 :     index_ele_t * ele = index_map_multi_iter_ele( iter, index_map_multi, index_pool );
     323        3423 :     ele->node_account_t_2 = ele->node_account_t_1;
     324        3423 :     ele->stake_t_2        = ele->stake_t_1;
     325        3423 :   }
     326             : 
     327        3417 :   fd_rwlock_unwrite( &vote_stakes->lock );
     328        3417 : }
     329             : 
     330             : ushort
     331         144 : fd_vote_stakes_new_child( fd_vote_stakes_t * vote_stakes ) {
     332         144 :   fd_rwlock_write( &vote_stakes->lock );
     333             : 
     334         144 :   fork_t *       fork_pool  = get_fork_pool( vote_stakes );
     335         144 :   fork_dlist_t * fork_dlist = get_fork_dlist( vote_stakes );
     336             : 
     337         144 :   if( FD_UNLIKELY( !fork_pool_free( fork_pool ) ) ) {
     338           0 :     FD_LOG_CRIT(( "no free forks in pool" ));
     339           0 :   }
     340             : 
     341         144 :   ushort idx = (ushort)fork_pool_idx_acquire( fork_pool );
     342             : 
     343         144 :   fork_dlist_idx_push_tail( fork_dlist, idx, fork_pool );
     344             : 
     345         144 :   fd_rwlock_unwrite( &vote_stakes->lock );
     346         144 :   return idx;
     347         144 : }
     348             : 
     349             : void
     350             : fd_vote_stakes_advance_root( fd_vote_stakes_t * vote_stakes,
     351          90 :                              ushort             root_idx ) {
     352          90 :   fd_rwlock_write( &vote_stakes->lock );
     353             : 
     354             :   /* Only expect the vote stakes to update once an epoch. */
     355          90 :   if( FD_LIKELY( root_idx==vote_stakes->root_idx ) ) {
     356          78 :     fd_rwlock_unwrite( &vote_stakes->lock );
     357          78 :     return;
     358          78 :   }
     359             : 
     360          12 :   fork_t *       fork_pool  = get_fork_pool( vote_stakes );
     361          12 :   fork_dlist_t * fork_dlist = get_fork_dlist( vote_stakes );
     362             : 
     363          12 :   index_ele_t *       index_pool      = get_index_pool( vote_stakes );
     364          12 :   index_map_t *       index_map       = get_index_map( vote_stakes );
     365          12 :   index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
     366             :   /* For every outstanding fork that is not the new candidate root,
     367             :      remove all stakes refcnts from the index.  If the index has no
     368             :      outstanding references, remove the index entry. */
     369          42 :   while( !fork_dlist_is_empty( fork_dlist, fork_pool ) ) {
     370          30 :     ushort fork_idx = (ushort)fork_dlist_idx_pop_head( fork_dlist, fork_pool );
     371          30 :     if( fork_idx==root_idx ) continue;
     372             : 
     373          18 :     stake_t *      stakes_pool = get_stakes_pool( vote_stakes, fork_idx );
     374          18 :     stakes_map_t * stakes_map  = get_stakes_map( vote_stakes, fork_idx );
     375          18 :     for( stakes_map_iter_t iter = stakes_map_iter_init( stakes_map, stakes_pool );
     376          75 :          !stakes_map_iter_done( iter, stakes_map, stakes_pool );
     377          57 :          iter = stakes_map_iter_next( iter, stakes_map, stakes_pool ) ) {
     378          57 :       stake_t *     stake = stakes_map_iter_ele( iter, stakes_map, stakes_pool );
     379          57 :       index_ele_t * ele   = index_pool_ele( index_pool, stake->idx );
     380          57 :       ele->refcnt--;
     381             : 
     382          57 :       if( FD_UNLIKELY( ele->refcnt==0U ) ) {
     383          57 :         FD_TEST( index_map_ele_remove( index_map, &ele->index_key, NULL, index_pool ) );
     384          57 :         FD_TEST( index_map_multi_ele_remove_fast( index_map_multi, ele, index_pool ) );
     385          57 :         index_pool_ele_release( index_pool, ele );
     386          57 :       }
     387          57 :     }
     388          18 :     fork_pool_idx_release( fork_pool, fork_idx );
     389          18 :     stakes_map_reset( get_stakes_map( vote_stakes, fork_idx ) );
     390          18 :     stakes_pool_reset( get_stakes_pool( vote_stakes, fork_idx ) );
     391          18 :   }
     392             :   /* TODO: There's probably a way to do a more efficient reset here. */
     393             : 
     394          12 :   fork_dlist_idx_push_head( fork_dlist, root_idx, fork_pool );
     395          12 :   vote_stakes->root_idx = root_idx;
     396             : 
     397          12 :   fd_rwlock_unwrite( &vote_stakes->lock );
     398          12 : }
     399             : 
     400             : static int
     401             : fd_vote_stakes_query_private( fd_vote_stakes_t *  vote_stakes,
     402             :                               ushort              fork_idx,
     403             :                               fd_pubkey_t const * pubkey,
     404             :                               ulong *             stake_t_1_out_opt,
     405             :                               ulong *             stake_t_2_out_opt,
     406             :                               fd_pubkey_t *       node_account_t_1_out_opt,
     407             :                               fd_pubkey_t *       node_account_t_2_out_opt,
     408             :                               uchar *             commission_t_1_out_opt,
     409             :                               uchar *             commission_t_2_out_opt,
     410             :                               uchar *             exists_t_1_out_opt,
     411         351 :                               uchar *             exists_t_2_out_opt ) {
     412             : 
     413         351 :   index_ele_t *       index_pool      = get_index_pool( vote_stakes );
     414         351 :   index_map_multi_t * index_map_multi = get_index_map_multi( vote_stakes );
     415             : 
     416         351 :   stake_t *      stakes_pool = get_stakes_pool( vote_stakes, fork_idx );
     417         351 :   stakes_map_t * stakes_map  = get_stakes_map( vote_stakes, fork_idx );
     418             : 
     419             :   /* The index may have multiple entries for the same pubkey, so every
     420             :      single matching index entry must be checked to see if the index
     421             :      exists in the given fork's stakes map.  If it does, return the
     422             :      t_2 stake value.*/
     423         351 :   uint ele_idx = (uint)index_map_multi_idx_query_const( index_map_multi, pubkey, UINT_MAX, index_pool );
     424         351 :   if( FD_UNLIKELY( ele_idx==UINT_MAX ) ) {
     425           0 :     return 0;
     426           0 :   }
     427             : 
     428         351 :   while( !stakes_map_ele_query_const( stakes_map, &ele_idx, NULL, stakes_pool ) ) {
     429           0 :     ele_idx = (uint)index_map_multi_idx_next_const( ele_idx, UINT_MAX, index_pool );
     430           0 :     if( FD_UNLIKELY( ele_idx==UINT_MAX ) ) {
     431           0 :       return 0;
     432           0 :     }
     433           0 :   }
     434             : 
     435         351 :   index_ele_t * index_ele = index_pool_ele( index_pool, ele_idx );
     436         351 :   if( stake_t_1_out_opt )        *stake_t_1_out_opt        = index_ele->stake_t_1;
     437         351 :   if( stake_t_2_out_opt )        *stake_t_2_out_opt        = index_ele->stake_t_2;
     438         351 :   if( node_account_t_1_out_opt ) *node_account_t_1_out_opt = index_ele->node_account_t_1;
     439         351 :   if( node_account_t_2_out_opt ) *node_account_t_2_out_opt = index_ele->node_account_t_2;
     440         351 :   if( commission_t_1_out_opt )   *commission_t_1_out_opt   = (uchar)index_ele->commission_t_1;
     441         351 :   if( commission_t_2_out_opt )   *commission_t_2_out_opt   = (uchar)index_ele->commission_t_2;
     442         351 :   if( exists_t_1_out_opt )       *exists_t_1_out_opt       = (uchar)index_ele->exists_t_1;
     443         351 :   if( exists_t_2_out_opt )       *exists_t_2_out_opt       = index_ele->exists_t_2;
     444         351 :   return 1;
     445         351 : }
     446             : 
     447             : int
     448             : fd_vote_stakes_query( fd_vote_stakes_t *  vote_stakes,
     449             :                       ushort              fork_idx,
     450             :                       fd_pubkey_t const * pubkey,
     451             :                       ulong *             stake_t_1_out_opt,
     452             :                       ulong *             stake_t_2_out_opt,
     453             :                       fd_pubkey_t *       node_account_t_1_out_opt,
     454             :                       fd_pubkey_t *       node_account_t_2_out_opt,
     455             :                       uchar *             commission_t_1_out_opt,
     456             :                       uchar *             commission_t_2_out_opt,
     457             :                       uchar *             exists_t_1_out_opt,
     458          69 :                       uchar *             exists_t_2_out_opt ) {
     459          69 :   fd_rwlock_read( &vote_stakes->lock );
     460          69 :   int result = fd_vote_stakes_query_private( vote_stakes,
     461          69 :                                              fork_idx,
     462          69 :                                              pubkey,
     463          69 :                                              stake_t_1_out_opt,
     464          69 :                                              stake_t_2_out_opt,
     465          69 :                                              node_account_t_1_out_opt,
     466          69 :                                              node_account_t_2_out_opt,
     467          69 :                                              commission_t_1_out_opt,
     468          69 :                                              commission_t_2_out_opt,
     469          69 :                                              exists_t_1_out_opt,
     470          69 :                                              exists_t_2_out_opt );
     471          69 :   fd_rwlock_unread( &vote_stakes->lock );
     472          69 :   return result;
     473          69 : }
     474             : 
     475             : int
     476             : fd_vote_stakes_query_t_1( fd_vote_stakes_t *  vote_stakes,
     477             :                           ushort              fork_idx,
     478             :                           fd_pubkey_t const * pubkey,
     479             :                           ulong *             stake_out,
     480             :                           fd_pubkey_t *       node_account_out,
     481         141 :                           uchar *             commission_out ) {
     482         141 :   fd_rwlock_read( &vote_stakes->lock );
     483         141 :   uchar exists_t_1 = 0;
     484         141 :   int found = fd_vote_stakes_query_private( vote_stakes, fork_idx, pubkey, stake_out, NULL, node_account_out, NULL, commission_out, NULL, &exists_t_1, 0 );
     485         141 :   fd_rwlock_unread( &vote_stakes->lock );
     486         141 :   return found && exists_t_1;
     487         141 : }
     488             : 
     489             : int
     490             : fd_vote_stakes_query_t_2( fd_vote_stakes_t *  vote_stakes,
     491             :                           ushort              fork_idx,
     492             :                           fd_pubkey_t const * pubkey,
     493             :                           ulong *             stake_out,
     494             :                           fd_pubkey_t *       node_account_out,
     495         141 :                           uchar *             commission_out ) {
     496         141 :   fd_rwlock_read( &vote_stakes->lock );
     497         141 :   uchar exists_t_2 = 0;
     498         141 :   int found = fd_vote_stakes_query_private( vote_stakes, fork_idx, pubkey, NULL, stake_out, NULL, node_account_out, NULL, commission_out, NULL, &exists_t_2 );
     499         141 :   fd_rwlock_unread( &vote_stakes->lock );
     500         141 :   return found && exists_t_2;
     501         141 : }
     502             : 
     503             : void
     504        6864 : fd_vote_stakes_reset( fd_vote_stakes_t * vote_stakes ) {
     505        6864 :   fd_rwlock_write( &vote_stakes->lock );
     506             : 
     507             :   /* Pop the fork dlist */
     508        6864 :   fork_t *       fork_pool  = get_fork_pool( vote_stakes );
     509        6864 :   fork_dlist_t * fork_dlist = get_fork_dlist( vote_stakes );
     510        6864 :   fork_dlist_remove_all( fork_dlist, fork_pool );
     511             : 
     512        6864 :   fork_pool_reset( fork_pool );
     513             : 
     514             :   /* For each fork, reset the stakes map and pool */
     515       34392 :   for( ushort i=0; i<vote_stakes->max_fork_width; i++ ) {
     516       27528 :     stakes_map_reset( get_stakes_map( vote_stakes, i ) );
     517       27528 :     stakes_pool_reset( get_stakes_pool( vote_stakes, i ) );
     518       27528 :   }
     519             : 
     520             :   /* Reset the index map and multi map */
     521        6864 :   index_map_reset( get_index_map( vote_stakes ) );
     522        6864 :   index_map_multi_reset( get_index_map_multi( vote_stakes ) );
     523             : 
     524             :   /* Reset the index pool */
     525        6864 :   index_pool_reset( get_index_pool( vote_stakes ) );
     526             : 
     527             :   /* Setup the pool again */
     528        6864 :   vote_stakes->root_idx = (ushort)fork_pool_idx_acquire( fork_pool );
     529        6864 :   fork_dlist_idx_push_tail( fork_dlist, vote_stakes->root_idx, fork_pool );
     530             : 
     531        6864 :   fd_rwlock_unwrite( &vote_stakes->lock );
     532        6864 : }
     533             : 
     534             : uint
     535             : fd_vote_stakes_ele_cnt( fd_vote_stakes_t * vote_stakes,
     536          21 :                         ushort             fork_idx ) {
     537          21 :   fd_rwlock_read( &vote_stakes->lock );
     538          21 :   stake_t * stakes_pool = get_stakes_pool( vote_stakes, fork_idx );
     539          21 :   uint cnt = (uint)stakes_pool_used( stakes_pool );
     540          21 :   fd_rwlock_unread( &vote_stakes->lock );
     541          21 :   return cnt;
     542          21 : }
     543             : 
     544             : ushort
     545        4008 : fd_vote_stakes_get_root_idx( fd_vote_stakes_t * vote_stakes ) {
     546        4008 :   fd_rwlock_read( &vote_stakes->lock );
     547        4008 :   ushort idx = vote_stakes->root_idx;
     548        4008 :   fd_rwlock_unread( &vote_stakes->lock );
     549        4008 :   return idx;
     550        4008 : }
     551             : 
     552             : fd_vote_stakes_iter_t *
     553             : fd_vote_stakes_fork_iter_init( fd_vote_stakes_t * vote_stakes,
     554             :                                ushort             fork_idx,
     555        3777 :                                uchar              iter_mem[ static FD_VOTE_STAKES_ITER_FOOTPRINT ] ) {
     556        3777 :   fd_rwlock_write( &vote_stakes->lock );
     557             : 
     558        3777 :   stakes_map_iter_t iter = stakes_map_iter_init( get_stakes_map( vote_stakes, fork_idx ), get_stakes_pool( vote_stakes, fork_idx ) );
     559        3777 :   memcpy( iter_mem, &iter, sizeof(stakes_map_iter_t) );
     560        3777 :   return (fd_vote_stakes_iter_t *)iter_mem;
     561        3777 : }
     562             : 
     563             : void
     564        3777 : fd_vote_stakes_fork_iter_fini( fd_vote_stakes_t * vote_stakes ) {
     565        3777 :   fd_rwlock_unwrite( &vote_stakes->lock );
     566        3777 : }
     567             : 
     568             : int
     569             : fd_vote_stakes_fork_iter_done( fd_vote_stakes_t *      vote_stakes,
     570             :                                ushort                  fork_idx,
     571        7581 :                                fd_vote_stakes_iter_t * iter ) {
     572        7581 :   stakes_map_iter_t * stakes_map_iter = (stakes_map_iter_t *)iter;
     573        7581 :   return stakes_map_iter_done( *stakes_map_iter, get_stakes_map( vote_stakes, fork_idx ), get_stakes_pool( vote_stakes, fork_idx ) );
     574        7581 : }
     575             : 
     576             : void
     577             : fd_vote_stakes_fork_iter_next( fd_vote_stakes_t *      vote_stakes,
     578             :                                ushort                  fork_idx,
     579        3804 :                                fd_vote_stakes_iter_t * iter ) {
     580        3804 :   stakes_map_iter_t * stakes_map_iter = (stakes_map_iter_t *)iter;
     581        3804 :   *stakes_map_iter = stakes_map_iter_next( *stakes_map_iter, get_stakes_map( vote_stakes, fork_idx ), get_stakes_pool( vote_stakes, fork_idx ) );
     582        3804 : }
     583             : 
     584             : void
     585             : fd_vote_stakes_fork_iter_ele( fd_vote_stakes_t *      vote_stakes,
     586             :                               ushort                  fork_idx,
     587             :                               fd_vote_stakes_iter_t * iter,
     588             :                               fd_pubkey_t *           pubkey_out,
     589             :                               ulong *                 stake_t_1_out_opt,
     590             :                               ulong *                 stake_t_2_out_opt,
     591             :                               fd_pubkey_t *           node_account_t_1_out_opt,
     592             :                               fd_pubkey_t *           node_account_t_2_out_opt,
     593             :                               uchar *                 commission_t_1_out_opt,
     594        3804 :                               uchar *                 commission_t_2_out_opt ) {
     595        3804 :   stakes_map_iter_t * stakes_map_iter = (stakes_map_iter_t *)iter;
     596        3804 :   stake_t * stake = stakes_map_iter_ele( *stakes_map_iter, get_stakes_map( vote_stakes, fork_idx ), get_stakes_pool( vote_stakes, fork_idx ) );
     597             : 
     598        3804 :   index_ele_t * index_pool = get_index_pool( vote_stakes );
     599        3804 :   index_ele_t * index_ele  = index_pool_ele( index_pool, stake->idx );
     600             : 
     601        3804 :   *pubkey_out = index_ele->index_key.pubkey;
     602             : 
     603        3804 :   if( stake_t_1_out_opt )        *stake_t_1_out_opt        = index_ele->index_key.stake_t_1;
     604        3804 :   if( stake_t_2_out_opt )        *stake_t_2_out_opt        = index_ele->stake_t_2;
     605        3804 :   if( node_account_t_1_out_opt ) *node_account_t_1_out_opt = index_ele->node_account_t_1;
     606        3804 :   if( node_account_t_2_out_opt ) *node_account_t_2_out_opt = index_ele->node_account_t_2;
     607        3804 :   if( commission_t_1_out_opt )   *commission_t_1_out_opt   = (uchar)index_ele->commission_t_1;
     608        3804 :   if( commission_t_2_out_opt )   *commission_t_2_out_opt   = (uchar)index_ele->commission_t_2;
     609        3804 : }

Generated by: LCOV version 1.14