github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/migration/nv10/test/modify_pending_proposals_test.go (about)

     1  package test_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  
     9  	addr "github.com/filecoin-project/go-address"
    10  	"github.com/filecoin-project/go-state-types/abi"
    11  	"github.com/filecoin-project/go-state-types/big"
    12  	"github.com/filecoin-project/go-state-types/crypto"
    13  	"github.com/filecoin-project/go-state-types/exitcode"
    14  	"github.com/filecoin-project/go-state-types/rt"
    15  	"github.com/ipfs/go-cid"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
    20  	market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market"
    21  	power2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/power"
    22  	ipld2 "github.com/filecoin-project/specs-actors/v2/support/ipld"
    23  	vm2 "github.com/filecoin-project/specs-actors/v2/support/vm"
    24  
    25  	builtin3 "github.com/filecoin-project/specs-actors/v3/actors/builtin"
    26  	exported3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/exported"
    27  	market3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/market"
    28  	miner3 "github.com/filecoin-project/specs-actors/v3/actors/builtin/miner"
    29  	"github.com/filecoin-project/specs-actors/v3/actors/migration/nv10"
    30  	states3 "github.com/filecoin-project/specs-actors/v3/actors/states"
    31  	tutil "github.com/filecoin-project/specs-actors/v3/support/testing"
    32  	vm3 "github.com/filecoin-project/specs-actors/v3/support/vm"
    33  )
    34  
    35  func TestUpdatePendingDealsMigration(t *testing.T) {
    36  	ctx := context.Background()
    37  	log := nv10.TestLogger{TB: t}
    38  	v := vm2.NewVMWithSingletons(ctx, t, ipld2.NewSyncBlockStoreInMemory())
    39  	addrs := vm2.CreateAccounts(ctx, t, v, 10, big.Mul(big.NewInt(100_000), vm2.FIL), 93837778)
    40  	worker := addrs[0]
    41  
    42  	minerBalance := big.Mul(big.NewInt(10_000), vm2.FIL)
    43  
    44  	// create miner
    45  	params := power2.CreateMinerParams{
    46  		Owner:         worker,
    47  		Worker:        worker,
    48  		SealProofType: abi.RegisteredSealProof_StackedDrg32GiBV1_1,
    49  		Peer:          abi.PeerID("not really a peer id"),
    50  	}
    51  	ret := vm2.ApplyOk(t, v, addrs[0], builtin2.StoragePowerActorAddr, minerBalance, builtin2.MethodsPower.CreateMiner, &params)
    52  
    53  	minerAddrs, ok := ret.(*power2.CreateMinerReturn)
    54  	require.True(t, ok)
    55  
    56  	// add market collateral for clients and miner
    57  	for i := 0; i < 9; i++ {
    58  		collateral := big.Mul(big.NewInt(30), vm2.FIL)
    59  		vm2.ApplyOk(t, v, addrs[i+1], builtin2.StorageMarketActorAddr, collateral, builtin2.MethodsMarket.AddBalance, &addrs[i+1])
    60  		collateral = big.Mul(big.NewInt(64), vm2.FIL)
    61  		vm2.ApplyOk(t, v, worker, builtin2.StorageMarketActorAddr, collateral, builtin2.MethodsMarket.AddBalance, &minerAddrs.IDAddress)
    62  	}
    63  
    64  	// create 100 deals over 100 epochs to fill pending proposals structure
    65  	dealStart := abi.ChainEpoch(252)
    66  	var deals []*market2.PublishStorageDealsReturn
    67  	for i := 0; i < 100; i++ {
    68  		var err error
    69  		v, err = v.WithEpoch(v.GetEpoch() + 1)
    70  		require.NoError(t, err)
    71  		deals = append(deals, publishDeal(t, v, worker, addrs[1+i%9], minerAddrs.IDAddress, fmt.Sprintf("deal%d", i),
    72  			1<<26, false, dealStart, 210*builtin2.EpochsInDay))
    73  	}
    74  
    75  	// run migration
    76  	nextRoot, err := nv10.MigrateStateTree(ctx, v.Store(), v.StateRoot(), v.GetEpoch(), nv10.Config{MaxWorkers: 1}, log, nv10.NewMemMigrationCache())
    77  	require.NoError(t, err)
    78  
    79  	lookup := map[cid.Cid]rt.VMActor{}
    80  	for _, ba := range exported3.BuiltinActors() {
    81  		lookup[ba.Code()] = ba
    82  	}
    83  
    84  	v3, err := vm3.NewVMAtEpoch(ctx, lookup, v.Store(), nextRoot, v.GetEpoch()+1)
    85  	require.NoError(t, err)
    86  
    87  	// add 10 more deals after migration
    88  	for i := 0; i < 10; i++ {
    89  		var err error
    90  		v3, err = v3.WithEpoch(v.GetEpoch() + 1)
    91  		require.NoError(t, err)
    92  
    93  		deals = append(deals, publishV3Deal(t, v3, worker, addrs[1+i%9], minerAddrs.IDAddress, fmt.Sprintf("deal1%d", i),
    94  			1<<26, false, dealStart, 210*builtin3.EpochsInDay))
    95  	}
    96  
    97  	// add even deals to a sector we will commit (to let the odd deals expire)
    98  	var dealIDs []abi.DealID
    99  	for i := 0; i < len(deals); i += 2 {
   100  		dealIDs = append(dealIDs, deals[i].IDs[0])
   101  	}
   102  
   103  	// precommit capacity upgrade sector with deals
   104  	sectorNumber := abi.SectorNumber(100)
   105  	sealedCid := tutil.MakeCID("100", &miner3.SealedCIDPrefix)
   106  	sealProof := abi.RegisteredSealProof_StackedDrg32GiBV1_1
   107  	preCommitParams := miner3.PreCommitSectorParams{
   108  		SealProof:     sealProof,
   109  		SectorNumber:  sectorNumber,
   110  		SealedCID:     sealedCid,
   111  		SealRandEpoch: v.GetEpoch() - 1,
   112  		DealIDs:       dealIDs,
   113  		Expiration:    v.GetEpoch() + 220*builtin3.EpochsInDay,
   114  	}
   115  	vm3.ApplyOk(t, v3, addrs[0], minerAddrs.RobustAddress, big.Zero(), builtin3.MethodsMiner.PreCommitSector, &preCommitParams)
   116  
   117  	// advance time to min seal duration
   118  	proveTime := v3.GetEpoch() + miner3.PreCommitChallengeDelay + 1
   119  	v3, _ = vm3.AdvanceByDeadlineTillEpoch(t, v3, minerAddrs.IDAddress, proveTime)
   120  
   121  	// Prove commit sector after max seal duration
   122  	v3, err = v3.WithEpoch(proveTime)
   123  	require.NoError(t, err)
   124  	proveCommitParams := miner3.ProveCommitSectorParams{
   125  		SectorNumber: sectorNumber,
   126  	}
   127  	vm3.ApplyOk(t, v3, worker, minerAddrs.RobustAddress, big.Zero(), builtin3.MethodsMiner.ProveCommitSector, &proveCommitParams)
   128  
   129  	// In the same epoch, trigger cron to validate prove commit
   130  	// This activates deals hitting the pending deals structure.
   131  	vm3.ApplyOk(t, v3, builtin3.SystemActorAddr, builtin3.CronActorAddr, big.Zero(), builtin3.MethodsCron.EpochTick, nil)
   132  
   133  	// Run cron after deal start to expire pending deals
   134  	v3, err = v3.WithEpoch(dealStart + 1)
   135  	require.NoError(t, err)
   136  	vm3.ApplyOk(t, v3, builtin3.SystemActorAddr, builtin3.CronActorAddr, big.Zero(), builtin3.MethodsCron.EpochTick, nil)
   137  
   138  	// Assert that no invariants are broken. CheckStateInvariants used to assert that Pending Proposal value cid
   139  	// matched its key, so this also checks that the market invariants have been corrected.
   140  	stateTree, err := v3.GetStateTree()
   141  	require.NoError(t, err)
   142  	totalBalance, err := v3.GetTotalActorBalance()
   143  	require.NoError(t, err)
   144  	msgs, err := states3.CheckStateInvariants(stateTree, totalBalance, v3.GetEpoch())
   145  	require.NoError(t, err)
   146  
   147  	assert.Equal(t, 0, len(msgs.Messages()), strings.Join(msgs.Messages(), "\n"))
   148  
   149  }
   150  
   151  func publishDeal(t *testing.T, v *vm2.VM, provider, dealClient, minerID addr.Address, dealLabel string,
   152  	pieceSize abi.PaddedPieceSize, verifiedDeal bool, dealStart abi.ChainEpoch, dealLifetime abi.ChainEpoch,
   153  ) *market2.PublishStorageDealsReturn {
   154  	deal := market2.DealProposal{
   155  		PieceCID:             tutil.MakeCID(dealLabel, &market2.PieceCIDPrefix),
   156  		PieceSize:            pieceSize,
   157  		VerifiedDeal:         verifiedDeal,
   158  		Client:               dealClient,
   159  		Provider:             minerID,
   160  		Label:                dealLabel,
   161  		StartEpoch:           dealStart,
   162  		EndEpoch:             dealStart + dealLifetime,
   163  		StoragePricePerEpoch: abi.NewTokenAmount(1 << 20),
   164  		ProviderCollateral:   big.Mul(big.NewInt(2), vm2.FIL),
   165  		ClientCollateral:     big.Mul(big.NewInt(1), vm2.FIL),
   166  	}
   167  
   168  	publishDealParams := market2.PublishStorageDealsParams{
   169  		Deals: []market2.ClientDealProposal{{
   170  			Proposal:        deal,
   171  			ClientSignature: crypto.Signature{},
   172  		}},
   173  	}
   174  	ret, code := v.ApplyMessage(provider, builtin2.StorageMarketActorAddr, big.Zero(), builtin2.MethodsMarket.PublishStorageDeals, &publishDealParams)
   175  	require.Equal(t, exitcode.Ok, code)
   176  
   177  	expectedPublishSubinvocations := []vm2.ExpectInvocation{
   178  		{To: minerID, Method: builtin2.MethodsMiner.ControlAddresses, SubInvocations: []vm2.ExpectInvocation{}},
   179  		{To: builtin2.RewardActorAddr, Method: builtin2.MethodsReward.ThisEpochReward, SubInvocations: []vm2.ExpectInvocation{}},
   180  		{To: builtin2.StoragePowerActorAddr, Method: builtin2.MethodsPower.CurrentTotalPower, SubInvocations: []vm2.ExpectInvocation{}},
   181  	}
   182  
   183  	vm2.ExpectInvocation{
   184  		To:             builtin2.StorageMarketActorAddr,
   185  		Method:         builtin2.MethodsMarket.PublishStorageDeals,
   186  		SubInvocations: expectedPublishSubinvocations,
   187  	}.Matches(t, v.LastInvocation())
   188  
   189  	return ret.(*market2.PublishStorageDealsReturn)
   190  }
   191  
   192  func publishV3Deal(t *testing.T, v *vm3.VM, provider, dealClient, minerID addr.Address, dealLabel string,
   193  	pieceSize abi.PaddedPieceSize, verifiedDeal bool, dealStart abi.ChainEpoch, dealLifetime abi.ChainEpoch,
   194  ) *market2.PublishStorageDealsReturn {
   195  	deal := market3.DealProposal{
   196  		PieceCID:             tutil.MakeCID(dealLabel, &market2.PieceCIDPrefix),
   197  		PieceSize:            pieceSize,
   198  		VerifiedDeal:         verifiedDeal,
   199  		Client:               dealClient,
   200  		Provider:             minerID,
   201  		Label:                dealLabel,
   202  		StartEpoch:           dealStart,
   203  		EndEpoch:             dealStart + dealLifetime,
   204  		StoragePricePerEpoch: abi.NewTokenAmount(1 << 20),
   205  		ProviderCollateral:   big.Mul(big.NewInt(2), vm2.FIL),
   206  		ClientCollateral:     big.Mul(big.NewInt(1), vm2.FIL),
   207  	}
   208  
   209  	publishDealParams := market3.PublishStorageDealsParams{
   210  		Deals: []market3.ClientDealProposal{{
   211  			Proposal:        deal,
   212  			ClientSignature: crypto.Signature{},
   213  		}},
   214  	}
   215  	ret, code := v.ApplyMessage(provider, builtin3.StorageMarketActorAddr, big.Zero(), builtin3.MethodsMarket.PublishStorageDeals, &publishDealParams)
   216  	require.Equal(t, exitcode.Ok, code)
   217  
   218  	expectedPublishSubinvocations := []vm3.ExpectInvocation{
   219  		{To: minerID, Method: builtin3.MethodsMiner.ControlAddresses, SubInvocations: []vm3.ExpectInvocation{}},
   220  		{To: builtin3.RewardActorAddr, Method: builtin3.MethodsReward.ThisEpochReward, SubInvocations: []vm3.ExpectInvocation{}},
   221  		{To: builtin3.StoragePowerActorAddr, Method: builtin3.MethodsPower.CurrentTotalPower, SubInvocations: []vm3.ExpectInvocation{}},
   222  	}
   223  
   224  	vm3.ExpectInvocation{
   225  		To:             builtin3.StorageMarketActorAddr,
   226  		Method:         builtin3.MethodsMarket.PublishStorageDeals,
   227  		SubInvocations: expectedPublishSubinvocations,
   228  	}.Matches(t, v.LastInvocation())
   229  
   230  	return ret.(*market2.PublishStorageDealsReturn)
   231  }