LCOV - code coverage report
Current view: top level - flamenco/rewards - fd_epoch_rewards.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 120 174 69.0 %
Date: 2025-08-05 05:04:49 Functions: 9 9 100.0 %

          Line data    Source code
       1             : #include "fd_epoch_rewards.h"
       2             : #include "../../ballet/siphash13/fd_siphash13.h"
       3             : 
       4             : ulong
       5         843 : fd_epoch_rewards_align( void ) {
       6         843 :   return FD_EPOCH_REWARDS_ALIGN;
       7         843 : }
       8             : 
       9             : ulong
      10          21 : fd_epoch_rewards_footprint( ulong stake_account_max ) {
      11          21 :   ulong l = FD_LAYOUT_INIT;
      12          21 :   l = FD_LAYOUT_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
      13          21 :   l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
      14          21 :   l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() * FD_REWARDS_MAX_PARTITIONS );
      15          21 :   return FD_LAYOUT_FINI( l, fd_epoch_rewards_align() );
      16          21 : }
      17             : 
      18             : void *
      19           9 : fd_epoch_rewards_new( void * shmem, ulong stake_account_max ) {
      20             : 
      21           9 :   if( FD_UNLIKELY( !shmem ) ) {
      22           3 :     FD_LOG_WARNING(( "NULL mem" ));
      23           3 :     return NULL;
      24           3 :   }
      25             : 
      26           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_epoch_rewards_align() ) ) ) {
      27           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      28           0 :     return NULL;
      29           0 :   }
      30             : 
      31           6 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      32           6 :   fd_epoch_rewards_t * epoch_rewards = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
      33             : 
      34           6 :   void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
      35           6 :   if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_new( pool, stake_account_max ) ) ) {
      36           0 :     FD_LOG_WARNING(( "bad pool" ));
      37           0 :     return NULL;
      38           0 :   }
      39             : 
      40        3096 :   for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
      41        3090 :     void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
      42        3090 :     if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_new( dlist ) ) ) {
      43           0 :       FD_LOG_WARNING(( "bad dlist at idx %lu", i ));
      44           0 :       return NULL;
      45           0 :     }
      46        3090 :   }
      47             : 
      48           6 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() ) != (ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
      49           0 :     FD_LOG_WARNING(( "bad footprint" ));
      50           0 :     return NULL;
      51           0 :   }
      52             : 
      53           6 :   memset( epoch_rewards, 0, sizeof(fd_epoch_rewards_t) );
      54             : 
      55           6 :   epoch_rewards->magic              = FD_EPOCH_REWARDS_MAGIC;
      56           6 :   epoch_rewards->stake_account_max_ = stake_account_max;
      57             : 
      58           6 :   return shmem;
      59           6 : }
      60             : 
      61             : fd_epoch_rewards_t *
      62          15 : fd_epoch_rewards_join( void * shmem ) {
      63          15 :   if( FD_UNLIKELY( !shmem ) ) {
      64           3 :     FD_LOG_WARNING(( "NULL mem" ));
      65           3 :     return NULL;
      66           3 :   }
      67             : 
      68          12 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_epoch_rewards_align() ) ) ) {
      69           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      70           0 :     return NULL;
      71           0 :   }
      72             : 
      73          12 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      74          12 :   fd_epoch_rewards_t * epoch_rewards = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
      75           0 :   ulong stake_account_max = epoch_rewards->stake_account_max_;
      76             : 
      77          12 :   void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
      78          12 :   if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_join( pool ) ) ) {
      79           0 :     FD_LOG_WARNING(( "bad pool" ));
      80           0 :     return NULL;
      81           0 :   }
      82             : 
      83        6192 :   for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
      84        6180 :     void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
      85        6180 :     if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_join( dlist ) ) ) {
      86           0 :       FD_LOG_WARNING(( "bad dlist at idx %lu", i ));
      87           0 :       return NULL;
      88           0 :     }
      89        6180 :   }
      90             : 
      91          12 :   if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() ) != (ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
      92           0 :     FD_LOG_WARNING(( "bad footprint" ));
      93           0 :     return NULL;
      94           0 :   }
      95             : 
      96          12 :   if( FD_UNLIKELY( epoch_rewards->magic!=FD_EPOCH_REWARDS_MAGIC ) ) {
      97           6 :     FD_LOG_WARNING(( "bad magic" ));
      98           6 :     return NULL;
      99           6 :   }
     100             : 
     101           6 :   return epoch_rewards;
     102          12 : }
     103             : 
     104             : void *
     105           6 : fd_epoch_rewards_leave( fd_epoch_rewards_t const * epoch_rewards ) {
     106           6 :   return (void *)epoch_rewards;
     107           6 : }
     108             : 
     109             : void *
     110           3 : fd_epoch_rewards_delete( void * epoch_rewards_shmem ) {
     111           3 :   fd_epoch_rewards_t * epoch_rewards = (fd_epoch_rewards_t *)epoch_rewards_shmem;
     112             : 
     113           3 :   if( FD_UNLIKELY( !epoch_rewards ) ) {
     114           0 :     FD_LOG_WARNING(( "NULL epoch_rewards" ));
     115           0 :     return NULL;
     116           0 :   }
     117             : 
     118           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)epoch_rewards, fd_epoch_rewards_align() ) ) ) {
     119           0 :     FD_LOG_WARNING(( "misaligned epoch_rewards" ));
     120           0 :     return NULL;
     121           0 :   }
     122             : 
     123           3 :   if( FD_UNLIKELY( epoch_rewards->magic != FD_EPOCH_REWARDS_MAGIC ) ) {
     124           0 :     FD_LOG_WARNING(( "bad magic" ));
     125           0 :     return NULL;
     126           0 :   }
     127             : 
     128           3 :   epoch_rewards->magic = 0UL;
     129             : 
     130           3 :   return epoch_rewards_shmem;
     131           3 : }
     132             : 
     133             : fd_epoch_stake_reward_dlist_t *
     134         324 : fd_epoch_rewards_get_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong idx ) {
     135         324 :   if( FD_UNLIKELY( idx >= epoch_rewards->num_partitions_ ) ) {
     136           9 :     FD_LOG_WARNING(( "idx: %lu is greater than num_partitions: %lu", idx, epoch_rewards->num_partitions_ ));
     137           9 :     return NULL;
     138           9 :   }
     139             : 
     140         315 :   FD_SCRATCH_ALLOC_INIT( l, epoch_rewards );
     141         315 :   FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
     142         315 :   FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( epoch_rewards->stake_account_max_ ) );
     143       15891 :   for( ulong i=0UL; i<idx; i++ ) {
     144       15576 :     FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
     145       15576 :   }
     146         315 :   void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
     147             : 
     148           0 :   fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_stake_reward_dlist_join( dlist );
     149         315 :   if( FD_UNLIKELY( !partition_dlist ) ) {
     150           0 :     FD_LOG_WARNING(( "bad dlist" ));
     151           0 :     return NULL;
     152           0 :   }
     153         315 :   return partition_dlist;
     154         315 : }
     155             : 
     156             : fd_epoch_stake_reward_t *
     157          15 : fd_epoch_rewards_get_stake_reward_pool( fd_epoch_rewards_t const * epoch_rewards ) {
     158          15 :   if( FD_UNLIKELY( !epoch_rewards ) ) {
     159           3 :     FD_LOG_WARNING(( "NULL epoch_rewards" ));
     160           3 :     return NULL;
     161           3 :   }
     162             : 
     163          12 :   FD_SCRATCH_ALLOC_INIT( l, epoch_rewards );
     164          12 :   FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
     165          12 :   void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( epoch_rewards->stake_account_max_ ) );
     166           0 :   fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_stake_reward_pool_join( pool );
     167          12 :   if( FD_UNLIKELY( !stake_reward_pool ) ) {
     168           0 :     FD_LOG_WARNING(( "bad stake_reward_pool" ));
     169           0 :     return NULL;
     170           0 :   }
     171          12 :   return stake_reward_pool;
     172          12 : }
     173             : 
     174             : int
     175             : fd_epoch_rewards_hash_and_insert( fd_epoch_rewards_t * epoch_rewards,
     176             :                                   fd_hash_t const *    parent_blockhash,
     177             :                                   fd_pubkey_t const *  pubkey,
     178             :                                   ulong                credits,
     179          18 :                                   ulong                lamports ) {
     180             : 
     181          18 :   if( FD_UNLIKELY( !epoch_rewards ) ) {
     182           3 :     FD_LOG_WARNING(( "NULL epoch_rewards" ));
     183           3 :     return 1;
     184           3 :   }
     185             : 
     186          15 :   if( FD_UNLIKELY( !parent_blockhash ) ) {
     187           3 :     FD_LOG_WARNING(( "NULL parent_blockhash" ));
     188           3 :     return 1;
     189           3 :   }
     190             : 
     191          12 :   if( FD_UNLIKELY( !pubkey ) ) {
     192           3 :     FD_LOG_WARNING(( "NULL pubkey" ));
     193           3 :     return 1;
     194           3 :   }
     195             : 
     196             :   /* First figure out which partition the pubkey belongs to. */
     197           9 :   fd_siphash13_t   sip[1] = {0};
     198           9 :   fd_siphash13_t * hasher = fd_siphash13_init( sip, 0UL, 0UL );
     199             : 
     200           9 :   hasher = fd_siphash13_append( hasher, parent_blockhash->hash, sizeof(fd_hash_t) );
     201           9 :   fd_siphash13_append( hasher, (uchar const *)pubkey, sizeof(fd_pubkey_t) );
     202           9 :   ulong hash64 = fd_siphash13_fini( hasher );
     203             : 
     204             :   /* Now get the correct dlist based on the hash. */
     205           9 :   ulong partition_index = (ulong)((uint128)epoch_rewards->num_partitions_ * (uint128) hash64 / ((uint128)ULONG_MAX + 1));
     206             : 
     207           9 :   fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, partition_index );
     208           9 :   if( FD_UNLIKELY( !partition_dlist ) ) {
     209           0 :     FD_LOG_WARNING(( "bad partition_dlist" ));
     210           0 :     return 1;
     211           0 :   }
     212             : 
     213             :   /* Acquire a stake reward from the pool's free list and add it to
     214             :      the tail of the dlist. */
     215           9 :   fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
     216           9 :   if( FD_UNLIKELY( !stake_reward_pool ) ) {
     217           0 :     FD_LOG_WARNING(( "bad stake_reward_pool" ));
     218           0 :     return 1;
     219           0 :   }
     220             : 
     221           9 :   if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_free( stake_reward_pool ) ) ) {
     222           0 :     FD_LOG_WARNING(( "stake_reward_pool is full" ));
     223           0 :     return 1;
     224           0 :   }
     225             : 
     226           9 :   fd_epoch_stake_reward_t * stake_reward = fd_epoch_stake_reward_pool_ele_acquire( stake_reward_pool );
     227           9 :   if( FD_UNLIKELY( !stake_reward ) ) {
     228           0 :     FD_LOG_WARNING(( "bad stake_reward" ));
     229           0 :     return 1;
     230           0 :   }
     231             : 
     232           9 :   stake_reward->stake_pubkey     = *pubkey;
     233           9 :   stake_reward->credits_observed = credits;
     234           9 :   stake_reward->lamports         = lamports;
     235             : 
     236           9 :   fd_epoch_stake_reward_dlist_ele_push_tail( partition_dlist, stake_reward, stake_reward_pool );
     237           9 :   return 0;
     238           9 : }
     239             : 

Generated by: LCOV version 1.14