github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/states/election_test.go (about) 1 package states_test 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/filecoin-project/go-address" 8 "github.com/filecoin-project/go-state-types/abi" 9 "github.com/filecoin-project/go-state-types/big" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 13 "github.com/filecoin-project/specs-actors/v4/actors/builtin" 14 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" 15 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power" 16 "github.com/filecoin-project/specs-actors/v4/actors/states" 17 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 18 "github.com/filecoin-project/specs-actors/v4/support/ipld" 19 tutil "github.com/filecoin-project/specs-actors/v4/support/testing" 20 ) 21 22 func TestMinerEligibleForElection(t *testing.T) { 23 ctx := context.Background() 24 store := ipld.NewADTStore(ctx) 25 proofType := abi.RegisteredPoStProof_StackedDrgWindow32GiBV1 26 pwr := abi.NewStoragePower(1) 27 28 owner := tutil.NewIDAddr(t, 100) 29 maddr := tutil.NewIDAddr(t, 101) 30 31 t.Run("miner eligible", func(t *testing.T) { 32 mstate := constructMinerState(ctx, t, store, owner) 33 pstate := constructPowerStateWithMiner(t, store, maddr, pwr, proofType) 34 assert.Equal(t, big.Zero(), mstate.InitialPledge) // Not directly relevant. 35 36 currEpoch := abi.ChainEpoch(100000) 37 eligible, err := states.MinerEligibleForElection(store, mstate, pstate, maddr, currEpoch) 38 require.NoError(t, err) 39 assert.True(t, eligible) 40 }) 41 42 t.Run("zero claim", func(t *testing.T) { 43 mstate := constructMinerState(ctx, t, store, owner) 44 pstate := constructPowerStateWithMiner(t, store, maddr, big.Zero(), proofType) 45 46 currEpoch := abi.ChainEpoch(100000) 47 eligible, err := states.MinerEligibleForElection(store, mstate, pstate, maddr, currEpoch) 48 require.NoError(t, err) 49 assert.False(t, eligible) 50 }) 51 52 t.Run("active consensus fault", func(t *testing.T) { 53 mstate := constructMinerState(ctx, t, store, owner) 54 pstate := constructPowerStateWithMiner(t, store, maddr, pwr, proofType) 55 56 info, err := mstate.GetInfo(store) 57 require.NoError(t, err) 58 info.ConsensusFaultElapsed = abi.ChainEpoch(55) 59 err = mstate.SaveInfo(store, info) 60 require.NoError(t, err) 61 62 currEpoch := abi.ChainEpoch(33) // 33 less than 55 so consensus fault still active 63 eligible, err := states.MinerEligibleForElection(store, mstate, pstate, maddr, currEpoch) 64 require.NoError(t, err) 65 assert.False(t, eligible) 66 }) 67 68 t.Run("fee debt", func(t *testing.T) { 69 mstate := constructMinerState(ctx, t, store, owner) 70 pstate := constructPowerStateWithMiner(t, store, maddr, pwr, proofType) 71 mstate.FeeDebt = abi.NewTokenAmount(1000) 72 73 currEpoch := abi.ChainEpoch(100000) 74 eligible, err := states.MinerEligibleForElection(store, mstate, pstate, maddr, currEpoch) 75 require.NoError(t, err) 76 assert.False(t, eligible) 77 }) 78 } 79 80 func TestMinerEligibleAtLookback(t *testing.T) { 81 ctx := context.Background() 82 store := ipld.NewADTStore(ctx) 83 windowPoStProofType := abi.RegisteredPoStProof_StackedDrgWindow32GiBV1 84 maddr := tutil.NewIDAddr(t, 101) 85 86 t.Run("power does not meet minimum", func(t *testing.T) { 87 // get minimums 88 pow32GiBMin, err := builtin.ConsensusMinerMinPower(windowPoStProofType) 89 require.NoError(t, err) 90 pow64GiBMin, err := builtin.ConsensusMinerMinPower(abi.RegisteredPoStProof_StackedDrgWindow64GiBV1) 91 require.NoError(t, err) 92 93 for _, tc := range []struct { 94 consensusMiners int64 95 minerProof abi.RegisteredPoStProof 96 power abi.StoragePower 97 eligible bool 98 }{{ 99 // below consensus minimum miners, power only needs to be positive to be eligible 100 consensusMiners: 0, 101 minerProof: windowPoStProofType, 102 power: big.Zero(), 103 eligible: false, 104 }, { 105 consensusMiners: 0, 106 minerProof: windowPoStProofType, 107 power: big.NewInt(1), 108 eligible: true, 109 }, { 110 // with enough miners above minimum, power must be at or above consensus min 111 consensusMiners: power.ConsensusMinerMinMiners, 112 minerProof: windowPoStProofType, 113 power: big.Sub(pow32GiBMin, big.NewInt(1)), 114 eligible: false, 115 }, { 116 consensusMiners: power.ConsensusMinerMinMiners, 117 minerProof: windowPoStProofType, 118 power: pow32GiBMin, 119 eligible: true, 120 }, { 121 // bigger sector size requires higher minimum 122 consensusMiners: power.ConsensusMinerMinMiners, 123 minerProof: abi.RegisteredPoStProof_StackedDrgWindow64GiBV1, 124 power: pow64GiBMin, 125 eligible: true, 126 }} { 127 pstate := constructPowerStateWithMiner(t, store, maddr, tc.power, tc.minerProof) 128 pstate.MinerAboveMinPowerCount = tc.consensusMiners 129 eligible, err := states.MinerPoStLookbackEligibleForElection(store, pstate, maddr) 130 require.NoError(t, err) 131 assert.Equal(t, tc.eligible, eligible) 132 } 133 }) 134 } 135 136 func constructMinerState(ctx context.Context, t *testing.T, store adt.Store, owner address.Address) *miner.State { 137 proofType := abi.RegisteredPoStProof_StackedDrgWindow32GiBV1 138 ssize, err := proofType.SectorSize() 139 require.NoError(t, err) 140 psize, err := builtin.PoStProofWindowPoStPartitionSectors(proofType) 141 require.NoError(t, err) 142 143 info := miner.MinerInfo{ 144 Owner: owner, 145 Worker: owner, 146 ControlAddresses: []address.Address{}, 147 PendingWorkerKey: nil, 148 PeerId: nil, 149 Multiaddrs: [][]byte{}, 150 WindowPoStProofType: proofType, 151 SectorSize: ssize, 152 WindowPoStPartitionSectors: psize, 153 ConsensusFaultElapsed: 0, 154 } 155 infoCid, err := store.Put(ctx, &info) 156 require.NoError(t, err) 157 158 periodStart := abi.ChainEpoch(0) 159 160 st, err := miner.ConstructState(store, infoCid, periodStart, 0) 161 require.NoError(t, err) 162 163 return st 164 } 165 166 func constructPowerStateWithMiner(t *testing.T, store adt.Store, maddr address.Address, pwr abi.StoragePower, proof abi.RegisteredPoStProof) *power.State { 167 pSt, err := power.ConstructState(store) 168 require.NoError(t, err) 169 170 claims, err := adt.AsMap(store, pSt.Claims, builtin.DefaultHamtBitwidth) 171 require.NoError(t, err) 172 173 claim := &power.Claim{WindowPoStProofType: proof, RawBytePower: pwr, QualityAdjPower: pwr} 174 175 err = claims.Put(abi.AddrKey(maddr), claim) 176 require.NoError(t, err) 177 178 pSt.MinerCount += 1 179 180 pSt.Claims, err = claims.Root() 181 require.NoError(t, err) 182 return pSt 183 }