LCOV - code coverage report
Current view: top level - flamenco/rewards - fd_integer_inflation.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 130 0.0 %
Date: 2026-11-11 12:40:43 Functions: 0 21 0.0 %

          Line data    Source code
       1             : #include "fd_integer_inflation.h"
       2             : #include "../features/fd_features.h"
       3             : #include "../runtime/fd_bank.h"
       4             : #include "../runtime/fd_slot_params.h"
       5             : #include "../runtime/sysvar/fd_sysvar_epoch_schedule.h"
       6             : 
       7             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/math-utils/src/inflation.rs#L6-L8 */
       8           0 : #define FD_INTEGER_INFLATION_RATE_SCALE  (1000000000000000UL)
       9           0 : #define FD_INTEGER_INFLATION_YEAR_NS     (31556925993600000UL)
      10           0 : #define FD_INTEGER_INFLATION_DECAY_SCALE (((uint128)1UL)<<64)
      11             : 
      12             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/runtime/src/bank.rs#L261-L262 */
      13           0 : #define FD_INTEGER_INFLATION_INITIAL_RATE  (80000000000000UL)
      14           0 : #define FD_INTEGER_INFLATION_TERMINAL_RATE (15000000000000UL)
      15             : 
      16             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/runtime/src/bank.rs#L3111
      17             :    https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/runtime/src/bank.rs#L3138-L3143 */
      18             : #define FD_INTEGER_INFLATION_TAPER_DEN                     (100U)
      19           0 : #define FD_INTEGER_INFLATION_TAPER_NUM                     (15U)
      20           0 : #define FD_INTEGER_INFLATION_DOUBLE_DISINFLATION_TAPER_NUM (30U)
      21             : 
      22             : /* approximate_logarithm computes ln(numerator/denominator) scaled by
      23             :    FD_INTEGER_INFLATION_DECAY_SCALE, using the first 32 terms of the
      24             :    atanh series.
      25             : 
      26             :    approximate_logarithm calculates ln(numerator/denominator) using
      27             :    the first 32 terms of the atanh series.  The terms are scaled by
      28             :    FD_INTEGER_INFLATION_DECAY_SCALE.
      29             : 
      30             :    https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/math-utils/src/inflation.rs#L50-L77 */
      31             : static int
      32             : approximate_logarithm( uint      numerator,
      33             :                        uint      denominator,
      34           0 :                        uint128 * out ) {
      35           0 :   if( FD_UNLIKELY( !denominator || numerator<denominator ) ) return -1;
      36             : 
      37           0 :   uint128 z_num    = (uint128)numerator - (uint128)denominator;
      38           0 :   uint128 z_den    = (uint128)numerator + (uint128)denominator;
      39           0 :   uint128 z_num_sq = z_num*z_num;
      40           0 :   uint128 z_den_sq = z_den*z_den;
      41             : 
      42           0 :   uint128 term = ( FD_INTEGER_INFLATION_DECAY_SCALE*z_num ) / z_den;
      43           0 :   uint128 sum  = 0;
      44           0 :   for( ulong i=0UL; i<32UL; i++ ) {
      45           0 :     sum += term / (uint128)( ( 2UL*i )+1UL );
      46           0 :     if( i<31UL ) term = ( term*z_num_sq ) / z_den_sq;
      47           0 :   }
      48             : 
      49           0 :   *out = sum*2;
      50           0 :   return 0;
      51           0 : }
      52             : 
      53             : /* approximate_exponential calculates an approximate value of e^-x
      54             :    using the first 4 terms of it's Taylor series.  x and the result
      55             :    are scaled by FD_INTEGER_INFLATION_DECAY_SCALE.
      56             : 
      57             :    https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/math-utils/src/inflation.rs#L80-L87 */
      58             : static int
      59             : approximate_exponential( uint128   x,
      60           0 :                          uint128 * out ) {
      61           0 :   uint128 x_sq;
      62           0 :   if( FD_UNLIKELY( __builtin_mul_overflow( x, x, &x_sq ) ) ) return -1;
      63           0 :   uint128 second = x_sq / ( 2*FD_INTEGER_INFLATION_DECAY_SCALE );
      64             : 
      65           0 :   uint128 second_x;
      66           0 :   if( FD_UNLIKELY( __builtin_mul_overflow( second, x, &second_x ) ) ) return -1;
      67           0 :   uint128 third = second_x / ( 3*FD_INTEGER_INFLATION_DECAY_SCALE );
      68             : 
      69           0 :   if( FD_UNLIKELY( second>x ) ) return -1;
      70           0 :   uint128 decrement;
      71           0 :   if( FD_UNLIKELY( __builtin_add_overflow( x-second, third, &decrement ) ) ) return -1;
      72           0 :   if( FD_UNLIKELY( decrement>FD_INTEGER_INFLATION_DECAY_SCALE ) ) return -1;
      73             : 
      74           0 :   *out = FD_INTEGER_INFLATION_DECAY_SCALE - decrement;
      75           0 :   return 0;
      76           0 : }
      77             : 
      78             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/math-utils/src/inflation.rs#L93-L101 */
      79             : static int
      80             : decay_per_slot( ulong     ns_per_slot,
      81             :                 uint      taper_num,
      82             :                 uint      taper_den,
      83           0 :                 uint128 * out ) {
      84           0 :   if( FD_UNLIKELY( !ns_per_slot || !taper_den || taper_num>=taper_den ) ) return -1;
      85             : 
      86           0 :   uint128 annual_exponent;
      87           0 :   if( FD_UNLIKELY( approximate_logarithm( taper_den, taper_den-taper_num, &annual_exponent ) ) ) return -1;
      88             : 
      89           0 :   uint128 product;
      90           0 :   if( FD_UNLIKELY( __builtin_mul_overflow( annual_exponent, (uint128)ns_per_slot, &product ) ) ) return -1;
      91             : 
      92           0 :   return approximate_exponential( product / (uint128)FD_INTEGER_INFLATION_YEAR_NS, out );
      93           0 : }
      94             : 
      95             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/math-utils/src/inflation.rs#L105-L116 */
      96             : static uint128
      97             : mul_decay_floor( uint128 a,
      98           0 :                  uint128 b ) {
      99           0 :   if( a==FD_INTEGER_INFLATION_DECAY_SCALE ) return b;
     100           0 :   if( b==FD_INTEGER_INFLATION_DECAY_SCALE ) return a;
     101           0 :   return ( a*b )>>64;
     102           0 : }
     103             : 
     104             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/math-utils/src/inflation.rs#L120-L135 */
     105             : static int
     106             : pow_decay_floor( uint128   base,
     107             :                  ulong     slots,
     108           0 :                  uint128 * out ) {
     109           0 :   if( FD_UNLIKELY( base>FD_INTEGER_INFLATION_DECAY_SCALE ) ) return -1;
     110           0 :   uint128 result = FD_INTEGER_INFLATION_DECAY_SCALE;
     111           0 :   while( slots ) {
     112           0 :     if( slots&1UL ) result = mul_decay_floor( result, base );
     113           0 :     slots >>= 1;
     114           0 :     if( slots ) base = mul_decay_floor( base, base );
     115           0 :   }
     116           0 :   *out = result;
     117           0 :   return 0;
     118           0 : }
     119             : 
     120             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/math-utils/src/inflation.rs#L138-L146 */
     121             : static int
     122             : apply_decay_floor( ulong   anchor_rate,
     123             :                    uint128 decay,
     124           0 :                    ulong * out ) {
     125           0 :   if( FD_UNLIKELY( anchor_rate>FD_INTEGER_INFLATION_RATE_SCALE || decay>FD_INTEGER_INFLATION_DECAY_SCALE ) ) return -1;
     126           0 :   *out = (ulong)( ( (uint128)anchor_rate*decay )>>64 );
     127           0 :   return 0;
     128           0 : }
     129             : 
     130             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/math-utils/src/inflation.rs#L12-L22 */
     131             : static int
     132             : decayed_rate( ulong   anchor_rate,
     133             :               uint    taper_num,
     134             :               uint    taper_den,
     135             :               ulong   ns_per_slot,
     136             :               ulong   slots,
     137           0 :               ulong * out ) {
     138           0 :   uint128 factor;
     139           0 :   if( FD_UNLIKELY( decay_per_slot( ns_per_slot, taper_num, taper_den, &factor ) ) ) return -1;
     140           0 :   uint128 decay;
     141           0 :   if( FD_UNLIKELY( pow_decay_floor( factor, slots, &decay ) ) ) return -1;
     142           0 :   return apply_decay_floor( anchor_rate, decay, out );
     143           0 : }
     144             : 
     145             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/math-utils/src/inflation.rs#L26-L43 */
     146             : static int
     147             : epoch_reward( ulong   capitalization,
     148             :               ulong   rate,
     149             :               ulong   slots_in_epoch,
     150             :               ulong   ns_per_slot,
     151           0 :               ulong * out ) {
     152           0 :   if( FD_UNLIKELY( rate>FD_INTEGER_INFLATION_RATE_SCALE || !ns_per_slot ) ) return -1;
     153             : 
     154           0 :   uint128 annual = ( (uint128)capitalization*(uint128)rate ) / (uint128)FD_INTEGER_INFLATION_RATE_SCALE;
     155             : 
     156           0 :   uint128 reward;
     157           0 :   if( FD_UNLIKELY( __builtin_mul_overflow( annual, (uint128)slots_in_epoch, &reward ) ||
     158           0 :                    __builtin_mul_overflow( reward, (uint128)ns_per_slot,    &reward ) ) ) return -1;
     159           0 :   reward /= (uint128)FD_INTEGER_INFLATION_YEAR_NS;
     160           0 :   if( FD_UNLIKELY( reward>(uint128)ULONG_MAX ) ) return -1;
     161             : 
     162           0 :   *out = (ulong)reward;
     163           0 :   return 0;
     164           0 : }
     165             : 
     166             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/runtime/src/bank.rs#L3089-L3120 */
     167             : static ulong
     168             : integer_inflation_rate_between( fd_bank_t const * bank,
     169             :                                 ulong             anchor_rate,
     170             :                                 ulong             start_slot,
     171             :                                 ulong             end_slot,
     172           0 :                                 uint              taper_num ) {
     173           0 :   if( FD_UNLIKELY( start_slot>end_slot ) ) {
     174           0 :     FD_LOG_ERR(( "inflation rate calculation failed (start_slot=%lu end_slot=%lu)", start_slot, end_slot ));
     175           0 :   }
     176             : 
     177           0 :   fd_features_t const *       features       = &bank->f.features;
     178           0 :   fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
     179             : 
     180           0 :   ulong rate   = anchor_rate;
     181           0 :   ulong cursor = start_slot;
     182           0 :   while( cursor<end_slot ) {
     183           0 :     ulong ns_per_slot = fd_slot_params_at_slot( bank, cursor ).ns_per_slot;
     184           0 :     ulong seg_end     = fd_ulong_min( fd_slot_params_next_transition( features, epoch_schedule, cursor, ns_per_slot ), end_slot );
     185           0 :     if( FD_UNLIKELY( decayed_rate( rate, taper_num, FD_INTEGER_INFLATION_TAPER_DEN, ns_per_slot, seg_end-cursor, &rate ) ) ) {
     186           0 :       FD_LOG_ERR(( "inflation rate calculation failed (rate=%lu taper=%u/%u ns_per_slot=%lu slots=%lu)",
     187           0 :                    rate, taper_num, FD_INTEGER_INFLATION_TAPER_DEN, ns_per_slot, seg_end-cursor ));
     188           0 :     }
     189           0 :     cursor = seg_end;
     190           0 :   }
     191           0 :   return rate;
     192           0 : }
     193             : 
     194             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/runtime/src/bank.rs#L3127-L3146 */
     195             : static ulong
     196             : integer_inflation_rate( fd_bank_t const * bank,
     197           0 :                         ulong             inflation_start_slot ) {
     198           0 :   fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
     199           0 :   ulong end_slot = fd_epoch_slot0( epoch_schedule, fd_slot_to_epoch( epoch_schedule, bank->f.slot, NULL ) );
     200             : 
     201           0 :   ulong rate;
     202           0 :   if( FD_FEATURE_ACTIVE_BANK( bank, double_disinflation_rate ) ) {
     203           0 :     ulong anchor_slot = fd_ulong_min( bank->f.features.double_disinflation_rate, end_slot );
     204           0 :     ulong anchor_rate = integer_inflation_rate_between( bank, FD_INTEGER_INFLATION_INITIAL_RATE, inflation_start_slot, anchor_slot, FD_INTEGER_INFLATION_TAPER_NUM );
     205           0 :     anchor_rate       = fd_ulong_max( anchor_rate, FD_INTEGER_INFLATION_TERMINAL_RATE );
     206           0 :     rate              = integer_inflation_rate_between( bank, anchor_rate, anchor_slot, end_slot, FD_INTEGER_INFLATION_DOUBLE_DISINFLATION_TAPER_NUM );
     207           0 :   } else {
     208           0 :     rate              = integer_inflation_rate_between( bank, FD_INTEGER_INFLATION_INITIAL_RATE, inflation_start_slot, end_slot, FD_INTEGER_INFLATION_TAPER_NUM );
     209           0 :   }
     210           0 :   return fd_ulong_max( rate, FD_INTEGER_INFLATION_TERMINAL_RATE );
     211           0 : }
     212             : 
     213             : /* https://github.com/anza-xyz/agave/blob/9bcf93e368b5fb52c21677ed8c7f0360eb93b5b7/runtime/src/bank.rs#L3155-L3172 */
     214             : ulong
     215             : fd_integer_inflation_epoch_rewards( fd_bank_t const * bank,
     216             :                                     ulong             inflation_start_slot,
     217             :                                     ulong             capitalization,
     218           0 :                                     ulong             epoch ) {
     219           0 :   fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
     220             : 
     221           0 :   ulong rate        = integer_inflation_rate( bank, inflation_start_slot );
     222           0 :   ulong ns_per_slot = fd_slot_params_at_slot( bank, fd_epoch_slot0( epoch_schedule, epoch ) ).ns_per_slot;
     223           0 :   ulong reward;
     224           0 :   if( FD_UNLIKELY( epoch_reward( capitalization, rate, fd_epoch_slot_cnt( epoch_schedule, epoch ), ns_per_slot, &reward ) ) ) {
     225           0 :     FD_LOG_ERR(( "epoch reward calculation failed (capitalization=%lu rate=%lu epoch=%lu)", capitalization, rate, epoch ));
     226           0 :   }
     227           0 :   ulong new_capitalization;
     228           0 :   if( FD_UNLIKELY( __builtin_uaddl_overflow( capitalization, reward, &new_capitalization ) ) ) {
     229           0 :     FD_LOG_ERR(( "capitalization overflow (capitalization=%lu reward=%lu)", capitalization, reward ));
     230           0 :   }
     231           0 :   return reward;
     232           0 : }

Generated by: LCOV version 1.14