github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/test/terminate_sectors_scenario_test.go (about) 1 package test_test 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/filecoin-project/go-bitfield" 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/market" 15 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" 16 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power" 17 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg" 18 "github.com/filecoin-project/specs-actors/v4/actors/runtime/proof" 19 "github.com/filecoin-project/specs-actors/v4/support/ipld" 20 tutil "github.com/filecoin-project/specs-actors/v4/support/testing" 21 vm "github.com/filecoin-project/specs-actors/v4/support/vm" 22 ) 23 24 // This scenario hits all Market Actor methods. 25 func TestTerminateSectors(t *testing.T) { 26 ctx := context.Background() 27 v := vm.NewVMWithSingletons(ctx, t, ipld.NewBlockStoreInMemory()) 28 addrs := vm.CreateAccounts(ctx, t, v, 4, big.Mul(big.NewInt(10_000), vm.FIL), 93837778) 29 owner, verifier, unverifiedClient, verifiedClient := addrs[0], addrs[1], addrs[2], addrs[3] 30 worker := owner 31 32 minerBalance := big.Mul(big.NewInt(1_000), vm.FIL) 33 sectorNumber := abi.SectorNumber(100) 34 sealedCid := tutil.MakeCID("100", &miner.SealedCIDPrefix) 35 sealProof := abi.RegisteredSealProof_StackedDrg32GiBV1_1 36 37 // create miner 38 ret := vm.ApplyOk(t, v, addrs[0], builtin.StoragePowerActorAddr, minerBalance, builtin.MethodsPower.CreateMiner, &power.CreateMinerParams{ 39 Owner: owner, 40 Worker: worker, 41 WindowPoStProofType: abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, 42 Peer: abi.PeerID("not really a peer id"), 43 }) 44 45 minerAddrs, ok := ret.(*power.CreateMinerReturn) 46 require.True(t, ok) 47 48 // 49 // publish verified and unverified deals 50 // 51 52 // register verifier then verified client 53 vm.ApplyOk(t, v, vm.VerifregRoot, builtin.VerifiedRegistryActorAddr, big.Zero(), builtin.MethodsVerifiedRegistry.AddVerifier, &verifreg.AddVerifierParams{ 54 Address: verifier, 55 Allowance: abi.NewStoragePower(32 << 40), 56 }) 57 58 vm.ApplyOk(t, v, verifier, builtin.VerifiedRegistryActorAddr, big.Zero(), builtin.MethodsVerifiedRegistry.AddVerifiedClient, &verifreg.AddVerifiedClientParams{ 59 Address: verifiedClient, 60 Allowance: abi.NewStoragePower(32 << 40), 61 }) 62 63 // add market collateral for clients and miner 64 collateral := big.Mul(big.NewInt(3), vm.FIL) 65 vm.ApplyOk(t, v, unverifiedClient, builtin.StorageMarketActorAddr, collateral, builtin.MethodsMarket.AddBalance, &unverifiedClient) 66 vm.ApplyOk(t, v, verifiedClient, builtin.StorageMarketActorAddr, collateral, builtin.MethodsMarket.AddBalance, &verifiedClient) 67 minerCollateral := big.Mul(big.NewInt(64), vm.FIL) 68 vm.ApplyOk(t, v, worker, builtin.StorageMarketActorAddr, minerCollateral, builtin.MethodsMarket.AddBalance, &minerAddrs.IDAddress) 69 70 // create 3 deals, some verified and some not 71 dealIDs := []abi.DealID{} 72 dealStart := v.GetEpoch() + miner.PreCommitChallengeDelay + 1 73 deals := publishDeal(t, v, worker, verifiedClient, minerAddrs.IDAddress, "deal1", 1<<30, true, dealStart, 181*builtin.EpochsInDay) 74 dealIDs = append(dealIDs, deals.IDs...) 75 deals = publishDeal(t, v, worker, verifiedClient, minerAddrs.IDAddress, "deal2", 1<<32, true, dealStart, 200*builtin.EpochsInDay) 76 dealIDs = append(dealIDs, deals.IDs...) 77 deals = publishDeal(t, v, worker, unverifiedClient, minerAddrs.IDAddress, "deal3", 1<<34, false, dealStart, 210*builtin.EpochsInDay) 78 dealIDs = append(dealIDs, deals.IDs...) 79 80 vm.ApplyOk(t, v, builtin.SystemActorAddr, builtin.CronActorAddr, big.Zero(), builtin.MethodsCron.EpochTick, nil) 81 for _, id := range dealIDs { 82 // deals are pending and don't yet have deal states 83 _, found := vm.GetDealState(t, v, id) 84 require.False(t, found) 85 } 86 87 // 88 // Precommit, Prove, Verify and PoSt sector with deals 89 // 90 91 // precommit sector with deals 92 vm.ApplyOk(t, v, addrs[0], minerAddrs.RobustAddress, big.Zero(), builtin.MethodsMiner.PreCommitSector, &miner.PreCommitSectorParams{ 93 SealProof: sealProof, 94 SectorNumber: sectorNumber, 95 SealedCID: sealedCid, 96 SealRandEpoch: v.GetEpoch() - 1, 97 DealIDs: dealIDs, 98 Expiration: v.GetEpoch() + 220*builtin.EpochsInDay, 99 ReplaceCapacity: false, 100 }) 101 102 // advance time to min seal duration 103 proveTime := v.GetEpoch() + miner.PreCommitChallengeDelay + 1 104 v, _ = vm.AdvanceByDeadlineTillEpoch(t, v, minerAddrs.IDAddress, proveTime) 105 106 // Prove commit sector after max seal duration 107 v, err := v.WithEpoch(proveTime) 108 require.NoError(t, err) 109 vm.ApplyOk(t, v, worker, minerAddrs.RobustAddress, big.Zero(), builtin.MethodsMiner.ProveCommitSector, &miner.ProveCommitSectorParams{ 110 SectorNumber: sectorNumber, 111 }) 112 113 // In the same epoch, trigger cron to validate prove commit 114 vm.ApplyOk(t, v, builtin.SystemActorAddr, builtin.CronActorAddr, big.Zero(), builtin.MethodsCron.EpochTick, nil) 115 116 // advance to proving period and submit post 117 dlInfo, pIdx, v := vm.AdvanceTillProvingDeadline(t, v, minerAddrs.IDAddress, sectorNumber) 118 vm.ApplyOk(t, v, worker, minerAddrs.RobustAddress, big.Zero(), builtin.MethodsMiner.SubmitWindowedPoSt, &miner.SubmitWindowedPoStParams{ 119 Deadline: dlInfo.Index, 120 Partitions: []miner.PoStPartition{{ 121 Index: pIdx, 122 Skipped: bitfield.New(), 123 }}, 124 Proofs: []proof.PoStProof{{ 125 PoStProof: abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, 126 }}, 127 ChainCommitEpoch: dlInfo.Challenge, 128 ChainCommitRand: []byte("not really random"), 129 }) 130 131 // proving period cron adds miner power 132 v, err = v.WithEpoch(dlInfo.Last()) 133 require.NoError(t, err) 134 vm.ApplyOk(t, v, builtin.SystemActorAddr, builtin.CronActorAddr, big.Zero(), builtin.MethodsCron.EpochTick, nil) 135 136 // market cron updates deal states indicating deals are no longer pending. 137 for _, id := range dealIDs { 138 state, found := vm.GetDealState(t, v, id) 139 require.True(t, found) 140 // non-zero 141 assert.Greater(t, uint64(state.LastUpdatedEpoch), uint64(0)) 142 // deal has not been slashed 143 assert.Equal(t, abi.ChainEpoch(-1), state.SlashEpoch) 144 } 145 146 // 147 // Terminate Sector 148 // 149 150 v, err = v.WithEpoch(v.GetEpoch() + 1) 151 require.NoError(t, err) 152 153 vm.ApplyOk(t, v, worker, minerAddrs.RobustAddress, big.Zero(), builtin.MethodsMiner.TerminateSectors, &miner.TerminateSectorsParams{ 154 Terminations: []miner.TerminationDeclaration{{ 155 Deadline: dlInfo.Index, 156 Partition: pIdx, 157 Sectors: bitfield.NewFromSet([]uint64{uint64(sectorNumber)}), 158 }}, 159 }) 160 161 noSubinvocations := []vm.ExpectInvocation{} 162 vm.ExpectInvocation{ 163 To: minerAddrs.IDAddress, 164 Method: builtin.MethodsMiner.TerminateSectors, 165 SubInvocations: []vm.ExpectInvocation{ 166 {To: builtin.RewardActorAddr, Method: builtin.MethodsReward.ThisEpochReward, SubInvocations: noSubinvocations}, 167 {To: builtin.StoragePowerActorAddr, Method: builtin.MethodsPower.CurrentTotalPower, SubInvocations: noSubinvocations}, 168 {To: builtin.BurntFundsActorAddr, Method: builtin.MethodSend, SubInvocations: noSubinvocations}, 169 {To: builtin.StoragePowerActorAddr, Method: builtin.MethodsPower.UpdatePledgeTotal, SubInvocations: noSubinvocations}, 170 {To: builtin.StorageMarketActorAddr, Method: builtin.MethodsMarket.OnMinerSectorsTerminate, SubInvocations: noSubinvocations}, 171 {To: builtin.StoragePowerActorAddr, Method: builtin.MethodsPower.UpdateClaimedPower, SubInvocations: noSubinvocations}, 172 }, 173 }.Matches(t, v.LastInvocation()) 174 175 // expect power, market and miner to be in base state 176 minerBalances := vm.GetMinerBalances(t, v, minerAddrs.IDAddress) 177 assert.Equal(t, big.Zero(), minerBalances.InitialPledge) 178 assert.Equal(t, big.Zero(), minerBalances.PreCommitDeposit) 179 180 // expect network stats to reflect power has been removed from sector 181 stats := vm.GetNetworkStats(t, v) 182 assert.Equal(t, int64(0), stats.MinerAboveMinPowerCount) 183 assert.Equal(t, big.Zero(), stats.TotalRawBytePower) 184 assert.Equal(t, big.Zero(), stats.TotalQualityAdjPower) 185 assert.Equal(t, big.Zero(), stats.TotalBytesCommitted) 186 assert.Equal(t, big.Zero(), stats.TotalQABytesCommitted) 187 assert.Equal(t, big.Zero(), stats.TotalPledgeCollateral) 188 189 // market cron slashes deals because sector has been terminated 190 for _, id := range dealIDs { 191 state, found := vm.GetDealState(t, v, id) 192 require.True(t, found) 193 // non-zero 194 assert.Greater(t, uint64(state.LastUpdatedEpoch), uint64(0)) 195 // deal has not been slashed 196 assert.Equal(t, v.GetEpoch(), state.SlashEpoch) 197 198 } 199 200 // advance a proving period and run cron to complete processing of termination 201 v, err = v.WithEpoch(v.GetEpoch() + 2880) 202 require.NoError(t, err) 203 vm.ApplyOk(t, v, builtin.SystemActorAddr, builtin.CronActorAddr, big.Zero(), builtin.MethodsCron.EpochTick, nil) 204 205 // Verified client should be able to withdraw all all deal collateral. 206 // Client added 3 FIL balance and had 2 deals with 1 FIL collateral apiece. 207 // Should only be able to withdraw the full 2 FIL only if deals have been slashed and balance was unlocked. 208 withdrawal := big.Mul(big.NewInt(2), vm.FIL) 209 vm.ApplyOk(t, v, verifiedClient, builtin.StorageMarketActorAddr, big.Zero(), builtin.MethodsMarket.WithdrawBalance, &market.WithdrawBalanceParams{ 210 ProviderOrClientAddress: verifiedClient, 211 Amount: withdrawal, 212 }) 213 214 verifiedIDAddr, found := v.NormalizeAddress(verifiedClient) 215 require.True(t, found) 216 vm.ExpectInvocation{ 217 To: builtin.StorageMarketActorAddr, 218 Method: builtin.MethodsMarket.WithdrawBalance, 219 SubInvocations: []vm.ExpectInvocation{ 220 {To: verifiedIDAddr, Method: builtin.MethodSend, Value: vm.ExpectAttoFil(withdrawal)}, 221 }, 222 }.Matches(t, v.LastInvocation()) 223 224 // Check that miner's collateral has been slashed by attempting to withdraw all funds 225 vm.ApplyOk(t, v, owner, builtin.StorageMarketActorAddr, big.Zero(), builtin.MethodsMarket.WithdrawBalance, &market.WithdrawBalanceParams{ 226 ProviderOrClientAddress: minerAddrs.IDAddress, 227 Amount: minerCollateral, 228 }) 229 230 // miner add 64 balance. Each of 3 deals required 2 FIL collateral, so provider collateral should have been 231 // slashed by 6 FIL. Miner's remaining market balance should be 64 - 6 + payment, where payment is for storage 232 // before the slash and should be << 1 FIL. Actual amount withdrawn should be between 58 and 59 FIL. 233 valueWithdrawn := vm.ValueForInvocation(t, v, len(v.Invocations())-1, 1) 234 assert.True(t, big.Mul(big.NewInt(58), vm.FIL).LessThan(valueWithdrawn)) 235 assert.True(t, big.Mul(big.NewInt(59), vm.FIL).GreaterThan(valueWithdrawn)) 236 }