github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/reward/reward_logic.go (about)

     1  package reward
     2  
     3  import (
     4  	"github.com/filecoin-project/go-state-types/abi"
     5  	"github.com/filecoin-project/go-state-types/big"
     6  
     7  	"github.com/filecoin-project/specs-actors/v4/actors/util/math"
     8  )
     9  
    10  // Baseline function = BaselineInitialValue * (BaselineExponent) ^(t), t in epochs
    11  // Note: we compute exponential iteratively using recurrence e(n) = e * e(n-1).
    12  // Caller of baseline power function is responsible for keeping track of intermediate,
    13  // state e(n-1), the baseline power function just does the next multiplication
    14  
    15  // Floor(e^(ln[1 + 100%] / epochsInYear) * 2^128
    16  // Q.128 formatted number such that f(epoch) = baseExponent^epoch grows 100% in one year of epochs
    17  // Calculation here: https://www.wolframalpha.com/input/?i=IntegerPart%5BExp%5BLog%5B1%2B100%25%5D%2F%28%28365+days%29%2F%2830+seconds%29%29%5D*2%5E128%5D
    18  var BaselineExponent = big.MustFromString("340282591298641078465964189926313473653") // Q.128
    19  
    20  // 2.5057116798121726 EiB
    21  var BaselineInitialValue = big.NewInt(2_888_888_880_000_000_000) // Q.0
    22  
    23  // Initialize baseline power for epoch -1 so that baseline power at epoch 0 is
    24  // BaselineInitialValue.
    25  func InitBaselinePower() abi.StoragePower {
    26  	baselineInitialValue256 := big.Lsh(BaselineInitialValue, 2*math.Precision128) // Q.0 => Q.256
    27  	baselineAtMinusOne := big.Div(baselineInitialValue256, BaselineExponent)      // Q.256 / Q.128 => Q.128
    28  	return big.Rsh(baselineAtMinusOne, math.Precision128)                         // Q.128 => Q.0
    29  }
    30  
    31  // Compute BaselinePower(t) from BaselinePower(t-1) with an additional multiplication
    32  // of the base exponent.
    33  func BaselinePowerFromPrev(prevEpochBaselinePower abi.StoragePower) abi.StoragePower {
    34  	thisEpochBaselinePower := big.Mul(prevEpochBaselinePower, BaselineExponent) // Q.0 * Q.128 => Q.128
    35  	return big.Rsh(thisEpochBaselinePower, math.Precision128)                   // Q.128 => Q.0
    36  }
    37  
    38  // These numbers are estimates of the onchain constants.  They are good for initializing state in
    39  // devnets and testing but will not match the on chain values exactly which depend on storage onboarding
    40  // and upgrade epoch history. They are in units of attoFIL, 10^-18 FIL
    41  var DefaultSimpleTotal = big.Mul(big.NewInt(330e6), big.NewInt(1e18))   // 330M
    42  var DefaultBaselineTotal = big.Mul(big.NewInt(770e6), big.NewInt(1e18)) // 770M
    43  
    44  // Computes RewardTheta which is is precise fractional value of effectiveNetworkTime.
    45  // The effectiveNetworkTime is defined by CumsumBaselinePower(theta) == CumsumRealizedPower
    46  // As baseline power is defined over integers and the RewardTheta is required to be fractional,
    47  // we perform linear interpolation between CumsumBaseline(⌊theta⌋) and CumsumBaseline(⌈theta⌉).
    48  // The effectiveNetworkTime argument is ceiling of theta.
    49  // The result is a fractional effectiveNetworkTime (theta) in Q.128 format.
    50  func ComputeRTheta(effectiveNetworkTime abi.ChainEpoch, baselinePowerAtEffectiveNetworkTime, cumsumRealized, cumsumBaseline big.Int) big.Int {
    51  	var rewardTheta big.Int
    52  	if effectiveNetworkTime != 0 {
    53  		rewardTheta = big.NewInt(int64(effectiveNetworkTime)) // Q.0
    54  		rewardTheta = big.Lsh(rewardTheta, math.Precision128) // Q.0 => Q.128
    55  		diff := big.Sub(cumsumBaseline, cumsumRealized)
    56  		diff = big.Lsh(diff, math.Precision128)                   // Q.0 => Q.128
    57  		diff = big.Div(diff, baselinePowerAtEffectiveNetworkTime) // Q.128 / Q.0 => Q.128
    58  		rewardTheta = big.Sub(rewardTheta, diff)                  // Q.128
    59  	} else {
    60  		// special case for initialization
    61  		rewardTheta = big.Zero()
    62  	}
    63  	return rewardTheta
    64  }
    65  
    66  var (
    67  	// lambda = ln(2) / (6 * epochsInYear)
    68  	// for Q.128: int(lambda * 2^128)
    69  	// Calculation here: https://www.wolframalpha.com/input/?i=IntegerPart%5BLog%5B2%5D+%2F+%286+*+%281+year+%2F+30+seconds%29%29+*+2%5E128%5D
    70  	Lambda = big.MustFromString("37396271439864487274534522888786")
    71  	// expLamSubOne = e^lambda - 1
    72  	// for Q.128: int(expLamSubOne * 2^128)
    73  	// Calculation here: https://www.wolframalpha.com/input/?i=IntegerPart%5B%5BExp%5BLog%5B2%5D+%2F+%286+*+%281+year+%2F+30+seconds%29%29%5D+-+1%5D+*+2%5E128%5D
    74  	ExpLamSubOne = big.MustFromString("37396273494747879394193016954629")
    75  )
    76  
    77  // Computes a reward for all expected leaders when effective network time changes from prevTheta to currTheta
    78  // Inputs are in Q.128 format
    79  func computeReward(epoch abi.ChainEpoch, prevTheta, currTheta, simpleTotal, baselineTotal big.Int) abi.TokenAmount {
    80  	simpleReward := big.Mul(simpleTotal, ExpLamSubOne)    //Q.0 * Q.128 =>  Q.128
    81  	epochLam := big.Mul(big.NewInt(int64(epoch)), Lambda) // Q.0 * Q.128 => Q.128
    82  
    83  	simpleReward = big.Mul(simpleReward, big.NewFromGo(math.ExpNeg(epochLam.Int))) // Q.128 * Q.128 => Q.256
    84  	simpleReward = big.Rsh(simpleReward, math.Precision128)                        // Q.256 >> 128 => Q.128
    85  
    86  	baselineReward := big.Sub(computeBaselineSupply(currTheta, baselineTotal), computeBaselineSupply(prevTheta, baselineTotal)) // Q.128
    87  
    88  	reward := big.Add(simpleReward, baselineReward) // Q.128
    89  
    90  	return big.Rsh(reward, math.Precision128) // Q.128 => Q.0
    91  }
    92  
    93  // Computes baseline supply based on theta in Q.128 format.
    94  // Return is in Q.128 format
    95  func computeBaselineSupply(theta, baselineTotal big.Int) big.Int {
    96  	thetaLam := big.Mul(theta, Lambda)              // Q.128 * Q.128 => Q.256
    97  	thetaLam = big.Rsh(thetaLam, math.Precision128) // Q.256 >> 128 => Q.128
    98  
    99  	eTL := big.NewFromGo(math.ExpNeg(thetaLam.Int)) // Q.128
   100  
   101  	one := big.NewInt(1)
   102  	one = big.Lsh(one, math.Precision128) // Q.0 => Q.128
   103  	oneSub := big.Sub(one, eTL)           // Q.128
   104  
   105  	return big.Mul(baselineTotal, oneSub) // Q.0 * Q.128 => Q.128
   106  }
   107  
   108  // SlowConvenientBaselineForEpoch computes baseline power for use in epoch t
   109  // by calculating the value of ThisEpochBaselinePower that shows up in block at t - 1
   110  // It multiplies ~t times so it should not be used in actor code directly.  It is exported as
   111  // convenience for consuming node.
   112  func SlowConvenientBaselineForEpoch(targetEpoch abi.ChainEpoch) abi.StoragePower {
   113  	baseline := InitBaselinePower()
   114  	baseline = BaselinePowerFromPrev(baseline) // value in genesis block (for epoch 1)
   115  	for i := abi.ChainEpoch(1); i < targetEpoch; i++ {
   116  		baseline = BaselinePowerFromPrev(baseline) // value in block i (for epoch i+1)
   117  	}
   118  	return baseline
   119  }