LCOV - code coverage report
Current view: top level - flamenco/stakes - fd_vote_stakes.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 278 387 71.8 %
Date: 2026-03-31 06:22:16 Functions: 20 24 83.3 %

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

Generated by: LCOV version 1.14