github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/miner/monies_test.go (about) 1 package miner_test 2 3 import ( 4 "testing" 5 6 "github.com/filecoin-project/go-state-types/abi" 7 "github.com/filecoin-project/go-state-types/big" 8 "github.com/stretchr/testify/assert" 9 10 "github.com/filecoin-project/specs-actors/v4/actors/builtin" 11 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" 12 "github.com/filecoin-project/specs-actors/v4/actors/util/smoothing" 13 ) 14 15 // Test termination fee 16 func TestPledgePenaltyForTermination(t *testing.T) { 17 epochTargetReward := abi.NewTokenAmount(1 << 50) 18 qaSectorPower := abi.NewStoragePower(1 << 36) 19 networkQAPower := abi.NewStoragePower(1 << 50) 20 21 rewardEstimate := smoothing.TestingConstantEstimate(epochTargetReward) 22 powerEstimate := smoothing.TestingConstantEstimate(networkQAPower) 23 24 undeclaredPenalty := miner.PledgePenaltyForTerminationLowerBound(rewardEstimate, powerEstimate, qaSectorPower) 25 bigInitialPledgeFactor := big.NewInt(int64(miner.InitialPledgeFactor)) 26 bigLifetimeCap := big.NewInt(int64(miner.TerminationLifetimeCap)) 27 28 t.Run("when undeclared fault fee exceeds expected reward, returns undeclaraed fault fee", func(t *testing.T) { 29 // small pledge and means undeclared penalty will be bigger 30 initialPledge := abi.NewTokenAmount(1 << 10) 31 dayReward := big.Div(initialPledge, bigInitialPledgeFactor) 32 twentyDayReward := big.Mul(dayReward, bigInitialPledgeFactor) 33 sectorAge := 20 * abi.ChainEpoch(builtin.EpochsInDay) 34 35 fee := miner.PledgePenaltyForTermination(dayReward, sectorAge, twentyDayReward, powerEstimate, qaSectorPower, rewardEstimate, big.Zero(), 0) 36 37 assert.Equal(t, undeclaredPenalty, fee) 38 }) 39 40 t.Run("when expected reward exceeds undeclared fault fee, returns expected reward", func(t *testing.T) { 41 // initialPledge equal to undeclaredPenalty guarantees expected reward is greater 42 initialPledge := undeclaredPenalty 43 dayReward := big.Div(initialPledge, bigInitialPledgeFactor) 44 twentyDayReward := big.Mul(dayReward, bigInitialPledgeFactor) 45 sectorAgeInDays := int64(20) 46 sectorAge := abi.ChainEpoch(sectorAgeInDays * builtin.EpochsInDay) 47 48 fee := miner.PledgePenaltyForTermination(dayReward, sectorAge, twentyDayReward, powerEstimate, qaSectorPower, rewardEstimate, big.Zero(), 0) 49 50 // expect fee to be pledge + br * age * factor where br = pledge/initialPledgeFactor 51 expectedFee := big.Add( 52 initialPledge, 53 big.Div( 54 big.Product(initialPledge, big.NewInt(sectorAgeInDays), miner.TerminationRewardFactor.Numerator), 55 big.Product(bigInitialPledgeFactor, miner.TerminationRewardFactor.Denominator))) 56 assert.Equal(t, expectedFee, fee) 57 }) 58 59 t.Run("sector age is capped", func(t *testing.T) { 60 initialPledge := undeclaredPenalty 61 dayReward := big.Div(initialPledge, bigInitialPledgeFactor) 62 twentyDayReward := big.Mul(dayReward, bigInitialPledgeFactor) 63 sectorAge := abi.ChainEpoch(500 * builtin.EpochsInDay) 64 65 fee := miner.PledgePenaltyForTermination(dayReward, sectorAge, twentyDayReward, powerEstimate, qaSectorPower, rewardEstimate, big.Zero(), 0) 66 67 // expect fee to be pledge * br * age-cap * factor where br = pledge/initialPledgeFactor 68 expectedFee := big.Add( 69 initialPledge, 70 big.Div( 71 big.Product(initialPledge, bigLifetimeCap, miner.TerminationRewardFactor.Numerator), 72 big.Product(bigInitialPledgeFactor, miner.TerminationRewardFactor.Denominator))) 73 assert.Equal(t, expectedFee, fee) 74 }) 75 76 t.Run("fee for replacement = fee for original sector when power, BR are unchanged", func(t *testing.T) { 77 // initialPledge equal to undeclaredPenalty guarantees expected reward is greater 78 initialPledge := undeclaredPenalty 79 dayReward := big.Div(initialPledge, bigInitialPledgeFactor) 80 twentyDayReward := big.Mul(dayReward, bigInitialPledgeFactor) 81 sectorAge := abi.ChainEpoch(20 * builtin.EpochsInDay) 82 replacementAge := abi.ChainEpoch(2 * builtin.EpochsInDay) 83 84 // use low power, so we don't test SP=SP 85 power := big.NewInt(1) 86 87 // fee for old sector if had terminated when it was replaced 88 unreplacedFee := miner.PledgePenaltyForTermination(dayReward, sectorAge, twentyDayReward, powerEstimate, power, rewardEstimate, big.Zero(), 0) 89 90 // actual fee including replacement parameters 91 actualFee := miner.PledgePenaltyForTermination(dayReward, replacementAge, twentyDayReward, powerEstimate, power, rewardEstimate, dayReward, sectorAge-replacementAge) 92 93 assert.Equal(t, unreplacedFee, actualFee) 94 }) 95 96 t.Run("fee for replacement = fee for same sector without replacement after lifetime cap", func(t *testing.T) { 97 // initialPledge equal to undeclaredPenalty guarantees expected reward is greater 98 initialPledge := undeclaredPenalty 99 dayReward := big.Div(initialPledge, bigInitialPledgeFactor) 100 twentyDayReward := big.Mul(dayReward, bigInitialPledgeFactor) 101 sectorAge := abi.ChainEpoch(20 * builtin.EpochsInDay) 102 replacementAge := abi.ChainEpoch(miner.TerminationLifetimeCap+1) * builtin.EpochsInDay 103 104 // use low power, so we don't test SP=SP 105 power := big.NewInt(1) 106 107 // fee for new sector with no replacement 108 noReplace := miner.PledgePenaltyForTermination(dayReward, replacementAge, twentyDayReward, powerEstimate, power, rewardEstimate, big.Zero(), 0) 109 110 // actual fee including replacement parameters 111 withReplace := miner.PledgePenaltyForTermination(dayReward, replacementAge, twentyDayReward, powerEstimate, power, rewardEstimate, dayReward, sectorAge) 112 113 assert.Equal(t, noReplace, withReplace) 114 }) 115 116 t.Run("charges for replaced sector at replaced sector day rate", func(t *testing.T) { 117 // initialPledge equal to undeclaredPenalty guarantees expected reward is greater 118 initialPledge := undeclaredPenalty 119 dayReward := big.Div(initialPledge, bigInitialPledgeFactor) 120 oldDayReward := big.Mul(big.NewInt(2), dayReward) 121 twentyDayReward := big.Mul(dayReward, bigInitialPledgeFactor) 122 oldSectorAgeInDays := int64(20) 123 oldSectorAge := abi.ChainEpoch(oldSectorAgeInDays * builtin.EpochsInDay) 124 replacementAgeInDays := int64(15) 125 replacementAge := abi.ChainEpoch(replacementAgeInDays * builtin.EpochsInDay) 126 127 // use low power, so termination fee exceeds SP 128 power := big.NewInt(1) 129 130 oldPenalty := big.Div( 131 big.Product(oldDayReward, big.NewInt(oldSectorAgeInDays), miner.TerminationRewardFactor.Numerator), 132 miner.TerminationRewardFactor.Denominator, 133 ) 134 newPenalty := big.Div( 135 big.Product(dayReward, big.NewInt(replacementAgeInDays), miner.TerminationRewardFactor.Numerator), 136 miner.TerminationRewardFactor.Denominator, 137 ) 138 expectedFee := big.Sum(twentyDayReward, oldPenalty, newPenalty) 139 140 fee := miner.PledgePenaltyForTermination(dayReward, replacementAge, twentyDayReward, powerEstimate, power, rewardEstimate, oldDayReward, oldSectorAge) 141 142 assert.Equal(t, expectedFee, fee) 143 }) 144 } 145 146 func TestNegativeBRClamp(t *testing.T) { 147 epochTargetReward := abi.NewTokenAmount(1 << 50) 148 qaSectorPower := abi.NewStoragePower(1 << 36) 149 networkQAPower := abi.NewStoragePower(1 << 10) 150 powerRateOfChange := abi.NewStoragePower(1 << 10).Neg() 151 rewardEstimate := smoothing.NewEstimate(epochTargetReward, big.Zero()) 152 powerEstimate := smoothing.NewEstimate(networkQAPower, powerRateOfChange) 153 154 fourBR := miner.ExpectedRewardForPower(rewardEstimate, powerEstimate, qaSectorPower, abi.ChainEpoch(4)) 155 assert.Equal(t, big.Zero(), fourBR) 156 } 157 158 func TestContinuedFault(t *testing.T) { 159 t.Run("zero power means zero fault penalty", func(t *testing.T) { 160 epochTargetReward := abi.NewTokenAmount(1 << 50) 161 zeroQAPower := abi.NewStoragePower(0) 162 networkQAPower := abi.NewStoragePower(1 << 10) 163 powerRateOfChange := abi.NewStoragePower(1 << 10) 164 rewardEstimate := smoothing.NewEstimate(epochTargetReward, big.Zero()) 165 powerEstimate := smoothing.NewEstimate(networkQAPower, powerRateOfChange) 166 167 penaltyForZeroPowerFaulted := miner.PledgePenaltyForContinuedFault(rewardEstimate, powerEstimate, zeroQAPower) 168 assert.Equal(t, big.Zero(), penaltyForZeroPowerFaulted) 169 }) 170 } 171 172 func TestExpectedRewardForPowerClamptedAtAttoFIL(t *testing.T) { 173 t.Run("expected zero valued BR clamped at 1 attofil", func(t *testing.T) { 174 epochTargetReward := abi.NewTokenAmount(1 << 50) 175 zeroQAPower := abi.NewStoragePower(0) 176 networkQAPower := abi.NewStoragePower(1 << 10) 177 powerRateOfChange := abi.NewStoragePower(1 << 10) 178 rewardEstimate := smoothing.NewEstimate(epochTargetReward, big.Zero()) 179 powerEstimate := smoothing.NewEstimate(networkQAPower, powerRateOfChange) 180 181 brClamped := miner.ExpectedRewardForPowerClampedAtAttoFIL(rewardEstimate, powerEstimate, zeroQAPower, abi.ChainEpoch(1)) 182 assert.Equal(t, big.NewInt(1), brClamped) 183 }) 184 185 t.Run("expected negative valued BR clamped at 1 atto FIL", func(t *testing.T) { 186 epochTargetReward := abi.NewTokenAmount(1 << 50) 187 qaSectorPower := abi.NewStoragePower(1 << 36) 188 networkQAPower := abi.NewStoragePower(1 << 10) 189 powerRateOfChange := abi.NewStoragePower(1 << 10).Neg() 190 rewardEstimate := smoothing.NewEstimate(epochTargetReward, big.Zero()) 191 powerEstimate := smoothing.NewEstimate(networkQAPower, powerRateOfChange) 192 193 fourBRClamped := miner.ExpectedRewardForPowerClampedAtAttoFIL(rewardEstimate, powerEstimate, qaSectorPower, abi.ChainEpoch(4)) 194 assert.Equal(t, big.NewInt(1), fourBRClamped) 195 }) 196 197 } 198 199 func TestPrecommitDepositAndInitialPledgePostiive(t *testing.T) { 200 epochTargetReward := abi.NewTokenAmount(0) // zero reward so IP Base unclamped is 0 201 qaSectorPower := abi.NewStoragePower(1 << 36) 202 networkQAPower := abi.NewStoragePower(1 << 10) 203 baselinePower := networkQAPower 204 powerRateOfChange := abi.NewStoragePower(1 << 10) 205 rewardEstimate := smoothing.NewEstimate(epochTargetReward, big.Zero()) 206 powerEstimate := smoothing.NewEstimate(networkQAPower, powerRateOfChange) 207 circulatingSupply := abi.NewTokenAmount(0) 208 t.Run("IP is clamped at 1 attofil", func(t *testing.T) { 209 ip := miner.InitialPledgeForPower(qaSectorPower, baselinePower, rewardEstimate, powerEstimate, circulatingSupply) 210 assert.Equal(t, abi.NewTokenAmount(1), ip) 211 }) 212 t.Run("PCD is clamped at 1 attoFIL", func(t *testing.T) { 213 pcd := miner.PreCommitDepositForPower(rewardEstimate, powerEstimate, qaSectorPower) 214 assert.Equal(t, abi.NewTokenAmount(1), pcd) 215 }) 216 }