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, ¶ms) 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 }