github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/market/market_test.go (about) 1 package market_test 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "strings" 8 "testing" 9 10 address "github.com/filecoin-project/go-address" 11 "github.com/filecoin-project/go-state-types/abi" 12 "github.com/filecoin-project/go-state-types/big" 13 "github.com/filecoin-project/go-state-types/cbor" 14 "github.com/filecoin-project/go-state-types/crypto" 15 "github.com/filecoin-project/go-state-types/exitcode" 16 cid "github.com/ipfs/go-cid" 17 cbg "github.com/whyrusleeping/cbor-gen" 18 19 "github.com/filecoin-project/specs-actors/v4/actors/builtin" 20 "github.com/filecoin-project/specs-actors/v4/actors/builtin/market" 21 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" 22 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power" 23 "github.com/filecoin-project/specs-actors/v4/actors/builtin/reward" 24 "github.com/filecoin-project/specs-actors/v4/actors/builtin/verifreg" 25 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 26 "github.com/filecoin-project/specs-actors/v4/support/mock" 27 tutil "github.com/filecoin-project/specs-actors/v4/support/testing" 28 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func mustCbor(o cbor.Marshaler) []byte { 34 buf := new(bytes.Buffer) 35 if err := o.MarshalCBOR(buf); err != nil { 36 panic(err) 37 } 38 39 return buf.Bytes() 40 } 41 42 func TestExports(t *testing.T) { 43 mock.CheckActorExports(t, market.Actor{}) 44 } 45 46 func TestRemoveAllError(t *testing.T) { 47 marketActor := tutil.NewIDAddr(t, 100) 48 builder := mock.NewBuilder(marketActor) 49 rt := builder.Build(t) 50 store := adt.AsStore(rt) 51 52 smm, err := market.MakeEmptySetMultimap(store, builtin.DefaultHamtBitwidth) 53 require.NoError(t, err) 54 55 if err := smm.RemoveAll(42); err != nil { 56 t.Fatalf("expected no error, got: %s", err) 57 } 58 } 59 60 func TestMarketActor(t *testing.T) { 61 owner := tutil.NewIDAddr(t, 101) 62 provider := tutil.NewIDAddr(t, 102) 63 worker := tutil.NewIDAddr(t, 103) 64 client := tutil.NewIDAddr(t, 104) 65 minerAddrs := &minerAddrs{owner, worker, provider, nil} 66 67 var st market.State 68 69 t.Run("simple construction", func(t *testing.T) { 70 actor := market.Actor{} 71 receiver := tutil.NewIDAddr(t, 100) 72 builder := mock.NewBuilder(receiver). 73 WithCaller(builtin.SystemActorAddr, builtin.InitActorCodeID) 74 75 rt := builder.Build(t) 76 77 rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) 78 79 ret := rt.Call(actor.Constructor, nil).(*abi.EmptyValue) 80 assert.Nil(t, ret) 81 rt.Verify() 82 83 store := adt.AsStore(rt) 84 85 emptyBalanceTable, err := adt.StoreEmptyMap(store, adt.BalanceTableBitwidth) 86 assert.NoError(t, err) 87 88 emptyMap, err := adt.StoreEmptyMap(store, builtin.DefaultHamtBitwidth) 89 assert.NoError(t, err) 90 91 emptyProposalsArrayCid, err := adt.StoreEmptyArray(store, market.ProposalsAmtBitwidth) 92 assert.NoError(t, err) 93 94 emptyStatesArrayCid, err := adt.StoreEmptyArray(store, market.StatesAmtBitwidth) 95 assert.NoError(t, err) 96 97 emptyMultiMap, err := market.StoreEmptySetMultimap(store, builtin.DefaultHamtBitwidth) 98 assert.NoError(t, err) 99 100 var state market.State 101 rt.GetState(&state) 102 103 assert.Equal(t, emptyProposalsArrayCid, state.Proposals) 104 assert.Equal(t, emptyStatesArrayCid, state.States) 105 assert.Equal(t, emptyMap, state.PendingProposals) 106 assert.Equal(t, emptyBalanceTable, state.EscrowTable) 107 assert.Equal(t, emptyBalanceTable, state.LockedTable) 108 assert.Equal(t, abi.DealID(0), state.NextID) 109 assert.Equal(t, emptyMultiMap, state.DealOpsByEpoch) 110 assert.Equal(t, abi.ChainEpoch(-1), state.LastCron) 111 }) 112 113 t.Run("AddBalance", func(t *testing.T) { 114 t.Run("adds to provider escrow funds", func(t *testing.T) { 115 testCases := []struct { 116 delta int64 117 total int64 118 }{ 119 {10, 10}, 120 {20, 30}, 121 {40, 70}, 122 } 123 124 // Test adding provider funds from both worker and owner address 125 for _, callerAddr := range []address.Address{owner, worker} { 126 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 127 128 for _, tc := range testCases { 129 rt.SetCaller(callerAddr, builtin.AccountActorCodeID) 130 rt.SetReceived(abi.NewTokenAmount(tc.delta)) 131 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 132 expectGetControlAddresses(rt, provider, owner, worker) 133 134 rt.Call(actor.AddBalance, &provider) 135 136 rt.Verify() 137 138 rt.GetState(&st) 139 assert.Equal(t, abi.NewTokenAmount(tc.total), actor.getEscrowBalance(rt, provider)) 140 141 actor.checkState(rt) 142 } 143 } 144 }) 145 146 t.Run("fails unless called by an account actor", func(t *testing.T) { 147 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 148 149 rt.SetReceived(abi.NewTokenAmount(10)) 150 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 151 152 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 153 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 154 rt.Call(actor.AddBalance, &provider) 155 }) 156 157 rt.Verify() 158 159 actor.checkState(rt) 160 }) 161 162 t.Run("adds to non-provider escrow funds", func(t *testing.T) { 163 testCases := []struct { 164 delta int64 165 total int64 166 }{ 167 {10, 10}, 168 {20, 30}, 169 {40, 70}, 170 } 171 172 // Test adding non-provider funds from both worker and client addresses 173 for _, callerAddr := range []address.Address{client, worker} { 174 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 175 176 for _, tc := range testCases { 177 rt.SetCaller(callerAddr, builtin.AccountActorCodeID) 178 rt.SetReceived(abi.NewTokenAmount(tc.delta)) 179 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 180 181 rt.Call(actor.AddBalance, &callerAddr) 182 183 rt.Verify() 184 185 rt.GetState(&st) 186 assert.Equal(t, abi.NewTokenAmount(tc.total), actor.getEscrowBalance(rt, callerAddr)) 187 188 actor.checkState(rt) 189 } 190 } 191 }) 192 193 t.Run("fail when balance is zero", func(t *testing.T) { 194 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 195 196 rt.SetCaller(tutil.NewIDAddr(t, 101), builtin.AccountActorCodeID) 197 rt.SetReceived(big.Zero()) 198 199 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 200 rt.Call(actor.AddBalance, &provider) 201 }) 202 rt.Verify() 203 204 actor.checkState(rt) 205 }) 206 }) 207 208 t.Run("WithdrawBalance", func(t *testing.T) { 209 startEpoch := abi.ChainEpoch(10) 210 endEpoch := startEpoch + 200*builtin.EpochsInDay 211 publishEpoch := abi.ChainEpoch(5) 212 213 t.Run("fails with a negative withdraw amount", func(t *testing.T) { 214 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 215 216 params := market.WithdrawBalanceParams{ 217 ProviderOrClientAddress: provider, 218 Amount: abi.NewTokenAmount(-1), 219 } 220 221 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 222 rt.Call(actor.WithdrawBalance, ¶ms) 223 }) 224 225 rt.Verify() 226 actor.checkState(rt) 227 }) 228 229 t.Run("fails if withdraw from non provider funds is not initiated by the recipient", func(t *testing.T) { 230 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 231 actor.addParticipantFunds(rt, client, abi.NewTokenAmount(20)) 232 233 rt.GetState(&st) 234 assert.Equal(t, abi.NewTokenAmount(20), actor.getEscrowBalance(rt, client)) 235 236 rt.ExpectValidateCallerAddr(client) 237 params := market.WithdrawBalanceParams{ 238 ProviderOrClientAddress: client, 239 Amount: abi.NewTokenAmount(1), 240 } 241 242 // caller is not the recipient 243 rt.SetCaller(tutil.NewIDAddr(t, 909), builtin.AccountActorCodeID) 244 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 245 rt.Call(actor.WithdrawBalance, ¶ms) 246 }) 247 rt.Verify() 248 249 // verify there was no withdrawal 250 rt.GetState(&st) 251 assert.Equal(t, abi.NewTokenAmount(20), actor.getEscrowBalance(rt, client)) 252 253 actor.checkState(rt) 254 }) 255 256 t.Run("fails if withdraw from provider funds is not initiated by the owner or worker", func(t *testing.T) { 257 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 258 actor.addProviderFunds(rt, abi.NewTokenAmount(20), minerAddrs) 259 260 rt.GetState(&st) 261 assert.Equal(t, abi.NewTokenAmount(20), actor.getEscrowBalance(rt, provider)) 262 263 // only signing parties can add balance for client AND provider. 264 rt.ExpectValidateCallerAddr(owner, worker) 265 params := market.WithdrawBalanceParams{ 266 ProviderOrClientAddress: provider, 267 Amount: abi.NewTokenAmount(1), 268 } 269 270 // caller is not owner or worker 271 rt.SetCaller(tutil.NewIDAddr(t, 909), builtin.AccountActorCodeID) 272 expectGetControlAddresses(rt, provider, owner, worker) 273 274 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 275 rt.Call(actor.WithdrawBalance, ¶ms) 276 }) 277 rt.Verify() 278 279 // verify there was no withdrawal 280 rt.GetState(&st) 281 assert.Equal(t, abi.NewTokenAmount(20), actor.getEscrowBalance(rt, provider)) 282 283 actor.checkState(rt) 284 }) 285 286 t.Run("withdraws from provider escrow funds and sends to owner", func(t *testing.T) { 287 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 288 289 actor.addProviderFunds(rt, abi.NewTokenAmount(20), minerAddrs) 290 291 rt.GetState(&st) 292 assert.Equal(t, abi.NewTokenAmount(20), actor.getEscrowBalance(rt, provider)) 293 294 // worker calls WithdrawBalance, balance is transferred to owner 295 withdrawAmount := abi.NewTokenAmount(1) 296 actor.withdrawProviderBalance(rt, withdrawAmount, withdrawAmount, minerAddrs) 297 298 rt.GetState(&st) 299 assert.Equal(t, abi.NewTokenAmount(19), actor.getEscrowBalance(rt, provider)) 300 301 actor.checkState(rt) 302 }) 303 304 t.Run("withdraws from non-provider escrow funds", func(t *testing.T) { 305 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 306 actor.addParticipantFunds(rt, client, abi.NewTokenAmount(20)) 307 308 rt.GetState(&st) 309 assert.Equal(t, abi.NewTokenAmount(20), actor.getEscrowBalance(rt, client)) 310 311 withdrawAmount := abi.NewTokenAmount(1) 312 actor.withdrawClientBalance(rt, client, withdrawAmount, withdrawAmount) 313 314 rt.GetState(&st) 315 assert.Equal(t, abi.NewTokenAmount(19), actor.getEscrowBalance(rt, client)) 316 317 actor.checkState(rt) 318 }) 319 320 t.Run("client withdrawing more than escrow balance limits to available funds", func(t *testing.T) { 321 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 322 actor.addParticipantFunds(rt, client, abi.NewTokenAmount(20)) 323 324 // withdraw amount greater than escrow balance 325 withdrawAmount := abi.NewTokenAmount(25) 326 expectedAmount := abi.NewTokenAmount(20) 327 actor.withdrawClientBalance(rt, client, withdrawAmount, expectedAmount) 328 329 actor.assertAccountZero(rt, client) 330 331 actor.checkState(rt) 332 }) 333 334 t.Run("worker withdrawing more than escrow balance limits to available funds", func(t *testing.T) { 335 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 336 actor.addProviderFunds(rt, abi.NewTokenAmount(20), minerAddrs) 337 338 rt.GetState(&st) 339 assert.Equal(t, abi.NewTokenAmount(20), actor.getEscrowBalance(rt, provider)) 340 341 // withdraw amount greater than escrow balance 342 withdrawAmount := abi.NewTokenAmount(25) 343 actualWithdrawn := abi.NewTokenAmount(20) 344 actor.withdrawProviderBalance(rt, withdrawAmount, actualWithdrawn, minerAddrs) 345 346 actor.assertAccountZero(rt, provider) 347 348 actor.checkState(rt) 349 }) 350 351 t.Run("balance after withdrawal must ALWAYS be greater than or equal to locked amount", func(t *testing.T) { 352 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 353 354 // publish the deal so that client AND provider collateral is locked 355 rt.SetEpoch(publishEpoch) 356 dealId := actor.generateAndPublishDeal(rt, client, minerAddrs, startEpoch, endEpoch, startEpoch) 357 deal := actor.getDealProposal(rt, dealId) 358 rt.GetState(&st) 359 require.Equal(t, deal.ProviderCollateral, actor.getEscrowBalance(rt, provider)) 360 require.Equal(t, deal.ClientBalanceRequirement(), actor.getEscrowBalance(rt, client)) 361 362 withDrawAmt := abi.NewTokenAmount(1) 363 withDrawableAmt := abi.NewTokenAmount(0) 364 // client cannot withdraw any funds since all it's balance is locked 365 actor.withdrawClientBalance(rt, client, withDrawAmt, withDrawableAmt) 366 // provider cannot withdraw any funds since all it's balance is locked 367 actor.withdrawProviderBalance(rt, withDrawAmt, withDrawableAmt, minerAddrs) 368 369 // add some more funds to the provider & ensure withdrawal is limited by the locked funds 370 withDrawAmt = abi.NewTokenAmount(30) 371 withDrawableAmt = abi.NewTokenAmount(25) 372 actor.addProviderFunds(rt, withDrawableAmt, minerAddrs) 373 actor.withdrawProviderBalance(rt, withDrawAmt, withDrawableAmt, minerAddrs) 374 375 // add some more funds to the client & ensure withdrawal is limited by the locked funds 376 actor.addParticipantFunds(rt, client, withDrawableAmt) 377 actor.withdrawClientBalance(rt, client, withDrawAmt, withDrawableAmt) 378 379 actor.checkState(rt) 380 }) 381 382 t.Run("worker balance after withdrawal must account for slashed funds", func(t *testing.T) { 383 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 384 385 // publish deal 386 rt.SetEpoch(publishEpoch) 387 dealID := actor.generateAndPublishDeal(rt, client, minerAddrs, startEpoch, endEpoch, startEpoch) 388 389 // activate the deal 390 actor.activateDeals(rt, endEpoch+1, provider, publishEpoch, dealID) 391 st := actor.getDealState(rt, dealID) 392 require.EqualValues(t, publishEpoch, st.SectorStartEpoch) 393 394 // slash the deal 395 newEpoch := publishEpoch + 1 396 rt.SetEpoch(newEpoch) 397 actor.terminateDeals(rt, provider, dealID) 398 st = actor.getDealState(rt, dealID) 399 require.EqualValues(t, publishEpoch+1, st.SlashEpoch) 400 401 // provider cannot withdraw any funds since all it's balance is locked 402 withDrawAmt := abi.NewTokenAmount(1) 403 actualWithdrawn := abi.NewTokenAmount(0) 404 actor.withdrawProviderBalance(rt, withDrawAmt, actualWithdrawn, minerAddrs) 405 406 // add some more funds to the provider & ensure withdrawal is limited by the locked funds 407 actor.addProviderFunds(rt, abi.NewTokenAmount(25), minerAddrs) 408 withDrawAmt = abi.NewTokenAmount(30) 409 actualWithdrawn = abi.NewTokenAmount(25) 410 411 actor.withdrawProviderBalance(rt, withDrawAmt, actualWithdrawn, minerAddrs) 412 413 actor.checkState(rt) 414 }) 415 }) 416 } 417 418 func TestPublishStorageDeals(t *testing.T) { 419 owner := tutil.NewIDAddr(t, 101) 420 provider := tutil.NewIDAddr(t, 102) 421 worker := tutil.NewIDAddr(t, 103) 422 client := tutil.NewIDAddr(t, 104) 423 control := tutil.NewIDAddr(t, 200) 424 startEpoch := abi.ChainEpoch(42) 425 endEpoch := startEpoch + 200*builtin.EpochsInDay 426 mAddr := &minerAddrs{owner, worker, provider, []address.Address{control}} 427 var st market.State 428 429 t.Run("simple deal", func(t *testing.T) { 430 startEpoch := abi.ChainEpoch(1000) 431 endEpoch := startEpoch + 200*builtin.EpochsInDay 432 publishEpoch := abi.ChainEpoch(1) 433 434 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 435 rt.SetEpoch(publishEpoch) 436 437 // Publish from miner worker. 438 deal1 := actor.generateDealAndAddFunds(rt, client, mAddr, startEpoch, endEpoch) 439 rt.SetCaller(worker, builtin.AccountActorCodeID) 440 _ = actor.publishDeals(rt, mAddr, publishDealReq{deal: deal1}) 441 442 // Publish from miner control address. 443 deal2 := actor.generateDealAndAddFunds(rt, client, mAddr, startEpoch+1, endEpoch+1) 444 rt.SetCaller(control, builtin.AccountActorCodeID) 445 _ = actor.publishDeals(rt, mAddr, publishDealReq{deal: deal2}) 446 447 actor.checkState(rt) 448 }) 449 450 t.Run("provider and client addresses are resolved before persisting state and sent to VerigReg actor for a verified deal", func(t *testing.T) { 451 // provider addresses 452 providerBls := tutil.NewBLSAddr(t, 101) 453 providerResolved := tutil.NewIDAddr(t, 102) 454 // client addresses 455 clientBls := tutil.NewBLSAddr(t, 900) 456 clientResolved := tutil.NewIDAddr(t, 333) 457 mAddr := &minerAddrs{owner, worker, providerBls, nil} 458 459 rt, actor := basicMarketSetup(t, owner, providerResolved, worker, clientResolved) 460 // mappings for resolving address 461 rt.AddIDAddress(providerBls, providerResolved) 462 rt.AddIDAddress(clientBls, clientResolved) 463 464 // generate deal and add required funds for deal 465 startEpoch := abi.ChainEpoch(42) 466 endEpoch := startEpoch + 200*builtin.EpochsInDay 467 deal := generateDealProposal(clientBls, mAddr.provider, startEpoch, endEpoch) 468 deal.VerifiedDeal = true 469 470 // add funds for cient using it's BLS address -> will be resolved and persisted 471 actor.addParticipantFunds(rt, clientBls, deal.ClientBalanceRequirement()) 472 require.EqualValues(t, deal.ClientBalanceRequirement(), actor.getEscrowBalance(rt, clientResolved)) 473 474 // add funds for provider using it's BLS address -> will be resolved and persisted 475 rt.SetReceived(deal.ProviderCollateral) 476 rt.SetCaller(mAddr.owner, builtin.AccountActorCodeID) 477 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 478 expectGetControlAddresses(rt, providerResolved, mAddr.owner, mAddr.worker) 479 rt.Call(actor.AddBalance, &mAddr.provider) 480 rt.Verify() 481 rt.SetBalance(big.Add(rt.Balance(), deal.ProviderCollateral)) 482 require.EqualValues(t, deal.ProviderCollateral, actor.getEscrowBalance(rt, providerResolved)) 483 484 // publish deal using the BLS addresses 485 rt.SetCaller(mAddr.worker, builtin.AccountActorCodeID) 486 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 487 expectGetControlAddresses(rt, providerResolved, mAddr.owner, mAddr.worker) 488 expectQueryNetworkInfo(rt, actor) 489 // create a client proposal with a valid signature 490 var params market.PublishStorageDealsParams 491 buf := bytes.Buffer{} 492 require.NoError(t, deal.MarshalCBOR(&buf), "failed to marshal deal proposal") 493 sig := crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("does not matter")} 494 clientProposal := market.ClientDealProposal{Proposal: deal, ClientSignature: sig} 495 params.Deals = append(params.Deals, clientProposal) 496 // expect a call to verify the above signature 497 rt.ExpectVerifySignature(sig, deal.Client, buf.Bytes(), nil) 498 499 // request is sent to the VerigReg actor using the resolved address 500 param := &verifreg.UseBytesParams{ 501 Address: clientResolved, 502 DealSize: big.NewIntUnsigned(uint64(deal.PieceSize)), 503 } 504 rt.ExpectSend(builtin.VerifiedRegistryActorAddr, builtin.MethodsVerifiedRegistry.UseBytes, param, abi.NewTokenAmount(0), nil, exitcode.Ok) 505 506 deal2 := deal 507 deal2.Client = clientResolved 508 deal2.Provider = providerResolved 509 actor.expectGetRandom(rt, &deal2, abi.ChainEpoch(100)) 510 511 ret := rt.Call(actor.PublishStorageDeals, ¶ms) 512 rt.Verify() 513 resp, ok := ret.(*market.PublishStorageDealsReturn) 514 require.True(t, ok) 515 dealId := resp.IDs[0] 516 517 // assert that deal is persisted with the resolved addresses 518 prop := actor.getDealProposal(rt, dealId) 519 require.EqualValues(t, clientResolved, prop.Client) 520 require.EqualValues(t, providerResolved, prop.Provider) 521 522 actor.checkState(rt) 523 }) 524 525 t.Run("publish a deal after activating a previous deal which has a start epoch far in the future", func(t *testing.T) { 526 startEpoch := abi.ChainEpoch(1000) 527 endEpoch := startEpoch + 200*builtin.EpochsInDay 528 publishEpoch := abi.ChainEpoch(1) 529 530 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 531 532 // publish the deal and activate it 533 rt.SetEpoch(publishEpoch) 534 deal1ID := actor.generateAndPublishDeal(rt, client, mAddr, startEpoch, endEpoch, startEpoch) 535 actor.activateDeals(rt, endEpoch, provider, publishEpoch, deal1ID) 536 st := actor.getDealState(rt, deal1ID) 537 require.EqualValues(t, publishEpoch, st.SectorStartEpoch) 538 539 // now publish a second deal and activate it 540 newEpoch := publishEpoch + 1 541 rt.SetEpoch(newEpoch) 542 deal2ID := actor.generateAndPublishDeal(rt, client, mAddr, startEpoch+1, endEpoch+1, startEpoch+1) 543 actor.activateDeals(rt, endEpoch+1, provider, newEpoch, deal2ID) 544 545 actor.checkState(rt) 546 }) 547 548 t.Run("publish a deal with enough collateral when circulating supply > 0", func(t *testing.T) { 549 startEpoch := abi.ChainEpoch(1000) 550 endEpoch := startEpoch + 200*builtin.EpochsInDay 551 publishEpoch := abi.ChainEpoch(1) 552 553 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 554 555 clientCollateral := abi.NewTokenAmount(10) // min is zero so this is placeholder 556 557 // given power and circ supply cancel this should be 1*dealqapower / 100 558 dealSize := abi.PaddedPieceSize(2048) // generateDealProposal's deal size 559 providerCollateral := big.Div( 560 big.Mul(big.NewInt(int64(dealSize)), market.ProviderCollateralSupplyTarget.Numerator), 561 market.ProviderCollateralSupplyTarget.Denominator, 562 ) 563 deal := actor.generateDealWithCollateralAndAddFunds(rt, client, mAddr, providerCollateral, clientCollateral, startEpoch, endEpoch) 564 rt.SetCirculatingSupply(actor.networkQAPower) // convenient for these two numbers to cancel out 565 566 // publish the deal successfully 567 rt.SetEpoch(publishEpoch) 568 rt.SetCaller(worker, builtin.AccountActorCodeID) 569 actor.publishDeals(rt, mAddr, publishDealReq{deal: deal}) 570 571 actor.checkState(rt) 572 }) 573 574 t.Run("publish multiple deals for different clients and ensure balances are correct", func(t *testing.T) { 575 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 576 client1 := tutil.NewIDAddr(t, 900) 577 client2 := tutil.NewIDAddr(t, 901) 578 client3 := tutil.NewIDAddr(t, 902) 579 580 // generate first deal for 581 deal1 := actor.generateDealAndAddFunds(rt, client1, mAddr, startEpoch, endEpoch) 582 583 // generate second deal 584 deal2 := actor.generateDealAndAddFunds(rt, client2, mAddr, startEpoch, endEpoch) 585 586 // generate third deal 587 deal3 := actor.generateDealAndAddFunds(rt, client3, mAddr, startEpoch, endEpoch) 588 589 rt.SetCaller(worker, builtin.AccountActorCodeID) 590 actor.publishDeals(rt, mAddr, publishDealReq{deal: deal1}, publishDealReq{deal: deal2}, 591 publishDealReq{deal: deal3}) 592 593 // assert locked balance for all clients and provider 594 providerLocked := big.Sum(deal1.ProviderCollateral, deal2.ProviderCollateral, deal3.ProviderCollateral) 595 client1Locked := actor.getLockedBalance(rt, client1) 596 client2Locked := actor.getLockedBalance(rt, client2) 597 client3Locked := actor.getLockedBalance(rt, client3) 598 require.EqualValues(t, deal1.ClientBalanceRequirement(), client1Locked) 599 require.EqualValues(t, deal2.ClientBalanceRequirement(), client2Locked) 600 require.EqualValues(t, deal3.ClientBalanceRequirement(), client3Locked) 601 require.EqualValues(t, providerLocked, actor.getLockedBalance(rt, provider)) 602 603 // assert locked funds dealStates 604 rt.GetState(&st) 605 totalClientCollateralLocked := big.Sum(deal3.ClientCollateral, deal1.ClientCollateral, deal2.ClientCollateral) 606 require.EqualValues(t, totalClientCollateralLocked, st.TotalClientLockedCollateral) 607 require.EqualValues(t, providerLocked, st.TotalProviderLockedCollateral) 608 totalStorageFee := big.Sum(deal1.TotalStorageFee(), deal2.TotalStorageFee(), deal3.TotalStorageFee()) 609 require.EqualValues(t, totalStorageFee, st.TotalClientStorageFee) 610 611 // publish two more deals for same clients with same provider 612 deal4 := actor.generateDealAndAddFunds(rt, client3, mAddr, abi.ChainEpoch(1000), abi.ChainEpoch(1000+200*builtin.EpochsInDay)) 613 deal5 := actor.generateDealAndAddFunds(rt, client3, mAddr, abi.ChainEpoch(100), abi.ChainEpoch(100+200*builtin.EpochsInDay)) 614 rt.SetCaller(worker, builtin.AccountActorCodeID) 615 actor.publishDeals(rt, mAddr, publishDealReq{deal: deal4}, publishDealReq{deal: deal5}) 616 617 // assert locked balances for clients and provider 618 rt.GetState(&st) 619 providerLocked = big.Sum(providerLocked, deal4.ProviderCollateral, deal5.ProviderCollateral) 620 require.EqualValues(t, providerLocked, actor.getLockedBalance(rt, provider)) 621 622 client3LockedUpdated := actor.getLockedBalance(rt, client3) 623 require.EqualValues(t, big.Sum(client3Locked, deal4.ClientBalanceRequirement(), deal5.ClientBalanceRequirement()), client3LockedUpdated) 624 625 client1Locked = actor.getLockedBalance(rt, client1) 626 client2Locked = actor.getLockedBalance(rt, client2) 627 require.EqualValues(t, deal1.ClientBalanceRequirement(), client1Locked) 628 require.EqualValues(t, deal2.ClientBalanceRequirement(), client2Locked) 629 630 // assert locked funds dealStates 631 totalClientCollateralLocked = big.Sum(totalClientCollateralLocked, deal4.ClientCollateral, deal5.ClientCollateral) 632 require.EqualValues(t, totalClientCollateralLocked, st.TotalClientLockedCollateral) 633 require.EqualValues(t, providerLocked, st.TotalProviderLockedCollateral) 634 635 totalStorageFee = big.Sum(totalStorageFee, deal4.TotalStorageFee(), deal5.TotalStorageFee()) 636 require.EqualValues(t, totalStorageFee, st.TotalClientStorageFee) 637 638 // PUBLISH DEALS with a different provider 639 provider2 := tutil.NewIDAddr(t, 109) 640 miner := &minerAddrs{owner, worker, provider2, nil} 641 642 // generate first deal for second provider 643 deal6 := actor.generateDealAndAddFunds(rt, client1, miner, abi.ChainEpoch(20), abi.ChainEpoch(20+200*builtin.EpochsInDay)) 644 645 // generate second deal for second provider 646 deal7 := actor.generateDealAndAddFunds(rt, client1, miner, abi.ChainEpoch(25), abi.ChainEpoch(60+200*builtin.EpochsInDay)) 647 648 // publish both the deals for the second provider 649 rt.SetCaller(worker, builtin.AccountActorCodeID) 650 actor.publishDeals(rt, miner, publishDealReq{deal: deal6}, publishDealReq{deal: deal7}) 651 652 // assertions 653 rt.GetState(&st) 654 provider2Locked := big.Add(deal6.ProviderCollateral, deal7.ProviderCollateral) 655 require.EqualValues(t, provider2Locked, actor.getLockedBalance(rt, provider2)) 656 client1LockedUpdated := actor.getLockedBalance(rt, client1) 657 require.EqualValues(t, big.Add(deal7.ClientBalanceRequirement(), big.Add(client1Locked, deal6.ClientBalanceRequirement())), client1LockedUpdated) 658 659 // assert first provider's balance as well 660 require.EqualValues(t, providerLocked, actor.getLockedBalance(rt, provider)) 661 662 totalClientCollateralLocked = big.Add(totalClientCollateralLocked, big.Add(deal6.ClientCollateral, deal7.ClientCollateral)) 663 require.EqualValues(t, totalClientCollateralLocked, st.TotalClientLockedCollateral) 664 require.EqualValues(t, big.Add(providerLocked, provider2Locked), st.TotalProviderLockedCollateral) 665 totalStorageFee = big.Add(totalStorageFee, big.Add(deal6.TotalStorageFee(), deal7.TotalStorageFee())) 666 require.EqualValues(t, totalStorageFee, st.TotalClientStorageFee) 667 668 actor.checkState(rt) 669 }) 670 } 671 672 func TestPublishStorageDealsFailures(t *testing.T) { 673 owner := tutil.NewIDAddr(t, 101) 674 provider := tutil.NewIDAddr(t, 102) 675 worker := tutil.NewIDAddr(t, 103) 676 client := tutil.NewIDAddr(t, 104) 677 mAddrs := &minerAddrs{owner, worker, provider, nil} 678 679 currentEpoch := abi.ChainEpoch(5) 680 startEpoch := abi.ChainEpoch(10) 681 endEpoch := startEpoch + 200*builtin.EpochsInDay 682 683 // simple failures because of invalid deal params 684 { 685 tcs := map[string]struct { 686 setup func(*mock.Runtime, *marketActorTestHarness, *market.DealProposal) 687 exitCode exitcode.ExitCode 688 signatureVerificationError error 689 }{ 690 "deal end after deal start": { 691 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 692 d.StartEpoch = 10 693 d.EndEpoch = 9 694 }, 695 exitCode: exitcode.ErrIllegalArgument, 696 }, 697 "current epoch greater than start epoch": { 698 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 699 d.StartEpoch = currentEpoch - 1 700 }, 701 exitCode: exitcode.ErrIllegalArgument, 702 }, 703 "deal duration greater than max deal duration": { 704 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 705 d.StartEpoch = abi.ChainEpoch(10) 706 d.EndEpoch = d.StartEpoch + (540 * builtin.EpochsInDay) + 1 707 }, 708 exitCode: exitcode.ErrIllegalArgument, 709 }, 710 "negative price per epoch": { 711 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 712 d.StoragePricePerEpoch = abi.NewTokenAmount(-1) 713 }, 714 exitCode: exitcode.ErrIllegalArgument, 715 }, 716 "price per epoch greater than total filecoin": { 717 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 718 d.StoragePricePerEpoch = big.Add(builtin.TotalFilecoin, big.NewInt(1)) 719 }, 720 exitCode: exitcode.ErrIllegalArgument, 721 }, 722 "negative provider collateral": { 723 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 724 d.ProviderCollateral = big.NewInt(-1) 725 }, 726 exitCode: exitcode.ErrIllegalArgument, 727 }, 728 "provider collateral greater than max collateral": { 729 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 730 d.ProviderCollateral = big.Add(builtin.TotalFilecoin, big.NewInt(1)) 731 }, 732 exitCode: exitcode.ErrIllegalArgument, 733 }, 734 "provider collateral less than bound": { 735 setup: func(rt *mock.Runtime, h *marketActorTestHarness, d *market.DealProposal) { 736 // with these two equal provider collatreal min is 5/100 * deal size 737 rt.SetCirculatingSupply(h.networkQAPower) 738 dealSize := big.NewInt(2048) // default deal size used 739 providerMin := big.Div( 740 big.Mul(dealSize, market.ProviderCollateralSupplyTarget.Numerator), 741 market.ProviderCollateralSupplyTarget.Denominator, 742 ) 743 d.ProviderCollateral = big.Sub(providerMin, big.NewInt(1)) 744 }, 745 exitCode: exitcode.ErrIllegalArgument, 746 }, 747 "negative client collateral": { 748 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 749 d.ClientCollateral = big.NewInt(-1) 750 }, 751 exitCode: exitcode.ErrIllegalArgument, 752 }, 753 "client collateral greater than max collateral": { 754 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 755 d.ClientCollateral = big.Add(builtin.TotalFilecoin, big.NewInt(1)) 756 }, 757 exitCode: exitcode.ErrIllegalArgument, 758 }, 759 "client does not have enough balance for collateral": { 760 setup: func(rt *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { 761 a.addParticipantFunds(rt, client, big.Sub(d.ClientBalanceRequirement(), big.NewInt(1))) 762 a.addProviderFunds(rt, d.ProviderCollateral, mAddrs) 763 }, 764 exitCode: exitcode.ErrInsufficientFunds, 765 }, 766 "provider does not have enough balance for collateral": { 767 setup: func(rt *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { 768 a.addParticipantFunds(rt, client, d.ClientBalanceRequirement()) 769 a.addProviderFunds(rt, big.Sub(d.ProviderCollateral, big.NewInt(1)), mAddrs) 770 }, 771 exitCode: exitcode.ErrInsufficientFunds, 772 }, 773 "unable to resolve client address": { 774 setup: func(_ *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { 775 d.Client = tutil.NewBLSAddr(t, 1) 776 }, 777 exitCode: exitcode.ErrNotFound, 778 }, 779 "signature is invalid": { 780 setup: func(_ *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { 781 782 }, 783 exitCode: exitcode.ErrIllegalArgument, 784 signatureVerificationError: errors.New("error"), 785 }, 786 "no entry for client in locked balance table": { 787 setup: func(rt *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { 788 a.addProviderFunds(rt, d.ProviderCollateral, mAddrs) 789 }, 790 exitCode: exitcode.ErrInsufficientFunds, 791 }, 792 "no entry for provider in locked balance table": { 793 setup: func(rt *mock.Runtime, a *marketActorTestHarness, d *market.DealProposal) { 794 a.addParticipantFunds(rt, client, d.ClientBalanceRequirement()) 795 }, 796 exitCode: exitcode.ErrInsufficientFunds, 797 }, 798 "bad piece CID": { 799 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 800 d.PieceCID = tutil.MakeCID("random cid", nil) 801 }, 802 exitCode: exitcode.ErrIllegalArgument, 803 }, 804 "zero piece size": { 805 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 806 d.PieceSize = abi.PaddedPieceSize(0) 807 }, 808 exitCode: exitcode.ErrIllegalArgument, 809 }, 810 "piece size less than 128 bytes": { 811 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 812 d.PieceSize = abi.PaddedPieceSize(64) 813 }, 814 exitCode: exitcode.ErrIllegalArgument, 815 }, 816 "piece size is not a power of 2": { 817 setup: func(_ *mock.Runtime, _ *marketActorTestHarness, d *market.DealProposal) { 818 d.PieceSize = abi.PaddedPieceSize(254) 819 }, 820 exitCode: exitcode.ErrIllegalArgument, 821 }, 822 } 823 824 for name, tc := range tcs { 825 t.Run(name, func(t *testing.T) { 826 _ = name 827 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 828 dealProposal := generateDealProposal(client, provider, startEpoch, endEpoch) 829 rt.SetEpoch(currentEpoch) 830 tc.setup(rt, actor, &dealProposal) 831 params := mkPublishStorageParams(dealProposal) 832 833 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 834 rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) 835 expectQueryNetworkInfo(rt, actor) 836 rt.SetCaller(worker, builtin.AccountActorCodeID) 837 rt.ExpectVerifySignature(crypto.Signature{}, dealProposal.Client, mustCbor(&dealProposal), tc.signatureVerificationError) 838 rt.ExpectAbort(tc.exitCode, func() { 839 rt.Call(actor.PublishStorageDeals, params) 840 }) 841 842 rt.Verify() 843 actor.checkState(rt) 844 }) 845 } 846 } 847 848 // fails when client or provider has some funds but not enough to cover a deal 849 { 850 t.Run("fail when client has some funds but not enough for a deal", func(t *testing.T) { 851 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 852 853 // 854 actor.addParticipantFunds(rt, client, abi.NewTokenAmount(100)) 855 startEpoch := abi.ChainEpoch(42) 856 deal1 := generateDealProposal(client, provider, startEpoch, startEpoch+200*builtin.EpochsInDay) 857 actor.addProviderFunds(rt, deal1.ProviderCollateral, mAddrs) 858 params := mkPublishStorageParams(deal1) 859 860 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 861 rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) 862 expectQueryNetworkInfo(rt, actor) 863 rt.SetCaller(worker, builtin.AccountActorCodeID) 864 rt.ExpectVerifySignature(crypto.Signature{}, deal1.Client, mustCbor(&deal1), nil) 865 rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { 866 rt.Call(actor.PublishStorageDeals, params) 867 }) 868 869 rt.Verify() 870 actor.checkState(rt) 871 }) 872 873 t.Run("fail when provider has some funds but not enough for a deal", func(t *testing.T) { 874 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 875 876 actor.addProviderFunds(rt, abi.NewTokenAmount(1), mAddrs) 877 deal1 := generateDealProposal(client, provider, startEpoch, endEpoch) 878 actor.addParticipantFunds(rt, client, deal1.ClientBalanceRequirement()) 879 880 params := mkPublishStorageParams(deal1) 881 882 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 883 rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) 884 expectQueryNetworkInfo(rt, actor) 885 rt.SetCaller(worker, builtin.AccountActorCodeID) 886 rt.ExpectVerifySignature(crypto.Signature{}, deal1.Client, mustCbor(&deal1), nil) 887 rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { 888 rt.Call(actor.PublishStorageDeals, params) 889 }) 890 891 rt.Verify() 892 actor.checkState(rt) 893 }) 894 } 895 896 // fail when deals have different providers 897 { 898 t.Run("fail when deals have different providers", func(t *testing.T) { 899 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 900 deal1 := actor.generateDealAndAddFunds(rt, client, mAddrs, startEpoch, endEpoch) 901 m2 := &minerAddrs{owner, worker, tutil.NewIDAddr(t, 1000), nil} 902 903 deal2 := actor.generateDealAndAddFunds(rt, client, m2, abi.ChainEpoch(1), endEpoch) 904 905 params := mkPublishStorageParams(deal1, deal2) 906 907 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 908 rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) 909 expectQueryNetworkInfo(rt, actor) 910 rt.SetCaller(worker, builtin.AccountActorCodeID) 911 rt.ExpectVerifySignature(crypto.Signature{}, deal1.Client, mustCbor(&deal1), nil) 912 rt.ExpectVerifySignature(crypto.Signature{}, deal2.Client, mustCbor(&deal2), nil) 913 914 actor.expectGetRandom(rt, &deal1, abi.ChainEpoch(100)) 915 916 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 917 rt.Call(actor.PublishStorageDeals, params) 918 }) 919 920 rt.Verify() 921 actor.checkState(rt) 922 }) 923 924 // failures because of incorrect call params 925 t.Run("fail when caller is not of signable type", func(t *testing.T) { 926 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 927 params := mkPublishStorageParams(generateDealProposal(client, provider, startEpoch, endEpoch)) 928 w := tutil.NewIDAddr(t, 1000) 929 rt.SetCaller(w, builtin.StorageMinerActorCodeID) 930 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 931 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 932 rt.Call(actor.PublishStorageDeals, params) 933 }) 934 actor.checkState(rt) 935 }) 936 937 t.Run("fail when no deals in params", func(t *testing.T) { 938 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 939 params := mkPublishStorageParams() 940 rt.SetCaller(worker, builtin.AccountActorCodeID) 941 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 942 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 943 rt.Call(actor.PublishStorageDeals, params) 944 }) 945 actor.checkState(rt) 946 }) 947 948 t.Run("fail to resolve provider address", func(t *testing.T) { 949 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 950 deal := generateDealProposal(client, provider, startEpoch, endEpoch) 951 deal.Provider = tutil.NewBLSAddr(t, 100) 952 953 params := mkPublishStorageParams(deal) 954 rt.SetCaller(worker, builtin.AccountActorCodeID) 955 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 956 rt.ExpectAbort(exitcode.ErrNotFound, func() { 957 rt.Call(actor.PublishStorageDeals, params) 958 }) 959 actor.checkState(rt) 960 }) 961 962 t.Run("caller is not the same as the worker address for miner", func(t *testing.T) { 963 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 964 deal := generateDealProposal(client, provider, startEpoch, endEpoch) 965 params := mkPublishStorageParams(deal) 966 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 967 rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: tutil.NewIDAddr(t, 999), Owner: owner}, 0) 968 rt.SetCaller(worker, builtin.AccountActorCodeID) 969 rt.ExpectAbort(exitcode.ErrForbidden, func() { 970 rt.Call(actor.PublishStorageDeals, params) 971 }) 972 973 rt.Verify() 974 actor.checkState(rt) 975 }) 976 } 977 978 t.Run("fails if provider is not a storage miner actor", func(t *testing.T) { 979 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 980 981 // deal provider will be a Storage Miner Actor. 982 p2 := tutil.NewIDAddr(t, 505) 983 rt.SetAddressActorType(p2, builtin.StoragePowerActorCodeID) 984 deal := generateDealProposal(client, p2, abi.ChainEpoch(1), abi.ChainEpoch(5)) 985 986 params := mkPublishStorageParams(deal) 987 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 988 rt.SetCaller(worker, builtin.AccountActorCodeID) 989 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 990 rt.Call(actor.PublishStorageDeals, params) 991 }) 992 993 rt.Verify() 994 actor.checkState(rt) 995 }) 996 } 997 998 func TestActivateDeals(t *testing.T) { 999 1000 owner := tutil.NewIDAddr(t, 101) 1001 provider := tutil.NewIDAddr(t, 102) 1002 worker := tutil.NewIDAddr(t, 103) 1003 client := tutil.NewIDAddr(t, 104) 1004 mAddrs := &minerAddrs{owner, worker, provider, nil} 1005 1006 startEpoch := abi.ChainEpoch(10) 1007 endEpoch := startEpoch + 200*builtin.EpochsInDay 1008 currentEpoch := abi.ChainEpoch(5) 1009 sectorExpiry := endEpoch + 100 1010 1011 t.Run("active deals multiple times with different providers", func(t *testing.T) { 1012 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1013 rt.SetEpoch(currentEpoch) 1014 1015 // provider 1 publishes deals1 and deals2 and deal3 1016 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1017 dealId2 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch+1, startEpoch) 1018 dealId3 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch+2, startEpoch) 1019 1020 // provider2 publishes deal4 and deal5 1021 provider2 := tutil.NewIDAddr(t, 401) 1022 mAddrs.provider = provider2 1023 dealId4 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1024 dealId5 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch+1, startEpoch) 1025 1026 // provider1 activates deal 1 and deal2 but that does not activate deal3 to deal5 1027 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId1, dealId2) 1028 actor.assertDealsNotActivated(rt, currentEpoch, dealId3, dealId4, dealId5) 1029 1030 // provider3 activates deal5 but that does not activate deal3 or deal4 1031 actor.activateDeals(rt, sectorExpiry, provider2, currentEpoch, dealId5) 1032 actor.assertDealsNotActivated(rt, currentEpoch, dealId3, dealId4) 1033 1034 // provider1 activates deal3 1035 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId3) 1036 actor.assertDealsNotActivated(rt, currentEpoch, dealId4) 1037 1038 actor.checkState(rt) 1039 }) 1040 } 1041 1042 func TestActivateDealFailures(t *testing.T) { 1043 owner := tutil.NewIDAddr(t, 101) 1044 provider := tutil.NewIDAddr(t, 102) 1045 worker := tutil.NewIDAddr(t, 103) 1046 client := tutil.NewIDAddr(t, 104) 1047 mAddrs := &minerAddrs{owner, worker, provider, nil} 1048 1049 startEpoch := abi.ChainEpoch(10) 1050 endEpoch := startEpoch + 200*builtin.EpochsInDay 1051 sectorExpiry := endEpoch + 100 1052 1053 // caller is not the provider 1054 { 1055 t.Run("fail when caller is not the provider of the deal", func(t *testing.T) { 1056 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1057 provider2 := tutil.NewIDAddr(t, 201) 1058 mAddrs2 := &minerAddrs{owner, worker, provider2, nil} 1059 dealId := actor.generateAndPublishDeal(rt, client, mAddrs2, startEpoch, endEpoch, startEpoch) 1060 1061 params := mkActivateDealParams(sectorExpiry, dealId) 1062 1063 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1064 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 1065 rt.ExpectAbort(exitcode.ErrForbidden, func() { 1066 rt.Call(actor.ActivateDeals, params) 1067 }) 1068 1069 rt.Verify() 1070 actor.checkState(rt) 1071 }) 1072 } 1073 1074 // caller is not a StorageMinerActor 1075 { 1076 t.Run("fail when caller is not a StorageMinerActor", func(t *testing.T) { 1077 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1078 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1079 rt.SetCaller(provider, builtin.AccountActorCodeID) 1080 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 1081 rt.Call(actor.ActivateDeals, &market.ActivateDealsParams{}) 1082 }) 1083 1084 rt.Verify() 1085 actor.checkState(rt) 1086 }) 1087 } 1088 1089 // deal has not been published before 1090 { 1091 t.Run("fail when deal has not been published before", func(t *testing.T) { 1092 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1093 params := mkActivateDealParams(sectorExpiry, abi.DealID(42)) 1094 1095 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1096 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 1097 rt.ExpectAbort(exitcode.ErrNotFound, func() { 1098 rt.Call(actor.ActivateDeals, params) 1099 }) 1100 1101 rt.Verify() 1102 actor.checkState(rt) 1103 }) 1104 } 1105 1106 // deal has ALREADY been activated 1107 { 1108 t.Run("fail when deal has already been activated", func(t *testing.T) { 1109 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1110 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1111 actor.activateDeals(rt, sectorExpiry, provider, 0, dealId) 1112 1113 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1114 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 1115 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1116 rt.Call(actor.ActivateDeals, mkActivateDealParams(sectorExpiry, dealId)) 1117 }) 1118 1119 rt.Verify() 1120 actor.checkState(rt) 1121 }) 1122 } 1123 1124 // deal has invalid params 1125 { 1126 t.Run("fail when current epoch greater than start epoch of deal", func(t *testing.T) { 1127 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1128 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1129 1130 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1131 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 1132 rt.SetEpoch(startEpoch + 1) 1133 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1134 rt.Call(actor.ActivateDeals, mkActivateDealParams(sectorExpiry, dealId)) 1135 }) 1136 1137 rt.Verify() 1138 actor.checkState(rt) 1139 }) 1140 1141 t.Run("fail when end epoch of deal greater than sector expiry", func(t *testing.T) { 1142 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1143 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1144 1145 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1146 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 1147 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1148 rt.Call(actor.ActivateDeals, mkActivateDealParams(endEpoch-1, dealId)) 1149 }) 1150 1151 rt.Verify() 1152 actor.checkState(rt) 1153 }) 1154 } 1155 1156 // all fail if one fails 1157 { 1158 t.Run("fail to activate all deals if one deal fails", func(t *testing.T) { 1159 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1160 1161 // activate deal1 so it fails later 1162 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1163 actor.activateDeals(rt, sectorExpiry, provider, 0, dealId1) 1164 1165 dealId2 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch+1, startEpoch) 1166 1167 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1168 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 1169 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1170 rt.Call(actor.ActivateDeals, mkActivateDealParams(sectorExpiry, dealId1, dealId2)) 1171 }) 1172 rt.Verify() 1173 1174 // no state for deal2 means deal2 activation has failed 1175 var st market.State 1176 rt.GetState(&st) 1177 1178 states, err := market.AsDealStateArray(adt.AsStore(rt), st.States) 1179 require.NoError(t, err) 1180 1181 _, found, err := states.Get(dealId2) 1182 require.NoError(t, err) 1183 require.False(t, found) 1184 1185 actor.checkState(rt) 1186 1187 }) 1188 } 1189 1190 } 1191 1192 func TestOnMinerSectorsTerminate(t *testing.T) { 1193 owner := tutil.NewIDAddr(t, 101) 1194 provider := tutil.NewIDAddr(t, 102) 1195 worker := tutil.NewIDAddr(t, 103) 1196 client := tutil.NewIDAddr(t, 104) 1197 mAddrs := &minerAddrs{owner, worker, provider, nil} 1198 1199 startEpoch := abi.ChainEpoch(10) 1200 endEpoch := startEpoch + 200*builtin.EpochsInDay 1201 currentEpoch := abi.ChainEpoch(5) 1202 sectorExpiry := endEpoch + 100 1203 1204 t.Run("terminate multiple deals from multiple providers", func(t *testing.T) { 1205 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1206 rt.SetEpoch(currentEpoch) 1207 1208 // provider1 publishes deal1,2 and 3 1209 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1210 dealId2 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch+1, startEpoch) 1211 dealId3 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch+2, startEpoch) 1212 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId1, dealId2, dealId3) 1213 1214 // provider2 publishes deal4 and deal5 1215 provider2 := tutil.NewIDAddr(t, 501) 1216 maddrs2 := &minerAddrs{owner, worker, provider2, nil} 1217 dealId4 := actor.generateAndPublishDeal(rt, client, maddrs2, startEpoch, endEpoch, startEpoch) 1218 dealId5 := actor.generateAndPublishDeal(rt, client, maddrs2, startEpoch, endEpoch+1, startEpoch) 1219 actor.activateDeals(rt, sectorExpiry, provider2, currentEpoch, dealId4, dealId5) 1220 1221 // provider1 terminates deal1 but that does not terminate deals2-5 1222 actor.terminateDeals(rt, provider, dealId1) 1223 actor.assertDealsTerminated(rt, currentEpoch, dealId1) 1224 actor.assertDeaslNotTerminated(rt, dealId2, dealId3, dealId4, dealId5) 1225 1226 // provider2 terminates deal5 but that does not terminate delals 2-4 1227 actor.terminateDeals(rt, provider2, dealId5) 1228 actor.assertDealsTerminated(rt, currentEpoch, dealId5) 1229 actor.assertDeaslNotTerminated(rt, dealId2, dealId3, dealId4) 1230 1231 // provider1 terminates deal2 and deal3 1232 actor.terminateDeals(rt, provider, dealId2, dealId3) 1233 actor.assertDealsTerminated(rt, currentEpoch, dealId2, dealId3) 1234 actor.assertDeaslNotTerminated(rt, dealId4) 1235 1236 // provider2 terminates deal4 1237 actor.terminateDeals(rt, provider2, dealId4) 1238 actor.assertDealsTerminated(rt, currentEpoch, dealId4) 1239 1240 actor.checkState(rt) 1241 }) 1242 1243 t.Run("ignore deal proposal that does not exist", func(t *testing.T) { 1244 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1245 rt.SetEpoch(currentEpoch) 1246 1247 // deal1 will be terminated and the other deal will be ignored because it does not exist 1248 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1249 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId1) 1250 1251 actor.terminateDeals(rt, provider, dealId1, abi.DealID(42)) 1252 st := actor.getDealState(rt, dealId1) 1253 require.EqualValues(t, currentEpoch, st.SlashEpoch) 1254 1255 actor.checkState(rt) 1256 }) 1257 1258 t.Run("terminate valid deals along with expired deals - only valid deals are terminated", func(t *testing.T) { 1259 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1260 rt.SetEpoch(currentEpoch) 1261 1262 // provider1 publishes deal1 and 2 and deal3 -> deal3 has the lowest endepoch 1263 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1264 dealId2 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch+1, startEpoch) 1265 dealId3 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch-1, startEpoch) 1266 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId1, dealId2, dealId3) 1267 1268 // set current epoch such that deal3 expires but the other two do not 1269 newEpoch := endEpoch - 1 1270 rt.SetEpoch(newEpoch) 1271 1272 // terminating all three deals ONLY terminates deal1 and deal2 because deal3 has expired 1273 actor.terminateDeals(rt, provider, dealId1, dealId2, dealId3) 1274 actor.assertDealsTerminated(rt, newEpoch, dealId1, dealId2) 1275 actor.assertDeaslNotTerminated(rt, dealId3) 1276 1277 actor.checkState(rt) 1278 }) 1279 1280 t.Run("terminating a deal the second time does not change it's slash epoch", func(t *testing.T) { 1281 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1282 rt.SetEpoch(currentEpoch) 1283 1284 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1285 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId1) 1286 1287 // terminating the deal so slash epoch is the current epoch 1288 actor.terminateDeals(rt, provider, dealId1) 1289 1290 // set a new epoch and terminate again -> however slash epoch will still be the old epoch. 1291 newEpoch := currentEpoch + 1 1292 rt.SetEpoch(newEpoch) 1293 actor.terminateDeals(rt, provider, dealId1) 1294 st := actor.getDealState(rt, dealId1) 1295 require.EqualValues(t, currentEpoch, st.SlashEpoch) 1296 1297 actor.checkState(rt) 1298 }) 1299 1300 t.Run("terminating new deals and an already terminated deal only terminates the new deals", func(t *testing.T) { 1301 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1302 rt.SetEpoch(currentEpoch) 1303 1304 // provider1 publishes deal1 and 2 and deal3 -> deal3 has the lowest endepoch 1305 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1306 dealId2 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch+1, startEpoch) 1307 dealId3 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch-1, startEpoch) 1308 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId1, dealId2, dealId3) 1309 1310 // terminating the deal so slash epoch is the current epoch 1311 actor.terminateDeals(rt, provider, dealId1) 1312 1313 // set a new epoch and terminate again -> however slash epoch will still be the old epoch. 1314 newEpoch := currentEpoch + 1 1315 rt.SetEpoch(newEpoch) 1316 actor.terminateDeals(rt, provider, dealId1, dealId2, dealId3) 1317 1318 st := actor.getDealState(rt, dealId1) 1319 require.EqualValues(t, currentEpoch, st.SlashEpoch) 1320 1321 st2 := actor.getDealState(rt, dealId2) 1322 require.EqualValues(t, newEpoch, st2.SlashEpoch) 1323 1324 st3 := actor.getDealState(rt, dealId3) 1325 require.EqualValues(t, newEpoch, st3.SlashEpoch) 1326 1327 actor.checkState(rt) 1328 }) 1329 1330 t.Run("do not terminate deal if end epoch is equal to or less than current epoch", func(t *testing.T) { 1331 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1332 rt.SetEpoch(currentEpoch) 1333 1334 // deal1 has endepoch equal to current epoch when terminate is called 1335 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1336 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId1) 1337 rt.SetEpoch(endEpoch) 1338 actor.terminateDeals(rt, provider, dealId1) 1339 actor.assertDeaslNotTerminated(rt, dealId1) 1340 1341 // deal2 has end epoch less than current epoch when terminate is called 1342 rt.SetEpoch(currentEpoch) 1343 dealId2 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch+1, endEpoch, startEpoch+1) 1344 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId2) 1345 rt.SetEpoch(endEpoch + 1) 1346 actor.terminateDeals(rt, provider, dealId2) 1347 actor.assertDeaslNotTerminated(rt, dealId2) 1348 1349 actor.checkState(rt) 1350 }) 1351 1352 t.Run("fail when caller is not a StorageMinerActor", func(t *testing.T) { 1353 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1354 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1355 rt.SetCaller(provider, builtin.AccountActorCodeID) 1356 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 1357 rt.Call(actor.OnMinerSectorsTerminate, &market.OnMinerSectorsTerminateParams{}) 1358 }) 1359 1360 rt.Verify() 1361 actor.checkState(rt) 1362 1363 }) 1364 1365 t.Run("fail when caller is not the provider of the deal", func(t *testing.T) { 1366 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1367 rt.SetEpoch(currentEpoch) 1368 1369 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1370 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId) 1371 1372 params := mkTerminateDealParams(currentEpoch, dealId) 1373 1374 provider2 := tutil.NewIDAddr(t, 501) 1375 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1376 rt.SetCaller(provider2, builtin.StorageMinerActorCodeID) 1377 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalState, "caller t0501 is not the provider t0102 of deal 0", func() { 1378 rt.Call(actor.OnMinerSectorsTerminate, params) 1379 }) 1380 1381 rt.Verify() 1382 actor.checkState(rt) 1383 1384 }) 1385 1386 t.Run("fail when deal has been published but not activated", func(t *testing.T) { 1387 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1388 rt.SetEpoch(currentEpoch) 1389 1390 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1391 1392 params := mkTerminateDealParams(currentEpoch, dealId) 1393 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1394 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 1395 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1396 rt.Call(actor.OnMinerSectorsTerminate, params) 1397 }) 1398 1399 rt.Verify() 1400 actor.checkState(rt) 1401 1402 }) 1403 1404 t.Run("termination of all deals should fail when one deal fails", func(t *testing.T) { 1405 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1406 rt.SetEpoch(currentEpoch) 1407 1408 // deal1 would terminate but deal2 will fail because deal2 has not been activated 1409 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1410 actor.activateDeals(rt, sectorExpiry, provider, currentEpoch, dealId1) 1411 dealId2 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch+1, startEpoch) 1412 1413 params := mkTerminateDealParams(currentEpoch, dealId1, dealId2) 1414 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 1415 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 1416 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1417 rt.Call(actor.OnMinerSectorsTerminate, params) 1418 }) 1419 1420 rt.Verify() 1421 1422 // verify deal1 has not been terminated 1423 actor.assertDeaslNotTerminated(rt, dealId1) 1424 1425 actor.checkState(rt) 1426 }) 1427 } 1428 1429 func TestCronTick(t *testing.T) { 1430 owner := tutil.NewIDAddr(t, 101) 1431 provider := tutil.NewIDAddr(t, 102) 1432 worker := tutil.NewIDAddr(t, 103) 1433 client := tutil.NewIDAddr(t, 104) 1434 mAddrs := &minerAddrs{owner, worker, provider, nil} 1435 1436 startEpoch := abi.ChainEpoch(50) 1437 endEpoch := startEpoch + 200*builtin.EpochsInDay 1438 sectorExpiry := endEpoch + 100 1439 1440 t.Run("fail when deal is activated but proposal is not found", func(t *testing.T) { 1441 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1442 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 1443 1444 // delete the deal proposal (this breaks state invariants) 1445 actor.deleteDealProposal(rt, dealId) 1446 1447 // move the current epoch to the start epoch of the deal 1448 rt.SetEpoch(startEpoch) 1449 rt.ExpectAbort(exitcode.ErrNotFound, func() { 1450 actor.cronTick(rt) 1451 }) 1452 }) 1453 1454 t.Run("fail when deal update epoch is in the future", func(t *testing.T) { 1455 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1456 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 1457 1458 // move the current epoch such that the deal's last updated field is set to the start epoch of the deal 1459 // and the next tick for it is scheduled at the endepoch. 1460 rt.SetEpoch(startEpoch) 1461 actor.cronTick(rt) 1462 1463 // update last updated to some time in the future 1464 actor.updateLastUpdated(rt, dealId, endEpoch+1000) 1465 1466 // set current epoch of the deal to the end epoch so it's picked up for "processing" in the next cron tick. 1467 rt.SetEpoch(endEpoch) 1468 1469 rt.ExpectAbort(exitcode.ErrIllegalState, func() { 1470 actor.cronTick(rt) 1471 }) 1472 }) 1473 1474 t.Run("crontick for a deal at it's start epoch results in zero payment and no slashing", func(t *testing.T) { 1475 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1476 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 1477 1478 // move the current epoch to startEpoch 1479 current := startEpoch 1480 rt.SetEpoch(current) 1481 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 1482 require.EqualValues(t, big.Zero(), pay) 1483 require.EqualValues(t, big.Zero(), slashed) 1484 1485 // deal proposal and state should NOT be deleted 1486 require.NotNil(t, actor.getDealProposal(rt, dealId)) 1487 require.NotNil(t, actor.getDealState(rt, dealId)) 1488 1489 actor.checkState(rt) 1490 }) 1491 1492 t.Run("slash a deal and make payment for another deal in the same epoch", func(t *testing.T) { 1493 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1494 1495 dealId1 := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 1496 d1 := actor.getDealProposal(rt, dealId1) 1497 1498 dealId2 := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch+1, endEpoch+1, 0, sectorExpiry, startEpoch+1) 1499 1500 // slash deal1 1501 slashEpoch := abi.ChainEpoch(150) 1502 rt.SetEpoch(slashEpoch) 1503 actor.terminateDeals(rt, provider, dealId1) 1504 1505 // cron tick will slash deal1 and make payment for deal2 1506 current := abi.ChainEpoch(151) 1507 rt.SetEpoch(current) 1508 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, d1.ProviderCollateral, nil, exitcode.Ok) 1509 actor.cronTick(rt) 1510 1511 actor.assertDealDeleted(rt, dealId1, d1) 1512 s2 := actor.getDealState(rt, dealId2) 1513 require.EqualValues(t, current, s2.LastUpdatedEpoch) 1514 1515 actor.checkState(rt) 1516 }) 1517 1518 t.Run("cannot publish the same deal twice BEFORE a cron tick", func(t *testing.T) { 1519 // Publish a deal 1520 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1521 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1522 d1 := actor.getDealProposal(rt, dealId1) 1523 1524 // now try to publish it again and it should fail because it will still be in pending state 1525 d2 := actor.generateDealAndAddFunds(rt, client, mAddrs, startEpoch, endEpoch) 1526 params := mkPublishStorageParams(d2) 1527 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 1528 rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) 1529 expectQueryNetworkInfo(rt, actor) 1530 rt.SetCaller(worker, builtin.AccountActorCodeID) 1531 rt.ExpectVerifySignature(crypto.Signature{}, d2.Client, mustCbor(&d2), nil) 1532 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1533 rt.Call(actor.PublishStorageDeals, params) 1534 }) 1535 rt.Verify() 1536 1537 // now a cron tick happens -> deal1 is no longer pending and then publishing the same deal again should work 1538 rt.SetEpoch(d1.StartEpoch - 1) 1539 actor.activateDeals(rt, sectorExpiry, provider, d1.StartEpoch-1, dealId1) 1540 rt.SetEpoch(d1.StartEpoch) 1541 actor.cronTick(rt) 1542 rt.SetCaller(worker, builtin.AccountActorCodeID) 1543 actor.publishDeals(rt, mAddrs, publishDealReq{deal: d2}) 1544 1545 actor.checkState(rt) 1546 }) 1547 } 1548 1549 func TestRandomCronEpochDuringPublish(t *testing.T) { 1550 owner := tutil.NewIDAddr(t, 101) 1551 provider := tutil.NewIDAddr(t, 102) 1552 worker := tutil.NewIDAddr(t, 103) 1553 client := tutil.NewIDAddr(t, 104) 1554 mAddrs := &minerAddrs{owner, worker, provider, nil} 1555 1556 startEpoch := abi.ChainEpoch(50) 1557 endEpoch := startEpoch + 200*builtin.EpochsInDay 1558 sectorExpiry := endEpoch + 1 1559 1560 t.Run("a random epoch in chosen as the cron processing epoch for a deal during publishing", func(t *testing.T) { 1561 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1562 processEpoch := startEpoch + 5 1563 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, processEpoch) 1564 d := actor.getDealProposal(rt, dealId) 1565 1566 // activate the deal 1567 rt.SetEpoch(startEpoch - 1) 1568 actor.activateDeals(rt, sectorExpiry, provider, d.StartEpoch-1, dealId) 1569 1570 // cron tick at deal start epoch does not do anything 1571 rt.SetEpoch(startEpoch) 1572 actor.cronTickNoChange(rt, client, provider) 1573 1574 // first cron tick at process epoch will make payment and schedule the deal for next epoch 1575 rt.SetEpoch(processEpoch) 1576 pay, _ := actor.cronTickAndAssertBalances(rt, client, provider, processEpoch, dealId) 1577 duration := big.Sub(big.NewInt(int64(processEpoch)), big.NewInt(int64(startEpoch))) 1578 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 1579 1580 // payment at next epoch 1581 current := processEpoch + market.DealUpdatesInterval 1582 rt.SetEpoch(current) 1583 pay, _ = actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 1584 duration = big.Sub(big.NewInt(int64(current)), big.NewInt(int64(processEpoch))) 1585 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 1586 1587 actor.checkState(rt) 1588 }) 1589 1590 t.Run("deals are scheduled for expiry later than the end epoch", func(t *testing.T) { 1591 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1592 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1593 d := actor.getDealProposal(rt, dealId) 1594 1595 rt.SetEpoch(startEpoch - 1) 1596 actor.activateDeals(rt, sectorExpiry, provider, d.StartEpoch-1, dealId) 1597 1598 // a cron tick at end epoch -1 schedules the deal for later than end epoch 1599 curr := endEpoch - 1 1600 rt.SetEpoch(curr) 1601 duration := big.NewInt(int64(curr - startEpoch)) 1602 pay, _ := actor.cronTickAndAssertBalances(rt, client, provider, curr, dealId) 1603 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 1604 1605 // cron tick at end epoch does NOT expire the deal 1606 rt.SetEpoch(endEpoch) 1607 actor.cronTickNoChange(rt, client, provider) 1608 require.NotNil(t, actor.getDealProposal(rt, dealId)) 1609 1610 // cron tick at nextEpoch expires the deal -> payment is ONLY for one epoch 1611 curr = curr + market.DealUpdatesInterval 1612 rt.SetEpoch(curr) 1613 pay, _ = actor.cronTickAndAssertBalances(rt, client, provider, curr, dealId) 1614 require.EqualValues(t, d.StoragePricePerEpoch, pay) 1615 actor.assertDealDeleted(rt, dealId, d) 1616 1617 actor.checkState(rt) 1618 }) 1619 1620 t.Run("deal is processed after it's end epoch -> should expire correctly", func(t *testing.T) { 1621 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1622 processEpoch := endEpoch + 100 1623 1624 activationEpoch := startEpoch - 1 1625 rt.SetEpoch(activationEpoch) 1626 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, activationEpoch, sectorExpiry, processEpoch) 1627 d := actor.getDealProposal(rt, dealId) 1628 1629 rt.SetEpoch(processEpoch) 1630 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, processEpoch, dealId) 1631 require.EqualValues(t, big.Zero(), slashed) 1632 duration := big.Sub(big.NewInt(int64(endEpoch)), big.NewInt(int64(startEpoch))) 1633 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 1634 1635 actor.assertDealDeleted(rt, dealId, d) 1636 1637 actor.checkState(rt) 1638 }) 1639 1640 t.Run("activation after deal start epoch but before it is processed fails", func(t *testing.T) { 1641 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1642 processEpoch := startEpoch + 5 1643 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, processEpoch) 1644 1645 // activate the deal after the start epoch 1646 rt.SetEpoch(startEpoch + 1) 1647 1648 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1649 actor.activateDeals(rt, sectorExpiry, provider, startEpoch+1, dealId) 1650 }) 1651 1652 actor.checkState(rt) 1653 }) 1654 1655 t.Run("cron processing of deal after missed activation should fail and slash", func(t *testing.T) { 1656 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1657 processEpoch := startEpoch + 5 1658 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, processEpoch) 1659 d := actor.getDealProposal(rt, dealId) 1660 1661 rt.SetEpoch(processEpoch) 1662 1663 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, d.ProviderCollateral, nil, exitcode.Ok) 1664 actor.cronTick(rt) 1665 1666 actor.assertDealDeleted(rt, dealId, d) 1667 1668 actor.checkState(rt) 1669 }) 1670 1671 } 1672 1673 func TestLockedFundTrackingStates(t *testing.T) { 1674 t.Parallel() 1675 owner := tutil.NewIDAddr(t, 101) 1676 worker := tutil.NewIDAddr(t, 103) 1677 1678 p1 := tutil.NewIDAddr(t, 201) 1679 p2 := tutil.NewIDAddr(t, 202) 1680 p3 := tutil.NewIDAddr(t, 203) 1681 1682 c1 := tutil.NewIDAddr(t, 104) 1683 c2 := tutil.NewIDAddr(t, 105) 1684 c3 := tutil.NewIDAddr(t, 106) 1685 1686 m1 := &minerAddrs{owner, worker, p1, nil} 1687 m2 := &minerAddrs{owner, worker, p2, nil} 1688 m3 := &minerAddrs{owner, worker, p3, nil} 1689 1690 startEpoch := abi.ChainEpoch(50) 1691 endEpoch := startEpoch + 200*builtin.EpochsInDay 1692 sectorExpiry := endEpoch + 400 1693 1694 var st market.State 1695 1696 // assert values are zero 1697 rt, actor := basicMarketSetup(t, owner, p1, worker, c1) 1698 rt.GetState(&st) 1699 require.True(t, st.TotalClientLockedCollateral.IsZero()) 1700 require.True(t, st.TotalProviderLockedCollateral.IsZero()) 1701 require.True(t, st.TotalClientStorageFee.IsZero()) 1702 1703 // Publish deal1, deal2 and deal3 with different client and provider 1704 dealId1 := actor.generateAndPublishDeal(rt, c1, m1, startEpoch, endEpoch, startEpoch) 1705 d1 := actor.getDealProposal(rt, dealId1) 1706 1707 dealId2 := actor.generateAndPublishDeal(rt, c2, m2, startEpoch, endEpoch, startEpoch) 1708 d2 := actor.getDealProposal(rt, dealId2) 1709 1710 dealId3 := actor.generateAndPublishDeal(rt, c3, m3, startEpoch, endEpoch, startEpoch) 1711 d3 := actor.getDealProposal(rt, dealId3) 1712 1713 csf := big.Sum(d1.TotalStorageFee(), d2.TotalStorageFee(), d3.TotalStorageFee()) 1714 plc := big.Sum(d1.ProviderCollateral, d2.ProviderCollateral, d3.ProviderCollateral) 1715 clc := big.Sum(d1.ClientCollateral, d2.ClientCollateral, d3.ClientCollateral) 1716 1717 actor.assertLockedFundStates(rt, csf, plc, clc) 1718 1719 // activation dosen't change anything 1720 curr := startEpoch - 1 1721 rt.SetEpoch(curr) 1722 actor.activateDeals(rt, sectorExpiry, p1, curr, dealId1) 1723 actor.activateDeals(rt, sectorExpiry, p2, curr, dealId2) 1724 1725 actor.assertLockedFundStates(rt, csf, plc, clc) 1726 1727 // make payment for p1 and p2, p3 times out as it has not been activated 1728 curr = 51 // startEpoch + 1 1729 rt.SetEpoch(curr) 1730 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, d3.ProviderCollateral, nil, exitcode.Ok) 1731 actor.cronTick(rt) 1732 payment := big.Product(big.NewInt(2), d1.StoragePricePerEpoch) 1733 csf = big.Sub(big.Sub(csf, payment), d3.TotalStorageFee()) 1734 plc = big.Sub(plc, d3.ProviderCollateral) 1735 clc = big.Sub(clc, d3.ClientCollateral) 1736 actor.assertLockedFundStates(rt, csf, plc, clc) 1737 1738 // deal1 and deal2 will now be charged at epoch curr + market.DealUpdatesInterval, so nothing changes before that. 1739 rt.SetEpoch(curr + market.DealUpdatesInterval - 1) 1740 actor.cronTick(rt) 1741 actor.assertLockedFundStates(rt, csf, plc, clc) 1742 1743 // one more round of payment for deal1 and deal2 1744 curr2 := curr + market.DealUpdatesInterval 1745 rt.SetEpoch(curr2) 1746 duration := big.NewInt(int64(curr2 - curr)) 1747 payment = big.Product(big.NewInt(2), d1.StoragePricePerEpoch, duration) 1748 csf = big.Sub(csf, payment) 1749 actor.cronTick(rt) 1750 actor.assertLockedFundStates(rt, csf, plc, clc) 1751 1752 // slash deal1 at 201 1753 slashEpoch := curr2 + 1 1754 rt.SetEpoch(slashEpoch) 1755 actor.terminateDeals(rt, m1.provider, dealId1) 1756 1757 // cron tick to slash deal1 and expire deal2 1758 rt.SetEpoch(endEpoch) 1759 csf = big.Zero() 1760 clc = big.Zero() 1761 plc = big.Zero() 1762 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, d1.ProviderCollateral, nil, exitcode.Ok) 1763 actor.cronTick(rt) 1764 actor.assertLockedFundStates(rt, csf, plc, clc) 1765 1766 actor.checkState(rt) 1767 } 1768 1769 func TestCronTickTimedoutDeals(t *testing.T) { 1770 owner := tutil.NewIDAddr(t, 101) 1771 provider := tutil.NewIDAddr(t, 102) 1772 worker := tutil.NewIDAddr(t, 103) 1773 client := tutil.NewIDAddr(t, 104) 1774 mAddrs := &minerAddrs{owner, worker, provider, nil} 1775 1776 startEpoch := abi.ChainEpoch(50) 1777 endEpoch := startEpoch + 200*builtin.EpochsInDay 1778 1779 t.Run("timed out deal is slashed and deleted", func(t *testing.T) { 1780 // publish a deal but do NOT activate it 1781 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1782 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1783 d := actor.getDealProposal(rt, dealId) 1784 1785 cEscrow := actor.getEscrowBalance(rt, client) 1786 1787 // do a cron tick for it -> should time out and get slashed 1788 rt.SetEpoch(startEpoch) 1789 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, d.ProviderCollateral, nil, exitcode.Ok) 1790 actor.cronTick(rt) 1791 1792 require.Equal(t, cEscrow, actor.getEscrowBalance(rt, client)) 1793 require.Equal(t, big.Zero(), actor.getLockedBalance(rt, client)) 1794 1795 actor.assertAccountZero(rt, provider) 1796 1797 actor.assertDealDeleted(rt, dealId, d) 1798 1799 actor.checkState(rt) 1800 }) 1801 1802 t.Run("publishing timed out deal again should work after cron tick as it should no longer be pending", func(t *testing.T) { 1803 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1804 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1805 d := actor.getDealProposal(rt, dealId) 1806 1807 // publishing will fail as it will be in pending 1808 d2 := actor.generateDealAndAddFunds(rt, client, mAddrs, startEpoch, endEpoch) 1809 params := mkPublishStorageParams(d2) 1810 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 1811 rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) 1812 expectQueryNetworkInfo(rt, actor) 1813 rt.SetCaller(worker, builtin.AccountActorCodeID) 1814 rt.ExpectVerifySignature(crypto.Signature{}, d2.Client, mustCbor(&d2), nil) 1815 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1816 rt.Call(actor.PublishStorageDeals, params) 1817 }) 1818 rt.Verify() 1819 1820 // do a cron tick for it -> should time out and get slashed 1821 rt.SetEpoch(startEpoch) 1822 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, d.ProviderCollateral, nil, exitcode.Ok) 1823 actor.cronTick(rt) 1824 actor.assertDealDeleted(rt, dealId, d) 1825 1826 // now publishing should work 1827 actor.generateAndPublishDeal(rt, client, mAddrs, startEpoch, endEpoch, startEpoch) 1828 1829 actor.checkState(rt) 1830 }) 1831 1832 t.Run("timed out and verified deals are slashed, deleted AND sent to the Registry actor", func(t *testing.T) { 1833 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1834 // deal1 and deal2 are verified 1835 deal1 := actor.generateDealAndAddFunds(rt, client, mAddrs, startEpoch, endEpoch) 1836 deal1.VerifiedDeal = true 1837 deal2 := actor.generateDealAndAddFunds(rt, client, mAddrs, startEpoch, endEpoch+1) 1838 deal2.VerifiedDeal = true 1839 1840 // deal3 is NOT verified 1841 deal3 := actor.generateDealAndAddFunds(rt, client, mAddrs, startEpoch, endEpoch+2) 1842 1843 // publishing verified deals 1844 rt.SetCaller(worker, builtin.AccountActorCodeID) 1845 dealIds := actor.publishDeals(rt, mAddrs, publishDealReq{deal1, startEpoch}, 1846 publishDealReq{deal2, startEpoch}, publishDealReq{deal3, startEpoch}) 1847 1848 // do a cron tick for it -> all should time out and get slashed 1849 // ONLY deal1 and deal2 should be sent to the Registry actor 1850 rt.SetEpoch(startEpoch) 1851 1852 // expected sends to the registry actor 1853 param1 := &verifreg.RestoreBytesParams{ 1854 Address: deal1.Client, 1855 DealSize: big.NewIntUnsigned(uint64(deal1.PieceSize)), 1856 } 1857 param2 := &verifreg.RestoreBytesParams{ 1858 Address: deal2.Client, 1859 DealSize: big.NewIntUnsigned(uint64(deal2.PieceSize)), 1860 } 1861 1862 rt.ExpectSend(builtin.VerifiedRegistryActorAddr, builtin.MethodsVerifiedRegistry.RestoreBytes, param1, 1863 abi.NewTokenAmount(0), nil, exitcode.Ok) 1864 rt.ExpectSend(builtin.VerifiedRegistryActorAddr, builtin.MethodsVerifiedRegistry.RestoreBytes, param2, 1865 abi.NewTokenAmount(0), nil, exitcode.Ok) 1866 1867 expectedBurn := big.Mul(big.NewInt(3), deal1.ProviderCollateral) 1868 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, expectedBurn, nil, exitcode.Ok) 1869 actor.cronTick(rt) 1870 1871 // a second cron tick for the same epoch should not change anything 1872 actor.cronTickNoChange(rt, client, provider) 1873 1874 actor.assertAccountZero(rt, provider) 1875 actor.assertDealDeleted(rt, dealIds[0], &deal1) 1876 actor.assertDealDeleted(rt, dealIds[1], &deal2) 1877 actor.assertDealDeleted(rt, dealIds[2], &deal3) 1878 1879 actor.checkState(rt) 1880 }) 1881 } 1882 1883 func TestCronTickDealExpiry(t *testing.T) { 1884 owner := tutil.NewIDAddr(t, 101) 1885 provider := tutil.NewIDAddr(t, 102) 1886 worker := tutil.NewIDAddr(t, 103) 1887 client := tutil.NewIDAddr(t, 104) 1888 mAddrs := &minerAddrs{owner, worker, provider, nil} 1889 1890 startEpoch := abi.ChainEpoch(50) 1891 endEpoch := startEpoch + 200*builtin.EpochsInDay 1892 sectorExpiry := endEpoch + 400 1893 1894 t.Run("deal expiry -> deal is correctly processed twice in the same crontick", func(t *testing.T) { 1895 t.Parallel() 1896 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1897 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 1898 d := actor.getDealProposal(rt, dealId) 1899 1900 // move the current epoch to startEpoch and scheduled next epoch at endepoch -1 1901 current := startEpoch 1902 rt.SetEpoch(current) 1903 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 1904 require.EqualValues(t, big.Zero(), pay) 1905 require.EqualValues(t, big.Zero(), slashed) 1906 // assert deal exists 1907 actor.getDealProposal(rt, dealId) 1908 1909 // move the epoch to endEpoch+5(anything greater than endEpoch), so deal is first processed at endEpoch - 1 AND then at it's end epoch 1910 // total payment = (end - start) 1911 current = endEpoch + 5 1912 rt.SetEpoch(current) 1913 pay, slashed = actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 1914 duration := big.NewInt(int64(endEpoch - startEpoch)) 1915 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 1916 require.EqualValues(t, big.Zero(), slashed) 1917 1918 // deal should be deleted as it should have expired 1919 actor.assertDealDeleted(rt, dealId, d) 1920 1921 actor.checkState(rt) 1922 }) 1923 1924 t.Run("deal expiry -> regular payments till deal expires and then locked funds are unlocked", func(t *testing.T) { 1925 t.Parallel() 1926 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1927 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 1928 d := actor.getDealProposal(rt, dealId) 1929 1930 // move the current epoch to startEpoch + 5 so payment is made 1931 current := startEpoch + 5 // 55 1932 rt.SetEpoch(current) 1933 // assert payment 1934 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 1935 require.EqualValues(t, pay, big.Mul(big.NewInt(5), d.StoragePricePerEpoch)) 1936 require.EqualValues(t, big.Zero(), slashed) 1937 1938 // Setting the current epoch to anything less than next schedule wont make any payment 1939 rt.SetEpoch(current + market.DealUpdatesInterval - 1) 1940 actor.cronTickNoChange(rt, client, provider) 1941 1942 // however setting the current epoch to next schedle will make the payment 1943 current2 := current + market.DealUpdatesInterval 1944 rt.SetEpoch(current2) 1945 duration := big.NewInt(int64(current2 - current)) 1946 pay, slashed = actor.cronTickAndAssertBalances(rt, client, provider, current2, dealId) 1947 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 1948 require.EqualValues(t, big.Zero(), slashed) 1949 1950 // a second cron tick for the same epoch should not change anything 1951 actor.cronTickNoChange(rt, client, provider) 1952 1953 // next epoch schedule 1954 current3 := current2 + market.DealUpdatesInterval 1955 rt.SetEpoch(current3) 1956 duration = big.NewInt(int64(current3 - current2)) 1957 pay, slashed = actor.cronTickAndAssertBalances(rt, client, provider, current3, dealId) 1958 require.EqualValues(t, pay, big.Mul(duration, d.StoragePricePerEpoch)) 1959 require.EqualValues(t, big.Zero(), slashed) 1960 1961 // setting epoch to greater than end will expire the deal, make the payment and unlock all funds 1962 current4 := endEpoch + 300 1963 rt.SetEpoch(current4) 1964 pay, slashed = actor.cronTickAndAssertBalances(rt, client, provider, current4, dealId) 1965 duration = big.NewInt(int64(endEpoch - current3)) 1966 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 1967 require.EqualValues(t, big.Zero(), slashed) 1968 1969 // deal should be deleted as it should have expired 1970 actor.assertDealDeleted(rt, dealId, d) 1971 1972 actor.checkState(rt) 1973 }) 1974 1975 t.Run("deal expiry -> payment for a deal if deal is already expired before a cron tick", func(t *testing.T) { 1976 t.Parallel() 1977 start := abi.ChainEpoch(5) 1978 end := start + 200*builtin.EpochsInDay 1979 1980 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 1981 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, start, end, 0, sectorExpiry, startEpoch) 1982 d := actor.getDealProposal(rt, dealId) 1983 1984 current := end + 25 1985 rt.SetEpoch(current) 1986 1987 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 1988 require.EqualValues(t, pay, big.Mul(big.NewInt(int64(end-start)), d.StoragePricePerEpoch)) 1989 require.EqualValues(t, big.Zero(), slashed) 1990 1991 actor.assertDealDeleted(rt, dealId, d) 1992 1993 // running cron tick again doesn't do anything 1994 actor.cronTickNoChange(rt, client, provider) 1995 1996 actor.checkState(rt) 1997 }) 1998 1999 t.Run("expired deal should unlock the remaining client and provider locked balance after payment and deal should be deleted", func(t *testing.T) { 2000 t.Parallel() 2001 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2002 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 2003 deal := actor.getDealProposal(rt, dealId) 2004 2005 cEscrow := actor.getEscrowBalance(rt, client) 2006 pEscrow := actor.getEscrowBalance(rt, provider) 2007 2008 // move the current epoch so that deal is expired 2009 rt.SetEpoch(endEpoch + 1000) 2010 actor.cronTick(rt) 2011 2012 // assert balances 2013 payment := deal.TotalStorageFee() 2014 2015 require.EqualValues(t, big.Sub(cEscrow, payment), actor.getEscrowBalance(rt, client)) 2016 require.EqualValues(t, big.Zero(), actor.getLockedBalance(rt, client)) 2017 2018 require.EqualValues(t, big.Add(pEscrow, payment), actor.getEscrowBalance(rt, provider)) 2019 require.EqualValues(t, big.Zero(), actor.getLockedBalance(rt, provider)) 2020 2021 // deal should be deleted 2022 actor.assertDealDeleted(rt, dealId, deal) 2023 2024 actor.checkState(rt) 2025 }) 2026 2027 t.Run("all payments are made for a deal -> deal expires -> client withdraws collateral and client account is removed", func(t *testing.T) { 2028 t.Parallel() 2029 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2030 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 2031 deal := actor.getDealProposal(rt, dealId) 2032 2033 // move the current epoch so that deal is expired 2034 rt.SetEpoch(endEpoch + 100) 2035 actor.cronTick(rt) 2036 require.EqualValues(t, deal.ClientCollateral, actor.getEscrowBalance(rt, client)) 2037 2038 // client withdraws collateral -> account should be removed as it now has zero balance 2039 actor.withdrawClientBalance(rt, client, deal.ClientCollateral, deal.ClientCollateral) 2040 actor.assertAccountZero(rt, client) 2041 2042 actor.checkState(rt) 2043 }) 2044 } 2045 2046 func TestCronTickDealSlashing(t *testing.T) { 2047 owner := tutil.NewIDAddr(t, 101) 2048 provider := tutil.NewIDAddr(t, 102) 2049 worker := tutil.NewIDAddr(t, 103) 2050 client := tutil.NewIDAddr(t, 104) 2051 mAddrs := &minerAddrs{owner, worker, provider, nil} 2052 sectorExpiry := abi.ChainEpoch(400 + 200*builtin.EpochsInDay) 2053 2054 // hairy edge cases 2055 { 2056 2057 tcs := map[string]struct { 2058 dealStart abi.ChainEpoch 2059 dealEnd abi.ChainEpoch 2060 activationEpoch abi.ChainEpoch 2061 terminationEpoch abi.ChainEpoch 2062 cronTickEpoch abi.ChainEpoch 2063 payment abi.TokenAmount 2064 }{ 2065 "deal is slashed after the startepoch and then the first crontick happens": { 2066 dealStart: abi.ChainEpoch(10), 2067 dealEnd: abi.ChainEpoch(10 + 200*builtin.EpochsInDay), 2068 activationEpoch: abi.ChainEpoch(5), 2069 terminationEpoch: abi.ChainEpoch(15), 2070 cronTickEpoch: abi.ChainEpoch(16), 2071 payment: abi.NewTokenAmount(50), // (15 - 10) * 10 as deal storage fee is 10 per epoch 2072 }, 2073 "deal is slashed at the startepoch and then the first crontick happens": { 2074 dealStart: abi.ChainEpoch(10), 2075 dealEnd: abi.ChainEpoch(10 + 200*builtin.EpochsInDay), 2076 activationEpoch: abi.ChainEpoch(5), 2077 terminationEpoch: abi.ChainEpoch(10), 2078 cronTickEpoch: abi.ChainEpoch(11), 2079 payment: abi.NewTokenAmount(0), // (10 - 10) * 10 2080 }, 2081 "deal is slashed before the startepoch and then the first crontick happens": { 2082 dealStart: abi.ChainEpoch(10), 2083 dealEnd: abi.ChainEpoch(10 + 200*builtin.EpochsInDay), 2084 activationEpoch: abi.ChainEpoch(5), 2085 terminationEpoch: abi.ChainEpoch(6), 2086 cronTickEpoch: abi.ChainEpoch(10), 2087 payment: abi.NewTokenAmount(0), // (10 - 10) * 10 2088 }, 2089 "deal is terminated at the activation epoch and then the first crontick happens": { 2090 dealStart: abi.ChainEpoch(10), 2091 dealEnd: abi.ChainEpoch(10 + 200*builtin.EpochsInDay), 2092 activationEpoch: abi.ChainEpoch(5), 2093 terminationEpoch: abi.ChainEpoch(5), 2094 cronTickEpoch: abi.ChainEpoch(10), 2095 payment: abi.NewTokenAmount(0), // (10 - 10) * 10 2096 }, 2097 "deal is slashed and then deal expiry happens on crontick, but slashing still occurs": { 2098 dealStart: abi.ChainEpoch(10), 2099 dealEnd: abi.ChainEpoch(10 + 200*builtin.EpochsInDay), 2100 activationEpoch: abi.ChainEpoch(5), 2101 terminationEpoch: abi.ChainEpoch(15), 2102 cronTickEpoch: abi.ChainEpoch(25), // deal has expired 2103 payment: abi.NewTokenAmount(50), 2104 }, 2105 "deal is slashed just BEFORE the end epoch": { 2106 dealStart: abi.ChainEpoch(10), 2107 dealEnd: abi.ChainEpoch(10 + 200*builtin.EpochsInDay), 2108 activationEpoch: abi.ChainEpoch(5), 2109 terminationEpoch: abi.ChainEpoch(19), 2110 cronTickEpoch: abi.ChainEpoch(19), 2111 payment: abi.NewTokenAmount(90), // (19 - 10) * 10 2112 }, 2113 } 2114 2115 for n, tc := range tcs { 2116 t.Run(n, func(t *testing.T) { 2117 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2118 2119 // publish and activate 2120 rt.SetEpoch(tc.activationEpoch) 2121 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, tc.dealStart, tc.dealEnd, tc.activationEpoch, sectorExpiry, tc.dealStart) 2122 d := actor.getDealProposal(rt, dealId) 2123 2124 // terminate 2125 rt.SetEpoch(tc.terminationEpoch) 2126 actor.terminateDeals(rt, provider, dealId) 2127 2128 // cron tick 2129 rt.SetEpoch(tc.cronTickEpoch) 2130 2131 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, tc.cronTickEpoch, dealId) 2132 require.EqualValues(t, tc.payment, pay) 2133 require.EqualValues(t, d.ProviderCollateral, slashed) 2134 actor.assertDealDeleted(rt, dealId, d) 2135 2136 // if there has been no payment, provider will have zero balance and hence should be slashed 2137 if tc.payment.Equals(big.Zero()) { 2138 actor.assertAccountZero(rt, provider) 2139 // client balances should not change 2140 cLocked := actor.getLockedBalance(rt, client) 2141 cEscrow := actor.getEscrowBalance(rt, client) 2142 actor.cronTick(rt) 2143 require.EqualValues(t, cEscrow, actor.getEscrowBalance(rt, client)) 2144 require.EqualValues(t, cLocked, actor.getLockedBalance(rt, client)) 2145 } else { 2146 // running cron tick again dosen't do anything 2147 actor.cronTickNoChange(rt, client, provider) 2148 } 2149 actor.checkState(rt) 2150 }) 2151 } 2152 } 2153 2154 startEpoch := abi.ChainEpoch(50) 2155 endEpoch := abi.ChainEpoch(50 + 200*builtin.EpochsInDay) 2156 2157 t.Run("deal is slashed AT the end epoch -> should NOT be slashed and should be considered expired", func(t *testing.T) { 2158 t.Parallel() 2159 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2160 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 2161 d := actor.getDealProposal(rt, dealId) 2162 2163 // set current epoch to deal end epoch and attempt to slash it -> should not be slashed 2164 // as deal is considered to be expired. 2165 current := endEpoch 2166 rt.SetEpoch(current) 2167 actor.terminateDeals(rt, provider, dealId) 2168 2169 // on the next cron tick, it will be processed as expired 2170 current = endEpoch + 300 2171 rt.SetEpoch(current) 2172 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 2173 duration := big.NewInt(int64(endEpoch - startEpoch)) // end - start 2174 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 2175 require.EqualValues(t, big.Zero(), slashed) 2176 2177 // deal should be deleted as it should have expired 2178 actor.assertDealDeleted(rt, dealId, d) 2179 2180 actor.checkState(rt) 2181 }) 2182 2183 t.Run("deal is correctly processed twice in the same crontick and slashed", func(t *testing.T) { 2184 t.Parallel() 2185 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2186 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 2187 d := actor.getDealProposal(rt, dealId) 2188 2189 // move the current epoch to startEpoch so next cron epoch will be start + Interval 2190 current := startEpoch 2191 rt.SetEpoch(current) 2192 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 2193 require.EqualValues(t, big.Zero(), pay) 2194 require.EqualValues(t, big.Zero(), slashed) 2195 2196 // set slash epoch of deal 2197 slashEpoch := current + market.DealUpdatesInterval + 1 2198 rt.SetEpoch(slashEpoch) 2199 actor.terminateDeals(rt, provider, dealId) 2200 2201 current2 := current + market.DealUpdatesInterval + 2 2202 rt.SetEpoch(current2) 2203 duration := big.NewInt(int64(slashEpoch - current)) 2204 pay, slashed = actor.cronTickAndAssertBalances(rt, client, provider, current2, dealId) 2205 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 2206 require.EqualValues(t, d.ProviderCollateral, slashed) 2207 2208 // deal should be deleted as it should have expired 2209 actor.assertDealDeleted(rt, dealId, d) 2210 2211 actor.checkState(rt) 2212 }) 2213 2214 // end-end tests for slashing 2215 t.Run("slash multiple deals in the same epoch", func(t *testing.T) { 2216 t.Parallel() 2217 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2218 2219 // three deals for slashing 2220 dealId1 := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 2221 d1 := actor.getDealProposal(rt, dealId1) 2222 2223 dealId2 := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch+1, 0, sectorExpiry, startEpoch) 2224 d2 := actor.getDealProposal(rt, dealId2) 2225 2226 dealId3 := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch+2, 0, sectorExpiry, startEpoch) 2227 d3 := actor.getDealProposal(rt, dealId3) 2228 2229 // set slash epoch of deal at 151 2230 current := abi.ChainEpoch(151) 2231 rt.SetEpoch(current) 2232 actor.terminateDeals(rt, provider, dealId1, dealId2, dealId3) 2233 2234 // process slashing of deals 2235 current = 300 2236 rt.SetEpoch(current) 2237 totalSlashed := big.Sum(d1.ProviderCollateral, d2.ProviderCollateral, d3.ProviderCollateral) 2238 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, totalSlashed, nil, exitcode.Ok) 2239 2240 actor.cronTick(rt) 2241 2242 actor.assertDealDeleted(rt, dealId1, d1) 2243 actor.assertDealDeleted(rt, dealId2, d2) 2244 actor.assertDealDeleted(rt, dealId3, d3) 2245 2246 actor.checkState(rt) 2247 }) 2248 2249 t.Run("regular payments till deal is slashed and then slashing is processed", func(t *testing.T) { 2250 t.Parallel() 2251 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2252 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 2253 d := actor.getDealProposal(rt, dealId) 2254 2255 // move the current epoch to startEpoch + 5 so payment is made 2256 current := startEpoch + 5 2257 rt.SetEpoch(current) 2258 // assert payment 2259 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 2260 require.EqualValues(t, pay, big.Mul(big.NewInt(5), d.StoragePricePerEpoch)) 2261 require.EqualValues(t, big.Zero(), slashed) 2262 2263 // Setting the current epoch to before the next schedule will NOT make any changes as the deal 2264 // is still not scheduled 2265 current2 := current + market.DealUpdatesInterval - 1 2266 rt.SetEpoch(current2) 2267 actor.cronTickNoChange(rt, client, provider) 2268 2269 // a second cron tick for the same epoch should not change anything 2270 actor.cronTickNoChange(rt, client, provider) 2271 2272 // make another payment 2273 current3 := current2 + 1 2274 rt.SetEpoch(current3) 2275 duration := big.NewInt(int64(current3 - current)) 2276 pay, slashed = actor.cronTickAndAssertBalances(rt, client, provider, current3, dealId) 2277 require.EqualValues(t, pay, big.Mul(duration, d.StoragePricePerEpoch)) 2278 require.EqualValues(t, big.Zero(), slashed) 2279 2280 // a second cron tick for the same epoch should not change anything 2281 actor.cronTickNoChange(rt, client, provider) 2282 2283 // now terminate the deal 2284 slashEpoch := current3 + 1 2285 rt.SetEpoch(slashEpoch) 2286 actor.terminateDeals(rt, provider, dealId) 2287 2288 // Setting the epoch to anything less than next schedule will not make any change even though the deal is slashed 2289 current4 := current3 + market.DealUpdatesInterval - 1 2290 rt.SetEpoch(current4) 2291 actor.cronTickNoChange(rt, client, provider) 2292 2293 // next epoch for cron schedule -> payment will be made and deal will be slashed 2294 current5 := current4 + 1 2295 rt.SetEpoch(current5) 2296 duration = big.NewInt(int64(slashEpoch - current3)) 2297 pay, slashed = actor.cronTickAndAssertBalances(rt, client, provider, current5, dealId) 2298 require.EqualValues(t, pay, big.Mul(duration, d.StoragePricePerEpoch)) 2299 require.EqualValues(t, d.ProviderCollateral, slashed) 2300 2301 // deal should be deleted as it should have expired 2302 actor.assertDealDeleted(rt, dealId, d) 2303 2304 actor.checkState(rt) 2305 }) 2306 2307 // expired deals should NOT be slashed 2308 t.Run("regular payments till deal expires and then we attempt to slash it but it will NOT be slashed", func(t *testing.T) { 2309 t.Parallel() 2310 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2311 dealId := actor.publishAndActivateDeal(rt, client, mAddrs, startEpoch, endEpoch, 0, sectorExpiry, startEpoch) 2312 d := actor.getDealProposal(rt, dealId) 2313 2314 // move the current epoch to startEpoch + 5 so payment is made and assert payment 2315 current := startEpoch + 5 // 55 2316 rt.SetEpoch(current) 2317 pay, slashed := actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 2318 require.EqualValues(t, pay, big.Mul(big.NewInt(5), d.StoragePricePerEpoch)) 2319 require.EqualValues(t, big.Zero(), slashed) 2320 2321 // Setting the current epoch to 155 will make another payment 2322 current2 := current + market.DealUpdatesInterval 2323 rt.SetEpoch(current2) 2324 duration := big.NewInt(int64(current2 - current)) 2325 pay, slashed = actor.cronTickAndAssertBalances(rt, client, provider, current2, dealId) 2326 require.EqualValues(t, pay, big.Mul(duration, d.StoragePricePerEpoch)) 2327 require.EqualValues(t, big.Zero(), slashed) 2328 2329 // set current epoch to deal end epoch and attempt to slash it -> should not be slashed 2330 // as deal is considered to be expired. 2331 rt.SetEpoch(endEpoch) 2332 actor.terminateDeals(rt, provider, dealId) 2333 2334 // next epoch for cron schedule is endEpoch + 300 -> 2335 // setting epoch to higher than that will cause deal to be expired, payment will be made 2336 // and deal will NOT be slashed 2337 current = endEpoch + 300 2338 rt.SetEpoch(current) 2339 pay, slashed = actor.cronTickAndAssertBalances(rt, client, provider, current, dealId) 2340 duration = big.NewInt(int64(endEpoch - current2)) 2341 require.EqualValues(t, big.Mul(duration, d.StoragePricePerEpoch), pay) 2342 require.EqualValues(t, big.Zero(), slashed) 2343 2344 // deal should be deleted as it should have expired 2345 actor.assertDealDeleted(rt, dealId, d) 2346 2347 actor.checkState(rt) 2348 }) 2349 } 2350 2351 func TestMarketActorDeals(t *testing.T) { 2352 owner := tutil.NewIDAddr(t, 101) 2353 provider := tutil.NewIDAddr(t, 102) 2354 worker := tutil.NewIDAddr(t, 103) 2355 client := tutil.NewIDAddr(t, 104) 2356 minerAddrs := &minerAddrs{owner, worker, provider, nil} 2357 2358 var st market.State 2359 2360 // Test adding provider funds from both worker and owner address 2361 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2362 actor.addProviderFunds(rt, abi.NewTokenAmount(20000000), minerAddrs) 2363 rt.GetState(&st) 2364 assert.Equal(t, abi.NewTokenAmount(20000000), actor.getEscrowBalance(rt, provider)) 2365 2366 actor.addParticipantFunds(rt, client, abi.NewTokenAmount(20000000)) 2367 2368 dealProposal := generateDealProposal(client, provider, abi.ChainEpoch(1), abi.ChainEpoch(200*builtin.EpochsInDay)) 2369 params := &market.PublishStorageDealsParams{Deals: []market.ClientDealProposal{{Proposal: dealProposal}}} 2370 2371 // First attempt at publishing the deal should work 2372 { 2373 rt.SetCaller(worker, builtin.AccountActorCodeID) 2374 actor.publishDeals(rt, minerAddrs, publishDealReq{deal: dealProposal}) 2375 } 2376 2377 // Second attempt at publishing the same deal should fail 2378 { 2379 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 2380 rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) 2381 expectQueryNetworkInfo(rt, actor) 2382 rt.ExpectVerifySignature(crypto.Signature{}, client, mustCbor(¶ms.Deals[0].Proposal), nil) 2383 rt.SetCaller(worker, builtin.AccountActorCodeID) 2384 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 2385 rt.Call(actor.PublishStorageDeals, params) 2386 }) 2387 2388 rt.Verify() 2389 } 2390 2391 dealProposal.Label = "foo" 2392 2393 // Same deal with a different label should work 2394 { 2395 rt.SetCaller(worker, builtin.AccountActorCodeID) 2396 actor.publishDeals(rt, minerAddrs, publishDealReq{deal: dealProposal}) 2397 } 2398 actor.checkState(rt) 2399 } 2400 2401 func TestMaxDealLabelSize(t *testing.T) { 2402 owner := tutil.NewIDAddr(t, 101) 2403 provider := tutil.NewIDAddr(t, 102) 2404 worker := tutil.NewIDAddr(t, 103) 2405 client := tutil.NewIDAddr(t, 104) 2406 minerAddrs := &minerAddrs{owner, worker, provider, nil} 2407 2408 var st market.State 2409 2410 // Test adding provider funds from both worker and owner address 2411 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2412 actor.addProviderFunds(rt, abi.NewTokenAmount(20000000), minerAddrs) 2413 rt.GetState(&st) 2414 assert.Equal(t, abi.NewTokenAmount(20000000), actor.getEscrowBalance(rt, provider)) 2415 2416 actor.addParticipantFunds(rt, client, abi.NewTokenAmount(20000000)) 2417 2418 dealProposal := generateDealProposal(client, provider, abi.ChainEpoch(1), abi.ChainEpoch(200*builtin.EpochsInDay)) 2419 dealProposal.Label = string(make([]byte, market.DealMaxLabelSize)) 2420 params := &market.PublishStorageDealsParams{Deals: []market.ClientDealProposal{{Proposal: dealProposal}}} 2421 2422 // Label at max size should work. 2423 { 2424 rt.SetCaller(worker, builtin.AccountActorCodeID) 2425 actor.publishDeals(rt, minerAddrs, publishDealReq{deal: dealProposal}) 2426 } 2427 2428 dealProposal.Label = string(make([]byte, market.DealMaxLabelSize+1)) 2429 2430 // Label greater than max size should fail. 2431 { 2432 rt.ExpectValidateCallerType(builtin.AccountActorCodeID, builtin.MultisigActorCodeID) 2433 rt.ExpectSend(provider, builtin.MethodsMiner.ControlAddresses, nil, abi.NewTokenAmount(0), &miner.GetControlAddressesReturn{Worker: worker, Owner: owner}, 0) 2434 expectQueryNetworkInfo(rt, actor) 2435 rt.ExpectVerifySignature(crypto.Signature{}, client, mustCbor(¶ms.Deals[0].Proposal), nil) 2436 rt.SetCaller(worker, builtin.AccountActorCodeID) 2437 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 2438 rt.Call(actor.PublishStorageDeals, params) 2439 }) 2440 2441 rt.Verify() 2442 } 2443 actor.checkState(rt) 2444 } 2445 2446 func TestComputeDataCommitment(t *testing.T) { 2447 owner := tutil.NewIDAddr(t, 101) 2448 provider := tutil.NewIDAddr(t, 102) 2449 worker := tutil.NewIDAddr(t, 103) 2450 client := tutil.NewIDAddr(t, 104) 2451 mAddrs := &minerAddrs{owner, worker, provider, nil} 2452 start := abi.ChainEpoch(10) 2453 end := start + 200*builtin.EpochsInDay 2454 2455 t.Run("successfully compute cid", func(t *testing.T) { 2456 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2457 dealId1 := actor.generateAndPublishDeal(rt, client, mAddrs, start, end, start) 2458 d1 := actor.getDealProposal(rt, dealId1) 2459 2460 dealId2 := actor.generateAndPublishDeal(rt, client, mAddrs, start, end+1, start) 2461 d2 := actor.getDealProposal(rt, dealId2) 2462 2463 param := &market.ComputeDataCommitmentParams{DealIDs: []abi.DealID{dealId1, dealId2}, SectorType: 1} 2464 2465 p1 := abi.PieceInfo{Size: d1.PieceSize, PieceCID: d1.PieceCID} 2466 p2 := abi.PieceInfo{Size: d2.PieceSize, PieceCID: d2.PieceCID} 2467 2468 c := tutil.MakeCID("100", &market.PieceCIDPrefix) 2469 2470 rt.ExpectComputeUnsealedSectorCID(1, []abi.PieceInfo{p1, p2}, c, nil) 2471 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 2472 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2473 2474 ret := rt.Call(actor.ComputeDataCommitment, param) 2475 val, ok := ret.(*cbg.CborCid) 2476 require.True(t, ok) 2477 require.Equal(t, c, *(*cid.Cid)(val)) 2478 rt.Verify() 2479 2480 actor.checkState(rt) 2481 }) 2482 2483 t.Run("fail when deal proposal is absent", func(t *testing.T) { 2484 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2485 param := &market.ComputeDataCommitmentParams{DealIDs: []abi.DealID{1}, SectorType: 1} 2486 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 2487 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2488 rt.ExpectAbort(exitcode.ErrNotFound, func() { 2489 rt.Call(actor.ComputeDataCommitment, param) 2490 }) 2491 actor.checkState(rt) 2492 }) 2493 2494 t.Run("fail when syscall returns an error", func(t *testing.T) { 2495 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2496 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, start, end, start) 2497 d := actor.getDealProposal(rt, dealId) 2498 param := &market.ComputeDataCommitmentParams{DealIDs: []abi.DealID{dealId}, SectorType: 1} 2499 2500 pi := abi.PieceInfo{Size: d.PieceSize, PieceCID: d.PieceCID} 2501 2502 rt.ExpectComputeUnsealedSectorCID(1, []abi.PieceInfo{pi}, cid.Cid{}, errors.New("error")) 2503 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 2504 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2505 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 2506 rt.Call(actor.ComputeDataCommitment, param) 2507 }) 2508 actor.checkState(rt) 2509 }) 2510 } 2511 2512 func TestVerifyDealsForActivation(t *testing.T) { 2513 owner := tutil.NewIDAddr(t, 101) 2514 provider := tutil.NewIDAddr(t, 102) 2515 worker := tutil.NewIDAddr(t, 103) 2516 client := tutil.NewIDAddr(t, 104) 2517 mAddrs := &minerAddrs{owner, worker, provider, nil} 2518 start := abi.ChainEpoch(10) 2519 end := start + 200*builtin.EpochsInDay 2520 sectorExpiry := end + 200 2521 2522 t.Run("verify deal and get deal weight for unverified deal proposal", func(t *testing.T) { 2523 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2524 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, start, end, start) 2525 d := actor.getDealProposal(rt, dealId) 2526 2527 resp := actor.verifyDealsForActivation(rt, provider, []market.SectorDeals{{ 2528 SectorExpiry: sectorExpiry, 2529 DealIDs: []abi.DealID{dealId}, 2530 }}) 2531 require.EqualValues(t, big.Zero(), resp.Sectors[0].VerifiedDealWeight) 2532 require.EqualValues(t, market.DealWeight(d), resp.Sectors[0].DealWeight) 2533 2534 actor.checkState(rt) 2535 }) 2536 2537 t.Run("verify deal and get deal weight for verified deal proposal", func(t *testing.T) { 2538 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2539 deal := actor.generateDealAndAddFunds(rt, client, mAddrs, start, end) 2540 deal.VerifiedDeal = true 2541 rt.SetCaller(worker, builtin.AccountActorCodeID) 2542 dealIds := actor.publishDeals(rt, mAddrs, publishDealReq{deal: deal}) 2543 2544 resp := actor.verifyDealsForActivation(rt, provider, []market.SectorDeals{{ 2545 SectorExpiry: sectorExpiry, 2546 DealIDs: dealIds, 2547 }}) 2548 require.EqualValues(t, market.DealWeight(&deal), resp.Sectors[0].VerifiedDealWeight) 2549 require.EqualValues(t, big.Zero(), resp.Sectors[0].DealWeight) 2550 2551 actor.checkState(rt) 2552 }) 2553 2554 t.Run("verification and weights for verified and unverified deals", func(T *testing.T) { 2555 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2556 2557 vd1 := actor.generateDealAndAddFunds(rt, client, mAddrs, start, end) 2558 vd1.VerifiedDeal = true 2559 2560 vd2 := actor.generateDealAndAddFunds(rt, client, mAddrs, start, end+1) 2561 vd2.VerifiedDeal = true 2562 2563 d1 := actor.generateDealAndAddFunds(rt, client, mAddrs, start, end+2) 2564 d2 := actor.generateDealAndAddFunds(rt, client, mAddrs, start, end+3) 2565 2566 rt.SetCaller(worker, builtin.AccountActorCodeID) 2567 dealIds := actor.publishDeals(rt, mAddrs, publishDealReq{deal: vd1}, publishDealReq{deal: vd2}, 2568 publishDealReq{deal: d1}, publishDealReq{deal: d2}) 2569 2570 resp := actor.verifyDealsForActivation(rt, provider, []market.SectorDeals{{ 2571 SectorExpiry: sectorExpiry, 2572 DealIDs: dealIds, 2573 }}) 2574 2575 verifiedWeight := big.Add(market.DealWeight(&vd1), market.DealWeight(&vd2)) 2576 nvweight := big.Add(market.DealWeight(&d1), market.DealWeight(&d2)) 2577 require.EqualValues(t, verifiedWeight, resp.Sectors[0].VerifiedDealWeight) 2578 require.EqualValues(t, nvweight, resp.Sectors[0].DealWeight) 2579 2580 actor.checkState(rt) 2581 }) 2582 2583 t.Run("fail when caller is not a StorageMinerActor", func(t *testing.T) { 2584 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2585 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, start, end, start) 2586 2587 param := &market.VerifyDealsForActivationParams{Sectors: []market.SectorDeals{{ 2588 SectorExpiry: sectorExpiry, 2589 DealIDs: []abi.DealID{dealId}, 2590 }}} 2591 rt.SetCaller(worker, builtin.AccountActorCodeID) 2592 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2593 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 2594 rt.Call(actor.VerifyDealsForActivation, param) 2595 }) 2596 actor.checkState(rt) 2597 }) 2598 2599 t.Run("fail when deal proposal is not found", func(t *testing.T) { 2600 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2601 param := &market.VerifyDealsForActivationParams{Sectors: []market.SectorDeals{{ 2602 SectorExpiry: sectorExpiry, 2603 DealIDs: []abi.DealID{1}, 2604 }}} 2605 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 2606 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2607 rt.ExpectAbort(exitcode.ErrNotFound, func() { 2608 rt.Call(actor.VerifyDealsForActivation, param) 2609 }) 2610 actor.checkState(rt) 2611 }) 2612 2613 t.Run("fail when caller is not the provider", func(t *testing.T) { 2614 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2615 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, start, end, start) 2616 2617 param := &market.VerifyDealsForActivationParams{Sectors: []market.SectorDeals{{ 2618 SectorExpiry: sectorExpiry, 2619 DealIDs: []abi.DealID{dealId}, 2620 }}} 2621 provider2 := tutil.NewIDAddr(t, 205) 2622 rt.SetCaller(provider2, builtin.StorageMinerActorCodeID) 2623 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2624 rt.ExpectAbort(exitcode.ErrForbidden, func() { 2625 rt.Call(actor.VerifyDealsForActivation, param) 2626 }) 2627 actor.checkState(rt) 2628 }) 2629 2630 t.Run("fail when current epoch is greater than proposal start epoch", func(t *testing.T) { 2631 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2632 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, start, end, start) 2633 2634 rt.SetEpoch(start + 1) 2635 param := &market.VerifyDealsForActivationParams{Sectors: []market.SectorDeals{{ 2636 SectorExpiry: sectorExpiry, 2637 DealIDs: []abi.DealID{dealId}, 2638 }}} 2639 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 2640 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2641 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 2642 rt.Call(actor.VerifyDealsForActivation, param) 2643 }) 2644 actor.checkState(rt) 2645 }) 2646 2647 t.Run("fail when deal end epoch is greater than sector expiration", func(t *testing.T) { 2648 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2649 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, start, end, start) 2650 2651 param := &market.VerifyDealsForActivationParams{Sectors: []market.SectorDeals{{ 2652 SectorExpiry: end - 1, 2653 DealIDs: []abi.DealID{dealId}, 2654 }}} 2655 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 2656 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2657 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 2658 rt.Call(actor.VerifyDealsForActivation, param) 2659 }) 2660 actor.checkState(rt) 2661 }) 2662 2663 t.Run("fail when the same deal ID is passed multiple times", func(t *testing.T) { 2664 rt, actor := basicMarketSetup(t, owner, provider, worker, client) 2665 dealId := actor.generateAndPublishDeal(rt, client, mAddrs, start, end, start) 2666 2667 param := &market.VerifyDealsForActivationParams{Sectors: []market.SectorDeals{{ 2668 SectorExpiry: sectorExpiry, 2669 DealIDs: []abi.DealID{dealId, dealId}, 2670 }}} 2671 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 2672 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2673 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "multiple times", func() { 2674 rt.Call(actor.VerifyDealsForActivation, param) 2675 }) 2676 actor.checkState(rt) 2677 }) 2678 } 2679 2680 type marketActorTestHarness struct { 2681 market.Actor 2682 t testing.TB 2683 2684 networkQAPower abi.StoragePower 2685 networkBaselinePower abi.StoragePower 2686 } 2687 2688 func (h *marketActorTestHarness) constructAndVerify(rt *mock.Runtime) { 2689 rt.ExpectValidateCallerAddr(builtin.SystemActorAddr) 2690 ret := rt.Call(h.Constructor, nil) 2691 assert.Nil(h.t, ret) 2692 rt.Verify() 2693 } 2694 2695 func (h *marketActorTestHarness) verifyDealsForActivation(rt *mock.Runtime, provider address.Address, 2696 sectorDeals []market.SectorDeals) *market.VerifyDealsForActivationReturn { 2697 param := &market.VerifyDealsForActivationParams{Sectors: sectorDeals} 2698 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2699 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 2700 2701 ret := rt.Call(h.VerifyDealsForActivation, param) 2702 rt.Verify() 2703 2704 val, ok := ret.(*market.VerifyDealsForActivationReturn) 2705 require.True(h.t, ok) 2706 require.NotNil(h.t, val) 2707 return val 2708 } 2709 2710 type minerAddrs struct { 2711 owner address.Address 2712 worker address.Address 2713 provider address.Address 2714 control []address.Address 2715 } 2716 2717 // addProviderFunds is a helper method to setup provider market funds 2718 func (h *marketActorTestHarness) addProviderFunds(rt *mock.Runtime, amount abi.TokenAmount, minerAddrs *minerAddrs) { 2719 rt.SetReceived(amount) 2720 rt.SetAddressActorType(minerAddrs.provider, builtin.StorageMinerActorCodeID) 2721 rt.SetCaller(minerAddrs.owner, builtin.AccountActorCodeID) 2722 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 2723 2724 expectGetControlAddresses(rt, minerAddrs.provider, minerAddrs.owner, minerAddrs.worker) 2725 2726 rt.Call(h.AddBalance, &minerAddrs.provider) 2727 2728 rt.Verify() 2729 2730 rt.SetBalance(big.Add(rt.Balance(), amount)) 2731 } 2732 2733 // addParticipantFunds is a helper method to setup non-provider storage market participant funds 2734 func (h *marketActorTestHarness) addParticipantFunds(rt *mock.Runtime, addr address.Address, amount abi.TokenAmount) { 2735 rt.SetReceived(amount) 2736 rt.SetCaller(addr, builtin.AccountActorCodeID) 2737 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 2738 2739 rt.Call(h.AddBalance, &addr) 2740 2741 rt.Verify() 2742 2743 rt.SetBalance(big.Add(rt.Balance(), amount)) 2744 } 2745 2746 func (h *marketActorTestHarness) withdrawProviderBalance(rt *mock.Runtime, withDrawAmt, expectedSend abi.TokenAmount, miner *minerAddrs) { 2747 rt.SetCaller(miner.worker, builtin.AccountActorCodeID) 2748 rt.ExpectValidateCallerAddr(miner.owner, miner.worker) 2749 expectGetControlAddresses(rt, miner.provider, miner.owner, miner.worker) 2750 2751 params := market.WithdrawBalanceParams{ 2752 ProviderOrClientAddress: miner.provider, 2753 Amount: withDrawAmt, 2754 } 2755 2756 rt.ExpectSend(miner.owner, builtin.MethodSend, nil, expectedSend, nil, exitcode.Ok) 2757 rt.Call(h.WithdrawBalance, ¶ms) 2758 rt.Verify() 2759 } 2760 2761 func (h *marketActorTestHarness) withdrawClientBalance(rt *mock.Runtime, client address.Address, withDrawAmt, expectedSend abi.TokenAmount) { 2762 rt.SetCaller(client, builtin.AccountActorCodeID) 2763 rt.ExpectSend(client, builtin.MethodSend, nil, expectedSend, nil, exitcode.Ok) 2764 rt.ExpectValidateCallerAddr(client) 2765 2766 params := market.WithdrawBalanceParams{ 2767 ProviderOrClientAddress: client, 2768 Amount: withDrawAmt, 2769 } 2770 2771 rt.Call(h.WithdrawBalance, ¶ms) 2772 rt.Verify() 2773 } 2774 2775 func (h *marketActorTestHarness) cronTickNoChange(rt *mock.Runtime, client, provider address.Address) { 2776 var st market.State 2777 rt.GetState(&st) 2778 epochCid := st.DealOpsByEpoch 2779 2780 // fetch current client and provider escrow balances 2781 cLocked := h.getLockedBalance(rt, client) 2782 cEscrow := h.getEscrowBalance(rt, client) 2783 pLocked := h.getLockedBalance(rt, provider) 2784 pEscrow := h.getEscrowBalance(rt, provider) 2785 2786 h.cronTick(rt) 2787 2788 rt.GetState(&st) 2789 require.True(h.t, epochCid.Equals(st.DealOpsByEpoch)) 2790 2791 require.EqualValues(h.t, cEscrow, h.getEscrowBalance(rt, client)) 2792 require.EqualValues(h.t, cLocked, h.getLockedBalance(rt, client)) 2793 require.EqualValues(h.t, pEscrow, h.getEscrowBalance(rt, provider)) 2794 require.EqualValues(h.t, pLocked, h.getLockedBalance(rt, provider)) 2795 } 2796 2797 // if this is the first crontick for the deal, it's next tick will be scheduled at `desiredNextEpoch` 2798 // if this is not the first crontick, the `desiredNextEpoch` param is ignored. 2799 func (h *marketActorTestHarness) cronTickAndAssertBalances(rt *mock.Runtime, client, provider address.Address, 2800 currentEpoch abi.ChainEpoch, dealId abi.DealID) (payment abi.TokenAmount, amountSlashed abi.TokenAmount) { 2801 // fetch current client and provider escrow balances 2802 cLocked := h.getLockedBalance(rt, client) 2803 cEscrow := h.getEscrowBalance(rt, client) 2804 pLocked := h.getLockedBalance(rt, provider) 2805 pEscrow := h.getEscrowBalance(rt, provider) 2806 amountSlashed = big.Zero() 2807 2808 s := h.getDealState(rt, dealId) 2809 d := h.getDealProposal(rt, dealId) 2810 2811 // end epoch for payment calc 2812 paymentEnd := d.EndEpoch 2813 if s.SlashEpoch != -1 { 2814 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, d.ProviderCollateral, nil, exitcode.Ok) 2815 amountSlashed = d.ProviderCollateral 2816 2817 if s.SlashEpoch < d.StartEpoch { 2818 paymentEnd = d.StartEpoch 2819 } else { 2820 paymentEnd = s.SlashEpoch 2821 } 2822 } else if currentEpoch < paymentEnd { 2823 paymentEnd = currentEpoch 2824 } 2825 2826 // start epoch for payment calc 2827 paymentStart := d.StartEpoch 2828 if s.LastUpdatedEpoch != -1 { 2829 paymentStart = s.LastUpdatedEpoch 2830 } 2831 duration := paymentEnd - paymentStart 2832 payment = big.Mul(big.NewInt(int64(duration)), d.StoragePricePerEpoch) 2833 2834 // expected updated amounts 2835 updatedClientEscrow := big.Sub(cEscrow, payment) 2836 updatedProviderEscrow := big.Add(pEscrow, payment) 2837 updatedProviderEscrow = big.Sub(updatedProviderEscrow, amountSlashed) 2838 updatedClientLocked := big.Sub(cLocked, payment) 2839 updatedProviderLocked := pLocked 2840 // if the deal has expired or been slashed, locked amount will be zero for provider and client. 2841 isDealExpired := paymentEnd == d.EndEpoch 2842 if isDealExpired || s.SlashEpoch != -1 { 2843 updatedClientLocked = big.Zero() 2844 updatedProviderLocked = big.Zero() 2845 } 2846 2847 h.cronTick(rt) 2848 2849 require.EqualValues(h.t, updatedClientEscrow, h.getEscrowBalance(rt, client)) 2850 require.EqualValues(h.t, updatedClientLocked, h.getLockedBalance(rt, client)) 2851 require.Equal(h.t, updatedProviderLocked, h.getLockedBalance(rt, provider)) 2852 require.Equal(h.t, updatedProviderEscrow.Int64(), h.getEscrowBalance(rt, provider).Int64()) 2853 2854 return 2855 } 2856 2857 func (h *marketActorTestHarness) cronTick(rt *mock.Runtime) { 2858 rt.ExpectValidateCallerAddr(builtin.CronActorAddr) 2859 rt.SetCaller(builtin.CronActorAddr, builtin.CronActorCodeID) 2860 param := abi.EmptyValue{} 2861 2862 rt.Call(h.CronTick, ¶m) 2863 rt.Verify() 2864 } 2865 2866 type publishDealReq struct { 2867 deal market.DealProposal 2868 requiredProcessEpoch abi.ChainEpoch 2869 } 2870 2871 func (h *marketActorTestHarness) expectGetRandom(rt *mock.Runtime, deal *market.DealProposal, requiredProcessEpoch abi.ChainEpoch) { 2872 dealBuf := bytes.Buffer{} 2873 epochBuf := bytes.Buffer{} 2874 2875 diff := uint64(requiredProcessEpoch - deal.StartEpoch) 2876 require.NoError(h.t, deal.MarshalCBOR(&dealBuf)) 2877 require.NoError(h.t, binary.Write(&epochBuf, binary.BigEndian, diff)) 2878 rt.ExpectGetRandomnessBeacon(crypto.DomainSeparationTag_MarketDealCronSeed, rt.Epoch()-1, dealBuf.Bytes(), epochBuf.Bytes()) 2879 } 2880 2881 func (h *marketActorTestHarness) publishDeals(rt *mock.Runtime, minerAddrs *minerAddrs, publishDealReqs ...publishDealReq) []abi.DealID { 2882 for _, pdr := range publishDealReqs { 2883 h.expectGetRandom(rt, &pdr.deal, pdr.requiredProcessEpoch) 2884 } 2885 2886 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 2887 rt.ExpectSend( 2888 minerAddrs.provider, 2889 builtin.MethodsMiner.ControlAddresses, 2890 nil, 2891 big.Zero(), 2892 &miner.GetControlAddressesReturn{Owner: minerAddrs.owner, Worker: minerAddrs.worker, ControlAddrs: minerAddrs.control}, 2893 exitcode.Ok, 2894 ) 2895 expectQueryNetworkInfo(rt, h) 2896 2897 var params market.PublishStorageDealsParams 2898 2899 for _, pdr := range publishDealReqs { 2900 // create a client proposal with a valid signature 2901 buf := bytes.Buffer{} 2902 require.NoError(h.t, pdr.deal.MarshalCBOR(&buf), "failed to marshal deal proposal") 2903 sig := crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("does not matter")} 2904 clientProposal := market.ClientDealProposal{Proposal: pdr.deal, ClientSignature: sig} 2905 params.Deals = append(params.Deals, clientProposal) 2906 2907 // expect a call to verify the above signature 2908 rt.ExpectVerifySignature(sig, pdr.deal.Client, buf.Bytes(), nil) 2909 if pdr.deal.VerifiedDeal { 2910 param := &verifreg.UseBytesParams{ 2911 Address: pdr.deal.Client, 2912 DealSize: big.NewIntUnsigned(uint64(pdr.deal.PieceSize)), 2913 } 2914 2915 rt.ExpectSend(builtin.VerifiedRegistryActorAddr, builtin.MethodsVerifiedRegistry.UseBytes, param, abi.NewTokenAmount(0), nil, exitcode.Ok) 2916 } 2917 } 2918 2919 ret := rt.Call(h.PublishStorageDeals, ¶ms) 2920 rt.Verify() 2921 2922 resp, ok := ret.(*market.PublishStorageDealsReturn) 2923 require.True(h.t, ok, "unexpected type returned from call to PublishStorageDeals") 2924 require.Len(h.t, resp.IDs, len(publishDealReqs)) 2925 2926 // assert state after publishing the deals 2927 dealIds := resp.IDs 2928 for i, deaId := range dealIds { 2929 expected := publishDealReqs[i].deal 2930 p := h.getDealProposal(rt, deaId) 2931 2932 require.Equal(h.t, expected.StartEpoch, p.StartEpoch) 2933 require.Equal(h.t, expected.EndEpoch, p.EndEpoch) 2934 require.Equal(h.t, expected.PieceCID, p.PieceCID) 2935 require.Equal(h.t, expected.PieceSize, p.PieceSize) 2936 require.Equal(h.t, expected.Client, p.Client) 2937 require.Equal(h.t, expected.Provider, p.Provider) 2938 require.Equal(h.t, expected.Label, p.Label) 2939 require.Equal(h.t, expected.VerifiedDeal, p.VerifiedDeal) 2940 require.Equal(h.t, expected.StoragePricePerEpoch, p.StoragePricePerEpoch) 2941 require.Equal(h.t, expected.ClientCollateral, p.ClientCollateral) 2942 require.Equal(h.t, expected.ProviderCollateral, p.ProviderCollateral) 2943 } 2944 2945 return resp.IDs 2946 } 2947 2948 func (h *marketActorTestHarness) assertDealsNotActivated(rt *mock.Runtime, epoch abi.ChainEpoch, dealIDs ...abi.DealID) { 2949 var st market.State 2950 rt.GetState(&st) 2951 2952 states, err := market.AsDealStateArray(adt.AsStore(rt), st.States) 2953 require.NoError(h.t, err) 2954 2955 for _, d := range dealIDs { 2956 _, found, err := states.Get(d) 2957 require.NoError(h.t, err) 2958 require.False(h.t, found) 2959 } 2960 } 2961 2962 func (h *marketActorTestHarness) activateDeals(rt *mock.Runtime, sectorExpiry abi.ChainEpoch, provider address.Address, currentEpoch abi.ChainEpoch, dealIDs ...abi.DealID) { 2963 rt.SetCaller(provider, builtin.StorageMinerActorCodeID) 2964 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 2965 2966 params := &market.ActivateDealsParams{DealIDs: dealIDs, SectorExpiry: sectorExpiry} 2967 2968 ret := rt.Call(h.ActivateDeals, params) 2969 rt.Verify() 2970 2971 require.Nil(h.t, ret) 2972 2973 for _, d := range dealIDs { 2974 s := h.getDealState(rt, d) 2975 require.EqualValues(h.t, currentEpoch, s.SectorStartEpoch) 2976 } 2977 } 2978 2979 func (h *marketActorTestHarness) getDealProposal(rt *mock.Runtime, dealID abi.DealID) *market.DealProposal { 2980 var st market.State 2981 rt.GetState(&st) 2982 2983 deals, err := market.AsDealProposalArray(adt.AsStore(rt), st.Proposals) 2984 require.NoError(h.t, err) 2985 2986 d, found, err := deals.Get(dealID) 2987 require.NoError(h.t, err) 2988 require.True(h.t, found) 2989 require.NotNil(h.t, d) 2990 2991 return d 2992 } 2993 2994 func (h *marketActorTestHarness) assertAccountZero(rt *mock.Runtime, addr address.Address) { 2995 var st market.State 2996 rt.GetState(&st) 2997 2998 et, err := adt.AsBalanceTable(adt.AsStore(rt), st.EscrowTable) 2999 require.NoError(h.t, err) 3000 3001 b, err := et.Get(addr) 3002 require.NoError(h.t, err) 3003 require.Equal(h.t, big.Zero(), b) 3004 3005 lt, err := adt.AsBalanceTable(adt.AsStore(rt), st.LockedTable) 3006 require.NoError(h.t, err) 3007 b, err = lt.Get(addr) 3008 require.NoError(h.t, err) 3009 require.Equal(h.t, big.Zero(), b) 3010 } 3011 3012 func (h *marketActorTestHarness) getEscrowBalance(rt *mock.Runtime, addr address.Address) abi.TokenAmount { 3013 var st market.State 3014 rt.GetState(&st) 3015 3016 et, err := adt.AsBalanceTable(adt.AsStore(rt), st.EscrowTable) 3017 require.NoError(h.t, err) 3018 3019 bal, err := et.Get(addr) 3020 require.NoError(h.t, err) 3021 3022 return bal 3023 } 3024 3025 func (h *marketActorTestHarness) getLockedBalance(rt *mock.Runtime, addr address.Address) abi.TokenAmount { 3026 var st market.State 3027 rt.GetState(&st) 3028 3029 lt, err := adt.AsBalanceTable(adt.AsStore(rt), st.LockedTable) 3030 require.NoError(h.t, err) 3031 3032 bal, err := lt.Get(addr) 3033 require.NoError(h.t, err) 3034 3035 return bal 3036 } 3037 3038 func (h *marketActorTestHarness) getDealState(rt *mock.Runtime, dealID abi.DealID) *market.DealState { 3039 var st market.State 3040 rt.GetState(&st) 3041 3042 states, err := market.AsDealStateArray(adt.AsStore(rt), st.States) 3043 require.NoError(h.t, err) 3044 3045 s, found, err := states.Get(dealID) 3046 require.NoError(h.t, err) 3047 require.True(h.t, found) 3048 require.NotNil(h.t, s) 3049 3050 return s 3051 } 3052 3053 func (h *marketActorTestHarness) assertLockedFundStates(rt *mock.Runtime, storageFee, providerCollateral, clientCollateral abi.TokenAmount) { 3054 var st market.State 3055 rt.GetState(&st) 3056 3057 require.Equal(h.t, clientCollateral, st.TotalClientLockedCollateral) 3058 require.Equal(h.t, providerCollateral, st.TotalProviderLockedCollateral) 3059 require.Equal(h.t, storageFee, st.TotalClientStorageFee) 3060 } 3061 3062 func (h *marketActorTestHarness) assertDealDeleted(rt *mock.Runtime, dealId abi.DealID, p *market.DealProposal) { 3063 var st market.State 3064 rt.GetState(&st) 3065 3066 proposals, err := market.AsDealProposalArray(adt.AsStore(rt), st.Proposals) 3067 require.NoError(h.t, err) 3068 _, found, err := proposals.Get(dealId) 3069 require.NoError(h.t, err) 3070 require.False(h.t, found) 3071 3072 states, err := market.AsDealStateArray(adt.AsStore(rt), st.States) 3073 require.NoError(h.t, err) 3074 _, found, err = states.Get(dealId) 3075 require.NoError(h.t, err) 3076 require.False(h.t, found) 3077 3078 pcid, err := p.Cid() 3079 require.NoError(h.t, err) 3080 pending, err := adt.AsMap(adt.AsStore(rt), st.PendingProposals, builtin.DefaultHamtBitwidth) 3081 require.NoError(h.t, err) 3082 found, err = pending.Get(abi.CidKey(pcid), nil) 3083 require.NoError(h.t, err) 3084 require.False(h.t, found) 3085 } 3086 3087 func (h *marketActorTestHarness) assertDealsTerminated(rt *mock.Runtime, epoch abi.ChainEpoch, dealIds ...abi.DealID) { 3088 for _, d := range dealIds { 3089 s := h.getDealState(rt, d) 3090 require.EqualValues(h.t, epoch, s.SlashEpoch) 3091 } 3092 } 3093 3094 func (h *marketActorTestHarness) assertDeaslNotTerminated(rt *mock.Runtime, dealIds ...abi.DealID) { 3095 for _, d := range dealIds { 3096 s := h.getDealState(rt, d) 3097 require.EqualValues(h.t, abi.ChainEpoch(-1), s.SlashEpoch) 3098 } 3099 } 3100 3101 func (h *marketActorTestHarness) terminateDeals(rt *mock.Runtime, minerAddr address.Address, dealIds ...abi.DealID) { 3102 rt.SetCaller(minerAddr, builtin.StorageMinerActorCodeID) 3103 rt.ExpectValidateCallerType(builtin.StorageMinerActorCodeID) 3104 3105 params := mkTerminateDealParams(rt.Epoch(), dealIds...) 3106 3107 ret := rt.Call(h.OnMinerSectorsTerminate, params) 3108 rt.Verify() 3109 require.Nil(h.t, ret) 3110 } 3111 3112 func (h *marketActorTestHarness) publishAndActivateDeal(rt *mock.Runtime, client address.Address, minerAddrs *minerAddrs, 3113 startEpoch, endEpoch, currentEpoch, sectorExpiry abi.ChainEpoch, requiredProcessEpoch abi.ChainEpoch) abi.DealID { 3114 deal := h.generateDealAndAddFunds(rt, client, minerAddrs, startEpoch, endEpoch) 3115 rt.SetCaller(minerAddrs.worker, builtin.AccountActorCodeID) 3116 dealIds := h.publishDeals(rt, minerAddrs, publishDealReq{deal: deal, requiredProcessEpoch: requiredProcessEpoch}) 3117 h.activateDeals(rt, sectorExpiry, minerAddrs.provider, currentEpoch, dealIds[0]) 3118 return dealIds[0] 3119 } 3120 3121 func (h *marketActorTestHarness) updateLastUpdated(rt *mock.Runtime, dealId abi.DealID, newLastUpdated abi.ChainEpoch) { 3122 var st market.State 3123 rt.GetState(&st) 3124 3125 states, err := market.AsDealStateArray(adt.AsStore(rt), st.States) 3126 require.NoError(h.t, err) 3127 s, found, err := states.Get(dealId) 3128 require.True(h.t, found) 3129 require.NoError(h.t, err) 3130 require.NotNil(h.t, s) 3131 3132 require.NoError(h.t, states.Set(dealId, &market.DealState{s.SectorStartEpoch, newLastUpdated, s.SlashEpoch})) 3133 st.States, err = states.Root() 3134 require.NoError(h.t, err) 3135 rt.ReplaceState(&st) 3136 } 3137 3138 func (h *marketActorTestHarness) deleteDealProposal(rt *mock.Runtime, dealId abi.DealID) { 3139 var st market.State 3140 rt.GetState(&st) 3141 deals, err := market.AsDealProposalArray(adt.AsStore(rt), st.Proposals) 3142 require.NoError(h.t, err) 3143 require.NoError(h.t, deals.Delete(dealId)) 3144 st.Proposals, err = deals.Root() 3145 require.NoError(h.t, err) 3146 rt.ReplaceState(&st) 3147 } 3148 3149 func (h *marketActorTestHarness) generateAndPublishDeal(rt *mock.Runtime, client address.Address, minerAddrs *minerAddrs, 3150 startEpoch, endEpoch abi.ChainEpoch, requiredProcessEpoch abi.ChainEpoch) abi.DealID { 3151 3152 deal := h.generateDealAndAddFunds(rt, client, minerAddrs, startEpoch, endEpoch) 3153 rt.SetCaller(minerAddrs.worker, builtin.AccountActorCodeID) 3154 dealIds := h.publishDeals(rt, minerAddrs, publishDealReq{deal: deal, requiredProcessEpoch: requiredProcessEpoch}) 3155 return dealIds[0] 3156 } 3157 3158 func (h *marketActorTestHarness) generateDealAndAddFunds(rt *mock.Runtime, client address.Address, minerAddrs *minerAddrs, 3159 startEpoch, endEpoch abi.ChainEpoch) market.DealProposal { 3160 deal4 := generateDealProposal(client, minerAddrs.provider, startEpoch, endEpoch) 3161 h.addProviderFunds(rt, deal4.ProviderCollateral, minerAddrs) 3162 h.addParticipantFunds(rt, client, deal4.ClientBalanceRequirement()) 3163 3164 return deal4 3165 } 3166 3167 func (h *marketActorTestHarness) generateDealWithCollateralAndAddFunds(rt *mock.Runtime, client address.Address, 3168 minerAddrs *minerAddrs, providerCollateral, clientCollateral abi.TokenAmount, startEpoch, endEpoch abi.ChainEpoch) market.DealProposal { 3169 deal := generateDealProposalWithCollateral(client, minerAddrs.provider, providerCollateral, clientCollateral, 3170 startEpoch, endEpoch) 3171 h.addProviderFunds(rt, deal.ProviderCollateral, minerAddrs) 3172 h.addParticipantFunds(rt, client, deal.ClientBalanceRequirement()) 3173 3174 return deal 3175 } 3176 3177 func (h *marketActorTestHarness) checkState(rt *mock.Runtime) { 3178 var st market.State 3179 rt.GetState(&st) 3180 _, msgs := market.CheckStateInvariants(&st, rt.AdtStore(), rt.Balance(), rt.Epoch()) 3181 assert.True(h.t, msgs.IsEmpty(), strings.Join(msgs.Messages(), "\n")) 3182 } 3183 3184 func generateDealProposalWithCollateral(client, provider address.Address, providerCollateral, clientCollateral abi.TokenAmount, startEpoch, endEpoch abi.ChainEpoch) market.DealProposal { 3185 pieceCid := tutil.MakeCID("1", &market.PieceCIDPrefix) 3186 pieceSize := abi.PaddedPieceSize(2048) 3187 storagePerEpoch := big.NewInt(10) 3188 3189 return market.DealProposal{PieceCID: pieceCid, PieceSize: pieceSize, Client: client, Provider: provider, Label: "label", StartEpoch: startEpoch, 3190 EndEpoch: endEpoch, StoragePricePerEpoch: storagePerEpoch, ProviderCollateral: providerCollateral, ClientCollateral: clientCollateral} 3191 } 3192 3193 func generateDealProposal(client, provider address.Address, startEpoch, endEpoch abi.ChainEpoch) market.DealProposal { 3194 clientCollateral := big.NewInt(10) 3195 providerCollateral := big.NewInt(10) 3196 3197 return generateDealProposalWithCollateral(client, provider, clientCollateral, providerCollateral, startEpoch, endEpoch) 3198 } 3199 3200 func basicMarketSetup(t *testing.T, owner, provider, worker, client address.Address) (*mock.Runtime, *marketActorTestHarness) { 3201 builder := mock.NewBuilder(builtin.StorageMarketActorAddr). 3202 WithCaller(builtin.SystemActorAddr, builtin.InitActorCodeID). 3203 WithBalance(big.Mul(big.NewInt(10), big.NewInt(1e18)), big.Zero()). 3204 WithActorType(owner, builtin.AccountActorCodeID). 3205 WithActorType(worker, builtin.AccountActorCodeID). 3206 WithActorType(provider, builtin.StorageMinerActorCodeID). 3207 WithActorType(client, builtin.AccountActorCodeID) 3208 3209 rt := builder.Build(t) 3210 power := abi.NewStoragePower(1 << 50) 3211 actor := marketActorTestHarness{ 3212 t: t, 3213 networkQAPower: power, 3214 networkBaselinePower: power, 3215 } 3216 actor.constructAndVerify(rt) 3217 3218 return rt, &actor 3219 } 3220 3221 func mkPublishStorageParams(proposals ...market.DealProposal) *market.PublishStorageDealsParams { 3222 m := &market.PublishStorageDealsParams{} 3223 for _, p := range proposals { 3224 m.Deals = append(m.Deals, market.ClientDealProposal{Proposal: p}) 3225 } 3226 return m 3227 } 3228 3229 func mkActivateDealParams(sectorExpiry abi.ChainEpoch, dealIds ...abi.DealID) *market.ActivateDealsParams { 3230 return &market.ActivateDealsParams{SectorExpiry: sectorExpiry, DealIDs: dealIds} 3231 } 3232 3233 func mkTerminateDealParams(epoch abi.ChainEpoch, dealIds ...abi.DealID) *market.OnMinerSectorsTerminateParams { 3234 return &market.OnMinerSectorsTerminateParams{Epoch: epoch, DealIDs: dealIds} 3235 } 3236 3237 func expectGetControlAddresses(rt *mock.Runtime, provider address.Address, owner, worker address.Address, controls ...address.Address) { 3238 result := &miner.GetControlAddressesReturn{Owner: owner, Worker: worker, ControlAddrs: controls} 3239 rt.ExpectSend( 3240 provider, 3241 builtin.MethodsMiner.ControlAddresses, 3242 nil, 3243 big.Zero(), 3244 result, 3245 exitcode.Ok, 3246 ) 3247 } 3248 3249 func expectQueryNetworkInfo(rt *mock.Runtime, h *marketActorTestHarness) { 3250 currentPower := power.CurrentTotalPowerReturn{ 3251 QualityAdjPower: h.networkQAPower, 3252 } 3253 currentReward := reward.ThisEpochRewardReturn{ 3254 ThisEpochBaselinePower: h.networkBaselinePower, 3255 } 3256 rt.ExpectSend( 3257 builtin.RewardActorAddr, 3258 builtin.MethodsReward.ThisEpochReward, 3259 nil, 3260 big.Zero(), 3261 ¤tReward, 3262 exitcode.Ok, 3263 ) 3264 3265 rt.ExpectSend( 3266 builtin.StoragePowerActorAddr, 3267 builtin.MethodsPower.CurrentTotalPower, 3268 nil, 3269 big.Zero(), 3270 ¤tPower, 3271 exitcode.Ok, 3272 ) 3273 }