LCOV - code coverage report
Current view: top level - flamenco/stakes - fd_stake_delegations.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 198 353 56.1 %
Date: 2026-03-19 18:19:27 Functions: 22 27 81.5 %

          Line data    Source code
       1             : #include "fd_stake_delegations.h"
       2             : #include "../accdb/fd_accdb_pipe.h"
       3             : #include "fd_stakes.h"
       4             : 
       5             : #define POOL_NAME  root_pool
       6          24 : #define POOL_T     fd_stake_delegation_t
       7      631590 : #define POOL_NEXT  next_
       8             : #define POOL_IDX_T uint
       9             : #include "../../util/tmpl/fd_pool.c"
      10             : 
      11             : #define MAP_NAME               root_map
      12             : #define MAP_KEY_T              fd_pubkey_t
      13             : #define MAP_ELE_T              fd_stake_delegation_t
      14         299 : #define MAP_KEY                stake_account
      15           0 : #define MAP_KEY_EQ(k0,k1)      (fd_pubkey_eq( k0, k1 ))
      16         598 : #define MAP_KEY_HASH(key,seed) (fd_funk_rec_key_hash1( key->uc, seed ))
      17         313 : #define MAP_NEXT               next_
      18        1236 : #define MAP_IDX_T              uint
      19             : #include "../../util/tmpl/fd_map_chain.c"
      20             : 
      21             : #define POOL_NAME  delta_pool
      22          24 : #define POOL_T     fd_stake_delegation_t
      23       24580 : #define POOL_NEXT  next_
      24             : #define POOL_IDX_T uint
      25             : #include "../../util/tmpl/fd_pool.c"
      26             : 
      27             : #define DLIST_NAME  fork_dlist
      28             : #define DLIST_ELE_T fd_stake_delegation_t
      29           2 : #define DLIST_PREV  prev_
      30           4 : #define DLIST_NEXT  next_
      31             : #define DLIST_IDX_T uint
      32             : #include "../../util/tmpl/fd_dlist.c"
      33             : 
      34             : struct fork_pool_ele { ushort next; };
      35             : typedef struct fork_pool_ele fork_pool_ele_t;
      36             : 
      37             : #define POOL_NAME  fork_pool
      38          24 : #define POOL_T     fork_pool_ele_t
      39             : #define POOL_IDX_T ushort
      40             : #include "../../util/tmpl/fd_pool.c"
      41             : 
      42             : /* Internal getters for base map + pool */
      43             : 
      44             : static inline fd_stake_delegation_t *
      45         620 : get_root_pool( fd_stake_delegations_t const * stake_delegations ) {
      46         620 :   return fd_type_pun( (uchar *)stake_delegations + stake_delegations->pool_offset_ );
      47         620 : }
      48             : 
      49             : static inline root_map_t *
      50         620 : get_root_map( fd_stake_delegations_t const * stake_delegations ) {
      51         620 :   return fd_type_pun( (uchar *)stake_delegations + stake_delegations->map_offset_ );
      52         620 : }
      53             : 
      54             : /* Internal getters for delta pool + fork structures */
      55             : 
      56             : static inline fd_stake_delegation_t *
      57         323 : get_delta_pool( fd_stake_delegations_t const * stake_delegations ) {
      58         323 :   return fd_type_pun( (uchar *)stake_delegations + stake_delegations->delta_pool_offset_ );
      59         323 : }
      60             : 
      61             : static inline fork_pool_ele_t *
      62         609 : get_fork_pool( fd_stake_delegations_t const * stake_delegations ) {
      63         609 :   return fd_type_pun( (uchar *)stake_delegations + stake_delegations->fork_pool_offset_ );
      64         609 : }
      65             : 
      66             : static inline fork_dlist_t *
      67             : get_fork_dlist( fd_stake_delegations_t const * stake_delegations,
      68         309 :                 ushort                         fork_idx ) {
      69         309 :   return fd_type_pun( (uchar *)stake_delegations + stake_delegations->dlist_offsets_[ fork_idx ] );
      70         309 : }
      71             : 
      72             : ulong
      73         671 : fd_stake_delegations_align( void ) {
      74         671 :   return FD_STAKE_DELEGATIONS_ALIGN;
      75         671 : }
      76             : 
      77             : ulong
      78             : fd_stake_delegations_footprint( ulong max_stake_accounts,
      79             :                                 ulong expected_stake_accounts,
      80          60 :                                 ulong max_live_slots ) {
      81             : 
      82          60 :   ulong map_chain_cnt = root_map_chain_cnt_est( expected_stake_accounts );
      83             : 
      84          60 :   ulong l = FD_LAYOUT_INIT;
      85          60 :   l = FD_LAYOUT_APPEND( l, fd_stake_delegations_align(), sizeof(fd_stake_delegations_t) );
      86          60 :   l = FD_LAYOUT_APPEND( l, root_pool_align(),            root_pool_footprint( max_stake_accounts ) );
      87          60 :   l = FD_LAYOUT_APPEND( l, root_map_align(),             root_map_footprint( map_chain_cnt ) );
      88          60 :   l = FD_LAYOUT_APPEND( l, delta_pool_align(),           delta_pool_footprint( max_stake_accounts ) );
      89          60 :   l = FD_LAYOUT_APPEND( l, fork_pool_align(),            fork_pool_footprint( max_live_slots ) );
      90         180 :   for( ulong i=0UL; i<max_live_slots; i++ ) {
      91         120 :     l = FD_LAYOUT_APPEND( l, fork_dlist_align(), fork_dlist_footprint() );
      92         120 :   }
      93             : 
      94          60 :   return FD_LAYOUT_FINI( l, fd_stake_delegations_align() );
      95          60 : }
      96             : 
      97             : void *
      98             : fd_stake_delegations_new( void * mem,
      99             :                           ulong  seed,
     100             :                           ulong  max_stake_accounts,
     101             :                           ulong  expected_stake_accounts,
     102          12 :                           ulong  max_live_slots ) {
     103          12 :   if( FD_UNLIKELY( !mem ) ) {
     104           0 :     FD_LOG_WARNING(( "NULL mem" ));
     105           0 :     return NULL;
     106           0 :   }
     107             : 
     108          12 :   if( FD_UNLIKELY( !max_stake_accounts ) ) {
     109           0 :     FD_LOG_WARNING(( "max_stake_accounts is 0" ));
     110           0 :     return NULL;
     111           0 :   }
     112             : 
     113          12 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_stake_delegations_align() ) ) ) {
     114           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     115           0 :     return NULL;
     116           0 :   }
     117             : 
     118          12 :   if( FD_UNLIKELY( max_live_slots>FD_STAKE_DELEGATIONS_FORK_MAX ) ) {
     119           0 :     FD_LOG_WARNING(( "max_live_slots is too large" ));
     120           0 :     return NULL;
     121           0 :   }
     122             : 
     123          12 :   ulong map_chain_cnt = root_map_chain_cnt_est( expected_stake_accounts );
     124             : 
     125          12 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     126          12 :   fd_stake_delegations_t * stake_delegations = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(), sizeof(fd_stake_delegations_t) );
     127          12 :   void *                   pool_mem          = FD_SCRATCH_ALLOC_APPEND( l, root_pool_align(),            root_pool_footprint( max_stake_accounts ) );
     128          12 :   void *                   map_mem           = FD_SCRATCH_ALLOC_APPEND( l, root_map_align(),             root_map_footprint( map_chain_cnt ) );
     129          12 :   void *                   delta_pool_mem    = FD_SCRATCH_ALLOC_APPEND( l, delta_pool_align(),           delta_pool_footprint( max_stake_accounts ) );
     130          12 :   void *                   fork_pool_mem     = FD_SCRATCH_ALLOC_APPEND( l, fork_pool_align(),            fork_pool_footprint( max_live_slots ) );
     131          36 :   for( ushort i=0; i<(ushort)max_live_slots; i++ ) {
     132          24 :     void * fork_dlist_mem = FD_SCRATCH_ALLOC_APPEND( l, fork_dlist_align(), fork_dlist_footprint() );
     133           0 :     fork_dlist_t * dlist = fork_dlist_join( fork_dlist_new( fork_dlist_mem ) );
     134          24 :     if( FD_UNLIKELY( !dlist ) ) {
     135           0 :       FD_LOG_WARNING(( "Failed to create fork dlist" ));
     136           0 :       return NULL;
     137           0 :     }
     138          24 :     stake_delegations->dlist_offsets_[ i ] = (ulong)dlist - (ulong)mem;
     139          24 :   }
     140             : 
     141          12 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_stake_delegations_align() )!=(ulong)mem+fd_stake_delegations_footprint( max_stake_accounts, expected_stake_accounts, max_live_slots ) ) ) {
     142           0 :     FD_LOG_WARNING(( "fd_stake_delegations_new: bad layout" ));
     143           0 :     return NULL;
     144           0 :   }
     145             : 
     146          12 :   fd_stake_delegation_t * root_pool = root_pool_join( root_pool_new( pool_mem, max_stake_accounts ) );
     147          12 :   if( FD_UNLIKELY( !root_pool ) ) {
     148           0 :     FD_LOG_WARNING(( "Failed to create stake delegations pool" ));
     149           0 :     return NULL;
     150           0 :   }
     151             : 
     152          12 :   root_map_t * root_map = root_map_join( root_map_new( map_mem, map_chain_cnt, seed ) );
     153          12 :   if( FD_UNLIKELY( !root_map ) ) {
     154           0 :     FD_LOG_WARNING(( "Failed to create stake delegations map" ));
     155           0 :     return NULL;
     156           0 :   }
     157             : 
     158          12 :   fd_stake_delegation_t * delta_pool = delta_pool_join( delta_pool_new( delta_pool_mem, max_stake_accounts ) );
     159          12 :   if( FD_UNLIKELY( !delta_pool ) ) {
     160           0 :     FD_LOG_WARNING(( "Failed to create stake delegation delta pool" ));
     161           0 :     return NULL;
     162           0 :   }
     163             : 
     164          12 :   fork_pool_ele_t * fork_pool = fork_pool_join( fork_pool_new( fork_pool_mem, max_live_slots ) );
     165          12 :   if( FD_UNLIKELY( !fork_pool ) ) {
     166           0 :     FD_LOG_WARNING(( "Failed to create fork pool" ));
     167           0 :     return NULL;
     168           0 :   }
     169             : 
     170          12 :   stake_delegations->max_stake_accounts_      = max_stake_accounts;
     171          12 :   stake_delegations->expected_stake_accounts_ = expected_stake_accounts;
     172          12 :   stake_delegations->pool_offset_             = (ulong)root_pool - (ulong)mem;
     173          12 :   stake_delegations->map_offset_              = (ulong)root_map - (ulong)mem;
     174          12 :   stake_delegations->delta_pool_offset_       = (ulong)delta_pool - (ulong)mem;
     175          12 :   stake_delegations->fork_pool_offset_        = (ulong)fork_pool - (ulong)mem;
     176             : 
     177          12 :   fd_rwlock_new( &stake_delegations->delta_lock );
     178             : 
     179          12 :   FD_COMPILER_MFENCE();
     180          12 :   FD_VOLATILE( stake_delegations->magic ) = FD_STAKE_DELEGATIONS_MAGIC;
     181          12 :   FD_COMPILER_MFENCE();
     182             : 
     183          12 :   return mem;
     184          12 : }
     185             : 
     186             : fd_stake_delegations_t *
     187         311 : fd_stake_delegations_join( void * mem ) {
     188         311 :   if( FD_UNLIKELY( !mem ) ) {
     189           0 :     FD_LOG_WARNING(( "NULL mem" ));
     190           0 :     return NULL;
     191           0 :   }
     192             : 
     193         311 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_stake_delegations_align() ) ) ) {
     194           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     195           0 :     return NULL;
     196           0 :   }
     197             : 
     198         311 :   fd_stake_delegations_t * stake_delegations = (fd_stake_delegations_t *)mem;
     199             : 
     200         311 :   if( FD_UNLIKELY( stake_delegations->magic!=FD_STAKE_DELEGATIONS_MAGIC ) ) {
     201           0 :     FD_LOG_WARNING(( "Invalid stake delegations magic" ));
     202           0 :     return NULL;
     203           0 :   }
     204             : 
     205         311 :   return stake_delegations;
     206         311 : }
     207             : 
     208             : void
     209         299 : fd_stake_delegations_init( fd_stake_delegations_t * stake_delegations ) {
     210         299 :   root_map_t *            map  = get_root_map( stake_delegations );
     211         299 :   fd_stake_delegation_t * pool = get_root_pool( stake_delegations );
     212         299 :   root_pool_reset( pool );
     213         299 :   root_map_reset( map );
     214         299 : }
     215             : 
     216             : void
     217             : fd_stake_delegations_root_update( fd_stake_delegations_t * stake_delegations,
     218             :                                   fd_pubkey_t const *      stake_account,
     219             :                                   fd_pubkey_t const *      vote_account,
     220             :                                   ulong                    stake,
     221             :                                   ulong                    activation_epoch,
     222             :                                   ulong                    deactivation_epoch,
     223             :                                   ulong                    credits_observed,
     224         299 :                                   double                   warmup_cooldown_rate ) {
     225         299 :   fd_stake_delegation_t * pool = get_root_pool( stake_delegations );
     226         299 :   root_map_t *            map = get_root_map( stake_delegations );
     227             : 
     228         299 :   fd_stake_delegation_t * stake_delegation = root_map_ele_query( map, stake_account, NULL, pool );
     229         299 :   if( !stake_delegation ) {
     230         299 :     FD_CRIT( root_pool_free( pool ), "no free stake delegations in pool" );
     231         299 :     stake_delegation = root_pool_ele_acquire( pool );
     232         299 :     stake_delegation->stake_account = *stake_account;
     233         299 :     FD_CRIT( root_map_ele_insert( map, stake_delegation, pool ), "unable to insert stake delegation into map" );
     234         299 :   }
     235             : 
     236         299 :   stake_delegation->vote_account         = *vote_account;
     237         299 :   stake_delegation->stake                = stake;
     238         299 :   stake_delegation->activation_epoch     = (ushort)fd_ulong_min( activation_epoch, USHORT_MAX );
     239         299 :   stake_delegation->deactivation_epoch   = (ushort)fd_ulong_min( deactivation_epoch, USHORT_MAX );
     240         299 :   stake_delegation->credits_observed     = credits_observed;
     241         299 :   stake_delegation->warmup_cooldown_rate = fd_stake_delegations_warmup_cooldown_rate_enum( warmup_cooldown_rate );
     242         299 :   stake_delegation->dne_in_root          = 0;
     243         299 :   stake_delegation->delta_idx            = UINT_MAX;
     244         299 : }
     245             : 
     246             : static inline void
     247             : fd_stake_delegations_remove( fd_stake_delegations_t * stake_delegations,
     248           0 :                              fd_pubkey_t const *      stake_account ) {
     249           0 :   fd_stake_delegation_t * pool = get_root_pool( stake_delegations );
     250           0 :   root_map_t *            map  = get_root_map( stake_delegations );
     251             : 
     252           0 :   ulong delegation_idx = root_map_idx_query( map, stake_account, UINT_MAX, pool );
     253           0 :   if( FD_UNLIKELY( delegation_idx==UINT_MAX ) ) return;
     254             : 
     255           0 :   root_map_idx_remove( map, stake_account, delegation_idx, pool );
     256           0 :   root_pool_idx_release( pool, delegation_idx );
     257           0 : }
     258             : 
     259             : void
     260             : fd_stake_delegations_refresh( fd_stake_delegations_t *  stake_delegations,
     261             :                               fd_accdb_user_t *         accdb,
     262           0 :                               fd_funk_txn_xid_t const * xid ) {
     263             : 
     264           0 :   root_map_t *            map  = get_root_map( stake_delegations );
     265           0 :   fd_stake_delegation_t * pool = get_root_pool( stake_delegations );
     266             : 
     267           0 :   fd_accdb_ro_pipe_t ro_pipe[1];
     268           0 :   fd_accdb_ro_pipe_init( ro_pipe, accdb, xid );
     269           0 :   ulong const job_cnt = fd_stake_delegations_cnt( stake_delegations );
     270           0 :   for( ulong i=0UL; i<job_cnt; i++ ) {
     271             : 
     272             :     /* stream out read requests */
     273           0 :     fd_accdb_ro_pipe_enqueue( ro_pipe, &pool[ i ].stake_account );
     274           0 :     if( FD_UNLIKELY( i+1UL==job_cnt ) ) {
     275           0 :       fd_accdb_ro_pipe_flush( ro_pipe );
     276           0 :     }
     277             : 
     278             :     /* handle a batch of completions */
     279           0 :     fd_accdb_ro_t * ro;
     280           0 :     while( (ro = fd_accdb_ro_pipe_poll( ro_pipe )) ) {
     281           0 :       fd_pubkey_t const * address = fd_accdb_ref_address( ro );
     282           0 :       fd_stake_delegation_t * delegation = root_map_ele_query( map, address, NULL, pool );
     283           0 :       if( FD_UNLIKELY( !delegation ) ) continue;
     284             : 
     285           0 :       if( FD_UNLIKELY( fd_accdb_ref_lamports( ro )==0UL ) ) goto remove;
     286             : 
     287           0 :       fd_stake_state_v2_t stake;
     288           0 :       int err = fd_stakes_get_state( ro->meta, &stake );
     289           0 :       if( FD_UNLIKELY( err ) ) goto remove;
     290           0 :       if( FD_UNLIKELY( !fd_stake_state_v2_is_stake( &stake ) ) ) goto remove;
     291             : 
     292           0 :       fd_stake_delegations_root_update(
     293           0 :           stake_delegations,
     294           0 :           address,
     295           0 :           &stake.inner.stake.stake.delegation.voter_pubkey,
     296           0 :           stake.inner.stake.stake.delegation.stake,
     297           0 :           stake.inner.stake.stake.delegation.activation_epoch,
     298           0 :           stake.inner.stake.stake.delegation.deactivation_epoch,
     299           0 :           stake.inner.stake.stake.credits_observed,
     300           0 :           stake.inner.stake.stake.delegation.warmup_cooldown_rate );
     301           0 :       continue; /* ok */
     302             : 
     303           0 :     remove:
     304           0 :       root_map_idx_remove( map, address, UINT_MAX, pool );
     305           0 :       root_pool_ele_release( pool, delegation );
     306           0 :     }
     307           0 :   }
     308           0 :   fd_accdb_ro_pipe_fini( ro_pipe );
     309           0 : }
     310             : 
     311             : ulong
     312           0 : fd_stake_delegations_cnt( fd_stake_delegations_t const * stake_delegations ) {
     313           0 :   return root_pool_used( get_root_pool( stake_delegations ) );
     314           0 : }
     315             : 
     316             : /* Fork-aware delta operations */
     317             : 
     318             : ushort
     319         311 : fd_stake_delegations_new_fork( fd_stake_delegations_t * stake_delegations ) {
     320         311 :   fork_pool_ele_t * fork_pool = get_fork_pool( stake_delegations );
     321         311 :   FD_CRIT( fork_pool_free( fork_pool ), "no free forks in pool" );
     322         311 :   ushort fork_idx = (ushort)fork_pool_idx_acquire( fork_pool );
     323             : 
     324         311 :   return fork_idx;
     325         311 : }
     326             : 
     327             : void
     328             : fd_stake_delegations_fork_update( fd_stake_delegations_t * stake_delegations,
     329             :                                   ushort                   fork_idx,
     330             :                                   fd_pubkey_t const *      stake_account,
     331             :                                   fd_pubkey_t const *      vote_account,
     332             :                                   ulong                    stake,
     333             :                                   ulong                    activation_epoch,
     334             :                                   ulong                    deactivation_epoch,
     335             :                                   ulong                    credits_observed,
     336           2 :                                   double                   warmup_cooldown_rate ) {
     337           2 :   fd_rwlock_write( &stake_delegations->delta_lock );
     338             : 
     339           2 :   fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
     340           2 :   FD_CRIT( delta_pool_free( delta_pool ), "no free stake delegations in pool" );
     341             : 
     342           2 :   fork_dlist_t * dlist = get_fork_dlist( stake_delegations, fork_idx );
     343             : 
     344           2 :   fd_stake_delegation_t * stake_delegation = delta_pool_ele_acquire( delta_pool );
     345             : 
     346           2 :   fork_dlist_ele_push_tail( dlist, stake_delegation, delta_pool );
     347             : 
     348           2 :   stake_delegation->stake_account        = *stake_account;
     349           2 :   stake_delegation->vote_account         = *vote_account;
     350           2 :   stake_delegation->stake                = stake;
     351           2 :   stake_delegation->activation_epoch     = (ushort)fd_ulong_min( activation_epoch, USHORT_MAX );
     352           2 :   stake_delegation->deactivation_epoch   = (ushort)fd_ulong_min( deactivation_epoch, USHORT_MAX );
     353           2 :   stake_delegation->credits_observed     = credits_observed;
     354           2 :   stake_delegation->warmup_cooldown_rate = fd_stake_delegations_warmup_cooldown_rate_enum( warmup_cooldown_rate );
     355           2 :   stake_delegation->is_tombstone         = 0;
     356             : 
     357           2 :   fd_rwlock_unwrite( &stake_delegations->delta_lock );
     358           2 : }
     359             : 
     360             : void
     361             : fd_stake_delegations_fork_remove( fd_stake_delegations_t * stake_delegations,
     362             :                                   ushort                   fork_idx,
     363           0 :                                   fd_pubkey_t const *      stake_account ) {
     364           0 :   fd_rwlock_write( &stake_delegations->delta_lock );
     365             : 
     366           0 :   fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
     367           0 :   FD_CRIT( delta_pool_free( delta_pool ), "no free stake delegations in pool" );
     368             : 
     369           0 :   fd_stake_delegation_t * stake_delegation = delta_pool_ele_acquire( delta_pool );
     370             : 
     371           0 :   fork_dlist_t * dlist = get_fork_dlist( stake_delegations, fork_idx );
     372           0 :   fork_dlist_ele_push_tail( dlist, stake_delegation, delta_pool );
     373             : 
     374           0 :   stake_delegation->stake_account = *stake_account;
     375           0 :   stake_delegation->is_tombstone  = 1;
     376             : 
     377           0 :   fd_rwlock_unwrite( &stake_delegations->delta_lock );
     378           0 : }
     379             : 
     380             : void
     381             : fd_stake_delegations_evict_fork( fd_stake_delegations_t * stake_delegations,
     382         299 :                                  ushort                   fork_idx ) {
     383         299 :   if( fork_idx==USHORT_MAX ) return;
     384             : 
     385         299 :   fd_rwlock_write( &stake_delegations->delta_lock );
     386             : 
     387         299 :   fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
     388             : 
     389         299 :   fork_dlist_t * dlist = get_fork_dlist( stake_delegations, fork_idx );
     390         301 :   while( !fork_dlist_is_empty( dlist, delta_pool ) ) {
     391           2 :     fd_stake_delegation_t * ele = fork_dlist_ele_pop_head( dlist, delta_pool );
     392           2 :     delta_pool_ele_release( delta_pool, ele );
     393           2 :   }
     394             : 
     395         299 :   fork_pool_idx_release( get_fork_pool( stake_delegations ), fork_idx );
     396             : 
     397         299 :   fd_rwlock_unwrite( &stake_delegations->delta_lock );
     398         299 : }
     399             : 
     400             : void
     401             : fd_stake_delegations_apply_fork_delta( fd_stake_delegations_t * stake_delegations,
     402           0 :                                        ushort                   fork_idx ) {
     403             : 
     404           0 :   fork_dlist_t *          dlist      = get_fork_dlist( stake_delegations, fork_idx );
     405           0 :   fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
     406             : 
     407           0 :   for( fork_dlist_iter_t iter = fork_dlist_iter_fwd_init( dlist, delta_pool );
     408           0 :        !fork_dlist_iter_done( iter, dlist, delta_pool );
     409           0 :        iter = fork_dlist_iter_fwd_next( iter, dlist, delta_pool ) ) {
     410           0 :     fd_stake_delegation_t * stake_delegation = fork_dlist_iter_ele( iter, dlist, delta_pool );
     411           0 :     if( FD_LIKELY( !stake_delegation->is_tombstone ) ) {
     412           0 :       fd_stake_delegations_root_update(
     413           0 :           stake_delegations,
     414           0 :           &stake_delegation->stake_account,
     415           0 :           &stake_delegation->vote_account,
     416           0 :           stake_delegation->stake,
     417           0 :           stake_delegation->activation_epoch,
     418           0 :           stake_delegation->deactivation_epoch,
     419           0 :           stake_delegation->credits_observed,
     420           0 :           fd_stake_delegations_warmup_cooldown_rate_to_double( stake_delegation->warmup_cooldown_rate ) );
     421           0 :     } else {
     422           0 :       fd_stake_delegations_remove( stake_delegations, &stake_delegation->stake_account );
     423           0 :     }
     424           0 :   }
     425           0 : }
     426             : 
     427             : /* Combined base+delta iterator */
     428             : 
     429             : fd_stake_delegation_t const *
     430          14 : fd_stake_delegations_iter_ele( fd_stake_delegations_iter_t * iter ) {
     431          14 :   ulong idx = root_map_iter_idx( iter->iter, iter->root_map, iter->root_pool );
     432          14 :   fd_stake_delegation_t * stake_delegation = root_pool_ele( iter->root_pool, idx );
     433          14 :   if( FD_UNLIKELY( stake_delegation->delta_idx!=UINT_MAX ) ) {
     434           0 :     return (fd_stake_delegation_t *)delta_pool_ele( iter->delta_pool, stake_delegation->delta_idx );
     435           0 :   }
     436          14 :   return stake_delegation;
     437          14 : }
     438             : 
     439             : ulong
     440          10 : fd_stake_delegations_iter_idx( fd_stake_delegations_iter_t * iter ) {
     441          10 :   return root_map_iter_idx( iter->iter, iter->root_map, iter->root_pool );
     442          10 : }
     443             : 
     444             : static void
     445          28 : skip_tombstones( fd_stake_delegations_iter_t * iter ) {
     446          28 :   while( !root_map_iter_done( iter->iter, iter->root_map, iter->root_pool ) ) {
     447          14 :     fd_stake_delegation_t *       root_delegation = root_map_iter_ele( iter->iter, iter->root_map, iter->root_pool );
     448          14 :     fd_stake_delegation_t const * ele             = (root_delegation->delta_idx != UINT_MAX)
     449          14 :       ? (fd_stake_delegation_t const *)delta_pool_ele( iter->delta_pool, root_delegation->delta_idx )
     450          14 :       : (fd_stake_delegation_t const *)root_delegation;
     451          14 :     if( FD_LIKELY( !ele->is_tombstone ) ) return;
     452           0 :     iter->iter = root_map_iter_next( iter->iter, iter->root_map, iter->root_pool );
     453           0 :   }
     454          28 : }
     455             : 
     456             : fd_stake_delegations_iter_t *
     457             : fd_stake_delegations_iter_init( fd_stake_delegations_iter_t *  iter,
     458          14 :                                 fd_stake_delegations_t const * stake_delegations ) {
     459          14 :   if( FD_UNLIKELY( !stake_delegations ) ) {
     460           0 :     FD_LOG_CRIT(( "NULL stake_delegations" ));
     461           0 :   }
     462             : 
     463          14 :   iter->root_map   = get_root_map( stake_delegations );
     464          14 :   iter->root_pool  = get_root_pool( stake_delegations );
     465          14 :   iter->iter       = root_map_iter_init( iter->root_map, iter->root_pool );
     466          14 :   iter->delta_pool = get_delta_pool( stake_delegations );
     467             : 
     468          14 :   skip_tombstones( iter );
     469             : 
     470          14 :   return iter;
     471          14 : }
     472             : 
     473             : void
     474          14 : fd_stake_delegations_iter_next( fd_stake_delegations_iter_t * iter ) {
     475          14 :   iter->iter = root_map_iter_next( iter->iter, iter->root_map, iter->root_pool );
     476          14 :   skip_tombstones( iter );
     477          14 : }
     478             : 
     479             : int
     480          28 : fd_stake_delegations_iter_done( fd_stake_delegations_iter_t * iter ) {
     481          28 :   return root_map_iter_done( iter->iter, iter->root_map, iter->root_pool );
     482          28 : }
     483             : 
     484             : void
     485             : fd_stake_delegations_mark_delta( fd_stake_delegations_t * stake_delegations,
     486           4 :                                  ushort                   fork_idx ) {
     487             : 
     488           4 :   root_map_t *            root_map   = get_root_map( stake_delegations );
     489           4 :   fd_stake_delegation_t * root_pool  = get_root_pool( stake_delegations );
     490           4 :   fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
     491           4 :   fork_dlist_t *          fork_dlist = get_fork_dlist( stake_delegations, fork_idx );
     492             : 
     493           4 :   for( fork_dlist_iter_t iter = fork_dlist_iter_fwd_init( fork_dlist, delta_pool );
     494           4 :        !fork_dlist_iter_done( iter, fork_dlist, delta_pool );
     495           4 :        iter = fork_dlist_iter_fwd_next( iter, fork_dlist, delta_pool ) ) {
     496           0 :     fd_stake_delegation_t * delta_delegation = fork_dlist_iter_ele( iter, fork_dlist, delta_pool );
     497             : 
     498           0 :     fd_stake_delegation_t * base_delegation = root_map_ele_query( root_map, &delta_delegation->stake_account, NULL, root_pool);
     499           0 :     if( FD_UNLIKELY( !base_delegation ) ) {
     500           0 :       base_delegation                = root_pool_ele_acquire( root_pool );
     501           0 :       base_delegation->stake_account = delta_delegation->stake_account;
     502           0 :       root_map_ele_insert( root_map, base_delegation, root_pool );
     503             : 
     504           0 :       base_delegation->dne_in_root = 1;
     505           0 :       base_delegation->delta_idx   = (uint)delta_pool_idx( delta_pool, delta_delegation );
     506           0 :     } else {
     507           0 :       base_delegation->delta_idx = (uint)delta_pool_idx( delta_pool, delta_delegation );
     508           0 :     }
     509           0 :   }
     510           4 : }
     511             : 
     512             : void
     513             : fd_stake_delegations_unmark_delta( fd_stake_delegations_t * stake_delegations,
     514           4 :                                    ushort                   fork_idx ) {
     515             : 
     516           4 :   root_map_t *            root_map   = get_root_map( stake_delegations );
     517           4 :   fd_stake_delegation_t * root_pool  = get_root_pool( stake_delegations );
     518           4 :   fork_dlist_t *          fork_dlist = get_fork_dlist( stake_delegations, fork_idx );
     519           4 :   fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
     520             : 
     521           4 :   for( fork_dlist_iter_t iter = fork_dlist_iter_fwd_init( fork_dlist, delta_pool );
     522           4 :        !fork_dlist_iter_done( iter, fork_dlist, delta_pool );
     523           4 :        iter = fork_dlist_iter_fwd_next( iter, fork_dlist, delta_pool ) ) {
     524           0 :     fd_stake_delegation_t * delta_delegation = fork_dlist_iter_ele( iter, fork_dlist, delta_pool );
     525             : 
     526           0 :     fd_stake_delegation_t * base_delegation = root_map_ele_query( root_map, &delta_delegation->stake_account, NULL, root_pool );
     527           0 :     if( FD_UNLIKELY( !base_delegation ) ) {
     528           0 :       continue;
     529           0 :     }
     530             : 
     531           0 :     if( FD_UNLIKELY( base_delegation->dne_in_root )) {
     532           0 :       base_delegation->dne_in_root = 0;
     533           0 :       base_delegation->delta_idx   = UINT_MAX;
     534           0 :       root_map_ele_remove( root_map, &delta_delegation->stake_account, NULL, root_pool );
     535           0 :       root_pool_ele_release( root_pool, base_delegation );
     536           0 :     } else {
     537           0 :       base_delegation->delta_idx = UINT_MAX;
     538           0 :     }
     539           0 :   }
     540           4 : }

Generated by: LCOV version 1.14