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  }