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 }