LCOV - code coverage report
Current view: top level - flamenco/rewards - fd_epoch_rewards.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 145 191 75.9 %
Date: 2026-01-22 05:10:09 Functions: 16 16 100.0 %

          Line data    Source code
       1             : #include "fd_epoch_rewards.h"
       2             : #include "../../ballet/siphash13/fd_siphash13.h"
       3             : 
       4             : #define POOL_NAME  fd_epoch_stake_reward_pool
       5         708 : #define POOL_T     fd_epoch_stake_reward_t
       6             : #define POOL_IDX_T uint
       7             : #include "../../util/tmpl/fd_pool.c"
       8             : 
       9             : #define MAP_NAME               fd_epoch_stake_reward_map
      10             : #define MAP_KEY_T              fd_pubkey_t
      11             : #define MAP_ELE_T              fd_epoch_stake_reward_t
      12           9 : #define MAP_KEY                stake_pubkey
      13           0 : #define MAP_KEY_EQ(k0,k1)      (fd_pubkey_eq( k0, k1 ))
      14          18 : #define MAP_KEY_HASH(key,seed) (fd_hash( seed, key, sizeof(fd_pubkey_t) ))
      15          18 : #define MAP_NEXT               next_map
      16         387 : #define MAP_IDX_T              uint
      17             : #include "../../util/tmpl/fd_map_chain.c"
      18             : 
      19             : static inline fd_epoch_stake_reward_t *
      20          42 : fd_epoch_rewards_get_stake_reward_pool( fd_epoch_rewards_t const * epoch_rewards ) {
      21          42 :   return fd_epoch_stake_reward_pool_join( (uchar *)epoch_rewards + epoch_rewards->pool_offset );
      22          42 : }
      23             : 
      24             : static inline fd_epoch_stake_reward_map_t *
      25          36 : fd_epoch_rewards_get_stake_reward_map( fd_epoch_rewards_t const * epoch_rewards ) {
      26          36 :   return fd_epoch_stake_reward_map_join( (uchar *)epoch_rewards + epoch_rewards->map_offset );
      27          36 : }
      28             : 
      29             : static inline fd_epoch_stake_reward_dlist_t *
      30        8811 : fd_epoch_rewards_get_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong idx ) {
      31        8811 :   fd_epoch_stake_reward_dlist_t * dlist_idx_zero  = (fd_epoch_stake_reward_dlist_t *)((uchar *)epoch_rewards + epoch_rewards->dlists_offset);
      32        8811 :   fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_stake_reward_dlist_join( dlist_idx_zero + idx );
      33        8811 :   return partition_dlist;
      34        8811 : }
      35             : 
      36             : ulong
      37        5364 : fd_epoch_rewards_align( void ) {
      38        5364 :   return FD_EPOCH_REWARDS_ALIGN;
      39        5364 : }
      40             : 
      41             : ulong
      42         672 : fd_epoch_rewards_footprint( ulong stake_account_max ) {
      43         672 :   ulong chain_cnt_est = fd_epoch_stake_reward_map_chain_cnt_est( stake_account_max );
      44             : 
      45         672 :   ulong l = FD_LAYOUT_INIT;
      46         672 :   l = FD_LAYOUT_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
      47         672 :   l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
      48         672 :   l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( chain_cnt_est ) );
      49         672 :   l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() * FD_REWARDS_MAX_PARTITIONS );
      50         672 :   return FD_LAYOUT_FINI( l, fd_epoch_rewards_align() );
      51         672 : }
      52             : 
      53             : void *
      54             : fd_epoch_rewards_new( void * shmem,
      55             :                       ulong  stake_account_max,
      56         327 :                       ulong  seed ) {
      57             : 
      58         327 :   if( FD_UNLIKELY( !shmem ) ) {
      59           3 :     FD_LOG_WARNING(( "NULL mem" ));
      60           3 :     return NULL;
      61           3 :   }
      62             : 
      63         324 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_epoch_rewards_align() ) ) ) {
      64           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      65           0 :     return NULL;
      66           0 :   }
      67             : 
      68         324 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      69         324 :   fd_epoch_rewards_t * epoch_rewards = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
      70           0 :   memset( epoch_rewards, 0, sizeof(fd_epoch_rewards_t) );
      71             : 
      72         324 :   void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
      73           0 :   epoch_rewards->pool_offset = (ulong)pool - (ulong)shmem;
      74         324 :   if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_new( pool, stake_account_max ) ) ) {
      75           0 :     FD_LOG_WARNING(( "bad pool" ));
      76           0 :     return NULL;
      77           0 :   }
      78             : 
      79         324 :   ulong chain_cnt_est = fd_epoch_stake_reward_map_chain_cnt_est( stake_account_max );
      80         324 :   void * map = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( chain_cnt_est ) );
      81           0 :   epoch_rewards->map_offset = (ulong)map - (ulong)shmem;
      82         324 :   if( FD_UNLIKELY( !fd_epoch_stake_reward_map_new( map, chain_cnt_est, seed ) ) ) {
      83           0 :     FD_LOG_WARNING(( "bad map" ));
      84           0 :     return NULL;
      85           0 :   }
      86             : 
      87      237816 :   for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
      88      237492 :     void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
      89      237492 :     if( i==0UL ) epoch_rewards->dlists_offset = (ulong)dlist - (ulong)shmem;
      90      237492 :     if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_new( dlist ) ) ) {
      91           0 :       FD_LOG_WARNING(( "bad dlist at idx %lu", i ));
      92           0 :       return NULL;
      93           0 :     }
      94      237492 :   }
      95             : 
      96         324 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() ) != (ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
      97           0 :     FD_LOG_WARNING(( "bad footprint" ));
      98           0 :     return NULL;
      99           0 :   }
     100             : 
     101             : 
     102         324 :   FD_COMPILER_MFENCE();
     103         324 :   epoch_rewards->magic = FD_EPOCH_REWARDS_MAGIC;
     104         324 :   FD_COMPILER_MFENCE();
     105             : 
     106         324 :   epoch_rewards->stake_account_max = stake_account_max;
     107             : 
     108         324 :   return shmem;
     109         324 : }
     110             : 
     111             : fd_epoch_rewards_t *
     112         345 : fd_epoch_rewards_join( void * shmem ) {
     113         345 :   if( FD_UNLIKELY( !shmem ) ) {
     114           3 :     FD_LOG_WARNING(( "NULL mem" ));
     115           3 :     return NULL;
     116           3 :   }
     117             : 
     118         342 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_epoch_rewards_align() ) ) ) {
     119           0 :     FD_LOG_WARNING(( "misaligned mem" ));
     120           0 :     return NULL;
     121           0 :   }
     122             : 
     123         342 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     124         342 :   fd_epoch_rewards_t * epoch_rewards = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
     125           0 :   ulong stake_account_max = epoch_rewards->stake_account_max;
     126             : 
     127         342 :   void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
     128         342 :   if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_join( pool ) ) ) {
     129           0 :     FD_LOG_WARNING(( "bad pool" ));
     130           0 :     return NULL;
     131           0 :   }
     132             : 
     133         342 :   ulong chain_cnt_est = fd_epoch_stake_reward_map_chain_cnt_est( stake_account_max );
     134         342 :   void * map = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( chain_cnt_est ) );
     135         342 :   if( FD_UNLIKELY( !fd_epoch_stake_reward_map_join( map ) ) ) {
     136           0 :     FD_LOG_WARNING(( "bad map" ));
     137           0 :     return NULL;
     138           0 :   }
     139             : 
     140      251028 :   for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
     141      250686 :     void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
     142      250686 :     if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_join( dlist ) ) ) {
     143           0 :       FD_LOG_WARNING(( "bad dlist at idx %lu", i ));
     144           0 :       return NULL;
     145           0 :     }
     146      250686 :   }
     147             : 
     148         342 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() )!=(ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
     149           0 :     FD_LOG_WARNING(( "bad footprint" ));
     150           0 :     return NULL;
     151           0 :   }
     152             : 
     153         342 :   if( FD_UNLIKELY( epoch_rewards->magic!=FD_EPOCH_REWARDS_MAGIC ) ) {
     154           6 :     FD_LOG_WARNING(( "bad magic" ));
     155           6 :     return NULL;
     156           6 :   }
     157             : 
     158         336 :   return epoch_rewards;
     159         342 : }
     160             : 
     161             : void *
     162           6 : fd_epoch_rewards_leave( fd_epoch_rewards_t const * epoch_rewards ) {
     163           6 :   return (void *)epoch_rewards;
     164           6 : }
     165             : 
     166             : void *
     167           3 : fd_epoch_rewards_delete( void * epoch_rewards_shmem ) {
     168           3 :   fd_epoch_rewards_t * epoch_rewards = (fd_epoch_rewards_t *)epoch_rewards_shmem;
     169             : 
     170           3 :   if( FD_UNLIKELY( !epoch_rewards ) ) {
     171           0 :     FD_LOG_WARNING(( "NULL epoch_rewards" ));
     172           0 :     return NULL;
     173           0 :   }
     174             : 
     175           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)epoch_rewards, fd_epoch_rewards_align() ) ) ) {
     176           0 :     FD_LOG_WARNING(( "misaligned epoch_rewards" ));
     177           0 :     return NULL;
     178           0 :   }
     179             : 
     180           3 :   if( FD_UNLIKELY( epoch_rewards->magic != FD_EPOCH_REWARDS_MAGIC ) ) {
     181           0 :     FD_LOG_WARNING(( "bad magic" ));
     182           0 :     return NULL;
     183           0 :   }
     184             : 
     185           3 :   epoch_rewards->magic = 0UL;
     186             : 
     187           3 :   return epoch_rewards_shmem;
     188           3 : }
     189             : 
     190             : void
     191          12 : fd_epoch_rewards_init( fd_epoch_rewards_t * epoch_rewards ) {
     192          12 :   fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
     193        8808 :   for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
     194        8796 :     fd_epoch_stake_reward_dlist_t * dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, i );
     195        8796 :     fd_epoch_stake_reward_dlist_remove_all( dlist, stake_reward_pool );
     196        8796 :   }
     197             : 
     198          12 :   fd_epoch_stake_reward_map_t * stake_reward_map  = fd_epoch_rewards_get_stake_reward_map( epoch_rewards );
     199          12 :   fd_epoch_stake_reward_map_reset( stake_reward_map );
     200             : 
     201          12 :   fd_epoch_stake_reward_pool_reset( stake_reward_pool );
     202             : 
     203          12 :   epoch_rewards->stake_rewards_cnt   = 0UL;
     204          12 :   epoch_rewards->total_stake_rewards = 0UL;
     205          12 : }
     206             : 
     207             : void
     208             : fd_epoch_rewards_insert( fd_epoch_rewards_t * epoch_rewards,
     209             :                          fd_pubkey_t const *  pubkey,
     210             :                          ulong                credits,
     211           9 :                          ulong                lamports ) {
     212           9 :   fd_epoch_stake_reward_t *     stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
     213           9 :   fd_epoch_stake_reward_map_t * stake_reward_map  = fd_epoch_rewards_get_stake_reward_map( epoch_rewards );
     214             : 
     215           9 :   if( FD_UNLIKELY( fd_epoch_stake_reward_map_ele_query( stake_reward_map, pubkey, NULL, stake_reward_pool ) ) ) {
     216           0 :     FD_LOG_CRIT(( "invariant violation: stake reward entry already exists" ));
     217           0 :   }
     218             : 
     219           9 :   fd_epoch_stake_reward_t * stake_reward = fd_epoch_stake_reward_pool_ele_acquire( stake_reward_pool );
     220             : 
     221           9 :   stake_reward->stake_pubkey     = *pubkey;
     222           9 :   stake_reward->credits_observed = credits;
     223           9 :   stake_reward->lamports         = lamports;
     224             : 
     225           9 :   fd_epoch_stake_reward_map_ele_insert( stake_reward_map, stake_reward, stake_reward_pool );
     226             : 
     227           9 :   epoch_rewards->total_stake_rewards += lamports;
     228           9 :   epoch_rewards->stake_rewards_cnt++;
     229             : 
     230           9 : }
     231             : 
     232             : void
     233             : fd_epoch_rewards_hash_into_partitions( fd_epoch_rewards_t * epoch_rewards,
     234             :                                        fd_hash_t const *    parent_blockhash,
     235          15 :                                        ulong                num_partitions ) {
     236             : 
     237          15 :   fd_epoch_stake_reward_t *     stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
     238          15 :   fd_epoch_stake_reward_map_t * stake_reward_map  = fd_epoch_rewards_get_stake_reward_map( epoch_rewards );
     239             : 
     240          15 :   epoch_rewards->num_partitions = num_partitions;
     241             : 
     242          15 :   for( fd_epoch_stake_reward_map_iter_t iter = fd_epoch_stake_reward_map_iter_init( stake_reward_map, stake_reward_pool );
     243          24 :        !fd_epoch_stake_reward_map_iter_done( iter, stake_reward_map, stake_reward_pool );
     244          15 :        iter = fd_epoch_stake_reward_map_iter_next( iter, stake_reward_map, stake_reward_pool ) ) {
     245             : 
     246           9 :     fd_epoch_stake_reward_t * stake_reward = fd_epoch_stake_reward_map_iter_ele( iter, stake_reward_map, stake_reward_pool );
     247             : 
     248           9 :     fd_siphash13_t   sip[1] = {0};
     249           9 :     fd_siphash13_t * hasher = fd_siphash13_init( sip, 0UL, 0UL );
     250           9 :     hasher = fd_siphash13_append( hasher, parent_blockhash->hash, sizeof(fd_hash_t) );
     251           9 :     fd_siphash13_append( hasher, (uchar const *)stake_reward->stake_pubkey.uc, sizeof(fd_pubkey_t) );
     252           9 :     ulong hash64 = fd_siphash13_fini( hasher );
     253             : 
     254             :     /* Now get the correct dlist based on the hash. */
     255           9 :     ulong partition_index = (ulong)((uint128)num_partitions * (uint128) hash64 / ((uint128)ULONG_MAX + 1));
     256             : 
     257           9 :     fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, partition_index );
     258             : 
     259           9 :     fd_epoch_stake_reward_dlist_ele_push_tail( partition_dlist, stake_reward, stake_reward_pool );
     260           9 :   }
     261          15 : }
     262             : 
     263             : fd_epoch_stake_reward_t *
     264           9 : fd_epoch_rewards_iter_ele( fd_epoch_rewards_iter_t * iter ) {
     265           9 :   return fd_epoch_stake_reward_dlist_iter_ele( iter->iter, iter->dlist, iter->pool );
     266           9 : }
     267             : 
     268             : fd_epoch_rewards_iter_t *
     269             : fd_epoch_rewards_iter_init( fd_epoch_rewards_iter_t *  iter,
     270             :                             fd_epoch_rewards_t const * epoch_rewards,
     271           6 :                             ulong                      partition_idx ) {
     272           6 :   iter->pool  = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
     273           6 :   iter->dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, partition_idx );
     274           6 :   iter->iter  = fd_epoch_stake_reward_dlist_iter_fwd_init( iter->dlist, iter->pool );
     275           6 :   return iter;
     276           6 : }
     277             : 
     278             : int
     279          15 : fd_epoch_rewards_iter_done( fd_epoch_rewards_iter_t * iter ) {
     280          15 :   return fd_epoch_stake_reward_dlist_iter_done( iter->iter, iter->dlist, iter->pool );
     281          15 : }
     282             : 
     283             : void
     284           9 : fd_epoch_rewards_iter_next( fd_epoch_rewards_iter_t * iter ) {
     285           9 :   iter->iter = fd_epoch_stake_reward_dlist_iter_fwd_next( iter->iter, iter->dlist, iter->pool );
     286           9 : }

Generated by: LCOV version 1.14