github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/miner/miner_test.go (about) 1 // nolint:unused // 20200716 until tests are restored from miner state refactor 2 package miner_test 3 4 import ( 5 "bytes" 6 "encoding/binary" 7 "fmt" 8 "strings" 9 "testing" 10 11 addr "github.com/filecoin-project/go-address" 12 bitfield "github.com/filecoin-project/go-bitfield" 13 "github.com/filecoin-project/go-state-types/abi" 14 "github.com/filecoin-project/go-state-types/big" 15 "github.com/filecoin-project/go-state-types/crypto" 16 "github.com/filecoin-project/go-state-types/dline" 17 "github.com/filecoin-project/go-state-types/exitcode" 18 "github.com/filecoin-project/go-state-types/network" 19 cid "github.com/ipfs/go-cid" 20 "github.com/minio/blake2b-simd" 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/require" 23 cbg "github.com/whyrusleeping/cbor-gen" 24 25 "github.com/filecoin-project/specs-actors/v4/actors/builtin" 26 "github.com/filecoin-project/specs-actors/v4/actors/builtin/market" 27 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" 28 "github.com/filecoin-project/specs-actors/v4/actors/builtin/power" 29 "github.com/filecoin-project/specs-actors/v4/actors/builtin/reward" 30 "github.com/filecoin-project/specs-actors/v4/actors/runtime" 31 "github.com/filecoin-project/specs-actors/v4/actors/runtime/proof" 32 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 33 "github.com/filecoin-project/specs-actors/v4/actors/util/smoothing" 34 "github.com/filecoin-project/specs-actors/v4/support/mock" 35 tutil "github.com/filecoin-project/specs-actors/v4/support/testing" 36 ) 37 38 var testPid abi.PeerID 39 var testMultiaddrs []abi.Multiaddrs 40 41 // A balance for use in tests where the miner's low balance is not interesting. 42 var bigBalance = big.Mul(big.NewInt(1_000_000), big.NewInt(1e18)) 43 44 // A reward amount for use in tests where the vesting amount wants to be large enough to cover penalties. 45 var bigRewards = big.Mul(big.NewInt(1_000), big.NewInt(1e18)) 46 47 // an expriration 1 greater than min expiration 48 const defaultSectorExpiration = 190 49 50 func init() { 51 testPid = abi.PeerID("peerID") 52 53 testMultiaddrs = []abi.Multiaddrs{ 54 []byte("foobar"), 55 []byte("imafilminer"), 56 } 57 58 // permit 2KiB sectors in tests 59 miner.PreCommitSealProofTypesV8[abi.RegisteredSealProof_StackedDrg2KiBV1_1] = struct{}{} 60 } 61 62 func TestExports(t *testing.T) { 63 mock.CheckActorExports(t, miner.Actor{}) 64 } 65 66 func TestConstruction(t *testing.T) { 67 actor := miner.Actor{} 68 owner := tutil.NewIDAddr(t, 100) 69 worker := tutil.NewIDAddr(t, 101) 70 workerKey := tutil.NewBLSAddr(t, 0) 71 72 controlAddrs := []addr.Address{tutil.NewIDAddr(t, 999), tutil.NewIDAddr(t, 998)} 73 74 receiver := tutil.NewIDAddr(t, 1000) 75 builder := mock.NewBuilder(receiver). 76 WithActorType(owner, builtin.AccountActorCodeID). 77 WithActorType(worker, builtin.AccountActorCodeID). 78 WithActorType(controlAddrs[0], builtin.AccountActorCodeID). 79 WithActorType(controlAddrs[1], builtin.AccountActorCodeID). 80 WithHasher(blake2b.Sum256). 81 WithCaller(builtin.InitActorAddr, builtin.InitActorCodeID) 82 83 t.Run("simple construction", func(t *testing.T) { 84 rt := builder.Build(t) 85 params := miner.ConstructorParams{ 86 OwnerAddr: owner, 87 WorkerAddr: worker, 88 ControlAddrs: controlAddrs, 89 WindowPoStProofType: abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, 90 PeerId: testPid, 91 Multiaddrs: testMultiaddrs, 92 } 93 94 provingPeriodStart := abi.ChainEpoch(-2222) // This is just set from running the code. 95 rt.ExpectValidateCallerAddr(builtin.InitActorAddr) 96 // Fetch worker pubkey. 97 rt.ExpectSend(worker, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &workerKey, exitcode.Ok) 98 // Register proving period cron. 99 dlIdx := (rt.Epoch() - provingPeriodStart) / miner.WPoStChallengeWindow 100 ret := rt.Call(actor.Constructor, ¶ms) 101 102 assert.Nil(t, ret) 103 rt.Verify() 104 105 var st miner.State 106 rt.GetState(&st) 107 info, err := st.GetInfo(adt.AsStore(rt)) 108 require.NoError(t, err) 109 assert.Equal(t, params.OwnerAddr, info.Owner) 110 assert.Equal(t, params.WorkerAddr, info.Worker) 111 assert.Equal(t, params.ControlAddrs, info.ControlAddresses) 112 assert.Equal(t, params.PeerId, info.PeerId) 113 assert.Equal(t, params.Multiaddrs, info.Multiaddrs) 114 assert.Equal(t, abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, info.WindowPoStProofType) 115 assert.Equal(t, abi.SectorSize(1<<35), info.SectorSize) 116 assert.Equal(t, uint64(2349), info.WindowPoStPartitionSectors) 117 118 assert.Equal(t, big.Zero(), st.PreCommitDeposits) 119 assert.Equal(t, big.Zero(), st.LockedFunds) 120 assert.True(t, st.PreCommittedSectors.Defined()) 121 122 assert.True(t, st.Sectors.Defined()) 123 assert.Equal(t, provingPeriodStart, st.ProvingPeriodStart) 124 assert.Equal(t, uint64(dlIdx), st.CurrentDeadline) 125 126 var deadlines miner.Deadlines 127 rt.StoreGet(st.Deadlines, &deadlines) 128 for i := uint64(0); i < miner.WPoStPeriodDeadlines; i++ { 129 var deadline miner.Deadline 130 rt.StoreGet(deadlines.Due[i], &deadline) 131 assert.True(t, deadline.Partitions.Defined()) 132 assert.True(t, deadline.ExpirationsEpochs.Defined()) 133 assertEmptyBitfield(t, deadline.PartitionsPoSted) 134 assertEmptyBitfield(t, deadline.EarlyTerminations) 135 assert.Equal(t, uint64(0), deadline.LiveSectors) 136 } 137 138 assertEmptyBitfield(t, st.EarlyTerminations) 139 140 _, msgs := miner.CheckStateInvariants(&st, rt.AdtStore(), rt.Balance()) 141 assert.True(t, msgs.IsEmpty(), strings.Join(msgs.Messages(), "\n")) 142 }) 143 144 t.Run("control addresses are resolved during construction", func(t *testing.T) { 145 control1 := tutil.NewBLSAddr(t, 501) 146 control1Id := tutil.NewIDAddr(t, 555) 147 148 control2 := tutil.NewBLSAddr(t, 502) 149 control2Id := tutil.NewIDAddr(t, 655) 150 151 rt := builder.WithActorType(control1Id, builtin.AccountActorCodeID). 152 WithActorType(control2Id, builtin.AccountActorCodeID).Build(t) 153 rt.AddIDAddress(control1, control1Id) 154 rt.AddIDAddress(control2, control2Id) 155 156 params := miner.ConstructorParams{ 157 OwnerAddr: owner, 158 WorkerAddr: worker, 159 ControlAddrs: []addr.Address{control1, control2}, 160 WindowPoStProofType: abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, 161 } 162 163 rt.ExpectValidateCallerAddr(builtin.InitActorAddr) 164 rt.ExpectSend(worker, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &workerKey, exitcode.Ok) 165 ret := rt.Call(actor.Constructor, ¶ms) 166 167 assert.Nil(t, ret) 168 rt.Verify() 169 170 var st miner.State 171 rt.GetState(&st) 172 info, err := st.GetInfo(adt.AsStore(rt)) 173 require.NoError(t, err) 174 assert.Equal(t, control1Id, info.ControlAddresses[0]) 175 assert.Equal(t, control2Id, info.ControlAddresses[1]) 176 }) 177 178 t.Run("fails if control address is not an account actor", func(t *testing.T) { 179 control1 := tutil.NewIDAddr(t, 501) 180 rt := builder.Build(t) 181 rt.SetAddressActorType(control1, builtin.PaymentChannelActorCodeID) 182 183 params := miner.ConstructorParams{ 184 OwnerAddr: owner, 185 WorkerAddr: worker, 186 ControlAddrs: []addr.Address{control1}, 187 WindowPoStProofType: abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, 188 } 189 190 rt.ExpectValidateCallerAddr(builtin.InitActorAddr) 191 rt.ExpectSend(worker, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &workerKey, exitcode.Ok) 192 193 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 194 rt.Call(actor.Constructor, ¶ms) 195 }) 196 rt.Verify() 197 }) 198 199 t.Run("test construct with invalid peer ID", func(t *testing.T) { 200 rt := builder.Build(t) 201 pid := [miner.MaxPeerIDLength + 1]byte{1, 2, 3, 4} 202 params := miner.ConstructorParams{ 203 OwnerAddr: owner, 204 WorkerAddr: worker, 205 WindowPoStProofType: abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, 206 PeerId: pid[:], 207 Multiaddrs: testMultiaddrs, 208 } 209 210 rt.ExpectValidateCallerAddr(builtin.InitActorAddr) 211 212 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "peer ID size", func() { 213 rt.Call(actor.Constructor, ¶ms) 214 }) 215 }) 216 217 t.Run("fails if control addresses exceeds maximum length", func(t *testing.T) { 218 rt := builder.Build(t) 219 220 controlAddrs := make([]addr.Address, 0, miner.MaxControlAddresses+1) 221 for i := 0; i <= miner.MaxControlAddresses; i++ { 222 controlAddrs = append(controlAddrs, tutil.NewIDAddr(t, uint64(i))) 223 } 224 225 params := miner.ConstructorParams{ 226 OwnerAddr: owner, 227 WorkerAddr: worker, 228 WindowPoStProofType: abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, 229 PeerId: testPid, 230 ControlAddrs: controlAddrs, 231 } 232 233 rt.ExpectValidateCallerAddr(builtin.InitActorAddr) 234 235 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "control addresses length", func() { 236 rt.Call(actor.Constructor, ¶ms) 237 }) 238 }) 239 240 t.Run("test construct with large multiaddr", func(t *testing.T) { 241 rt := builder.Build(t) 242 maddrs := make([]abi.Multiaddrs, 100) 243 for i := range maddrs { 244 maddrs[i] = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} 245 } 246 params := miner.ConstructorParams{ 247 OwnerAddr: owner, 248 WorkerAddr: worker, 249 WindowPoStProofType: abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, 250 PeerId: testPid, 251 Multiaddrs: maddrs, 252 } 253 254 rt.ExpectValidateCallerAddr(builtin.InitActorAddr) 255 256 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "multiaddr size", func() { 257 rt.Call(actor.Constructor, ¶ms) 258 }) 259 }) 260 261 t.Run("test construct with empty multiaddr", func(t *testing.T) { 262 rt := builder.Build(t) 263 maddrs := []abi.Multiaddrs{ 264 {}, 265 {1}, 266 } 267 params := miner.ConstructorParams{ 268 OwnerAddr: owner, 269 WorkerAddr: worker, 270 WindowPoStProofType: abi.RegisteredPoStProof_StackedDrgWindow32GiBV1, 271 PeerId: testPid, 272 Multiaddrs: maddrs, 273 } 274 275 rt.ExpectValidateCallerAddr(builtin.InitActorAddr) 276 277 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "invalid empty multiaddr", func() { 278 rt.Call(actor.Constructor, ¶ms) 279 }) 280 }) 281 } 282 283 // Test operations related to peer info (peer ID/multiaddrs) 284 func TestPeerInfo(t *testing.T) { 285 h := newHarness(t, 0) 286 builder := builderForHarness(h) 287 288 t.Run("can set peer id", func(t *testing.T) { 289 rt := builder.Build(t) 290 h.constructAndVerify(rt) 291 292 h.setPeerID(rt, abi.PeerID("new peer id")) 293 h.checkState(rt) 294 }) 295 296 t.Run("can clear peer id", func(t *testing.T) { 297 rt := builder.Build(t) 298 h.constructAndVerify(rt) 299 300 h.setPeerID(rt, nil) 301 h.checkState(rt) 302 }) 303 304 t.Run("can't set large peer id", func(t *testing.T) { 305 rt := builder.Build(t) 306 h.constructAndVerify(rt) 307 308 largePid := [miner.MaxPeerIDLength + 1]byte{1, 2, 3} 309 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "peer ID size", func() { 310 h.setPeerID(rt, largePid[:]) 311 }) 312 h.checkState(rt) 313 }) 314 315 t.Run("can set multiaddrs", func(t *testing.T) { 316 rt := builder.Build(t) 317 h.constructAndVerify(rt) 318 319 h.setMultiaddrs(rt, abi.Multiaddrs("imanewminer")) 320 h.checkState(rt) 321 }) 322 323 t.Run("can set multiple multiaddrs", func(t *testing.T) { 324 rt := builder.Build(t) 325 h.constructAndVerify(rt) 326 327 h.setMultiaddrs(rt, abi.Multiaddrs("imanewminer"), abi.Multiaddrs("ihavemany")) 328 h.checkState(rt) 329 }) 330 331 t.Run("can set clear the multiaddr", func(t *testing.T) { 332 rt := builder.Build(t) 333 h.constructAndVerify(rt) 334 335 h.setMultiaddrs(rt) 336 h.checkState(rt) 337 }) 338 339 t.Run("can't set empty multiaddrs", func(t *testing.T) { 340 rt := builder.Build(t) 341 h.constructAndVerify(rt) 342 343 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "invalid empty multiaddr", func() { 344 h.setMultiaddrs(rt, nil) 345 }) 346 h.checkState(rt) 347 }) 348 349 t.Run("can't set large multiaddrs", func(t *testing.T) { 350 rt := builder.Build(t) 351 h.constructAndVerify(rt) 352 353 maddrs := make([]abi.Multiaddrs, 100) 354 for i := range maddrs { 355 maddrs[i] = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} 356 } 357 358 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "multiaddr size", func() { 359 h.setMultiaddrs(rt, maddrs...) 360 }) 361 h.checkState(rt) 362 }) 363 } 364 365 // Tests for fetching and manipulating miner addresses. 366 func TestControlAddresses(t *testing.T) { 367 actor := newHarness(t, 0) 368 builder := builderForHarness(actor) 369 370 t.Run("get addresses", func(t *testing.T) { 371 rt := builder.Build(t) 372 actor.constructAndVerify(rt) 373 374 o, w, control := actor.controlAddresses(rt) 375 assert.Equal(t, actor.owner, o) 376 assert.Equal(t, actor.worker, w) 377 assert.NotEmpty(t, control) 378 assert.Equal(t, actor.controlAddrs, control) 379 actor.checkState(rt) 380 }) 381 382 } 383 384 // Test for sector precommitment and proving. 385 func TestCommitments(t *testing.T) { 386 periodOffset := abi.ChainEpoch(100) 387 t.Run("valid precommit then provecommit", func(t *testing.T) { 388 actor := newHarness(t, periodOffset) 389 rt := builderForHarness(actor). 390 WithBalance(bigBalance, big.Zero()). 391 Build(t) 392 precommitEpoch := periodOffset + 1 393 rt.SetEpoch(precommitEpoch) 394 actor.constructAndVerify(rt) 395 dlInfo := actor.deadline(rt) 396 397 // Make a good commitment for the proof to target. 398 // Use the max sector number to make sure everything works. 399 sectorNo := abi.SectorNumber(abi.MaxSectorNumber) 400 proveCommitEpoch := precommitEpoch + miner.PreCommitChallengeDelay + 1 401 expiration := dlInfo.PeriodEnd() + defaultSectorExpiration*miner.WPoStProvingPeriod // something on deadline boundary but > 180 days 402 // Fill the sector with verified deals 403 sectorWeight := big.Mul(big.NewInt(int64(actor.sectorSize)), big.NewInt(int64(expiration-proveCommitEpoch))) 404 dealWeight := big.Zero() 405 verifiedDealWeight := sectorWeight 406 407 // Pre-commit with a deal in order to exercise non-zero deal weights. 408 precommitParams := actor.makePreCommit(sectorNo, precommitEpoch-1, expiration, []abi.DealID{1}) 409 precommit := actor.preCommitSector(rt, precommitParams, preCommitConf{ 410 dealWeight: dealWeight, 411 verifiedDealWeight: verifiedDealWeight, 412 }, true) 413 414 // assert precommit exists and meets expectations 415 onChainPrecommit := actor.getPreCommit(rt, sectorNo) 416 417 // deal weights must be set in precommit onchain info 418 assert.Equal(t, dealWeight, onChainPrecommit.DealWeight) 419 assert.Equal(t, verifiedDealWeight, onChainPrecommit.VerifiedDealWeight) 420 421 pwrEstimate := miner.QAPowerForWeight(actor.sectorSize, precommit.Info.Expiration-precommitEpoch, onChainPrecommit.DealWeight, onChainPrecommit.VerifiedDealWeight) 422 expectedDeposit := miner.PreCommitDepositForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, pwrEstimate) 423 assert.Equal(t, expectedDeposit, onChainPrecommit.PreCommitDeposit) 424 425 // expect total precommit deposit to equal our new deposit 426 st := getState(rt) 427 assert.Equal(t, expectedDeposit, st.PreCommitDeposits) 428 429 // run prove commit logic 430 rt.SetEpoch(proveCommitEpoch) 431 rt.SetBalance(big.Mul(big.NewInt(1000), big.NewInt(1e18))) 432 actor.proveCommitSectorAndConfirm(rt, precommit, makeProveCommit(sectorNo), proveCommitConf{}) 433 434 // expect precommit to have been removed 435 st = getState(rt) 436 _, found, err := st.GetPrecommittedSector(rt.AdtStore(), sectorNo) 437 require.NoError(t, err) 438 require.False(t, found) 439 440 // expect deposit to have been transferred to initial pledges 441 assert.Equal(t, big.Zero(), st.PreCommitDeposits) 442 443 // The sector is exactly full with verified deals, so expect fully verified power. 444 expectedPower := big.Mul(big.NewInt(int64(actor.sectorSize)), big.Div(builtin.VerifiedDealWeightMultiplier, builtin.QualityBaseMultiplier)) 445 qaPower := miner.QAPowerForWeight(actor.sectorSize, precommit.Info.Expiration-rt.Epoch(), onChainPrecommit.DealWeight, onChainPrecommit.VerifiedDealWeight) 446 assert.Equal(t, expectedPower, qaPower) 447 expectedInitialPledge := miner.InitialPledgeForPower(qaPower, actor.baselinePower, actor.epochRewardSmooth, 448 actor.epochQAPowerSmooth, rt.TotalFilCircSupply()) 449 assert.Equal(t, expectedInitialPledge, st.InitialPledge) 450 451 // expect new onchain sector 452 sector := actor.getSector(rt, sectorNo) 453 sectorPower := miner.NewPowerPair(big.NewIntUnsigned(uint64(actor.sectorSize)), qaPower) 454 455 // expect deal weights to be transferred to on chain info 456 assert.Equal(t, onChainPrecommit.DealWeight, sector.DealWeight) 457 assert.Equal(t, onChainPrecommit.VerifiedDealWeight, sector.VerifiedDealWeight) 458 459 // expect activation epoch to be current epoch 460 assert.Equal(t, rt.Epoch(), sector.Activation) 461 462 // expect initial plege of sector to be set 463 assert.Equal(t, expectedInitialPledge, sector.InitialPledge) 464 465 // expect locked initial pledge of sector to be the same as pledge requirement 466 assert.Equal(t, expectedInitialPledge, st.InitialPledge) 467 468 // expect sector to be assigned a deadline/partition 469 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), sectorNo) 470 require.NoError(t, err) 471 deadline, partition := actor.getDeadlineAndPartition(rt, dlIdx, pIdx) 472 assert.Equal(t, uint64(1), deadline.LiveSectors) 473 assertEmptyBitfield(t, deadline.PartitionsPoSted) 474 assertEmptyBitfield(t, deadline.EarlyTerminations) 475 476 quant := st.QuantSpecForDeadline(dlIdx) 477 quantizedExpiration := quant.QuantizeUp(precommit.Info.Expiration) 478 479 dQueue := actor.collectDeadlineExpirations(rt, deadline) 480 assert.Equal(t, map[abi.ChainEpoch][]uint64{ 481 quantizedExpiration: {pIdx}, 482 }, dQueue) 483 484 assertBitfieldEquals(t, partition.Sectors, uint64(sectorNo)) 485 assertEmptyBitfield(t, partition.Faults) 486 assertEmptyBitfield(t, partition.Recoveries) 487 assertEmptyBitfield(t, partition.Terminated) 488 assert.Equal(t, sectorPower, partition.LivePower) 489 assert.Equal(t, miner.NewPowerPairZero(), partition.FaultyPower) 490 assert.Equal(t, miner.NewPowerPairZero(), partition.RecoveringPower) 491 492 pQueue := actor.collectPartitionExpirations(rt, partition) 493 entry, ok := pQueue[quantizedExpiration] 494 require.True(t, ok) 495 assertBitfieldEquals(t, entry.OnTimeSectors, uint64(sectorNo)) 496 assertEmptyBitfield(t, entry.EarlySectors) 497 assert.Equal(t, expectedInitialPledge, entry.OnTimePledge) 498 assert.Equal(t, sectorPower, entry.ActivePower) 499 assert.Equal(t, miner.NewPowerPairZero(), entry.FaultyPower) 500 }) 501 502 for _, test := range []struct { 503 name string 504 version network.Version 505 expectedPledgeDelta abi.TokenAmount 506 sealProofType abi.RegisteredSealProof 507 }{{ 508 name: "precommit does not vest funds in version 8", 509 version: network.Version8, 510 expectedPledgeDelta: abi.NewTokenAmount(0), 511 sealProofType: abi.RegisteredSealProof_StackedDrg32GiBV1_1, 512 }} { 513 t.Run(test.name, func(t *testing.T) { 514 actor := newHarness(t, periodOffset) 515 actor.setProofType(test.sealProofType) 516 rt := builderForHarness(actor). 517 WithBalance(bigBalance, big.Zero()). 518 WithNetworkVersion(test.version). 519 Build(t) 520 precommitEpoch := periodOffset + 1 521 rt.SetEpoch(precommitEpoch) 522 actor.constructAndVerify(rt) 523 dlInfo := actor.deadline(rt) 524 525 // Make a good commitment for the proof to target. 526 sectorNo := abi.SectorNumber(100) 527 expiration := dlInfo.PeriodEnd() + defaultSectorExpiration*miner.WPoStProvingPeriod // something on deadline boundary but > 180 days 528 529 // add 1000 tokens that vest immediately 530 st := getState(rt) 531 _, err := st.AddLockedFunds(rt.AdtStore(), rt.Epoch(), abi.NewTokenAmount(1000), &miner.VestSpec{ 532 InitialDelay: 0, 533 VestPeriod: 1, 534 StepDuration: 1, 535 Quantization: 1, 536 }) 537 require.NoError(t, err) 538 rt.ReplaceState(st) 539 540 rt.SetEpoch(rt.Epoch() + 2) 541 542 // Pre-commit with a deal in order to exercise non-zero deal weights. 543 precommitParams := actor.makePreCommit(sectorNo, precommitEpoch-1, expiration, []abi.DealID{1}) 544 actor.preCommitSector(rt, precommitParams, preCommitConf{ 545 pledgeDelta: &test.expectedPledgeDelta, 546 }, true) 547 }) 548 } 549 550 t.Run("insufficient funds for pre-commit", func(t *testing.T) { 551 actor := newHarness(t, periodOffset) 552 insufficientBalance := abi.NewTokenAmount(10) // 10 AttoFIL 553 rt := builderForHarness(actor). 554 WithBalance(insufficientBalance, big.Zero()). 555 Build(t) 556 precommitEpoch := periodOffset + 1 557 rt.SetEpoch(precommitEpoch) 558 actor.constructAndVerify(rt) 559 deadline := actor.deadline(rt) 560 challengeEpoch := precommitEpoch - 1 561 expiration := deadline.PeriodEnd() + defaultSectorExpiration*miner.WPoStProvingPeriod 562 563 rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { 564 actor.preCommitSector(rt, actor.makePreCommit(101, challengeEpoch, expiration, nil), preCommitConf{}, true) 565 }) 566 actor.checkState(rt) 567 }) 568 569 t.Run("deal space exceeds sector space", func(t *testing.T) { 570 actor := newHarness(t, periodOffset) 571 rt := builderForHarness(actor). 572 WithBalance(bigBalance, big.Zero()). 573 Build(t) 574 575 precommitEpoch := periodOffset + 1 576 rt.SetEpoch(precommitEpoch) 577 actor.constructAndVerify(rt) 578 deadline := actor.deadline(rt) 579 challengeEpoch := precommitEpoch - 1 580 expiration := deadline.PeriodEnd() + defaultSectorExpiration*miner.WPoStProvingPeriod 581 582 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "deals too large to fit in sector", func() { 583 actor.preCommitSector(rt, actor.makePreCommit(101, challengeEpoch, expiration, []abi.DealID{1}), preCommitConf{ 584 dealSpace: actor.sectorSize + 1, 585 }, true) 586 }) 587 actor.checkState(rt) 588 }) 589 590 t.Run("precommit pays back fee debt", func(t *testing.T) { 591 actor := newHarness(t, periodOffset) 592 rt := builderForHarness(actor). 593 WithBalance(bigBalance, big.Zero()). 594 Build(t) 595 596 precommitEpoch := periodOffset + 1 597 rt.SetEpoch(precommitEpoch) 598 actor.constructAndVerify(rt) 599 deadline := actor.deadline(rt) 600 challengeEpoch := precommitEpoch - 1 601 expiration := deadline.PeriodEnd() + defaultSectorExpiration*miner.WPoStProvingPeriod 602 603 st := getState(rt) 604 st.FeeDebt = abi.NewTokenAmount(9999) 605 rt.ReplaceState(st) 606 607 actor.preCommitSector(rt, actor.makePreCommit(101, challengeEpoch, expiration, nil), preCommitConf{}, true) 608 st = getState(rt) 609 assert.Equal(t, big.Zero(), st.FeeDebt) 610 actor.checkState(rt) 611 }) 612 613 t.Run("invalid pre-commit rejected", func(t *testing.T) { 614 actor := newHarness(t, periodOffset) 615 rt := builderForHarness(actor). 616 WithBalance(bigBalance, big.Zero()). 617 Build(t) 618 precommitEpoch := periodOffset + 1 619 rt.SetEpoch(precommitEpoch) 620 actor.constructAndVerify(rt) 621 deadline := actor.deadline(rt) 622 challengeEpoch := precommitEpoch - 1 623 624 oldSector := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true)[0] 625 st := getState(rt) 626 assert.True(t, st.DeadlineCronActive) 627 // Good commitment. 628 expiration := deadline.PeriodEnd() + defaultSectorExpiration*miner.WPoStProvingPeriod 629 actor.preCommitSector(rt, actor.makePreCommit(101, challengeEpoch, expiration, nil), preCommitConf{}, false) 630 // Duplicate pre-commit sector ID 631 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "already been allocated", func() { 632 actor.preCommitSector(rt, actor.makePreCommit(101, challengeEpoch, expiration, nil), preCommitConf{}, false) 633 }) 634 rt.Reset() 635 636 // Sector ID already committed 637 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "already been allocated", func() { 638 actor.preCommitSector(rt, actor.makePreCommit(oldSector.SectorNumber, challengeEpoch, expiration, nil), preCommitConf{}, false) 639 }) 640 rt.Reset() 641 642 // Bad sealed CID 643 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "sealed CID had wrong prefix", func() { 644 pc := actor.makePreCommit(102, challengeEpoch, deadline.PeriodEnd(), nil) 645 pc.SealedCID = tutil.MakeCID("Random Data", nil) 646 actor.preCommitSector(rt, pc, preCommitConf{}, false) 647 }) 648 rt.Reset() 649 650 // Bad seal proof type 651 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "unsupported seal proof type", func() { 652 pc := actor.makePreCommit(102, challengeEpoch, deadline.PeriodEnd(), nil) 653 pc.SealProof = abi.RegisteredSealProof_StackedDrg8MiBV1_1 654 actor.preCommitSector(rt, pc, preCommitConf{}, false) 655 }) 656 rt.Reset() 657 658 // Expires at current epoch 659 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "must be after activation", func() { 660 actor.preCommitSector(rt, actor.makePreCommit(102, challengeEpoch, rt.Epoch(), nil), preCommitConf{}, false) 661 }) 662 rt.Reset() 663 664 // Expires before current epoch 665 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "must be after activation", func() { 666 actor.preCommitSector(rt, actor.makePreCommit(102, challengeEpoch, rt.Epoch()-1, nil), preCommitConf{}, false) 667 }) 668 rt.Reset() 669 670 // Expires too early 671 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "must exceed", func() { 672 actor.preCommitSector(rt, actor.makePreCommit(102, challengeEpoch, expiration-20*builtin.EpochsInDay, nil), preCommitConf{}, false) 673 }) 674 rt.Reset() 675 676 // Expires before min duration + max seal duration 677 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "must exceed", func() { 678 expiration := rt.Epoch() + miner.MinSectorExpiration + miner.MaxProveCommitDuration[actor.sealProofType] - 1 679 actor.preCommitSector(rt, actor.makePreCommit(102, challengeEpoch, expiration, nil), preCommitConf{}, false) 680 }) 681 rt.Reset() 682 683 // Errors when expiry too far in the future 684 rt.SetEpoch(precommitEpoch) 685 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "invalid expiration", func() { 686 expiration := deadline.PeriodEnd() + miner.WPoStProvingPeriod*(miner.MaxSectorExpirationExtension/miner.WPoStProvingPeriod+1) 687 actor.preCommitSector(rt, actor.makePreCommit(102, challengeEpoch, expiration, nil), preCommitConf{}, false) 688 }) 689 rt.Reset() 690 691 // Sector ID out of range 692 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "out of range", func() { 693 actor.preCommitSector(rt, actor.makePreCommit(abi.MaxSectorNumber+1, challengeEpoch, expiration, nil), preCommitConf{}, false) 694 }) 695 rt.Reset() 696 697 // Seal randomness challenge too far in past 698 tooOldChallengeEpoch := precommitEpoch - miner.ChainFinality - miner.MaxProveCommitDuration[actor.sealProofType] - 1 699 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "too old", func() { 700 actor.preCommitSector(rt, actor.makePreCommit(102, tooOldChallengeEpoch, expiration, nil), preCommitConf{}, false) 701 }) 702 rt.Reset() 703 704 // Try to precommit while in fee debt with insufficient balance 705 st = getState(rt) 706 st.FeeDebt = big.Add(rt.Balance(), abi.NewTokenAmount(1e18)) 707 rt.ReplaceState(st) 708 rt.ExpectAbortContainsMessage(exitcode.ErrInsufficientFunds, "unlocked balance can not repay fee debt", func() { 709 actor.preCommitSector(rt, actor.makePreCommit(102, challengeEpoch, expiration, nil), preCommitConf{}, false) 710 }) 711 // reset state back to normal 712 st.FeeDebt = big.Zero() 713 rt.ReplaceState(st) 714 rt.Reset() 715 716 // Try to precommit with an active consensus fault 717 st = getState(rt) 718 719 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 720 Target: actor.receiver, 721 Epoch: rt.Epoch() - 1, 722 Type: runtime.ConsensusFaultDoubleForkMining, 723 }) 724 rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, "precommit not allowed during active consensus fault", func() { 725 actor.preCommitSector(rt, actor.makePreCommit(102, challengeEpoch, expiration, nil), preCommitConf{}, false) 726 }) 727 // reset state back to normal 728 rt.ReplaceState(st) 729 rt.Reset() 730 actor.checkState(rt) 731 }) 732 733 t.Run("prove commit just after period start permits PoSt", func(t *testing.T) { 734 actor := newHarness(t, periodOffset) 735 rt := builderForHarness(actor). 736 WithBalance(bigBalance, big.Zero()). 737 Build(t) 738 739 // Epoch 101 should be at the beginning of the miner's proving period so there will be time to commit 740 // and PoSt a sector. 741 rt.SetEpoch(101) 742 actor.constructAndVerify(rt) 743 744 // Commit a sector the very next epoch 745 rt.SetEpoch(102) 746 sector := actor.commitAndProveSector(rt, abi.MaxSectorNumber, defaultSectorExpiration, nil) 747 748 // advance cron to activate power. 749 advanceAndSubmitPoSts(rt, actor, sector) 750 actor.checkState(rt) 751 }) 752 753 t.Run("invalid proof rejected", func(t *testing.T) { 754 actor := newHarness(t, periodOffset) 755 rt := builderForHarness(actor). 756 WithBalance(bigBalance, big.Zero()). 757 Build(t) 758 precommitEpoch := periodOffset + 1 759 rt.SetEpoch(precommitEpoch) 760 actor.constructAndVerify(rt) 761 deadline := actor.deadline(rt) 762 763 // Make a good commitment for the proof to target. 764 sectorNo := abi.SectorNumber(100) 765 params := actor.makePreCommit(sectorNo, precommitEpoch-1, deadline.PeriodEnd()+defaultSectorExpiration*miner.WPoStProvingPeriod, []abi.DealID{1}) 766 precommit := actor.preCommitSector(rt, params, preCommitConf{}, true) 767 768 // Sector pre-commitment missing. 769 rt.SetEpoch(precommitEpoch + miner.PreCommitChallengeDelay + 1) 770 rt.ExpectAbort(exitcode.ErrNotFound, func() { 771 actor.proveCommitSectorAndConfirm(rt, precommit, makeProveCommit(sectorNo+1), proveCommitConf{}) 772 }) 773 rt.Reset() 774 775 // Too late. 776 rt.SetEpoch(precommitEpoch + miner.MaxProveCommitDuration[precommit.Info.SealProof] + 1) 777 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 778 actor.proveCommitSectorAndConfirm(rt, precommit, makeProveCommit(sectorNo), proveCommitConf{}) 779 }) 780 rt.Reset() 781 782 // Too early. 783 rt.SetEpoch(precommitEpoch + miner.PreCommitChallengeDelay - 1) 784 rt.ExpectAbort(exitcode.ErrForbidden, func() { 785 actor.proveCommitSectorAndConfirm(rt, precommit, makeProveCommit(sectorNo), proveCommitConf{}) 786 }) 787 rt.Reset() 788 789 // Set the right epoch for all following tests 790 rt.SetEpoch(precommitEpoch + miner.PreCommitChallengeDelay + 1) 791 792 // Invalid deals (market ActivateDeals aborts) 793 verifyDealsExit := map[abi.SectorNumber]exitcode.ExitCode{ 794 precommit.Info.SectorNumber: exitcode.ErrIllegalArgument, 795 } 796 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 797 actor.proveCommitSectorAndConfirm(rt, precommit, makeProveCommit(sectorNo), proveCommitConf{ 798 verifyDealsExit: verifyDealsExit, 799 }) 800 }) 801 rt.Reset() 802 803 rt.SetBalance(big.Mul(big.NewInt(1000), big.NewInt(1e18))) 804 805 proveCommit := makeProveCommit(sectorNo) 806 actor.proveCommitSectorAndConfirm(rt, precommit, proveCommit, proveCommitConf{}) 807 st := getState(rt) 808 809 // Verify new sectors 810 // TODO minerstate 811 //newSectors, err := st.NewSectors.All(miner.SectorsMax) 812 //require.NoError(t, err) 813 //assert.Equal(t, []uint64{uint64(sectorNo)}, newSectors) 814 // Verify pledge lock-up 815 assert.True(t, st.InitialPledge.GreaterThan(big.Zero())) 816 rt.Reset() 817 818 // Duplicate proof (sector no-longer pre-committed) 819 rt.ExpectAbort(exitcode.ErrNotFound, func() { 820 actor.proveCommitSectorAndConfirm(rt, precommit, makeProveCommit(sectorNo), proveCommitConf{}) 821 }) 822 rt.Reset() 823 actor.checkState(rt) 824 }) 825 826 for _, test := range []struct { 827 name string 828 version network.Version 829 vestingPledgeDelta abi.TokenAmount 830 sealProofType abi.RegisteredSealProof 831 }{{ 832 name: "verify proof does not vest at version 8", 833 version: network.Version8, 834 vestingPledgeDelta: abi.NewTokenAmount(0), 835 sealProofType: abi.RegisteredSealProof_StackedDrg32GiBV1_1, 836 }} { 837 t.Run(test.name, func(t *testing.T) { 838 actor := newHarness(t, periodOffset) 839 actor.setProofType(test.sealProofType) 840 rt := builderForHarness(actor). 841 WithNetworkVersion(test.version). 842 WithBalance(bigBalance, big.Zero()). 843 Build(t) 844 precommitEpoch := periodOffset + 1 845 rt.SetEpoch(precommitEpoch) 846 actor.constructAndVerify(rt) 847 deadline := actor.deadline(rt) 848 849 // Make a good commitment for the proof to target. 850 sectorNo := abi.SectorNumber(100) 851 params := actor.makePreCommit(sectorNo, precommitEpoch-1, deadline.PeriodEnd()+defaultSectorExpiration*miner.WPoStProvingPeriod, []abi.DealID{1}) 852 precommit := actor.preCommitSector(rt, params, preCommitConf{}, true) 853 854 // add 1000 tokens that vest immediately 855 st := getState(rt) 856 _, err := st.AddLockedFunds(rt.AdtStore(), rt.Epoch(), abi.NewTokenAmount(1000), &miner.VestSpec{ 857 InitialDelay: 0, 858 VestPeriod: 1, 859 StepDuration: 1, 860 Quantization: 1, 861 }) 862 require.NoError(t, err) 863 rt.ReplaceState(st) 864 865 // Set the right epoch for all following tests 866 rt.SetEpoch(precommitEpoch + miner.PreCommitChallengeDelay + 1) 867 rt.SetBalance(big.Mul(big.NewInt(1000), big.NewInt(1e18))) 868 869 // Too big at version 4 870 proveCommit := makeProveCommit(sectorNo) 871 proveCommit.Proof = make([]byte, 192) 872 actor.proveCommitSectorAndConfirm(rt, precommit, proveCommit, proveCommitConf{ 873 vestingPledgeDelta: &test.vestingPledgeDelta, 874 }) 875 }) 876 877 } 878 879 t.Run("sector with non-positive lifetime is skipped in confirmation", func(t *testing.T) { 880 actor := newHarness(t, periodOffset) 881 rt := builderForHarness(actor). 882 WithBalance(bigBalance, big.Zero()). 883 Build(t) 884 precommitEpoch := periodOffset + 1 885 rt.SetEpoch(precommitEpoch) 886 actor.constructAndVerify(rt) 887 deadline := actor.deadline(rt) 888 889 sectorNo := abi.SectorNumber(100) 890 params := actor.makePreCommit(sectorNo, precommitEpoch-1, deadline.PeriodEnd()+defaultSectorExpiration*miner.WPoStProvingPeriod, nil) 891 precommit := actor.preCommitSector(rt, params, preCommitConf{}, true) 892 893 // precommit at correct epoch 894 rt.SetEpoch(rt.Epoch() + miner.PreCommitChallengeDelay + 1) 895 actor.proveCommitSector(rt, precommit, makeProveCommit(sectorNo)) 896 897 // confirm at sector expiration (this probably can't happen) 898 rt.SetEpoch(precommit.Info.Expiration) 899 // sector skipped but no failure occurs 900 actor.confirmSectorProofsValid(rt, proveCommitConf{}, precommit) 901 rt.ExpectLogsContain("less than minimum. ignoring") 902 903 // it still skips if sector lifetime is negative 904 rt.ClearLogs() 905 rt.SetEpoch(precommit.Info.Expiration + 1) 906 actor.confirmSectorProofsValid(rt, proveCommitConf{}, precommit) 907 rt.ExpectLogsContain("less than minimum. ignoring") 908 909 // it fails up to the miniumum expiration 910 rt.ClearLogs() 911 rt.SetEpoch(precommit.Info.Expiration - miner.MinSectorExpiration + 1) 912 actor.confirmSectorProofsValid(rt, proveCommitConf{}, precommit) 913 rt.ExpectLogsContain("less than minimum. ignoring") 914 actor.checkState(rt) 915 }) 916 917 t.Run("fails with too many deals", func(t *testing.T) { 918 setup := func(proof abi.RegisteredSealProof) (*mock.Runtime, *actorHarness, *dline.Info) { 919 actor := newHarness(t, periodOffset) 920 actor.setProofType(proof) 921 rt := builderForHarness(actor). 922 WithBalance(bigBalance, big.Zero()). 923 Build(t) 924 rt.SetEpoch(periodOffset + 1) 925 actor.constructAndVerify(rt) 926 deadline := actor.deadline(rt) 927 return rt, actor, deadline 928 } 929 930 makeDealIDs := func(n int) []abi.DealID { 931 ids := make([]abi.DealID, n) 932 for i := range ids { 933 ids[i] = abi.DealID(i) 934 } 935 return ids 936 } 937 938 // Make a good commitment for the proof to target. 939 sectorNo := abi.SectorNumber(100) 940 941 dealLimits := map[abi.RegisteredSealProof]int{ 942 abi.RegisteredSealProof_StackedDrg2KiBV1_1: 256, 943 abi.RegisteredSealProof_StackedDrg32GiBV1_1: 256, 944 abi.RegisteredSealProof_StackedDrg64GiBV1_1: 512, 945 } 946 947 for proof, limit := range dealLimits { 948 // attempt to pre-commmit a sector with too many sectors 949 rt, actor, deadline := setup(proof) 950 expiration := deadline.PeriodEnd() + defaultSectorExpiration*miner.WPoStProvingPeriod 951 precommit := actor.makePreCommit(sectorNo, rt.Epoch()-1, expiration, makeDealIDs(limit+1)) 952 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "too many deals for sector", func() { 953 actor.preCommitSector(rt, precommit, preCommitConf{}, true) 954 }) 955 956 // sector at or below limit succeeds 957 rt, actor, _ = setup(proof) 958 precommit = actor.makePreCommit(sectorNo, rt.Epoch()-1, expiration, makeDealIDs(limit)) 959 actor.preCommitSector(rt, precommit, preCommitConf{}, true) 960 actor.checkState(rt) 961 } 962 }) 963 964 t.Run("precommit checks seal proof version", func(t *testing.T) { 965 actor := newHarness(t, periodOffset) 966 actor.setProofType(abi.RegisteredSealProof_StackedDrg32GiBV1) 967 rt := builderForHarness(actor). 968 WithBalance(bigBalance, big.Zero()). 969 Build(t) 970 971 // Create miner before version 7 972 rt.SetNetworkVersion(network.Version6) 973 actor.constructAndVerify(rt) 974 precommitEpoch := periodOffset + 1 975 rt.SetEpoch(precommitEpoch) 976 deadline := actor.deadline(rt) 977 challengeEpoch := precommitEpoch - 1 978 expiration := deadline.PeriodEnd() + defaultSectorExpiration*miner.WPoStProvingPeriod 979 { 980 // After version 7, only V1_1 accepted 981 rt.SetNetworkVersion(network.Version8) 982 pc := actor.makePreCommit(104, challengeEpoch, expiration, nil) 983 pc.SealProof = abi.RegisteredSealProof_StackedDrg32GiBV1 984 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 985 actor.preCommitSector(rt, pc, preCommitConf{}, true) 986 }) 987 rt.Reset() 988 pc.SealProof = abi.RegisteredSealProof_StackedDrg32GiBV1_1 989 actor.preCommitSector(rt, pc, preCommitConf{}, true) 990 } 991 992 actor.checkState(rt) 993 }) 994 } 995 996 // Test sector lifecycle when a sector is upgraded 997 func TestCCUpgrade(t *testing.T) { 998 periodOffset := abi.ChainEpoch(100) 999 t.Run("valid committed capacity upgrade", func(t *testing.T) { 1000 actor := newHarness(t, periodOffset) 1001 rt := builderForHarness(actor). 1002 WithBalance(bigBalance, big.Zero()). 1003 Build(t) 1004 actor.constructAndVerify(rt) 1005 1006 // Move the current epoch forward so that the first deadline is a stable candidate for both sectors 1007 rt.SetEpoch(periodOffset + miner.WPoStChallengeWindow) 1008 1009 // Commit a sector to upgrade 1010 // Use the max sector number to make sure everything works. 1011 oldSector := actor.commitAndProveSector(rt, abi.MaxSectorNumber, defaultSectorExpiration, nil) 1012 1013 // advance cron to activate power. 1014 advanceAndSubmitPoSts(rt, actor, oldSector) 1015 1016 st := getState(rt) 1017 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 1018 require.NoError(t, err) 1019 1020 // Reduce the epoch reward so that a new sector's initial pledge would otherwise be lesser. 1021 // It has to be reduced quite a lot to overcome the new sector having more power due to verified deal weight. 1022 actor.epochRewardSmooth = smoothing.TestingConstantEstimate(big.Div(actor.epochRewardSmooth.Estimate(), big.NewInt(20))) 1023 1024 challengeEpoch := rt.Epoch() - 1 1025 upgradeParams := actor.makePreCommit(200, challengeEpoch, oldSector.Expiration, []abi.DealID{1}) 1026 upgradeParams.ReplaceCapacity = true 1027 upgradeParams.ReplaceSectorDeadline = dlIdx 1028 upgradeParams.ReplaceSectorPartition = partIdx 1029 upgradeParams.ReplaceSectorNumber = oldSector.SectorNumber 1030 upgrade := actor.preCommitSector(rt, upgradeParams, preCommitConf{}, false) 1031 1032 // Check new pre-commit in state 1033 assert.True(t, upgrade.Info.ReplaceCapacity) 1034 assert.Equal(t, upgradeParams.ReplaceSectorNumber, upgrade.Info.ReplaceSectorNumber) 1035 1036 // Old sector is unchanged 1037 oldSectorAgain := actor.getSector(rt, oldSector.SectorNumber) 1038 assert.Equal(t, oldSector, oldSectorAgain) 1039 1040 // Deposit and pledge as expected 1041 st = getState(rt) 1042 assert.Equal(t, st.PreCommitDeposits, upgrade.PreCommitDeposit) 1043 assert.Equal(t, st.InitialPledge, oldSector.InitialPledge) 1044 1045 // Prove new sector 1046 rt.SetEpoch(upgrade.PreCommitEpoch + miner.PreCommitChallengeDelay + 1) 1047 newSector := actor.proveCommitSectorAndConfirm(rt, upgrade, makeProveCommit(upgrade.Info.SectorNumber), proveCommitConf{}) 1048 1049 // Both sectors' deposits are returned, and pledge is committed 1050 st = getState(rt) 1051 assert.Equal(t, big.Zero(), st.PreCommitDeposits) 1052 assert.Equal(t, st.InitialPledge, big.Add(oldSector.InitialPledge, newSector.InitialPledge)) 1053 // new sector pledge is max of computed pledge and pledge from old sector 1054 assert.Equal(t, oldSector.InitialPledge, newSector.InitialPledge) 1055 1056 // Both sectors are present (in the same deadline/partition). 1057 deadline, partition := actor.getDeadlineAndPartition(rt, dlIdx, partIdx) 1058 assert.Equal(t, uint64(2), deadline.TotalSectors) 1059 assert.Equal(t, uint64(2), deadline.LiveSectors) 1060 assertEmptyBitfield(t, deadline.EarlyTerminations) 1061 1062 assertBitfieldEquals(t, partition.Sectors, uint64(newSector.SectorNumber), uint64(oldSector.SectorNumber)) 1063 assertEmptyBitfield(t, partition.Faults) 1064 assertEmptyBitfield(t, partition.Recoveries) 1065 assertEmptyBitfield(t, partition.Terminated) 1066 1067 // The old sector's expiration has changed to the end of this proving deadline. 1068 // The new one expires when the old one used to. 1069 // The partition is registered with an expiry at both epochs. 1070 dQueue := actor.collectDeadlineExpirations(rt, deadline) 1071 dlInfo := miner.NewDeadlineInfo(st.ProvingPeriodStart, dlIdx, rt.Epoch()) 1072 quantizedExpiration := miner.QuantSpecForDeadline(dlInfo).QuantizeUp(oldSector.Expiration) 1073 assert.Equal(t, map[abi.ChainEpoch][]uint64{ 1074 dlInfo.NextNotElapsed().Last(): {uint64(0)}, 1075 quantizedExpiration: {uint64(0)}, 1076 }, dQueue) 1077 1078 pQueue := actor.collectPartitionExpirations(rt, partition) 1079 assertBitfieldEquals(t, pQueue[dlInfo.NextNotElapsed().Last()].OnTimeSectors, uint64(oldSector.SectorNumber)) 1080 assertBitfieldEquals(t, pQueue[quantizedExpiration].OnTimeSectors, uint64(newSector.SectorNumber)) 1081 1082 // Roll forward to the beginning of the next iteration of this deadline 1083 advanceToEpochWithCron(rt, actor, dlInfo.NextNotElapsed().Open) 1084 1085 // Fail to submit PoSt. This means that both sectors will be detected faulty. 1086 // Expect the old sector to be marked as terminated. 1087 bothSectors := []*miner.SectorOnChainInfo{oldSector, newSector} 1088 lostPower := actor.powerPairForSectors(bothSectors[:1]).Neg() // new sector not active yet. 1089 faultExpiration := miner.QuantSpecForDeadline(dlInfo).QuantizeUp(dlInfo.NextNotElapsed().Last() + miner.FaultMaxAge) 1090 1091 advanceDeadline(rt, actor, &cronConfig{ 1092 detectedFaultsPowerDelta: &lostPower, 1093 expiredSectorsPledgeDelta: oldSector.InitialPledge.Neg(), 1094 }) 1095 1096 // The old sector is marked as terminated 1097 st = getState(rt) 1098 deadline, partition = actor.getDeadlineAndPartition(rt, dlIdx, partIdx) 1099 assert.Equal(t, uint64(2), deadline.TotalSectors) 1100 assert.Equal(t, uint64(1), deadline.LiveSectors) 1101 assertBitfieldEquals(t, partition.Sectors, uint64(newSector.SectorNumber), uint64(oldSector.SectorNumber)) 1102 assertBitfieldEquals(t, partition.Terminated, uint64(oldSector.SectorNumber)) 1103 assertBitfieldEquals(t, partition.Faults, uint64(newSector.SectorNumber)) 1104 newSectorPower := miner.PowerForSector(actor.sectorSize, newSector) 1105 assert.True(t, newSectorPower.Equals(partition.LivePower)) 1106 assert.True(t, newSectorPower.Equals(partition.FaultyPower)) 1107 1108 // we expect the partition expiration to be scheduled twice, once early 1109 // and once on-time (inside the partition, the sector is scheduled only once). 1110 dQueue = actor.collectDeadlineExpirations(rt, deadline) 1111 assert.Equal(t, map[abi.ChainEpoch][]uint64{ 1112 miner.QuantSpecForDeadline(dlInfo).QuantizeUp(newSector.Expiration): {uint64(0)}, 1113 faultExpiration: {uint64(0)}, 1114 }, dQueue) 1115 1116 // Old sector gone from pledge requirement and deposit 1117 assert.Equal(t, st.InitialPledge, newSector.InitialPledge) 1118 actor.checkState(rt) 1119 }) 1120 1121 t.Run("invalid committed capacity upgrade rejected", func(t *testing.T) { 1122 actor := newHarness(t, periodOffset) 1123 rt := builderForHarness(actor). 1124 WithBalance(bigBalance, big.Zero()). 1125 Build(t) 1126 actor.constructAndVerify(rt) 1127 1128 // Commit sectors to target upgrade. The first has no deals, the second has a deal. 1129 oldSectors := actor.commitAndProveSectors(rt, 2, defaultSectorExpiration, [][]abi.DealID{nil, {10}}, true) 1130 1131 st := getState(rt) 1132 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSectors[0].SectorNumber) 1133 require.NoError(t, err) 1134 1135 challengeEpoch := rt.Epoch() - 1 1136 upgradeParams := actor.makePreCommit(200, challengeEpoch, oldSectors[0].Expiration, []abi.DealID{20}) 1137 upgradeParams.ReplaceCapacity = true 1138 upgradeParams.ReplaceSectorDeadline = dlIdx 1139 upgradeParams.ReplaceSectorPartition = partIdx 1140 upgradeParams.ReplaceSectorNumber = oldSectors[0].SectorNumber 1141 1142 { // Must have deals 1143 params := *upgradeParams 1144 params.DealIDs = nil 1145 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1146 actor.preCommitSector(rt, ¶ms, preCommitConf{}, false) 1147 }) 1148 rt.Reset() 1149 } 1150 { // Old sector cannot have deals 1151 params := *upgradeParams 1152 params.ReplaceSectorNumber = oldSectors[1].SectorNumber 1153 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1154 actor.preCommitSector(rt, ¶ms, preCommitConf{}, false) 1155 }) 1156 rt.Reset() 1157 } 1158 { // Target sector must exist 1159 params := *upgradeParams 1160 params.ReplaceSectorNumber = 999 1161 rt.ExpectAbort(exitcode.ErrNotFound, func() { 1162 actor.preCommitSector(rt, ¶ms, preCommitConf{}, false) 1163 }) 1164 rt.Reset() 1165 } 1166 { // Target partition must exist 1167 params := *upgradeParams 1168 params.ReplaceSectorPartition = 999 1169 rt.ExpectAbortContainsMessage(exitcode.ErrNotFound, "no partition 999", func() { 1170 actor.preCommitSector(rt, ¶ms, preCommitConf{}, false) 1171 }) 1172 rt.Reset() 1173 } 1174 { // Expiration must not be sooner than target 1175 params := *upgradeParams 1176 params.Expiration = params.Expiration - miner.WPoStProvingPeriod 1177 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 1178 actor.preCommitSector(rt, ¶ms, preCommitConf{}, false) 1179 }) 1180 rt.Reset() 1181 } 1182 { // Target must not be faulty 1183 params := *upgradeParams 1184 st := getState(rt) 1185 prevState := *st 1186 quant := st.QuantSpecForDeadline(dlIdx) 1187 deadlines, err := st.LoadDeadlines(rt.AdtStore()) 1188 require.NoError(t, err) 1189 deadline, err := deadlines.LoadDeadline(rt.AdtStore(), dlIdx) 1190 require.NoError(t, err) 1191 partitions, err := deadline.PartitionsArray(rt.AdtStore()) 1192 require.NoError(t, err) 1193 var partition miner.Partition 1194 found, err := partitions.Get(partIdx, &partition) 1195 require.True(t, found) 1196 require.NoError(t, err) 1197 sectorArr, err := miner.LoadSectors(rt.AdtStore(), st.Sectors) 1198 require.NoError(t, err) 1199 newFaults, _, _, err := partition.RecordFaults(rt.AdtStore(), sectorArr, bf(uint64(oldSectors[0].SectorNumber)), 100000, 1200 actor.sectorSize, quant) 1201 require.NoError(t, err) 1202 assertBitfieldEquals(t, newFaults, uint64(oldSectors[0].SectorNumber)) 1203 require.NoError(t, partitions.Set(partIdx, &partition)) 1204 deadline.Partitions, err = partitions.Root() 1205 require.NoError(t, err) 1206 deadlines.Due[dlIdx] = rt.StorePut(deadline) 1207 require.NoError(t, st.SaveDeadlines(rt.AdtStore(), deadlines)) 1208 // Phew! 1209 1210 rt.ReplaceState(st) 1211 rt.ExpectAbort(exitcode.ErrForbidden, func() { 1212 actor.preCommitSector(rt, ¶ms, preCommitConf{}, false) 1213 }) 1214 rt.ReplaceState(&prevState) 1215 rt.Reset() 1216 } 1217 1218 { // Target must not be terminated 1219 params := *upgradeParams 1220 st := getState(rt) 1221 prevState := *st 1222 quant := st.QuantSpecForDeadline(dlIdx) 1223 deadlines, err := st.LoadDeadlines(rt.AdtStore()) 1224 require.NoError(t, err) 1225 deadline, err := deadlines.LoadDeadline(rt.AdtStore(), dlIdx) 1226 require.NoError(t, err) 1227 partitions, err := deadline.PartitionsArray(rt.AdtStore()) 1228 require.NoError(t, err) 1229 var partition miner.Partition 1230 found, err := partitions.Get(partIdx, &partition) 1231 require.True(t, found) 1232 require.NoError(t, err) 1233 sectorArr, err := miner.LoadSectors(rt.AdtStore(), st.Sectors) 1234 require.NoError(t, err) 1235 result, err := partition.TerminateSectors(rt.AdtStore(), sectorArr, rt.Epoch(), bf(uint64(oldSectors[0].SectorNumber)), 1236 actor.sectorSize, quant) 1237 require.NoError(t, err) 1238 assertBitfieldEquals(t, result.OnTimeSectors, uint64(oldSectors[0].SectorNumber)) 1239 require.NoError(t, partitions.Set(partIdx, &partition)) 1240 deadline.Partitions, err = partitions.Root() 1241 require.NoError(t, err) 1242 deadlines.Due[dlIdx] = rt.StorePut(deadline) 1243 require.NoError(t, st.SaveDeadlines(rt.AdtStore(), deadlines)) 1244 // Phew! 1245 1246 rt.ReplaceState(st) 1247 rt.ExpectAbort(exitcode.ErrNotFound, func() { 1248 actor.preCommitSector(rt, ¶ms, preCommitConf{}, false) 1249 }) 1250 rt.ReplaceState(&prevState) 1251 rt.Reset() 1252 } 1253 1254 // Demonstrate that the params are otherwise ok 1255 actor.preCommitSector(rt, upgradeParams, preCommitConf{}, false) 1256 rt.Verify() 1257 actor.checkState(rt) 1258 }) 1259 1260 t.Run("upgrade sector before it is proven", func(t *testing.T) { 1261 actor := newHarness(t, periodOffset) 1262 rt := builderForHarness(actor). 1263 WithBalance(bigBalance, big.Zero()). 1264 Build(t) 1265 actor.constructAndVerify(rt) 1266 1267 // Move the current epoch forward so that the first deadline is a stable candidate for both sectors 1268 rt.SetEpoch(periodOffset + miner.WPoStChallengeWindow) 1269 1270 // Commit a sector to upgrade 1271 // Use the max sector number to make sure everything works. 1272 oldSector := actor.commitAndProveSector(rt, abi.MaxSectorNumber, defaultSectorExpiration, nil) 1273 1274 st := getState(rt) 1275 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 1276 require.NoError(t, err) 1277 1278 // Reduce the epoch reward so that a new sector's initial pledge would otherwise be lesser. 1279 // It has to be reduced quite a lot to overcome the new sector having more power due to verified deal weight. 1280 actor.epochRewardSmooth = smoothing.TestingConstantEstimate(big.Div(actor.epochRewardSmooth.Estimate(), big.NewInt(20))) 1281 1282 challengeEpoch := rt.Epoch() - 1 1283 upgradeParams := actor.makePreCommit(200, challengeEpoch, oldSector.Expiration, []abi.DealID{1}) 1284 upgradeParams.ReplaceCapacity = true 1285 upgradeParams.ReplaceSectorDeadline = dlIdx 1286 upgradeParams.ReplaceSectorPartition = partIdx 1287 upgradeParams.ReplaceSectorNumber = oldSector.SectorNumber 1288 upgrade := actor.preCommitSector(rt, upgradeParams, preCommitConf{}, false) 1289 1290 // Check new pre-commit in state 1291 assert.True(t, upgrade.Info.ReplaceCapacity) 1292 assert.Equal(t, upgradeParams.ReplaceSectorNumber, upgrade.Info.ReplaceSectorNumber) 1293 1294 // Old sector is unchanged 1295 oldSectorAgain := actor.getSector(rt, oldSector.SectorNumber) 1296 assert.Equal(t, oldSector, oldSectorAgain) 1297 1298 // Deposit and pledge as expected 1299 st = getState(rt) 1300 assert.Equal(t, st.PreCommitDeposits, upgrade.PreCommitDeposit) 1301 assert.Equal(t, st.InitialPledge, oldSector.InitialPledge) 1302 1303 // Prove new sector 1304 rt.SetEpoch(upgrade.PreCommitEpoch + miner.PreCommitChallengeDelay + 1) 1305 newSector := actor.proveCommitSectorAndConfirm(rt, upgrade, makeProveCommit(upgrade.Info.SectorNumber), proveCommitConf{}) 1306 1307 // Both sectors' deposits are returned, and pledge is committed 1308 st = getState(rt) 1309 assert.Equal(t, big.Zero(), st.PreCommitDeposits) 1310 assert.Equal(t, st.InitialPledge, big.Add(oldSector.InitialPledge, newSector.InitialPledge)) 1311 // new sector pledge is max of computed pledge and pledge from old sector 1312 assert.Equal(t, oldSector.InitialPledge, newSector.InitialPledge) 1313 1314 // Both sectors are present (in the same deadline/partition). 1315 deadline, partition := actor.getDeadlineAndPartition(rt, dlIdx, partIdx) 1316 assert.Equal(t, uint64(2), deadline.TotalSectors) 1317 assert.Equal(t, uint64(2), deadline.LiveSectors) 1318 assertEmptyBitfield(t, deadline.EarlyTerminations) 1319 1320 assertBitfieldEquals(t, partition.Sectors, uint64(newSector.SectorNumber), uint64(oldSector.SectorNumber)) 1321 assertEmptyBitfield(t, partition.Faults) 1322 assertEmptyBitfield(t, partition.Recoveries) 1323 assertEmptyBitfield(t, partition.Terminated) 1324 1325 // The old sector's expiration has changed to the end of this proving deadline. 1326 // The new one expires when the old one used to. 1327 // The partition is registered with an expiry at both epochs. 1328 dQueue := actor.collectDeadlineExpirations(rt, deadline) 1329 dlInfo := miner.NewDeadlineInfo(st.ProvingPeriodStart, dlIdx, rt.Epoch()) 1330 quantizedExpiration := miner.QuantSpecForDeadline(dlInfo).QuantizeUp(oldSector.Expiration) 1331 assert.Equal(t, map[abi.ChainEpoch][]uint64{ 1332 dlInfo.NextNotElapsed().Last(): {uint64(0)}, 1333 quantizedExpiration: {uint64(0)}, 1334 }, dQueue) 1335 1336 pQueue := actor.collectPartitionExpirations(rt, partition) 1337 assertBitfieldEquals(t, pQueue[dlInfo.NextNotElapsed().Last()].OnTimeSectors, uint64(oldSector.SectorNumber)) 1338 assertBitfieldEquals(t, pQueue[quantizedExpiration].OnTimeSectors, uint64(newSector.SectorNumber)) 1339 1340 // advance to sector proving deadline 1341 dlInfo = actor.deadline(rt) 1342 for dlIdx != dlInfo.Index { 1343 advanceDeadline(rt, actor, &cronConfig{}) 1344 dlInfo = actor.deadline(rt) 1345 } 1346 1347 // PoSt both sectors. They both gain power and no penalties are incurred. 1348 rt.SetEpoch(dlInfo.Last()) 1349 oldPower := miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), miner.QAPowerForSector(actor.sectorSize, oldSector)) 1350 newPower := miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), miner.QAPowerForSector(actor.sectorSize, newSector)) 1351 expectedPower := oldPower.Add(newPower) 1352 partitions := []miner.PoStPartition{ 1353 {Index: partIdx, Skipped: bitfield.New()}, 1354 } 1355 actor.submitWindowPoSt(rt, dlInfo, partitions, []*miner.SectorOnChainInfo{newSector, oldSector}, &poStConfig{ 1356 expectedPowerDelta: expectedPower, 1357 }) 1358 1359 // replaced sector expires at cron, removing its power and pledge. 1360 expectedPowerDelta := oldPower.Neg() 1361 actor.onDeadlineCron(rt, &cronConfig{ 1362 expiredSectorsPowerDelta: &expectedPowerDelta, 1363 expiredSectorsPledgeDelta: oldSector.InitialPledge.Neg(), 1364 expectedEnrollment: rt.Epoch() + miner.WPoStChallengeWindow, 1365 }) 1366 actor.checkState(rt) 1367 }) 1368 1369 t.Run("declare fault for replaced cc upgrade sector doesn't double subtract power", func(t *testing.T) { 1370 actor := newHarness(t, periodOffset) 1371 rt := builderForHarness(actor). 1372 WithBalance(bigBalance, big.Zero()). 1373 Build(t) 1374 actor.constructAndVerify(rt) 1375 1376 oldSector, newSector := actor.commitProveAndUpgradeSector(rt, 100, 200, defaultSectorExpiration, []abi.DealID{1}) 1377 1378 st := getState(rt) 1379 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 1380 require.NoError(t, err) 1381 1382 advanceToEpochWithCron(rt, actor, rt.Epoch()) 1383 // now declare old sector faulty 1384 actor.declareFaults(rt, oldSector) 1385 1386 pIdx := uint64(0) 1387 deadline, partition := actor.getDeadlineAndPartition(rt, dlIdx, partIdx) 1388 dQueue := actor.collectDeadlineExpirations(rt, deadline) 1389 dlInfo := miner.NewDeadlineInfo(st.ProvingPeriodStart, dlIdx, rt.Epoch()) 1390 expectedReplacedExpiration := miner.QuantSpecForDeadline(dlInfo).QuantizeUp(rt.Epoch() + miner.FaultMaxAge) 1391 quantizedExpiration := miner.QuantSpecForDeadline(dlInfo).QuantizeUp(oldSector.Expiration) 1392 1393 // deadling marks expirations for partition at expiration epoch 1394 assert.Equal(t, map[abi.ChainEpoch][]uint64{ 1395 dlInfo.NextNotElapsed().Last(): {pIdx}, 1396 expectedReplacedExpiration: {pIdx}, 1397 quantizedExpiration: {pIdx}, 1398 }, dQueue) 1399 1400 // but partitions expiration set at that epoch is empty 1401 queue, err := miner.LoadExpirationQueue(rt.AdtStore(), partition.ExpirationsEpochs, miner.QuantSpecForDeadline(dlInfo), miner.PartitionExpirationAmtBitwidth) 1402 require.NoError(t, err) 1403 var es miner.ExpirationSet 1404 expirationSetNotEmpty, err := queue.Get(uint64(expectedReplacedExpiration), &es) 1405 require.NoError(t, err) 1406 assert.False(t, expirationSetNotEmpty) 1407 1408 // advance to sector proving deadline 1409 dlInfo = actor.deadline(rt) 1410 for dlIdx != dlInfo.Index { 1411 advanceDeadline(rt, actor, &cronConfig{}) 1412 dlInfo = actor.deadline(rt) 1413 } 1414 1415 // submit post for new sector. Power is added for new sector and no penalties are paid yet 1416 rt.SetEpoch(dlInfo.Last()) 1417 newPower := miner.QAPowerForSector(actor.sectorSize, newSector) 1418 partitions := []miner.PoStPartition{ 1419 {Index: pIdx, Skipped: bitfield.New()}, 1420 } 1421 // Old sector is faulty, so expect new sector twice in PoSt. 1422 actor.submitWindowPoSt(rt, dlInfo, partitions, []*miner.SectorOnChainInfo{newSector, newSector}, &poStConfig{ 1423 expectedPowerDelta: miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), newPower), 1424 }) 1425 1426 // At proving period cron expect to pay declared fee for old sector 1427 // and to have its pledge requirement deducted indicating it has expired. 1428 // Importantly, power is NOT removed, because it was taken when fault was declared. 1429 oldPower := miner.QAPowerForSector(actor.sectorSize, oldSector) 1430 expectedFee := miner.PledgePenaltyForContinuedFault(actor.epochRewardSmooth, actor.epochQAPowerSmooth, oldPower) 1431 expectedPowerDelta := miner.NewPowerPairZero() 1432 actor.applyRewards(rt, bigRewards, big.Zero()) 1433 actor.onDeadlineCron(rt, &cronConfig{ 1434 continuedFaultsPenalty: expectedFee, 1435 expiredSectorsPledgeDelta: oldSector.InitialPledge.Neg(), 1436 expiredSectorsPowerDelta: &expectedPowerDelta, 1437 expectedEnrollment: rt.Epoch() + miner.WPoStChallengeWindow, 1438 }) 1439 actor.checkState(rt) 1440 }) 1441 1442 t.Run("skip replaced sector in its last PoSt", func(t *testing.T) { 1443 actor := newHarness(t, periodOffset) 1444 rt := builderForHarness(actor). 1445 WithBalance(bigBalance, big.Zero()). 1446 Build(t) 1447 actor.constructAndVerify(rt) 1448 actor.applyRewards(rt, bigRewards, big.Zero()) 1449 1450 oldSector, newSector := actor.commitProveAndUpgradeSector(rt, 100, 200, defaultSectorExpiration, []abi.DealID{1}) 1451 1452 st := getState(rt) 1453 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 1454 require.NoError(t, err) 1455 1456 // advance to sector proving deadline 1457 dlInfo := actor.deadline(rt) 1458 for dlIdx != dlInfo.Index { 1459 advanceDeadline(rt, actor, &cronConfig{}) 1460 dlInfo = actor.deadline(rt) 1461 } 1462 1463 // skip old sector when submitting post. Expect newSector to fill place of old sector in proof. 1464 // Miner should gain power for new sector, lose power for old sector (with no penalty). 1465 rt.SetEpoch(dlInfo.Last()) 1466 1467 oldQAPower := miner.QAPowerForSector(actor.sectorSize, oldSector) 1468 newQAPower := miner.QAPowerForSector(actor.sectorSize, newSector) 1469 expectedPowerDelta := miner.NewPowerPair(big.Zero(), big.Sub(newQAPower, oldQAPower)) 1470 1471 partitions := []miner.PoStPartition{ 1472 {Index: pIdx, Skipped: bf(uint64(oldSector.SectorNumber))}, 1473 } 1474 actor.submitWindowPoSt(rt, dlInfo, partitions, []*miner.SectorOnChainInfo{newSector, newSector}, &poStConfig{ 1475 expectedPowerDelta: expectedPowerDelta, 1476 }) 1477 1478 // At proving period cron expect to pay continued fee for old (now faulty) sector 1479 // and to have its pledge requirement deducted indicating it has expired. 1480 // Importantly, power is NOT removed, because it was taken when sector was skipped in Windowe PoSt. 1481 faultFee := miner.PledgePenaltyForContinuedFault(actor.epochRewardSmooth, actor.epochQAPowerSmooth, oldQAPower) 1482 1483 actor.onDeadlineCron(rt, &cronConfig{ 1484 continuedFaultsPenalty: faultFee, 1485 expiredSectorsPledgeDelta: oldSector.InitialPledge.Neg(), 1486 expectedEnrollment: rt.Epoch() + miner.WPoStChallengeWindow, 1487 }) 1488 actor.checkState(rt) 1489 }) 1490 1491 t.Run("skip PoSt altogether on replaced sector expiry", func(t *testing.T) { 1492 actor := newHarness(t, periodOffset) 1493 rt := builderForHarness(actor). 1494 WithBalance(bigBalance, big.Zero()). 1495 Build(t) 1496 actor.constructAndVerify(rt) 1497 1498 oldSector, _ := actor.commitProveAndUpgradeSector(rt, 100, 200, defaultSectorExpiration, []abi.DealID{1}) 1499 1500 st := getState(rt) 1501 dlIdx, _, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 1502 require.NoError(t, err) 1503 1504 // advance to sector proving deadline 1505 dlInfo := actor.deadline(rt) 1506 for dlIdx != dlInfo.Index { 1507 advanceDeadline(rt, actor, &cronConfig{}) 1508 dlInfo = actor.deadline(rt) 1509 } 1510 rt.SetEpoch(dlInfo.Last()) 1511 1512 // do not PoSt 1513 // expect old sector to lose power (new sector hasn't added any yet) 1514 // both sectors are detected faulty for the first time, with no penalty. 1515 oldQAPower := miner.QAPowerForSector(actor.sectorSize, oldSector) 1516 expectedPowerDelta := miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), oldQAPower).Neg() 1517 1518 // At cron, expect both sectors to be treated as undeclared faults. 1519 // The replaced sector will expire anyway, so its pledge will be removed. 1520 actor.onDeadlineCron(rt, &cronConfig{ 1521 expiredSectorsPowerDelta: &expectedPowerDelta, 1522 expiredSectorsPledgeDelta: oldSector.InitialPledge.Neg(), 1523 expectedEnrollment: rt.Epoch() + miner.WPoStChallengeWindow, 1524 }) 1525 actor.checkState(rt) 1526 }) 1527 1528 t.Run("terminate replaced sector early", func(t *testing.T) { 1529 actor := newHarness(t, periodOffset) 1530 rt := builderForHarness(actor). 1531 WithBalance(bigBalance, big.Zero()). 1532 Build(t) 1533 actor.constructAndVerify(rt) 1534 1535 // create sector and upgrade it 1536 oldSector, newSector := actor.commitProveAndUpgradeSector(rt, 100, 200, defaultSectorExpiration, []abi.DealID{1}) 1537 1538 st := getState(rt) 1539 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 1540 require.NoError(t, err) 1541 1542 // now terminate replaced sector 1543 sectorPower := miner.QAPowerForSector(actor.sectorSize, oldSector) 1544 expectedFee := miner.PledgePenaltyForTermination(oldSector.ExpectedDayReward, rt.Epoch()-oldSector.Activation, 1545 oldSector.ExpectedStoragePledge, actor.epochQAPowerSmooth, sectorPower, actor.epochRewardSmooth, 1546 oldSector.ReplacedDayReward, oldSector.ReplacedSectorAge) 1547 actor.applyRewards(rt, bigRewards, big.Zero()) 1548 powerDelta, pledgeDelta := actor.terminateSectors(rt, bf(uint64(oldSector.SectorNumber)), expectedFee) 1549 1550 // power and pledge should have been removed 1551 assert.Equal(t, miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), sectorPower).Neg(), powerDelta) 1552 assert.Equal(t, big.Sum(oldSector.InitialPledge.Neg(), expectedFee.Neg()), pledgeDelta) 1553 1554 // advance to sector proving deadline 1555 dlInfo := actor.deadline(rt) 1556 for dlIdx != dlInfo.Index { 1557 advanceDeadline(rt, actor, &cronConfig{}) 1558 dlInfo = actor.deadline(rt) 1559 } 1560 1561 // oldSector is no longer active, so expect newSector twice in validation; once for its proof and once 1562 // to replace oldSector. Power is added for new sector and no penalties are paid. 1563 rt.SetEpoch(dlInfo.Last()) 1564 newPower := miner.QAPowerForSector(actor.sectorSize, newSector) 1565 partitions := []miner.PoStPartition{ 1566 {Index: partIdx, Skipped: bitfield.New()}, 1567 } 1568 actor.submitWindowPoSt(rt, dlInfo, partitions, []*miner.SectorOnChainInfo{newSector, newSector}, &poStConfig{ 1569 expectedPowerDelta: miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), newPower), 1570 }) 1571 1572 // Nothing interesting happens at cron. 1573 // Importantly, power and pledge are NOT removed. This happened when sector was terminated 1574 actor.onDeadlineCron(rt, &cronConfig{ 1575 expectedEnrollment: rt.Epoch() + miner.WPoStChallengeWindow, 1576 }) 1577 actor.checkState(rt) 1578 }) 1579 1580 t.Run("extend a replaced sector's expiration", func(t *testing.T) { 1581 actor := newHarness(t, periodOffset) 1582 rt := builderForHarness(actor). 1583 WithBalance(bigBalance, big.Zero()). 1584 Build(t) 1585 actor.constructAndVerify(rt) 1586 1587 // create sector and upgrade it 1588 oldSector, newSector := actor.commitProveAndUpgradeSector(rt, 100, 200, defaultSectorExpiration, []abi.DealID{1}) 1589 1590 st := getState(rt) 1591 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 1592 require.NoError(t, err) 1593 1594 params := &miner.ExtendSectorExpirationParams{ 1595 Extensions: []miner.ExpirationExtension{{ 1596 Deadline: dlIdx, 1597 Partition: partIdx, 1598 Sectors: bf(uint64(oldSector.SectorNumber)), 1599 NewExpiration: rt.Epoch() + 250*builtin.EpochsInDay, 1600 }}, 1601 } 1602 actor.extendSectors(rt, params) 1603 1604 // advance to sector proving deadline 1605 dlInfo := actor.deadline(rt) 1606 for dlIdx != dlInfo.Index { 1607 advanceDeadline(rt, actor, &cronConfig{}) 1608 dlInfo = actor.deadline(rt) 1609 } 1610 1611 // both sectors are now active and not set to expire 1612 rt.SetEpoch(dlInfo.Last()) 1613 newPower := miner.QAPowerForSector(actor.sectorSize, newSector) 1614 partitions := []miner.PoStPartition{ 1615 {Index: partIdx, Skipped: bitfield.New()}, 1616 } 1617 actor.submitWindowPoSt(rt, dlInfo, partitions, []*miner.SectorOnChainInfo{oldSector, newSector}, &poStConfig{ 1618 expectedPowerDelta: miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), newPower), 1619 }) 1620 1621 // Nothing interesting happens at cron because both sectors are active 1622 actor.onDeadlineCron(rt, &cronConfig{ 1623 expectedEnrollment: rt.Epoch() + miner.WPoStChallengeWindow, 1624 }) 1625 1626 actor.checkState(rt) 1627 }) 1628 1629 t.Run("fault and recover a replaced sector", func(t *testing.T) { 1630 actor := newHarness(t, periodOffset) 1631 rt := builderForHarness(actor). 1632 WithBalance(bigBalance, big.Zero()). 1633 Build(t) 1634 actor.constructAndVerify(rt) 1635 1636 // create sector and upgrade it 1637 oldSector, newSector := actor.commitProveAndUpgradeSector(rt, 100, 200, defaultSectorExpiration, []abi.DealID{1}) 1638 1639 advanceToEpochWithCron(rt, actor, rt.Epoch()) 1640 1641 // declare replaced sector faulty 1642 powerDelta := actor.declareFaults(rt, oldSector) 1643 1644 // power for old sector should have been removed 1645 oldQAPower := miner.QAPowerForSector(actor.sectorSize, oldSector) 1646 oldSectorPower := miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), oldQAPower) 1647 assert.Equal(t, oldSectorPower.Neg(), powerDelta) 1648 1649 st := getState(rt) 1650 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 1651 require.NoError(t, err) 1652 1653 // recover replaced sector 1654 actor.declareRecoveries(rt, dlIdx, partIdx, bf(uint64(oldSector.SectorNumber)), big.Zero()) 1655 1656 // advance to sector proving deadline 1657 dlInfo := actor.deadline(rt) 1658 for dlIdx != dlInfo.Index { 1659 advanceDeadline(rt, actor, &cronConfig{}) 1660 dlInfo = actor.deadline(rt) 1661 } 1662 1663 // both sectors now need to be proven. 1664 // Upon success, new sector will gain power and replaced sector will briefly regain power. 1665 rt.SetEpoch(dlInfo.Last()) 1666 newQAPower := miner.QAPowerForSector(actor.sectorSize, newSector) 1667 newSectorPower := miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), newQAPower) 1668 expectedPowerDelta := oldSectorPower.Add(newSectorPower) 1669 1670 partitions := []miner.PoStPartition{ 1671 {Index: partIdx, Skipped: bitfield.New()}, 1672 } 1673 actor.submitWindowPoSt(rt, dlInfo, partitions, []*miner.SectorOnChainInfo{oldSector, newSector}, &poStConfig{ 1674 expectedPowerDelta: expectedPowerDelta, 1675 }) 1676 1677 // At cron replaced sector's power is removed because it expires, and its initial pledge is removed 1678 expectedPowerDelta = oldSectorPower.Neg() 1679 actor.onDeadlineCron(rt, &cronConfig{ 1680 expiredSectorsPowerDelta: &expectedPowerDelta, 1681 expiredSectorsPledgeDelta: oldSector.InitialPledge.Neg(), 1682 expectedEnrollment: rt.Epoch() + miner.WPoStChallengeWindow, 1683 }) 1684 actor.checkState(rt) 1685 }) 1686 1687 t.Run("try to upgrade committed capacity sector twice", func(t *testing.T) { 1688 actor := newHarness(t, periodOffset) 1689 rt := builderForHarness(actor). 1690 WithBalance(bigBalance, big.Zero()). 1691 Build(t) 1692 actor.constructAndVerify(rt) 1693 1694 // Move the current epoch forward so that the first deadline is a stable candidate for both sectors 1695 rt.SetEpoch(periodOffset + miner.WPoStChallengeWindow) 1696 1697 // Commit a sector to upgrade 1698 // Use the max sector number to make sure everything works. 1699 oldSector := actor.commitAndProveSector(rt, abi.MaxSectorNumber, defaultSectorExpiration, nil) 1700 1701 // advance cron to activate power. 1702 advanceAndSubmitPoSts(rt, actor, oldSector) 1703 1704 st := getState(rt) 1705 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 1706 require.NoError(t, err) 1707 1708 // Reduce the epoch reward so that a new sector's initial pledge would otherwise be lesser. 1709 actor.epochRewardSmooth = smoothing.TestingConstantEstimate(big.Div(actor.epochRewardSmooth.Estimate(), big.NewInt(20))) 1710 1711 challengeEpoch := rt.Epoch() - 1 1712 1713 // Upgrade 1 1714 upgradeParams1 := actor.makePreCommit(200, challengeEpoch, oldSector.Expiration, []abi.DealID{1}) 1715 upgradeParams1.ReplaceCapacity = true 1716 upgradeParams1.ReplaceSectorDeadline = dlIdx 1717 upgradeParams1.ReplaceSectorPartition = partIdx 1718 upgradeParams1.ReplaceSectorNumber = oldSector.SectorNumber 1719 upgrade1 := actor.preCommitSector(rt, upgradeParams1, preCommitConf{}, false) 1720 1721 // Check new pre-commit in state 1722 assert.True(t, upgrade1.Info.ReplaceCapacity) 1723 assert.Equal(t, upgradeParams1.ReplaceSectorNumber, upgrade1.Info.ReplaceSectorNumber) 1724 1725 // Upgrade 2 1726 upgradeParams2 := actor.makePreCommit(201, challengeEpoch, oldSector.Expiration, []abi.DealID{1}) 1727 upgradeParams2.ReplaceCapacity = true 1728 upgradeParams2.ReplaceSectorDeadline = dlIdx 1729 upgradeParams2.ReplaceSectorPartition = partIdx 1730 upgradeParams2.ReplaceSectorNumber = oldSector.SectorNumber 1731 upgrade2 := actor.preCommitSector(rt, upgradeParams2, preCommitConf{}, false) 1732 1733 // Check new pre-commit in state 1734 assert.True(t, upgrade2.Info.ReplaceCapacity) 1735 assert.Equal(t, upgradeParams2.ReplaceSectorNumber, upgrade2.Info.ReplaceSectorNumber) 1736 1737 // Old sector is unchanged 1738 oldSectorAgain := actor.getSector(rt, oldSector.SectorNumber) 1739 assert.Equal(t, oldSector, oldSectorAgain) 1740 1741 // Deposit and pledge as expected 1742 st = getState(rt) 1743 assert.Equal(t, st.PreCommitDeposits, big.Add(upgrade1.PreCommitDeposit, upgrade2.PreCommitDeposit)) 1744 assert.Equal(t, st.InitialPledge, oldSector.InitialPledge) 1745 1746 // Prove new sectors 1747 rt.SetEpoch(upgrade1.PreCommitEpoch + miner.PreCommitChallengeDelay + 1) 1748 actor.proveCommitSector(rt, upgrade1, makeProveCommit(upgrade1.Info.SectorNumber)) 1749 actor.proveCommitSector(rt, upgrade2, makeProveCommit(upgrade2.Info.SectorNumber)) 1750 1751 // confirm both. 1752 actor.confirmSectorProofsValid(rt, proveCommitConf{}, upgrade1, upgrade2) 1753 1754 newSector1 := actor.getSector(rt, upgrade1.Info.SectorNumber) 1755 newSector2 := actor.getSector(rt, upgrade2.Info.SectorNumber) 1756 1757 // All three sectors pre-commit deposits are released, and have pledge committed. 1758 st = getState(rt) 1759 assert.Equal(t, big.Zero(), st.PreCommitDeposits) 1760 assert.Equal(t, st.InitialPledge, big.Sum( 1761 oldSector.InitialPledge, newSector1.InitialPledge, newSector2.InitialPledge, 1762 )) 1763 // Both new sectors' pledge are at least the old sector's pledge 1764 assert.Equal(t, oldSector.InitialPledge, newSector1.InitialPledge) 1765 assert.Equal(t, oldSector.InitialPledge, newSector2.InitialPledge) 1766 1767 // All three sectors are present (in the same deadline/partition). 1768 deadline, partition := actor.getDeadlineAndPartition(rt, dlIdx, partIdx) 1769 assert.Equal(t, uint64(3), deadline.TotalSectors) 1770 assert.Equal(t, uint64(3), deadline.LiveSectors) 1771 assertEmptyBitfield(t, deadline.EarlyTerminations) 1772 1773 assertBitfieldEquals(t, partition.Sectors, 1774 uint64(newSector1.SectorNumber), 1775 uint64(newSector2.SectorNumber), 1776 uint64(oldSector.SectorNumber)) 1777 assertEmptyBitfield(t, partition.Faults) 1778 assertEmptyBitfield(t, partition.Recoveries) 1779 assertEmptyBitfield(t, partition.Terminated) 1780 1781 // The old sector's expiration has changed to the end of this proving deadline. 1782 // The new one expires when the old one used to. 1783 // The partition is registered with an expiry at both epochs. 1784 dQueue := actor.collectDeadlineExpirations(rt, deadline) 1785 dlInfo := miner.NewDeadlineInfo(st.ProvingPeriodStart, dlIdx, rt.Epoch()) 1786 quantizedExpiration := miner.QuantSpecForDeadline(dlInfo).QuantizeUp(oldSector.Expiration) 1787 assert.Equal(t, map[abi.ChainEpoch][]uint64{ 1788 dlInfo.NextNotElapsed().Last(): {uint64(0)}, 1789 quantizedExpiration: {uint64(0)}, 1790 }, dQueue) 1791 1792 pQueue := actor.collectPartitionExpirations(rt, partition) 1793 assertBitfieldEquals(t, pQueue[dlInfo.NextNotElapsed().Last()].OnTimeSectors, uint64(oldSector.SectorNumber)) 1794 assertBitfieldEquals(t, pQueue[quantizedExpiration].OnTimeSectors, 1795 uint64(newSector1.SectorNumber), uint64(newSector2.SectorNumber), 1796 ) 1797 1798 // Roll forward to the beginning of the next iteration of this deadline 1799 advanceToEpochWithCron(rt, actor, dlInfo.NextNotElapsed().Open) 1800 1801 // Fail to submit PoSt. This means that both sectors will be detected faulty (no penalty). 1802 // Expect the old sector to be marked as terminated. 1803 allSectors := []*miner.SectorOnChainInfo{oldSector, newSector1, newSector2} 1804 lostPower := actor.powerPairForSectors(allSectors[:1]).Neg() // new sectors not active yet. 1805 faultExpiration := miner.QuantSpecForDeadline(dlInfo).QuantizeUp(dlInfo.NextNotElapsed().Last() + miner.FaultMaxAge) 1806 1807 advanceDeadline(rt, actor, &cronConfig{ 1808 detectedFaultsPowerDelta: &lostPower, 1809 expiredSectorsPledgeDelta: oldSector.InitialPledge.Neg(), 1810 }) 1811 1812 // The old sector is marked as terminated 1813 st = getState(rt) 1814 deadline, partition = actor.getDeadlineAndPartition(rt, dlIdx, partIdx) 1815 assert.Equal(t, uint64(3), deadline.TotalSectors) 1816 assert.Equal(t, uint64(2), deadline.LiveSectors) 1817 assertBitfieldEquals(t, partition.Sectors, 1818 uint64(newSector1.SectorNumber), 1819 uint64(newSector2.SectorNumber), 1820 uint64(oldSector.SectorNumber), 1821 ) 1822 assertBitfieldEquals(t, partition.Terminated, uint64(oldSector.SectorNumber)) 1823 assertBitfieldEquals(t, partition.Faults, 1824 uint64(newSector1.SectorNumber), 1825 uint64(newSector2.SectorNumber), 1826 ) 1827 newPower := miner.PowerForSectors(actor.sectorSize, allSectors[1:]) 1828 assert.True(t, newPower.Equals(partition.LivePower)) 1829 assert.True(t, newPower.Equals(partition.FaultyPower)) 1830 1831 // we expect the expiration to be scheduled twice, once early 1832 // and once on-time. 1833 dQueue = actor.collectDeadlineExpirations(rt, deadline) 1834 assert.Equal(t, map[abi.ChainEpoch][]uint64{ 1835 miner.QuantSpecForDeadline(dlInfo).QuantizeUp(newSector1.Expiration): {uint64(0)}, 1836 faultExpiration: {uint64(0)}, 1837 }, dQueue) 1838 1839 // Old sector gone from pledge 1840 assert.Equal(t, st.InitialPledge, big.Add(newSector1.InitialPledge, newSector2.InitialPledge)) 1841 actor.checkState(rt) 1842 }) 1843 } 1844 1845 func TestWindowPost(t *testing.T) { 1846 periodOffset := abi.ChainEpoch(100) 1847 actor := newHarness(t, periodOffset) 1848 actor.setProofType(abi.RegisteredSealProof_StackedDrg2KiBV1_1) 1849 precommitEpoch := abi.ChainEpoch(1) 1850 builder := builderForHarness(actor). 1851 WithEpoch(precommitEpoch). 1852 WithBalance(bigBalance, big.Zero()) 1853 1854 testBasicPoSt := func(disputeSucceed bool) { 1855 proofs := makePoStProofs(actor.windowPostProofType) 1856 1857 rt := builder.Build(t) 1858 actor.constructAndVerify(rt) 1859 store := rt.AdtStore() 1860 sector := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true)[0] 1861 pwr := miner.PowerForSector(actor.sectorSize, sector) 1862 1863 st := getState(rt) 1864 dlIdx, pIdx, err := st.FindSector(store, sector.SectorNumber) 1865 require.NoError(t, err) 1866 1867 // Skip over deadlines until the beginning of the one with the new sector 1868 dlinfo := actor.deadline(rt) 1869 for dlinfo.Index != dlIdx { 1870 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 1871 } 1872 1873 // Submit PoSt 1874 partitions := []miner.PoStPartition{ 1875 {Index: pIdx, Skipped: bitfield.New()}, 1876 } 1877 actor.submitWindowPoStRaw(rt, dlinfo, partitions, []*miner.SectorOnChainInfo{sector}, proofs, &poStConfig{ 1878 expectedPowerDelta: pwr, 1879 }) 1880 1881 // Verify proof recorded 1882 deadline := actor.getDeadline(rt, dlIdx) 1883 assertBitfieldEquals(t, deadline.PartitionsPoSted, pIdx) 1884 1885 postsCid := deadline.OptimisticPoStSubmissions 1886 1887 posts, err := adt.AsArray(store, postsCid, miner.DeadlineOptimisticPoStSubmissionsAmtBitwidth) 1888 require.NoError(t, err) 1889 require.EqualValues(t, posts.Length(), 1) 1890 var post miner.WindowedPoSt 1891 found, err := posts.Get(0, &post) 1892 require.NoError(t, err) 1893 require.True(t, found) 1894 assertBitfieldEquals(t, post.Partitions, pIdx) 1895 1896 // Advance to end-of-deadline cron to verify no penalties. 1897 advanceDeadline(rt, actor, &cronConfig{}) 1898 actor.checkState(rt) 1899 1900 deadline = actor.getDeadline(rt, dlIdx) 1901 1902 // Proofs should exist in snapshot. 1903 require.Equal(t, deadline.OptimisticPoStSubmissionsSnapshot, postsCid) 1904 1905 var result *poStDisputeResult 1906 if disputeSucceed { 1907 expectedFee := miner.PledgePenaltyForInvalidWindowPoSt(actor.epochRewardSmooth, actor.epochQAPowerSmooth, pwr.QA) 1908 result = &poStDisputeResult{ 1909 expectedPowerDelta: pwr.Neg(), 1910 expectedPenalty: expectedFee, 1911 expectedReward: miner.BaseRewardForDisputedWindowPoSt, 1912 expectedPledgeDelta: big.Zero(), 1913 } 1914 } 1915 actor.disputeWindowPoSt(rt, dlinfo, 0, []*miner.SectorOnChainInfo{sector}, result) 1916 } 1917 1918 t.Run("test proof", func(t *testing.T) { 1919 testBasicPoSt(true) 1920 }) 1921 1922 t.Run("test bad proof accepted and disputed", func(t *testing.T) { 1923 testBasicPoSt(false) 1924 }) 1925 1926 t.Run("test duplicate proof rejected", func(t *testing.T) { 1927 rt := builder.Build(t) 1928 actor.constructAndVerify(rt) 1929 store := rt.AdtStore() 1930 sector := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true)[0] 1931 pwr := miner.PowerForSector(actor.sectorSize, sector) 1932 1933 st := getState(rt) 1934 dlIdx, pIdx, err := st.FindSector(store, sector.SectorNumber) 1935 require.NoError(t, err) 1936 1937 // Skip over deadlines until the beginning of the one with the new sector 1938 dlinfo := actor.deadline(rt) 1939 for dlinfo.Index != dlIdx { 1940 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 1941 } 1942 1943 // Submit PoSt 1944 partitions := []miner.PoStPartition{ 1945 {Index: pIdx, Skipped: bitfield.New()}, 1946 } 1947 actor.submitWindowPoSt(rt, dlinfo, partitions, []*miner.SectorOnChainInfo{sector}, &poStConfig{ 1948 expectedPowerDelta: pwr, 1949 }) 1950 1951 // Verify proof recorded 1952 deadline := actor.getDeadline(rt, dlIdx) 1953 assertBitfieldEquals(t, deadline.PartitionsPoSted, pIdx) 1954 1955 // Submit a duplicate proof for the same partition. This will be rejected because after ignoring the 1956 // already-proven partition, there are no sectors remaining. 1957 // The skipped fault declared here has no effect. 1958 commitRand := abi.Randomness("chaincommitment") 1959 params := miner.SubmitWindowedPoStParams{ 1960 Deadline: dlIdx, 1961 Partitions: []miner.PoStPartition{{ 1962 Index: pIdx, 1963 Skipped: bf(uint64(sector.SectorNumber)), 1964 }}, 1965 Proofs: makePoStProofs(actor.windowPostProofType), 1966 ChainCommitEpoch: dlinfo.Challenge, 1967 ChainCommitRand: commitRand, 1968 } 1969 expectQueryNetworkInfo(rt, actor) 1970 rt.SetCaller(actor.worker, builtin.AccountActorCodeID) 1971 1972 // From version 7, a duplicate is explicitly rejected. 1973 rt.ExpectValidateCallerAddr(append(actor.controlAddrs, actor.owner, actor.worker)...) 1974 rt.ExpectGetRandomnessTickets(crypto.DomainSeparationTag_PoStChainCommit, dlinfo.Challenge, nil, commitRand) 1975 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "partition already proven", func() { 1976 rt.Call(actor.a.SubmitWindowedPoSt, ¶ms) 1977 }) 1978 rt.Reset() 1979 1980 // Advance to end-of-deadline cron to verify no penalties. 1981 advanceDeadline(rt, actor, &cronConfig{}) 1982 actor.checkState(rt) 1983 }) 1984 1985 t.Run("test duplicate proof rejected with many partitions", func(t *testing.T) { 1986 rt := builder.Build(t) 1987 actor.constructAndVerify(rt) 1988 store := rt.AdtStore() 1989 // Commit more sectors than fit in one partition in every eligible deadline, overflowing to a second partition. 1990 sectorsToCommit := ((miner.WPoStPeriodDeadlines - 2) * actor.partitionSize) + 1 1991 sectors := actor.commitAndProveSectors(rt, int(sectorsToCommit), defaultSectorExpiration, nil, true) 1992 lastSector := sectors[len(sectors)-1] 1993 1994 st := getState(rt) 1995 dlIdx, pIdx, err := st.FindSector(store, lastSector.SectorNumber) 1996 require.NoError(t, err) 1997 require.Equal(t, uint64(2), dlIdx) // Deadlines 0 and 1 are empty (no PoSt needed) because excluded by proximity 1998 require.Equal(t, uint64(1), pIdx) // Overflowed from partition 0 to partition 1 1999 2000 // Skip over deadlines until the beginning of the one with two partitions 2001 dlinfo := actor.deadline(rt) 2002 for dlinfo.Index != dlIdx { 2003 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2004 } 2005 2006 { 2007 // Submit PoSt for partition 0 on its own. 2008 partitions := []miner.PoStPartition{ 2009 {Index: 0, Skipped: bitfield.New()}, 2010 } 2011 sectorsToProve := sectors[:actor.partitionSize] 2012 pwr := miner.PowerForSectors(actor.sectorSize, sectorsToProve) 2013 actor.submitWindowPoSt(rt, dlinfo, partitions, sectorsToProve, &poStConfig{ 2014 expectedPowerDelta: pwr, 2015 }) 2016 // Verify proof recorded 2017 deadline := actor.getDeadline(rt, dlIdx) 2018 assertBitfieldEquals(t, deadline.PartitionsPoSted, 0) 2019 } 2020 { 2021 // Attempt PoSt for both partitions, thus duplicating proof for partition 0, so rejected 2022 partitions := []miner.PoStPartition{ 2023 {Index: 0, Skipped: bitfield.New()}, 2024 {Index: 1, Skipped: bitfield.New()}, 2025 } 2026 sectorsToProve := append(sectors[:actor.partitionSize], lastSector) 2027 pwr := miner.PowerForSectors(actor.sectorSize, sectorsToProve) 2028 2029 // From network version 7, the miner outright rejects attempts to prove a partition twice. 2030 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "partition already proven", func() { 2031 actor.submitWindowPoSt(rt, dlinfo, partitions, sectorsToProve, &poStConfig{ 2032 expectedPowerDelta: pwr, 2033 }) 2034 }) 2035 rt.Reset() 2036 } 2037 { 2038 // Submit PoSt for partition 1 on its own is ok. 2039 partitions := []miner.PoStPartition{ 2040 {Index: 1, Skipped: bitfield.New()}, 2041 } 2042 sectorsToProve := []*miner.SectorOnChainInfo{lastSector} 2043 pwr := miner.PowerForSectors(actor.sectorSize, sectorsToProve) 2044 actor.submitWindowPoSt(rt, dlinfo, partitions, sectorsToProve, &poStConfig{ 2045 expectedPowerDelta: pwr, 2046 }) 2047 // Verify both proofs now recorded 2048 deadline := actor.getDeadline(rt, dlIdx) 2049 assertBitfieldEquals(t, deadline.PartitionsPoSted, 0, 1) 2050 } 2051 2052 // Advance to end-of-deadline cron to verify no penalties. 2053 advanceDeadline(rt, actor, &cronConfig{}) 2054 actor.checkState(rt) 2055 }) 2056 2057 t.Run("successful recoveries recover power", func(t *testing.T) { 2058 rt := builder.Build(t) 2059 2060 actor.constructAndVerify(rt) 2061 infos := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 2062 pwr := miner.PowerForSectors(actor.sectorSize, infos) 2063 2064 actor.applyRewards(rt, bigRewards, big.Zero()) 2065 initialLocked := actor.getLockedFunds(rt) 2066 2067 // Submit first PoSt to ensure we are sufficiently early to add a fault 2068 // advance to next proving period 2069 advanceAndSubmitPoSts(rt, actor, infos[0]) 2070 2071 // advance deadline and declare fault 2072 advanceDeadline(rt, actor, &cronConfig{}) 2073 actor.declareFaults(rt, infos...) 2074 2075 // advance a deadline and declare recovery 2076 advanceDeadline(rt, actor, &cronConfig{}) 2077 2078 // declare recovery 2079 st := getState(rt) 2080 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), infos[0].SectorNumber) 2081 require.NoError(t, err) 2082 actor.declareRecoveries(rt, dlIdx, pIdx, bf(uint64(infos[0].SectorNumber)), big.Zero()) 2083 2084 // advance to epoch when submitPoSt is due 2085 dlinfo := actor.deadline(rt) 2086 for dlinfo.Index != dlIdx { 2087 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2088 } 2089 2090 // Now submit PoSt 2091 // Power should return for recovered sector. 2092 cfg := &poStConfig{ 2093 expectedPowerDelta: miner.NewPowerPair(pwr.Raw, pwr.QA), 2094 } 2095 partitions := []miner.PoStPartition{ 2096 {Index: pIdx, Skipped: bitfield.New()}, 2097 } 2098 actor.submitWindowPoSt(rt, dlinfo, partitions, infos, cfg) 2099 2100 // faulty power has been removed, partition no longer has faults or recoveries 2101 deadline, partition := actor.findSector(rt, infos[0].SectorNumber) 2102 assert.Equal(t, miner.NewPowerPairZero(), deadline.FaultyPower) 2103 assert.Equal(t, miner.NewPowerPairZero(), partition.FaultyPower) 2104 assertBitfieldEmpty(t, partition.Faults) 2105 assertBitfieldEmpty(t, partition.Recoveries) 2106 2107 // We restored power, so we should not have recorded a post. 2108 deadline = actor.getDeadline(rt, dlIdx) 2109 assertBitfieldEquals(t, deadline.PartitionsPoSted, pIdx) 2110 postsCid := deadline.OptimisticPoStSubmissions 2111 posts, err := adt.AsArray(rt.AdtStore(), postsCid, 2112 miner.DeadlineOptimisticPoStSubmissionsAmtBitwidth) 2113 require.NoError(t, err) 2114 require.EqualValues(t, posts.Length(), 0) 2115 2116 // Next deadline cron does not charge for the fault 2117 advanceDeadline(rt, actor, &cronConfig{}) 2118 2119 assert.Equal(t, initialLocked, actor.getLockedFunds(rt)) 2120 actor.checkState(rt) 2121 }) 2122 2123 t.Run("skipped faults adjust power", func(t *testing.T) { 2124 rt := builder.Build(t) 2125 2126 actor.constructAndVerify(rt) 2127 infos := actor.commitAndProveSectors(rt, 2, defaultSectorExpiration, nil, true) 2128 2129 actor.applyRewards(rt, bigRewards, big.Zero()) 2130 2131 // advance to epoch when submitPoSt is due 2132 st := getState(rt) 2133 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), infos[0].SectorNumber) 2134 require.NoError(t, err) 2135 dlIdx2, pIdx2, err := st.FindSector(rt.AdtStore(), infos[1].SectorNumber) 2136 require.NoError(t, err) 2137 assert.Equal(t, dlIdx, dlIdx2) // this test will need to change when these are not equal 2138 2139 dlinfo := actor.deadline(rt) 2140 for dlinfo.Index != dlIdx { 2141 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2142 } 2143 2144 // Now submit PoSt with a skipped fault for first sector 2145 // First sector's power should not be activated. 2146 powerActive := miner.PowerForSectors(actor.sectorSize, infos[1:]) 2147 cfg := &poStConfig{ 2148 expectedPowerDelta: powerActive, 2149 } 2150 partitions := []miner.PoStPartition{ 2151 {Index: pIdx, Skipped: bf(uint64(infos[0].SectorNumber))}, 2152 } 2153 actor.submitWindowPoSt(rt, dlinfo, partitions, infos, cfg) 2154 2155 // expect continued fault fee to be charged during cron 2156 faultFee := actor.continuedFaultPenalty(infos[:1]) 2157 dlinfo = advanceDeadline(rt, actor, &cronConfig{continuedFaultsPenalty: faultFee}) 2158 2159 // advance to next proving period, expect no fees 2160 for dlinfo.Index != dlIdx { 2161 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2162 } 2163 2164 // Attempt to skip second sector 2165 pwrDelta := miner.PowerForSectors(actor.sectorSize, infos[1:2]) 2166 2167 cfg = &poStConfig{ 2168 expectedPowerDelta: pwrDelta.Neg(), 2169 } 2170 partitions = []miner.PoStPartition{ 2171 {Index: pIdx2, Skipped: bf(uint64(infos[1].SectorNumber))}, 2172 } 2173 // Now all sectors are faulty so there's nothing to prove. 2174 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "no active sectors", func() { 2175 actor.submitWindowPoSt(rt, dlinfo, partitions, infos, cfg) 2176 }) 2177 rt.Reset() 2178 2179 // The second sector is detected faulty but pays nothing yet. 2180 // Expect ongoing fault penalty for only the first, continuing-faulty sector. 2181 pwrDelta = miner.PowerForSectors(actor.sectorSize, infos[1:2]).Neg() 2182 faultFee = actor.continuedFaultPenalty(infos[:1]) 2183 advanceDeadline(rt, actor, &cronConfig{ 2184 detectedFaultsPowerDelta: &pwrDelta, 2185 continuedFaultsPenalty: faultFee, 2186 }) 2187 actor.checkState(rt) 2188 }) 2189 2190 t.Run("skipping all sectors in a partition rejected", func(t *testing.T) { 2191 rt := builder.Build(t) 2192 2193 actor.constructAndVerify(rt) 2194 infos := actor.commitAndProveSectors(rt, 2, defaultSectorExpiration, nil, true) 2195 2196 actor.applyRewards(rt, bigRewards, big.Zero()) 2197 2198 // advance to epoch when submitPoSt is due 2199 st := getState(rt) 2200 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), infos[0].SectorNumber) 2201 require.NoError(t, err) 2202 dlIdx2, pIdx2, err := st.FindSector(rt.AdtStore(), infos[1].SectorNumber) 2203 require.NoError(t, err) 2204 assert.Equal(t, dlIdx, dlIdx2) // this test will need to change when these are not equal 2205 assert.Equal(t, pIdx, pIdx2) // this test will need to change when these are not equal 2206 2207 dlinfo := actor.deadline(rt) 2208 for dlinfo.Index != dlIdx { 2209 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2210 } 2211 2212 // PoSt with all sectors skipped fails to validate, leaving power un-activated. 2213 partitions := []miner.PoStPartition{ 2214 {Index: pIdx, Skipped: bf(uint64(infos[0].SectorNumber), uint64(infos[1].SectorNumber))}, 2215 } 2216 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 2217 actor.submitWindowPoSt(rt, dlinfo, partitions, infos, nil) 2218 }) 2219 rt.Reset() 2220 2221 // These sectors are detected faulty and pay no penalty this time. 2222 advanceDeadline(rt, actor, &cronConfig{continuedFaultsPenalty: big.Zero()}) 2223 actor.checkState(rt) 2224 }) 2225 2226 t.Run("skipped recoveries are penalized and do not recover power", func(t *testing.T) { 2227 rt := builder.Build(t) 2228 2229 actor.constructAndVerify(rt) 2230 infos := actor.commitAndProveSectors(rt, 2, defaultSectorExpiration, nil, true) 2231 2232 actor.applyRewards(rt, bigRewards, big.Zero()) 2233 2234 // Submit first PoSt to ensure we are sufficiently early to add a fault 2235 // advance to next proving period 2236 advanceAndSubmitPoSts(rt, actor, infos...) 2237 2238 // advance deadline and declare fault on the first sector 2239 advanceDeadline(rt, actor, &cronConfig{}) 2240 actor.declareFaults(rt, infos[0]) 2241 2242 // advance a deadline and declare recovery 2243 advanceDeadline(rt, actor, &cronConfig{}) 2244 2245 // declare recovery 2246 st := getState(rt) 2247 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), infos[0].SectorNumber) 2248 require.NoError(t, err) 2249 actor.declareRecoveries(rt, dlIdx, pIdx, bf(uint64(infos[0].SectorNumber)), big.Zero()) 2250 2251 // advance to epoch when submitPoSt is due 2252 dlinfo := actor.deadline(rt) 2253 for dlinfo.Index != dlIdx { 2254 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2255 } 2256 2257 // Now submit PoSt and skip recovered sector. 2258 // No power should be returned 2259 cfg := &poStConfig{ 2260 expectedPowerDelta: miner.NewPowerPairZero(), 2261 } 2262 partitions := []miner.PoStPartition{ 2263 {Index: pIdx, Skipped: bf(uint64(infos[0].SectorNumber))}, 2264 } 2265 actor.submitWindowPoSt(rt, dlinfo, partitions, infos, cfg) 2266 2267 // sector will be charged ongoing fee at proving period cron 2268 ongoingFee := actor.continuedFaultPenalty(infos[:1]) 2269 advanceDeadline(rt, actor, &cronConfig{continuedFaultsPenalty: ongoingFee}) 2270 actor.checkState(rt) 2271 }) 2272 2273 t.Run("skipping a fault from the wrong partition is an error", func(t *testing.T) { 2274 rt := builder.Build(t) 2275 actor.constructAndVerify(rt) 2276 2277 // create enough sectors that one will be in a different partition 2278 n := 95 2279 infos := actor.commitAndProveSectors(rt, n, defaultSectorExpiration, nil, true) 2280 2281 // add lots of funds so we can pay penalties without going into debt 2282 st := getState(rt) 2283 dlIdx0, pIdx0, err := st.FindSector(rt.AdtStore(), infos[0].SectorNumber) 2284 require.NoError(t, err) 2285 dlIdx1, pIdx1, err := st.FindSector(rt.AdtStore(), infos[n-1].SectorNumber) 2286 require.NoError(t, err) 2287 2288 // if these assertions no longer hold, the test must be changed 2289 require.LessOrEqual(t, dlIdx0, dlIdx1) 2290 require.NotEqual(t, pIdx0, pIdx1) 2291 2292 // advance to deadline when sector is due 2293 dlinfo := actor.deadline(rt) 2294 for dlinfo.Index != dlIdx0 { 2295 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2296 } 2297 2298 // Now submit PoSt for partition 1 and skip sector from other partition 2299 cfg := &poStConfig{ 2300 expectedPowerDelta: miner.NewPowerPairZero(), 2301 } 2302 partitions := []miner.PoStPartition{ 2303 {Index: pIdx0, Skipped: bf(uint64(infos[n-1].SectorNumber))}, 2304 } 2305 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "skipped faults contains sectors outside partition", func() { 2306 actor.submitWindowPoSt(rt, dlinfo, partitions, infos, cfg) 2307 }) 2308 actor.checkState(rt) 2309 }) 2310 2311 t.Run("cannot dispute posts when the challenge window is open", func(t *testing.T) { 2312 proofs := makePoStProofs(actor.windowPostProofType) 2313 2314 rt := builder.Build(t) 2315 actor.constructAndVerify(rt) 2316 store := rt.AdtStore() 2317 sector := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true)[0] 2318 pwr := miner.PowerForSector(actor.sectorSize, sector) 2319 2320 st := getState(rt) 2321 dlIdx, pIdx, err := st.FindSector(store, sector.SectorNumber) 2322 require.NoError(t, err) 2323 2324 // Skip over deadlines until the beginning of the one with the new sector 2325 dlinfo := actor.deadline(rt) 2326 for dlinfo.Index != dlIdx { 2327 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2328 } 2329 2330 // Submit PoSt 2331 partitions := []miner.PoStPartition{ 2332 {Index: pIdx, Skipped: bitfield.New()}, 2333 } 2334 actor.submitWindowPoStRaw(rt, dlinfo, partitions, []*miner.SectorOnChainInfo{sector}, proofs, &poStConfig{ 2335 expectedPowerDelta: pwr, 2336 }) 2337 2338 // Dispute it. 2339 params := miner.DisputeWindowedPoStParams{ 2340 Deadline: dlinfo.Index, 2341 PoStIndex: 0, 2342 } 2343 2344 rt.SetCaller(actor.worker, builtin.AccountActorCodeID) 2345 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 2346 2347 expectQueryNetworkInfo(rt, actor) 2348 2349 rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, "can only dispute window posts during the dispute window", func() { 2350 rt.Call(actor.a.DisputeWindowedPoSt, ¶ms) 2351 }) 2352 rt.Verify() 2353 }) 2354 t.Run("can dispute up till window end, but not after", func(t *testing.T) { 2355 rt := builder.Build(t) 2356 actor.constructAndVerify(rt) 2357 store := rt.AdtStore() 2358 sector := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true)[0] 2359 2360 st := getState(rt) 2361 dlIdx, _, err := st.FindSector(store, sector.SectorNumber) 2362 require.NoError(t, err) 2363 2364 nextDl := miner.NewDeadlineInfo(st.ProvingPeriodStart, dlIdx, rt.Epoch()). 2365 NextNotElapsed() 2366 2367 advanceAndSubmitPoSts(rt, actor, sector) 2368 2369 windowEnd := nextDl.Close + miner.WPoStDisputeWindow 2370 2371 // first, try to dispute right before the window end. 2372 // We expect this to fail "normally" (fail to disprove). 2373 rt.SetEpoch(windowEnd - 1) 2374 actor.disputeWindowPoSt(rt, nextDl, 0, []*miner.SectorOnChainInfo{sector}, nil) 2375 2376 // Now set the epoch at the window end. We expect a different error. 2377 rt.SetEpoch(windowEnd) 2378 2379 // Now try to dispute. 2380 params := miner.DisputeWindowedPoStParams{ 2381 Deadline: dlIdx, 2382 PoStIndex: 0, 2383 } 2384 2385 rt.SetCaller(actor.worker, builtin.AccountActorCodeID) 2386 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 2387 2388 currentReward := reward.ThisEpochRewardReturn{ 2389 ThisEpochBaselinePower: actor.baselinePower, 2390 ThisEpochRewardSmoothed: actor.epochRewardSmooth, 2391 } 2392 rt.ExpectSend(builtin.RewardActorAddr, builtin.MethodsReward.ThisEpochReward, nil, big.Zero(), ¤tReward, exitcode.Ok) 2393 2394 networkPower := big.NewIntUnsigned(1 << 50) 2395 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.CurrentTotalPower, nil, big.Zero(), 2396 &power.CurrentTotalPowerReturn{ 2397 RawBytePower: networkPower, 2398 QualityAdjPower: networkPower, 2399 PledgeCollateral: actor.networkPledge, 2400 QualityAdjPowerSmoothed: actor.epochQAPowerSmooth, 2401 }, 2402 exitcode.Ok) 2403 2404 rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, "can only dispute window posts during the dispute window", func() { 2405 rt.Call(actor.a.DisputeWindowedPoSt, ¶ms) 2406 }) 2407 rt.Verify() 2408 }) 2409 2410 t.Run("can't dispute up with an invalid deadline", func(t *testing.T) { 2411 rt := builder.Build(t) 2412 actor.constructAndVerify(rt) 2413 2414 params := miner.DisputeWindowedPoStParams{ 2415 Deadline: 50, 2416 PoStIndex: 0, 2417 } 2418 2419 rt.SetCaller(actor.worker, builtin.AccountActorCodeID) 2420 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 2421 2422 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "invalid deadline", func() { 2423 rt.Call(actor.a.DisputeWindowedPoSt, ¶ms) 2424 }) 2425 rt.Verify() 2426 }) 2427 2428 t.Run("can dispute test after proving period changes", func(t *testing.T) { 2429 rt := builder.Build(t) 2430 actor.constructAndVerify(rt) 2431 2432 periodStart := actor.deadline(rt).NextPeriodStart() 2433 2434 // go to the next deadline 0 2435 rt.SetEpoch(periodStart) 2436 2437 // fill one partition in each mutable deadline. 2438 numSectors := int(actor.partitionSize * (miner.WPoStPeriodDeadlines - 2)) 2439 2440 // creates a partition in every deadline except 0 and 47 2441 sectors := actor.commitAndProveSectors(rt, numSectors, defaultSectorExpiration, nil, true) 2442 actor.t.Log("here") 2443 2444 // prove every sector once to activate power. This 2445 // simplifies the test a bit. 2446 advanceAndSubmitPoSts(rt, actor, sectors...) 2447 2448 // Make sure we're in the correct deadline. We should 2449 // finish at deadline 2 because precommit takes some 2450 // time. 2451 dlinfo := actor.deadline(rt) 2452 require.True(t, dlinfo.Index < 46, 2453 "we need to be before the target deadline for this test to make sense") 2454 2455 // Now challenge find the sectors in the last partition. 2456 _, partition := actor.getDeadlineAndPartition(rt, 46, 0) 2457 var targetSectors []*miner.SectorOnChainInfo 2458 err := partition.Sectors.ForEach(func(i uint64) error { 2459 for _, sector := range sectors { 2460 if uint64(sector.SectorNumber) == i { 2461 targetSectors = append(targetSectors, sector) 2462 } 2463 } 2464 return nil 2465 }) 2466 require.NoError(t, err) 2467 require.NotEmpty(t, targetSectors) 2468 2469 pwr := miner.PowerForSectors(actor.sectorSize, targetSectors) 2470 2471 // And challenge the last partition. 2472 var result *poStDisputeResult 2473 expectedFee := miner.PledgePenaltyForInvalidWindowPoSt(actor.epochRewardSmooth, actor.epochQAPowerSmooth, pwr.QA) 2474 result = &poStDisputeResult{ 2475 expectedPowerDelta: pwr.Neg(), 2476 expectedPenalty: expectedFee, 2477 expectedReward: miner.BaseRewardForDisputedWindowPoSt, 2478 expectedPledgeDelta: big.Zero(), 2479 } 2480 2481 targetDlInfo := miner.NewDeadlineInfo(periodStart, 46, rt.Epoch()) 2482 actor.disputeWindowPoSt(rt, targetDlInfo, 0, targetSectors, result) 2483 }) 2484 } 2485 2486 func TestProveCommit(t *testing.T) { 2487 periodOffset := abi.ChainEpoch(100) 2488 actor := newHarness(t, periodOffset) 2489 builder := builderForHarness(actor). 2490 WithBalance(bigBalance, big.Zero()) 2491 2492 t.Run("prove commit aborts if pledge requirement not met", func(t *testing.T) { 2493 rt := builder.Build(t) 2494 actor.constructAndVerify(rt) 2495 // Set the circulating supply high and expected reward low in order to coerce 2496 // pledge requirements (BR + share of money supply, but capped at 1FIL) 2497 // to exceed pre-commit deposit (BR only). 2498 rt.SetCirculatingSupply(big.Mul(big.NewInt(100_000_000), big.NewInt(1e18))) 2499 actor.epochRewardSmooth = smoothing.TestingConstantEstimate(big.NewInt(1e15)) 2500 2501 // prove one sector to establish collateral and locked funds 2502 sectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 2503 2504 // preecommit another sector so we may prove it 2505 expiration := defaultSectorExpiration*miner.WPoStProvingPeriod + periodOffset - 1 2506 precommitEpoch := rt.Epoch() + 1 2507 rt.SetEpoch(precommitEpoch) 2508 params := actor.makePreCommit(actor.nextSectorNo, rt.Epoch()-1, expiration, nil) 2509 precommit := actor.preCommitSector(rt, params, preCommitConf{}, false) 2510 2511 // Confirm the unlocked PCD will not cover the new IP 2512 assert.True(t, sectors[0].InitialPledge.GreaterThan(precommit.PreCommitDeposit)) 2513 2514 // Set balance to exactly cover locked funds. 2515 st := getState(rt) 2516 rt.SetBalance(big.Sum(st.PreCommitDeposits, st.InitialPledge, st.LockedFunds)) 2517 2518 rt.SetEpoch(precommitEpoch + miner.MaxProveCommitDuration[actor.sealProofType] - 1) 2519 rt.ExpectAbort(exitcode.ErrInsufficientFunds, func() { 2520 actor.proveCommitSectorAndConfirm(rt, precommit, makeProveCommit(actor.nextSectorNo), proveCommitConf{}) 2521 }) 2522 rt.Reset() 2523 2524 // succeeds with enough free balance (enough to cover 2x IP) 2525 rt.SetBalance(big.Sum(st.PreCommitDeposits, st.InitialPledge, st.InitialPledge, st.LockedFunds)) 2526 actor.proveCommitSectorAndConfirm(rt, precommit, makeProveCommit(actor.nextSectorNo), proveCommitConf{}) 2527 actor.checkState(rt) 2528 }) 2529 2530 t.Run("drop invalid prove commit while processing valid one", func(t *testing.T) { 2531 rt := builder.Build(t) 2532 actor.constructAndVerify(rt) 2533 2534 // make two precommits 2535 expiration := defaultSectorExpiration*miner.WPoStProvingPeriod + periodOffset - 1 2536 precommitEpoch := rt.Epoch() + 1 2537 rt.SetEpoch(precommitEpoch) 2538 paramsA := actor.makePreCommit(actor.nextSectorNo, rt.Epoch()-1, expiration, []abi.DealID{1}) 2539 preCommitA := actor.preCommitSector(rt, paramsA, preCommitConf{}, true) 2540 sectorNoA := actor.nextSectorNo 2541 actor.nextSectorNo++ 2542 paramsB := actor.makePreCommit(actor.nextSectorNo, rt.Epoch()-1, expiration, []abi.DealID{2}) 2543 preCommitB := actor.preCommitSector(rt, paramsB, preCommitConf{}, false) 2544 sectorNoB := actor.nextSectorNo 2545 2546 // handle both prove commits in the same epoch 2547 rt.SetEpoch(precommitEpoch + miner.MaxProveCommitDuration[actor.sealProofType] - 1) 2548 2549 actor.proveCommitSector(rt, preCommitA, makeProveCommit(sectorNoA)) 2550 actor.proveCommitSector(rt, preCommitB, makeProveCommit(sectorNoB)) 2551 2552 conf := proveCommitConf{ 2553 verifyDealsExit: map[abi.SectorNumber]exitcode.ExitCode{ 2554 sectorNoA: exitcode.ErrIllegalArgument, 2555 }, 2556 } 2557 actor.confirmSectorProofsValid(rt, conf, preCommitA, preCommitB) 2558 actor.checkState(rt) 2559 }) 2560 } 2561 2562 func TestDeadlineCron(t *testing.T) { 2563 periodOffset := abi.ChainEpoch(100) 2564 actor := newHarness(t, periodOffset) 2565 builder := builderForHarness(actor). 2566 WithBalance(bigBalance, big.Zero()) 2567 2568 t.Run("cron on inactive state", func(t *testing.T) { 2569 rt := builder.Build(t) 2570 actor.constructAndVerify(rt) 2571 st := getState(rt) 2572 assert.Equal(t, periodOffset-miner.WPoStProvingPeriod, st.ProvingPeriodStart) 2573 assert.False(t, st.ContinueDeadlineCron()) 2574 2575 // cron does nothing and does not enroll another cron 2576 deadline := actor.deadline(rt) 2577 rt.SetEpoch(deadline.Last()) 2578 actor.onDeadlineCron(rt, &cronConfig{noEnrollment: true}) 2579 2580 actor.checkState(rt) 2581 }) 2582 2583 t.Run("sector expires", func(t *testing.T) { 2584 rt := builder.Build(t) 2585 actor.constructAndVerify(rt) 2586 2587 sectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 2588 // advance cron to activate power. 2589 advanceAndSubmitPoSts(rt, actor, sectors...) 2590 activePower := miner.PowerForSectors(actor.sectorSize, sectors) 2591 2592 st := getState(rt) 2593 initialPledge := st.InitialPledge 2594 expirationRaw := sectors[0].Expiration 2595 assert.True(t, st.DeadlineCronActive) 2596 2597 // setup state to simulate moving forward all the way to expiry 2598 2599 dlIdx, _, err := st.FindSector(rt.AdtStore(), sectors[0].SectorNumber) 2600 require.NoError(t, err) 2601 expQuantSpec := st.QuantSpecForDeadline(dlIdx) 2602 expiration := expQuantSpec.QuantizeUp(expirationRaw) 2603 remainingEpochs := expiration - st.ProvingPeriodStart 2604 remainingPeriods := remainingEpochs/miner.WPoStProvingPeriod + 1 2605 st.ProvingPeriodStart += remainingPeriods * miner.WPoStProvingPeriod 2606 st.CurrentDeadline = dlIdx 2607 rt.ReplaceState(st) 2608 2609 // Advance to expiration epoch and expect expiration during cron 2610 rt.SetEpoch(expiration) 2611 powerDelta := activePower.Neg() 2612 // because we skip forward in state the sector is detected faulty, no penalty 2613 advanceDeadline(rt, actor, &cronConfig{ 2614 noEnrollment: true, // the last power has expired so we expect cron to go inactive 2615 expiredSectorsPowerDelta: &powerDelta, 2616 expiredSectorsPledgeDelta: initialPledge.Neg(), 2617 }) 2618 st = getState(rt) 2619 assert.False(t, st.DeadlineCronActive) 2620 actor.checkState(rt) 2621 }) 2622 2623 t.Run("sector expires and repays fee debt", func(t *testing.T) { 2624 rt := builder.Build(t) 2625 actor.constructAndVerify(rt) 2626 2627 sectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 2628 // advance cron to activate power. 2629 advanceAndSubmitPoSts(rt, actor, sectors...) 2630 activePower := miner.PowerForSectors(actor.sectorSize, sectors) 2631 2632 st := getState(rt) 2633 initialPledge := st.InitialPledge 2634 expirationRaw := sectors[0].Expiration 2635 assert.True(t, st.DeadlineCronActive) 2636 2637 // setup state to simulate moving forward all the way to expiry 2638 dlIdx, _, err := st.FindSector(rt.AdtStore(), sectors[0].SectorNumber) 2639 require.NoError(t, err) 2640 expQuantSpec := st.QuantSpecForDeadline(dlIdx) 2641 expiration := expQuantSpec.QuantizeUp(expirationRaw) 2642 remainingEpochs := expiration - st.ProvingPeriodStart 2643 remainingPeriods := remainingEpochs/miner.WPoStProvingPeriod + 1 2644 st.ProvingPeriodStart += remainingPeriods * miner.WPoStProvingPeriod 2645 st.CurrentDeadline = dlIdx 2646 rt.ReplaceState(st) 2647 2648 // Advance to expiration epoch and expect expiration during cron 2649 rt.SetEpoch(expiration) 2650 powerDelta := activePower.Neg() 2651 2652 // introduce lots of fee debt 2653 st = getState(rt) 2654 feeDebt := big.Mul(big.NewInt(400), big.NewInt(1e18)) 2655 st.FeeDebt = feeDebt 2656 rt.ReplaceState(st) 2657 // Miner balance = IP, debt repayment covered by unlocked funds 2658 rt.SetBalance(st.InitialPledge) 2659 2660 // because we skip forward in state and don't check post, there's no penalty. 2661 // this is the first time the sector is detected faulty 2662 advanceDeadline(rt, actor, &cronConfig{ 2663 noEnrollment: true, 2664 expiredSectorsPowerDelta: &powerDelta, 2665 expiredSectorsPledgeDelta: initialPledge.Neg(), 2666 repaidFeeDebt: initialPledge, // We repay unlocked IP as fees 2667 }) 2668 st = getState(rt) 2669 assert.False(t, st.DeadlineCronActive) 2670 actor.checkState(rt) 2671 }) 2672 2673 t.Run("detects and penalizes faults", func(t *testing.T) { 2674 rt := builder.Build(t) 2675 actor.constructAndVerify(rt) 2676 2677 activeSectors := actor.commitAndProveSectors(rt, 2, defaultSectorExpiration, nil, true) 2678 // advance cron to activate power. 2679 advanceAndSubmitPoSts(rt, actor, activeSectors...) 2680 activePower := miner.PowerForSectors(actor.sectorSize, activeSectors) 2681 2682 unprovenSectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, false) 2683 unprovenPower := miner.PowerForSectors(actor.sectorSize, unprovenSectors) 2684 2685 totalPower := unprovenPower.Add(activePower) 2686 allSectors := append(activeSectors, unprovenSectors...) 2687 2688 // add lots of funds so penalties come from vesting funds 2689 actor.applyRewards(rt, bigRewards, big.Zero()) 2690 2691 st := getState(rt) 2692 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), activeSectors[0].SectorNumber) 2693 require.NoError(t, err) 2694 2695 // advance to next deadline where we expect the first sectors to appear 2696 dlinfo := actor.deadline(rt) 2697 for dlinfo.Index != dlIdx { 2698 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2699 } 2700 2701 // Skip to end of the deadline, cron detects sectors as faulty 2702 activePowerDelta := activePower.Neg() 2703 advanceDeadline(rt, actor, &cronConfig{ 2704 detectedFaultsPowerDelta: &activePowerDelta, 2705 }) 2706 2707 // expect faulty power to be added to state 2708 deadline := actor.getDeadline(rt, dlIdx) 2709 assert.True(t, totalPower.Equals(deadline.FaultyPower)) 2710 2711 // advance 3 deadlines 2712 advanceDeadline(rt, actor, &cronConfig{}) 2713 advanceDeadline(rt, actor, &cronConfig{}) 2714 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2715 2716 actor.declareRecoveries(rt, dlIdx, pIdx, sectorInfoAsBitfield(allSectors[1:]), big.Zero()) 2717 2718 // Skip to end of proving period for sectors, cron detects all sectors as faulty 2719 for dlinfo.Index != dlIdx { 2720 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2721 } 2722 2723 // Un-recovered faults (incl failed recovery) are charged as ongoing faults 2724 ongoingPwr := miner.PowerForSectors(actor.sectorSize, allSectors) 2725 ongoingPenalty := miner.PledgePenaltyForContinuedFault(actor.epochRewardSmooth, actor.epochQAPowerSmooth, ongoingPwr.QA) 2726 2727 advanceDeadline(rt, actor, &cronConfig{ 2728 continuedFaultsPenalty: ongoingPenalty, 2729 }) 2730 2731 // recorded faulty power is unchanged 2732 deadline = actor.getDeadline(rt, dlIdx) 2733 assert.True(t, totalPower.Equals(deadline.FaultyPower)) 2734 checkDeadlineInvariants(t, rt.AdtStore(), deadline, st.QuantSpecForDeadline(dlIdx), actor.sectorSize, allSectors) 2735 actor.checkState(rt) 2736 }) 2737 2738 t.Run("test cron run trigger faults", func(t *testing.T) { 2739 rt := builder.Build(t) 2740 actor.constructAndVerify(rt) 2741 2742 // add lots of funds so we can pay penalties without going into debt 2743 actor.applyRewards(rt, bigRewards, big.Zero()) 2744 2745 // create enough sectors that one will be in a different partition 2746 allSectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 2747 2748 // advance cron to activate power. 2749 advanceAndSubmitPoSts(rt, actor, allSectors...) 2750 2751 st := getState(rt) 2752 dlIdx, _, err := st.FindSector(rt.AdtStore(), allSectors[0].SectorNumber) 2753 require.NoError(t, err) 2754 2755 // advance to deadline prior to first 2756 dlinfo := actor.deadline(rt) 2757 for dlinfo.Index != dlIdx { 2758 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2759 } 2760 2761 rt.SetEpoch(dlinfo.Last()) 2762 2763 // run cron and expect all sectors to be detected as faults (no penalty) 2764 pwr := miner.PowerForSectors(actor.sectorSize, allSectors) 2765 2766 // power for sectors is removed 2767 powerDeltaClaim := miner.NewPowerPair(pwr.Raw.Neg(), pwr.QA.Neg()) 2768 2769 // expect next cron to be one deadline period after expected cron for this deadline 2770 nextCron := dlinfo.Last() + miner.WPoStChallengeWindow 2771 2772 actor.onDeadlineCron(rt, &cronConfig{ 2773 expectedEnrollment: nextCron, 2774 detectedFaultsPowerDelta: &powerDeltaClaim, 2775 }) 2776 actor.checkState(rt) 2777 }) 2778 } 2779 2780 // cronControl is a convenience harness on top of the actor harness giving the caller access to common 2781 // sequences of miner actor actions useful for checking that cron starts, runs, stops and continues 2782 type cronControl struct { 2783 rt *mock.Runtime 2784 actor *actorHarness 2785 preCommitNum int 2786 } 2787 2788 func newCronControl(rt *mock.Runtime, actor *actorHarness) *cronControl { 2789 return &cronControl{ 2790 rt: rt, 2791 actor: actor, 2792 preCommitNum: 0, 2793 } 2794 } 2795 2796 // Start cron by precommitting at preCommitEpoch, return expiry epoch. 2797 // Verifies that cron is not started, precommit is run and cron is enrolled. 2798 // Returns expiration of precommit. 2799 func (h *cronControl) preCommitToStartCron(t *testing.T, preCommitEpoch abi.ChainEpoch) abi.ChainEpoch { 2800 h.rt.SetEpoch(preCommitEpoch) 2801 st := getState(h.rt) 2802 h.requireCronInactive(t) 2803 2804 dlinfo := miner.NewDeadlineInfoFromOffsetAndEpoch(st.ProvingPeriodStart, preCommitEpoch) // actor.deadline might be out of date 2805 sectorNo := abi.SectorNumber(h.preCommitNum) 2806 h.preCommitNum++ 2807 expiration := dlinfo.PeriodEnd() + defaultSectorExpiration*miner.WPoStProvingPeriod // something on deadline boundary but > 180 days 2808 precommitParams := h.actor.makePreCommit(sectorNo, preCommitEpoch-1, expiration, nil) 2809 h.actor.preCommitSector(h.rt, precommitParams, preCommitConf{}, true) 2810 2811 // PCD != 0 so cron must be active 2812 h.requireCronActive(t) 2813 expiryEpoch := preCommitEpoch + builtin.EpochsInDay + miner.PreCommitChallengeDelay + abi.ChainEpoch(1) 2814 return expiryEpoch 2815 } 2816 2817 // Stop cron by advancing to the preCommit expiry epoch. 2818 // Assumes no proved sectors, no vesting funds. 2819 // Verifies cron runs until expiry, PCD burnt and cron discontinued during last deadline 2820 // Return open of first deadline after expiration. 2821 func (h *cronControl) expirePreCommitStopCron(t *testing.T, startEpoch, expiryEpoch abi.ChainEpoch) abi.ChainEpoch { 2822 h.requireCronActive(t) 2823 st := getState(h.rt) 2824 dlinfo := miner.NewDeadlineInfoFromOffsetAndEpoch(st.ProvingPeriodStart, startEpoch) // actor.deadline might be out of date 2825 2826 for dlinfo.Open <= expiryEpoch { // PCDs are quantized to expire on the *next* new deadline after the one they expire in 2827 // asserts cron is rescheduled 2828 dlinfo = advanceDeadline(h.rt, h.actor, &cronConfig{}) 2829 } 2830 // We expect PCD burnt and cron not rescheduled here. 2831 h.rt.SetEpoch(dlinfo.Last()) 2832 h.actor.onDeadlineCron(h.rt, &cronConfig{ 2833 noEnrollment: true, 2834 expiredPrecommitPenalty: st.PreCommitDeposits, 2835 }) 2836 h.rt.SetEpoch(dlinfo.NextOpen()) 2837 2838 h.requireCronInactive(t) 2839 return h.rt.Epoch() 2840 } 2841 2842 func (h *cronControl) requireCronInactive(t *testing.T) { 2843 st := getState(h.rt) 2844 assert.False(t, st.DeadlineCronActive) // No cron running now 2845 assert.False(t, st.ContinueDeadlineCron()) // No reason to cron now, state inactive 2846 } 2847 2848 func (h *cronControl) requireCronActive(t *testing.T) { 2849 st := getState(h.rt) 2850 require.True(t, st.DeadlineCronActive) 2851 require.True(t, st.ContinueDeadlineCron()) 2852 } 2853 2854 func (h *cronControl) preCommitStartCronExpireStopCron(t *testing.T, startEpoch abi.ChainEpoch) abi.ChainEpoch { 2855 expiryEpoch := h.preCommitToStartCron(t, startEpoch) 2856 return h.expirePreCommitStopCron(t, startEpoch, expiryEpoch) 2857 } 2858 2859 func TestDeadlineCronDefersStopsRestarts(t *testing.T) { 2860 periodOffset := abi.ChainEpoch(100) 2861 actor := newHarness(t, periodOffset) 2862 builder := builderForHarness(actor). 2863 WithBalance(bigBalance, big.Zero()) 2864 2865 t.Run("cron enrolls on precommit, prove commits and continues enrolling", func(t *testing.T) { 2866 rt := builder.Build(t) 2867 actor.constructAndVerify(rt) 2868 cronCtrl := newCronControl(rt, actor) 2869 longExpiration := uint64(500) 2870 2871 cronCtrl.requireCronInactive(t) 2872 sectors := actor.commitAndProveSectors(rt, 1, longExpiration, nil, true) 2873 cronCtrl.requireCronActive(t) 2874 2875 // advance cron to activate power. 2876 advanceAndSubmitPoSts(rt, actor, sectors...) 2877 // advance 499 days of deadline (1 before expiration occurrs) 2878 // this asserts that cron continues to enroll within advanceAndSubmitPoSt 2879 for i := 0; i < 499; i++ { 2880 advanceAndSubmitPoSts(rt, actor, sectors...) 2881 } 2882 actor.checkState(rt) 2883 st := getState(rt) 2884 assert.True(t, st.DeadlineCronActive) 2885 }) 2886 2887 t.Run("cron enrolls on precommit, expires on pcd expiration, re-enrolls on new precommit immediately", func(t *testing.T) { 2888 rt := builder.Build(t) 2889 epoch := periodOffset + 1 2890 rt.SetEpoch(epoch) 2891 actor.constructAndVerify(rt) 2892 cronCtrl := newCronControl(rt, actor) 2893 2894 epoch = cronCtrl.preCommitStartCronExpireStopCron(t, epoch) 2895 cronCtrl.preCommitToStartCron(t, epoch) 2896 }) 2897 2898 t.Run("cron enrolls on precommit, expires on pcd expiration, re-enrolls on new precommit after falling out of date", func(t *testing.T) { 2899 rt := builder.Build(t) 2900 epoch := periodOffset + 1 2901 rt.SetEpoch(epoch) 2902 actor.constructAndVerify(rt) 2903 cronCtrl := newCronControl(rt, actor) 2904 2905 epoch = cronCtrl.preCommitStartCronExpireStopCron(t, epoch) 2906 // Advance some epochs to fall several pp out of date, then precommit again reenrolling cron 2907 epoch = epoch + 200*miner.WPoStProvingPeriod 2908 epoch = cronCtrl.preCommitStartCronExpireStopCron(t, epoch) 2909 // Stay within the same deadline but advance an epoch 2910 epoch = epoch + 1 2911 cronCtrl.preCommitToStartCron(t, epoch) 2912 }) 2913 2914 t.Run("enroll, pcd expire, re-enroll x 1000", func(t *testing.T) { 2915 rt := builder.Build(t) 2916 epoch := periodOffset + 1 2917 rt.SetEpoch(epoch) 2918 actor.constructAndVerify(rt) 2919 cronCtrl := newCronControl(rt, actor) 2920 for i := 0; i < 1000; i++ { 2921 epoch = cronCtrl.preCommitStartCronExpireStopCron(t, epoch) + 42 2922 } 2923 }) 2924 } 2925 2926 func TestDeclareFaults(t *testing.T) { 2927 periodOffset := abi.ChainEpoch(100) 2928 actor := newHarness(t, periodOffset) 2929 builder := builderForHarness(actor). 2930 WithBalance(bigBalance, big.Zero()) 2931 2932 t.Run("declare fault pays fee at window post", func(t *testing.T) { 2933 // Get sector into proving state 2934 rt := builder.Build(t) 2935 actor.constructAndVerify(rt) 2936 allSectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 2937 pwr := miner.PowerForSectors(actor.sectorSize, allSectors) 2938 2939 // add lots of funds so penalties come from vesting funds 2940 actor.applyRewards(rt, bigRewards, big.Zero()) 2941 2942 // find deadline for sector 2943 st := getState(rt) 2944 dlIdx, _, err := st.FindSector(rt.AdtStore(), allSectors[0].SectorNumber) 2945 require.NoError(t, err) 2946 2947 // advance to first proving period and submit so we'll have time to declare the fault next cycle 2948 advanceAndSubmitPoSts(rt, actor, allSectors...) 2949 2950 // Declare the sector as faulted 2951 actor.declareFaults(rt, allSectors...) 2952 2953 // faults are recorded in state 2954 dl := actor.getDeadline(rt, dlIdx) 2955 assert.True(t, pwr.Equals(dl.FaultyPower)) 2956 2957 // Skip to end of proving period. 2958 dlinfo := actor.deadline(rt) 2959 for dlinfo.Index != dlIdx { 2960 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 2961 } 2962 2963 // faults are charged at ongoing rate and no additional power is removed 2964 ongoingPwr := miner.PowerForSectors(actor.sectorSize, allSectors) 2965 ongoingPenalty := miner.PledgePenaltyForContinuedFault(actor.epochRewardSmooth, actor.epochQAPowerSmooth, ongoingPwr.QA) 2966 2967 advanceDeadline(rt, actor, &cronConfig{ 2968 continuedFaultsPenalty: ongoingPenalty, 2969 }) 2970 actor.checkState(rt) 2971 }) 2972 } 2973 2974 func TestDeclareRecoveries(t *testing.T) { 2975 periodOffset := abi.ChainEpoch(100) 2976 actor := newHarness(t, periodOffset) 2977 builder := builderForHarness(actor). 2978 WithBalance(bigBalance, big.Zero()) 2979 2980 t.Run("recovery happy path", func(t *testing.T) { 2981 rt := builder.Build(t) 2982 actor.constructAndVerify(rt) 2983 oneSector := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 2984 2985 // advance to first proving period and submit so we'll have time to declare the fault next cycle 2986 advanceAndSubmitPoSts(rt, actor, oneSector...) 2987 2988 // Declare the sector as faulted 2989 actor.declareFaults(rt, oneSector...) 2990 2991 // Declare recoveries updates state 2992 st := getState(rt) 2993 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), oneSector[0].SectorNumber) 2994 require.NoError(t, err) 2995 actor.declareRecoveries(rt, dlIdx, pIdx, bf(uint64(oneSector[0].SectorNumber)), big.Zero()) 2996 2997 dl := actor.getDeadline(rt, dlIdx) 2998 p, err := dl.LoadPartition(rt.AdtStore(), pIdx) 2999 require.NoError(t, err) 3000 assert.Equal(t, p.Faults, p.Recoveries) 3001 actor.checkState(rt) 3002 }) 3003 3004 t.Run("recovery must pay back fee debt", func(t *testing.T) { 3005 rt := builder.Build(t) 3006 actor.constructAndVerify(rt) 3007 oneSector := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 3008 // advance to first proving period and submit so we'll have time to declare the fault next cycle 3009 advanceAndSubmitPoSts(rt, actor, oneSector...) 3010 3011 // Fault will take miner into fee debt 3012 st := getState(rt) 3013 rt.SetBalance(big.Sum(st.PreCommitDeposits, st.InitialPledge, st.LockedFunds)) 3014 3015 actor.declareFaults(rt, oneSector...) 3016 3017 st = getState(rt) 3018 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), oneSector[0].SectorNumber) 3019 require.NoError(t, err) 3020 3021 // Skip to end of proving period. 3022 dlinfo := actor.deadline(rt) 3023 for dlinfo.Index != dlIdx { 3024 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 3025 } 3026 3027 // Can't pay during this deadline so miner goes into fee debt 3028 ongoingPwr := miner.PowerForSectors(actor.sectorSize, oneSector) 3029 ff := miner.PledgePenaltyForContinuedFault(actor.epochRewardSmooth, actor.epochQAPowerSmooth, ongoingPwr.QA) 3030 advanceDeadline(rt, actor, &cronConfig{ 3031 continuedFaultsPenalty: big.Zero(), // fee is instead added to debt 3032 }) 3033 3034 st = getState(rt) 3035 assert.Equal(t, ff, st.FeeDebt) 3036 3037 // Recovery fails when it can't pay back fee debt 3038 rt.ExpectAbortContainsMessage(exitcode.ErrInsufficientFunds, "unlocked balance can not repay fee debt", func() { 3039 actor.declareRecoveries(rt, dlIdx, pIdx, bf(uint64(oneSector[0].SectorNumber)), big.Zero()) 3040 }) 3041 3042 // Recovery pays back fee debt and IP requirements and succeeds 3043 funds := big.Add(ff, st.InitialPledge) 3044 rt.SetBalance(funds) // this is how we send funds along with recovery message using mock rt 3045 actor.declareRecoveries(rt, dlIdx, pIdx, bf(uint64(oneSector[0].SectorNumber)), ff) 3046 3047 dl := actor.getDeadline(rt, dlIdx) 3048 p, err := dl.LoadPartition(rt.AdtStore(), pIdx) 3049 require.NoError(t, err) 3050 assert.Equal(t, p.Faults, p.Recoveries) 3051 st = getState(rt) 3052 assert.Equal(t, big.Zero(), st.FeeDebt) 3053 actor.checkState(rt) 3054 }) 3055 3056 t.Run("recovery fails during active consensus fault", func(t *testing.T) { 3057 rt := builder.Build(t) 3058 actor.constructAndVerify(rt) 3059 oneSector := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 3060 3061 // consensus fault 3062 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 3063 Target: actor.receiver, 3064 Epoch: rt.Epoch() - 1, 3065 Type: runtime.ConsensusFaultDoubleForkMining, 3066 }) 3067 3068 // advance to first proving period and submit so we'll have time to declare the fault next cycle 3069 advanceAndSubmitPoSts(rt, actor, oneSector...) 3070 3071 // Declare the sector as faulted 3072 actor.declareFaults(rt, oneSector...) 3073 3074 st := getState(rt) 3075 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), oneSector[0].SectorNumber) 3076 require.NoError(t, err) 3077 rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, "recovery not allowed during active consensus fault", func() { 3078 actor.declareRecoveries(rt, dlIdx, pIdx, bf(uint64(oneSector[0].SectorNumber)), big.Zero()) 3079 }) 3080 actor.checkState(rt) 3081 }) 3082 } 3083 3084 func TestExtendSectorExpiration(t *testing.T) { 3085 periodOffset := abi.ChainEpoch(100) 3086 actor := newHarness(t, periodOffset) 3087 precommitEpoch := abi.ChainEpoch(1) 3088 builder := builderForHarness(actor). 3089 WithEpoch(precommitEpoch). 3090 WithBalance(bigBalance, big.Zero()) 3091 3092 commitSector := func(t *testing.T, rt *mock.Runtime) *miner.SectorOnChainInfo { 3093 actor.constructAndVerify(rt) 3094 sectorInfo := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 3095 return sectorInfo[0] 3096 } 3097 3098 t.Run("rejects negative extension", func(t *testing.T) { 3099 rt := builder.Build(t) 3100 sector := commitSector(t, rt) 3101 3102 // attempt to shorten epoch 3103 newExpiration := sector.Expiration - abi.ChainEpoch(miner.WPoStProvingPeriod) 3104 3105 // find deadline and partition 3106 st := getState(rt) 3107 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), sector.SectorNumber) 3108 require.NoError(t, err) 3109 3110 params := &miner.ExtendSectorExpirationParams{ 3111 Extensions: []miner.ExpirationExtension{{ 3112 Deadline: dlIdx, 3113 Partition: pIdx, 3114 Sectors: bf(uint64(sector.SectorNumber)), 3115 NewExpiration: newExpiration, 3116 }}, 3117 } 3118 3119 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, fmt.Sprintf("cannot reduce sector %d's expiration", sector.SectorNumber), func() { 3120 actor.extendSectors(rt, params) 3121 }) 3122 actor.checkState(rt) 3123 }) 3124 3125 t.Run("rejects extension too far in future", func(t *testing.T) { 3126 rt := builder.Build(t) 3127 sector := commitSector(t, rt) 3128 3129 // extend by even proving period after max 3130 rt.SetEpoch(sector.Expiration) 3131 extension := miner.WPoStProvingPeriod * (miner.MaxSectorExpirationExtension/miner.WPoStProvingPeriod + 1) 3132 newExpiration := rt.Epoch() + extension 3133 3134 // find deadline and partition 3135 st := getState(rt) 3136 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), sector.SectorNumber) 3137 require.NoError(t, err) 3138 3139 params := &miner.ExtendSectorExpirationParams{ 3140 Extensions: []miner.ExpirationExtension{{ 3141 Deadline: dlIdx, 3142 Partition: pIdx, 3143 Sectors: bf(uint64(sector.SectorNumber)), 3144 NewExpiration: newExpiration, 3145 }}, 3146 } 3147 3148 expectedMessage := fmt.Sprintf("cannot be more than %d past current epoch", miner.MaxSectorExpirationExtension) 3149 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, expectedMessage, func() { 3150 actor.extendSectors(rt, params) 3151 }) 3152 actor.checkState(rt) 3153 }) 3154 3155 t.Run("rejects extension past max for seal proof", func(t *testing.T) { 3156 rt := builder.Build(t) 3157 sector := commitSector(t, rt) 3158 // and prove it once to activate it. 3159 advanceAndSubmitPoSts(rt, actor, sector) 3160 3161 maxLifetime, err := builtin.SealProofSectorMaximumLifetime(sector.SealProof, network.VersionMax) 3162 require.NoError(t, err) 3163 3164 st := getState(rt) 3165 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), sector.SectorNumber) 3166 require.NoError(t, err) 3167 3168 // extend sector until just below threshold 3169 rt.SetEpoch(sector.Expiration) 3170 extension := abi.ChainEpoch(miner.MinSectorExpiration) 3171 expiration := sector.Expiration + extension 3172 for ; expiration-sector.Activation < maxLifetime; expiration += extension { 3173 params := &miner.ExtendSectorExpirationParams{ 3174 Extensions: []miner.ExpirationExtension{{ 3175 Deadline: dlIdx, 3176 Partition: pIdx, 3177 Sectors: bf(uint64(sector.SectorNumber)), 3178 NewExpiration: expiration, 3179 }}, 3180 } 3181 3182 actor.extendSectors(rt, params) 3183 sector.Expiration = expiration 3184 rt.SetEpoch(expiration) 3185 } 3186 3187 // next extension fails because it extends sector past max lifetime 3188 params := &miner.ExtendSectorExpirationParams{ 3189 Extensions: []miner.ExpirationExtension{{ 3190 Deadline: dlIdx, 3191 Partition: pIdx, 3192 Sectors: bf(uint64(sector.SectorNumber)), 3193 NewExpiration: expiration, 3194 }}, 3195 } 3196 3197 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "total sector lifetime", func() { 3198 actor.extendSectors(rt, params) 3199 }) 3200 3201 actor.checkState(rt) 3202 }) 3203 3204 t.Run("updates expiration with valid params", func(t *testing.T) { 3205 rt := builder.Build(t) 3206 oldSector := commitSector(t, rt) 3207 advanceAndSubmitPoSts(rt, actor, oldSector) 3208 3209 st := getState(rt) 3210 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 3211 require.NoError(t, err) 3212 3213 extension := 42 * miner.WPoStProvingPeriod 3214 newExpiration := oldSector.Expiration + extension 3215 params := &miner.ExtendSectorExpirationParams{ 3216 Extensions: []miner.ExpirationExtension{{ 3217 Deadline: dlIdx, 3218 Partition: pIdx, 3219 Sectors: bf(uint64(oldSector.SectorNumber)), 3220 NewExpiration: newExpiration, 3221 }}, 3222 } 3223 3224 actor.extendSectors(rt, params) 3225 3226 // assert sector expiration is set to the new value 3227 newSector := actor.getSector(rt, oldSector.SectorNumber) 3228 assert.Equal(t, newExpiration, newSector.Expiration) 3229 3230 quant := st.QuantSpecForDeadline(dlIdx) 3231 3232 // assert that new expiration exists 3233 _, partition := actor.getDeadlineAndPartition(rt, dlIdx, pIdx) 3234 expirationSet, err := partition.PopExpiredSectors(rt.AdtStore(), newExpiration-1, quant) 3235 require.NoError(t, err) 3236 empty, err := expirationSet.IsEmpty() 3237 require.NoError(t, err) 3238 assert.True(t, empty) 3239 3240 expirationSet, err = partition.PopExpiredSectors(rt.AdtStore(), quant.QuantizeUp(newExpiration), quant) 3241 require.NoError(t, err) 3242 empty, err = expirationSet.IsEmpty() 3243 require.NoError(t, err) 3244 assert.False(t, empty) 3245 3246 actor.checkState(rt) 3247 }) 3248 3249 t.Run("updates many sectors", func(t *testing.T) { 3250 rt := builder.Build(t) 3251 actor.constructAndVerify(rt) 3252 3253 const sectorCount = 4000 3254 3255 // commit a bunch of sectors to ensure that we get multiple partitions. 3256 sectorInfos := actor.commitAndProveSectors(rt, sectorCount, defaultSectorExpiration, nil, true) 3257 advanceAndSubmitPoSts(rt, actor, sectorInfos...) 3258 3259 newExpiration := sectorInfos[0].Expiration + 42*miner.WPoStProvingPeriod 3260 3261 var params miner.ExtendSectorExpirationParams 3262 3263 // extend all odd-numbered sectors. 3264 { 3265 st := getState(rt) 3266 deadlines, err := st.LoadDeadlines(rt.AdtStore()) 3267 require.NoError(t, err) 3268 require.NoError(t, deadlines.ForEach(rt.AdtStore(), func(dlIdx uint64, dl *miner.Deadline) error { 3269 partitions, err := dl.PartitionsArray(rt.AdtStore()) 3270 require.NoError(t, err) 3271 var partition miner.Partition 3272 require.NoError(t, partitions.ForEach(&partition, func(partIdx int64) error { 3273 oldSectorNos, err := partition.Sectors.All(miner.AddressedSectorsMax) 3274 require.NoError(t, err) 3275 3276 // filter out even-numbered sectors. 3277 newSectorNos := make([]uint64, 0, len(oldSectorNos)/2) 3278 for _, sno := range oldSectorNos { 3279 if sno%2 == 0 { 3280 continue 3281 } 3282 newSectorNos = append(newSectorNos, sno) 3283 } 3284 params.Extensions = append(params.Extensions, miner.ExpirationExtension{ 3285 Deadline: dlIdx, 3286 Partition: uint64(partIdx), 3287 Sectors: bf(newSectorNos...), 3288 NewExpiration: newExpiration, 3289 }) 3290 return nil 3291 })) 3292 return nil 3293 })) 3294 } 3295 3296 // Make sure we're touching at least two sectors. 3297 require.GreaterOrEqual(t, len(params.Extensions), 2, 3298 "test error: this test should touch more than one partition", 3299 ) 3300 3301 actor.extendSectors(rt, ¶ms) 3302 3303 { 3304 st := getState(rt) 3305 deadlines, err := st.LoadDeadlines(rt.AdtStore()) 3306 require.NoError(t, err) 3307 3308 // Half the sectors should expire on-time. 3309 var onTimeTotal uint64 3310 require.NoError(t, deadlines.ForEach(rt.AdtStore(), func(dlIdx uint64, dl *miner.Deadline) error { 3311 expirationSet, err := dl.PopExpiredSectors(rt.AdtStore(), newExpiration-1, st.QuantSpecForDeadline(dlIdx)) 3312 require.NoError(t, err) 3313 3314 count, err := expirationSet.Count() 3315 require.NoError(t, err) 3316 onTimeTotal += count 3317 return nil 3318 })) 3319 assert.EqualValues(t, sectorCount/2, onTimeTotal) 3320 3321 // Half the sectors should expire late. 3322 var extendedTotal uint64 3323 require.NoError(t, deadlines.ForEach(rt.AdtStore(), func(dlIdx uint64, dl *miner.Deadline) error { 3324 expirationSet, err := dl.PopExpiredSectors(rt.AdtStore(), newExpiration-1, st.QuantSpecForDeadline(dlIdx)) 3325 require.NoError(t, err) 3326 3327 count, err := expirationSet.Count() 3328 require.NoError(t, err) 3329 extendedTotal += count 3330 return nil 3331 })) 3332 assert.EqualValues(t, sectorCount/2, extendedTotal) 3333 } 3334 3335 actor.checkState(rt) 3336 }) 3337 3338 t.Run("supports extensions off deadline boundary", func(t *testing.T) { 3339 rt := builder.Build(t) 3340 oldSector := commitSector(t, rt) 3341 advanceAndSubmitPoSts(rt, actor, oldSector) 3342 3343 st := getState(rt) 3344 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 3345 require.NoError(t, err) 3346 3347 extension := 42*miner.WPoStProvingPeriod + miner.WPoStProvingPeriod/3 3348 newExpiration := oldSector.Expiration + extension 3349 params := &miner.ExtendSectorExpirationParams{ 3350 Extensions: []miner.ExpirationExtension{{ 3351 Deadline: dlIdx, 3352 Partition: pIdx, 3353 Sectors: bf(uint64(oldSector.SectorNumber)), 3354 NewExpiration: newExpiration, 3355 }}, 3356 } 3357 3358 actor.extendSectors(rt, params) 3359 3360 // assert sector expiration is set to the new value 3361 st = getState(rt) 3362 newSector := actor.getSector(rt, oldSector.SectorNumber) 3363 assert.Equal(t, newExpiration, newSector.Expiration) 3364 3365 // advance clock to expiration 3366 rt.SetEpoch(newSector.Expiration) 3367 st.ProvingPeriodStart += miner.WPoStProvingPeriod * ((rt.Epoch()-st.ProvingPeriodStart)/miner.WPoStProvingPeriod + 1) 3368 rt.ReplaceState(st) 3369 3370 // confirm it is not in sector's deadline 3371 dlinfo := actor.deadline(rt) 3372 assert.NotEqual(t, dlIdx, dlinfo.Index) 3373 3374 // advance to deadline and submit one last PoSt 3375 for dlinfo.Index != dlIdx { 3376 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 3377 } 3378 partitions := []miner.PoStPartition{ 3379 {Index: pIdx, Skipped: bitfield.New()}, 3380 } 3381 actor.submitWindowPoSt(rt, dlinfo, partitions, []*miner.SectorOnChainInfo{newSector}, nil) 3382 3383 // advance one more time. No missed PoSt fees are charged. Total Power and pledge are lowered. 3384 pwr := miner.PowerForSectors(actor.sectorSize, []*miner.SectorOnChainInfo{newSector}).Neg() 3385 advanceDeadline(rt, actor, &cronConfig{ 3386 noEnrollment: true, 3387 expiredSectorsPowerDelta: &pwr, 3388 expiredSectorsPledgeDelta: newSector.InitialPledge.Neg(), 3389 }) 3390 st = getState(rt) 3391 assert.False(t, st.DeadlineCronActive) 3392 actor.checkState(rt) 3393 }) 3394 3395 t.Run("prevents extending old seal proof types", func(t *testing.T) { 3396 actor := newHarness(t, periodOffset) 3397 actor.setProofType(abi.RegisteredSealProof_StackedDrg32GiBV1) 3398 rt := builderForHarness(actor). 3399 WithBalance(bigBalance, big.Zero()). 3400 Build(t) 3401 rt.SetNetworkVersion(network.Version7) 3402 actor.constructAndVerify(rt) 3403 3404 // Commit and prove first sector with V1 3405 rt.SetEpoch(periodOffset + miner.WPoStChallengeWindow) 3406 sector := actor.commitAndProveSector(rt, 101, defaultSectorExpiration, nil) 3407 assert.Equal(t, abi.RegisteredSealProof_StackedDrg32GiBV1, sector.SealProof) 3408 3409 st := getState(rt) 3410 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), sector.SectorNumber) 3411 require.NoError(t, err) 3412 3413 newExpiration := sector.Expiration + abi.ChainEpoch(miner.MinSectorExpiration) 3414 params := &miner.ExtendSectorExpirationParams{ 3415 Extensions: []miner.ExpirationExtension{{ 3416 Deadline: dlIdx, 3417 Partition: pIdx, 3418 Sectors: bf(uint64(sector.SectorNumber)), 3419 NewExpiration: newExpiration, 3420 }}, 3421 } 3422 3423 rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, "unsupported seal type", func() { 3424 actor.extendSectors(rt, params) 3425 }) 3426 actor.checkState(rt) 3427 }) 3428 } 3429 3430 func TestTerminateSectors(t *testing.T) { 3431 periodOffset := abi.ChainEpoch(100) 3432 actor := newHarness(t, periodOffset) 3433 builder := builderForHarness(actor). 3434 WithBalance(big.Mul(big.NewInt(1e18), big.NewInt(200000)), big.Zero()) 3435 3436 t.Run("removes sector with correct accounting", func(t *testing.T) { 3437 rt := builder.Build(t) 3438 actor.constructAndVerify(rt) 3439 rt.SetEpoch(abi.ChainEpoch(1)) 3440 sectorInfo := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 3441 sector := sectorInfo[0] 3442 advanceAndSubmitPoSts(rt, actor, sector) 3443 3444 // A miner will pay the minimum of termination fee and locked funds. Add some locked funds to ensure 3445 // correct fee calculation is used. 3446 actor.applyRewards(rt, bigRewards, big.Zero()) 3447 st := getState(rt) 3448 initialLockedFunds := st.LockedFunds 3449 3450 sectorSize, err := sector.SealProof.SectorSize() 3451 require.NoError(t, err) 3452 sectorPower := miner.QAPowerForSector(sectorSize, sector) 3453 dayReward := miner.ExpectedRewardForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, sectorPower, builtin.EpochsInDay) 3454 twentyDayReward := miner.ExpectedRewardForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, sectorPower, miner.InitialPledgeProjectionPeriod) 3455 sectorAge := rt.Epoch() - sector.Activation 3456 expectedFee := miner.PledgePenaltyForTermination(dayReward, sectorAge, twentyDayReward, actor.epochQAPowerSmooth, sectorPower, actor.epochRewardSmooth, big.Zero(), 0) 3457 3458 sectors := bf(uint64(sector.SectorNumber)) 3459 actor.terminateSectors(rt, sectors, expectedFee) 3460 3461 { 3462 st := getState(rt) 3463 3464 // expect sector to be marked as terminated and the early termination queue to be empty (having been fully processed) 3465 _, partition := actor.findSector(rt, sector.SectorNumber) 3466 terminated, err := partition.Terminated.IsSet(uint64(sector.SectorNumber)) 3467 require.NoError(t, err) 3468 assert.True(t, terminated) 3469 result, _, err := partition.PopEarlyTerminations(rt.AdtStore(), 1000) 3470 require.NoError(t, err) 3471 assert.True(t, result.IsEmpty()) 3472 3473 // expect fee to have been unlocked and burnt 3474 assert.Equal(t, big.Sub(initialLockedFunds, expectedFee), st.LockedFunds) 3475 3476 // expect pledge requirement to have been decremented 3477 assert.Equal(t, big.Zero(), st.InitialPledge) 3478 } 3479 actor.checkState(rt) 3480 }) 3481 3482 t.Run("charges correct fee for young termination of committed capacity upgrade", func(t *testing.T) { 3483 actor := newHarness(t, periodOffset) 3484 rt := builderForHarness(actor). 3485 WithBalance(bigBalance, big.Zero()). 3486 Build(t) 3487 actor.constructAndVerify(rt) 3488 3489 // Move the current epoch forward so that the first deadline is a stable candidate for both sectors 3490 rt.SetEpoch(periodOffset + miner.WPoStChallengeWindow) 3491 3492 // Commit a sector to upgrade 3493 oldSector := actor.commitAndProveSector(rt, 1, defaultSectorExpiration, nil) 3494 advanceAndSubmitPoSts(rt, actor, oldSector) // activate power 3495 st := getState(rt) 3496 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 3497 require.NoError(t, err) 3498 3499 // advance clock so upgrade happens later 3500 for i := 0; i < 4; i++ { // 4 * 2880 = 11,520 3501 advanceAndSubmitPoSts(rt, actor, oldSector) 3502 } 3503 3504 challengeEpoch := rt.Epoch() - 1 3505 upgradeParams := actor.makePreCommit(200, challengeEpoch, oldSector.Expiration, []abi.DealID{1}) 3506 upgradeParams.ReplaceCapacity = true 3507 upgradeParams.ReplaceSectorDeadline = dlIdx 3508 upgradeParams.ReplaceSectorPartition = partIdx 3509 upgradeParams.ReplaceSectorNumber = oldSector.SectorNumber 3510 upgrade := actor.preCommitSector(rt, upgradeParams, preCommitConf{}, false) 3511 3512 // Prove new sector 3513 rt.SetEpoch(upgrade.PreCommitEpoch + miner.PreCommitChallengeDelay + 1) 3514 newSector := actor.proveCommitSectorAndConfirm(rt, upgrade, makeProveCommit(upgrade.Info.SectorNumber), proveCommitConf{}) 3515 3516 // Expect replace parameters have been set 3517 assert.Equal(t, oldSector.ExpectedDayReward, newSector.ReplacedDayReward) 3518 assert.Equal(t, rt.Epoch()-oldSector.Activation, newSector.ReplacedSectorAge) 3519 3520 // advance to deadline of new and old sectors 3521 dlInfo := actor.currentDeadline(rt) 3522 for dlInfo.Index != dlIdx { 3523 dlInfo = advanceDeadline(rt, actor, &cronConfig{}) 3524 } 3525 /**/ 3526 // PoSt both sectors. They both gain power and no penalties are incurred. 3527 rt.SetEpoch(dlInfo.Last()) 3528 oldPower := miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), miner.QAPowerForSector(actor.sectorSize, oldSector)) 3529 newPower := miner.NewPowerPair(big.NewInt(int64(actor.sectorSize)), miner.QAPowerForSector(actor.sectorSize, newSector)) 3530 partitions := []miner.PoStPartition{ 3531 {Index: partIdx, Skipped: bitfield.New()}, 3532 } 3533 actor.submitWindowPoSt(rt, dlInfo, partitions, []*miner.SectorOnChainInfo{newSector, oldSector}, &poStConfig{ 3534 expectedPowerDelta: newPower, 3535 }) 3536 3537 // replaced sector expires at cron, removing its power and pledge. 3538 expectedPowerDelta := oldPower.Neg() 3539 actor.onDeadlineCron(rt, &cronConfig{ 3540 expiredSectorsPowerDelta: &expectedPowerDelta, 3541 expiredSectorsPledgeDelta: oldSector.InitialPledge.Neg(), 3542 expectedEnrollment: rt.Epoch() + miner.WPoStChallengeWindow, 3543 }) 3544 actor.checkState(rt) 3545 3546 // advance clock a little and terminate new sector 3547 rt.SetEpoch(rt.Epoch() + 5_000) 3548 3549 // Add some locked funds to ensure full termination fee appears as pledge change. 3550 actor.applyRewards(rt, bigRewards, big.Zero()) 3551 3552 sectorPower := miner.QAPowerForSector(actor.sectorSize, newSector) 3553 twentyDayReward := miner.ExpectedRewardForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, sectorPower, miner.InitialPledgeProjectionPeriod) 3554 newSectorAge := rt.Epoch() - newSector.Activation 3555 oldSectorAge := newSector.Activation - oldSector.Activation 3556 expectedFee := miner.PledgePenaltyForTermination(newSector.ExpectedDayReward, newSectorAge, twentyDayReward, 3557 actor.epochQAPowerSmooth, sectorPower, actor.epochRewardSmooth, oldSector.ExpectedDayReward, oldSectorAge) 3558 3559 sectors := bf(uint64(newSector.SectorNumber)) 3560 actor.terminateSectors(rt, sectors, expectedFee) 3561 actor.checkState(rt) 3562 }) 3563 3564 t.Run("cannot terminate a sector when the challenge window is open", func(t *testing.T) { 3565 rt := builder.Build(t) 3566 actor.constructAndVerify(rt) 3567 rt.SetEpoch(abi.ChainEpoch(1)) 3568 sectorInfo := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 3569 sector := sectorInfo[0] 3570 3571 st := getState(rt) 3572 dlIdx, pIdx, err := st.FindSector(rt.AdtStore(), sector.SectorNumber) 3573 require.NoError(t, err) 3574 3575 // advance into the deadline, but not past it. 3576 dlinfo := actor.deadline(rt) 3577 for dlinfo.Index != dlIdx { 3578 dlinfo = advanceDeadline(rt, actor, &cronConfig{}) 3579 } 3580 3581 params := &miner.TerminateSectorsParams{Terminations: []miner.TerminationDeclaration{{ 3582 Deadline: dlIdx, 3583 Partition: pIdx, 3584 Sectors: bf(uint64(sector.SectorNumber)), 3585 }}} 3586 rt.SetCaller(actor.worker, builtin.AccountActorCodeID) 3587 rt.ExpectValidateCallerAddr(append(actor.controlAddrs, actor.owner, actor.worker)...) 3588 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "cannot terminate sectors in immutable deadline", func() { 3589 rt.Call(actor.a.TerminateSectors, params) 3590 }) 3591 3592 actor.checkState(rt) 3593 }) 3594 3595 } 3596 3597 func TestWithdrawBalance(t *testing.T) { 3598 periodOffset := abi.ChainEpoch(100) 3599 actor := newHarness(t, periodOffset) 3600 builder := builderForHarness(actor). 3601 WithBalance(bigBalance, big.Zero()) 3602 3603 onePercentBalance := big.Div(bigBalance, big.NewInt(100)) 3604 3605 t.Run("happy path withdraws funds", func(t *testing.T) { 3606 rt := builder.Build(t) 3607 actor.constructAndVerify(rt) 3608 3609 // withdraw 1% of balance 3610 actor.withdrawFunds(rt, onePercentBalance, onePercentBalance, big.Zero()) 3611 actor.checkState(rt) 3612 }) 3613 3614 t.Run("fails if miner can't repay fee debt", func(t *testing.T) { 3615 rt := builder.Build(t) 3616 actor.constructAndVerify(rt) 3617 3618 st := getState(rt) 3619 st.FeeDebt = big.Add(rt.Balance(), abi.NewTokenAmount(1e18)) 3620 rt.ReplaceState(st) 3621 rt.ExpectAbortContainsMessage(exitcode.ErrInsufficientFunds, "unlocked balance can not repay fee debt", func() { 3622 actor.withdrawFunds(rt, onePercentBalance, onePercentBalance, big.Zero()) 3623 }) 3624 actor.checkState(rt) 3625 }) 3626 3627 t.Run("withdraw only what we can after fee debt", func(t *testing.T) { 3628 rt := builder.Build(t) 3629 actor.constructAndVerify(rt) 3630 3631 st := getState(rt) 3632 feeDebt := big.Sub(bigBalance, onePercentBalance) 3633 st.FeeDebt = feeDebt 3634 rt.ReplaceState(st) 3635 3636 requested := rt.Balance() 3637 expectedWithdraw := big.Sub(requested, feeDebt) 3638 actor.withdrawFunds(rt, requested, expectedWithdraw, feeDebt) 3639 actor.checkState(rt) 3640 }) 3641 } 3642 3643 func TestRepayDebts(t *testing.T) { 3644 actor := newHarness(t, abi.ChainEpoch(100)) 3645 builder := builderForHarness(actor). 3646 WithBalance(big.Zero(), big.Zero()) 3647 3648 t.Run("repay with no avaialable funds does nothing", func(t *testing.T) { 3649 rt := builder.Build(t) 3650 actor.constructAndVerify(rt) 3651 3652 // introduce fee debt 3653 st := getState(rt) 3654 feeDebt := big.Mul(big.NewInt(4), big.NewInt(1e18)) 3655 st.FeeDebt = feeDebt 3656 rt.ReplaceState(st) 3657 3658 actor.repayDebt(rt, big.Zero(), big.Zero(), big.Zero()) 3659 3660 st = getState(rt) 3661 assert.Equal(t, feeDebt, st.FeeDebt) 3662 actor.checkState(rt) 3663 }) 3664 3665 t.Run("pay debt entirely from balance", func(t *testing.T) { 3666 rt := builder.Build(t) 3667 actor.constructAndVerify(rt) 3668 3669 // introduce fee debt 3670 st := getState(rt) 3671 feeDebt := big.Mul(big.NewInt(4), big.NewInt(1e18)) 3672 st.FeeDebt = feeDebt 3673 rt.ReplaceState(st) 3674 3675 debtToRepay := big.Mul(big.NewInt(2), feeDebt) 3676 actor.repayDebt(rt, debtToRepay, big.Zero(), feeDebt) 3677 3678 st = getState(rt) 3679 assert.Equal(t, big.Zero(), st.FeeDebt) 3680 actor.checkState(rt) 3681 }) 3682 3683 t.Run("partially repay debt", func(t *testing.T) { 3684 rt := builder.Build(t) 3685 actor.constructAndVerify(rt) 3686 3687 // introduce fee debt 3688 st := getState(rt) 3689 feeDebt := big.Mul(big.NewInt(4), big.NewInt(1e18)) 3690 st.FeeDebt = feeDebt 3691 rt.ReplaceState(st) 3692 3693 debtToRepay := big.Mul(big.NewInt(3), big.Div(feeDebt, big.NewInt(4))) 3694 actor.repayDebt(rt, debtToRepay, big.Zero(), debtToRepay) 3695 3696 st = getState(rt) 3697 assert.Equal(t, big.Div(feeDebt, big.NewInt(4)), st.FeeDebt) 3698 actor.checkState(rt) 3699 }) 3700 3701 t.Run("pay debt partially from vested funds", func(t *testing.T) { 3702 rt := builder.Build(t) 3703 actor.constructAndVerify(rt) 3704 3705 rewardAmount := big.Mul(big.NewInt(4), big.NewInt(1e18)) 3706 amountLocked, _ := miner.LockedRewardFromReward(rewardAmount) 3707 rt.SetBalance(amountLocked) 3708 actor.applyRewards(rt, rewardAmount, big.Zero()) 3709 require.Equal(t, amountLocked, actor.getLockedFunds(rt)) 3710 3711 // introduce fee debt 3712 st := getState(rt) 3713 feeDebt := big.Mul(big.NewInt(4), big.NewInt(1e18)) 3714 st.FeeDebt = feeDebt 3715 rt.ReplaceState(st) 3716 3717 // send 1 FIL and repay all debt from vesting funds and balance 3718 actor.repayDebt(rt, 3719 big.NewInt(1e18), // send 1 FIL 3720 amountLocked, // 3 FIL comes from vesting funds 3721 big.NewInt(1e18)) // 1 FIL sent from balance 3722 3723 st = getState(rt) 3724 assert.Equal(t, big.Zero(), st.FeeDebt) 3725 actor.checkState(rt) 3726 }) 3727 } 3728 3729 func TestChangePeerID(t *testing.T) { 3730 periodOffset := abi.ChainEpoch(100) 3731 actor := newHarness(t, periodOffset) 3732 builder := builderForHarness(actor). 3733 WithBalance(bigBalance, big.Zero()) 3734 3735 t.Run("successfully change peer id", func(t *testing.T) { 3736 rt := builder.Build(t) 3737 actor.constructAndVerify(rt) 3738 3739 newPID := tutil.MakePID("test-change-peer-id") 3740 actor.changePeerID(rt, newPID) 3741 actor.checkState(rt) 3742 }) 3743 } 3744 3745 func TestCompactPartitions(t *testing.T) { 3746 periodOffset := abi.ChainEpoch(100) 3747 actor := newHarness(t, periodOffset) 3748 builder := builderForHarness(actor). 3749 WithBalance(bigBalance, big.Zero()) 3750 3751 assertSectorExists := func(store adt.Store, st *miner.State, sectorNum abi.SectorNumber, expectPart uint64, expectDeadline uint64) { 3752 _, found, err := st.GetSector(store, sectorNum) 3753 require.NoError(t, err) 3754 require.True(t, found) 3755 3756 deadline, pid, err := st.FindSector(store, sectorNum) 3757 require.NoError(t, err) 3758 require.EqualValues(t, expectPart, pid) 3759 require.EqualValues(t, expectDeadline, deadline) 3760 } 3761 3762 assertSectorNotFound := func(store adt.Store, st *miner.State, sectorNum abi.SectorNumber) { 3763 _, found, err := st.GetSector(store, sectorNum) 3764 require.NoError(t, err) 3765 require.False(t, found) 3766 3767 _, _, err = st.FindSector(store, sectorNum) 3768 require.Error(t, err) 3769 require.Contains(t, err.Error(), "not due at any deadline") 3770 } 3771 3772 t.Run("compacting a partition with both live and dead sectors removes the dead sectors but retains the live sectors", func(t *testing.T) { 3773 rt := builder.Build(t) 3774 actor.constructAndVerify(rt) 3775 3776 rt.SetEpoch(200) 3777 // create 4 sectors in partition 0 3778 info := actor.commitAndProveSectors(rt, 4, defaultSectorExpiration, [][]abi.DealID{{10}, {20}, {30}, {40}}, true) 3779 3780 advanceAndSubmitPoSts(rt, actor, info...) // prove and activate power. 3781 3782 sector1 := info[0].SectorNumber 3783 sector2 := info[1].SectorNumber 3784 sector3 := info[2].SectorNumber 3785 sector4 := info[3].SectorNumber 3786 3787 // terminate sector1 3788 rt.SetEpoch(rt.Epoch() + 100) 3789 actor.applyRewards(rt, bigRewards, big.Zero()) 3790 tsector := info[0] 3791 sectorSize, err := tsector.SealProof.SectorSize() 3792 require.NoError(t, err) 3793 sectorPower := miner.QAPowerForSector(sectorSize, tsector) 3794 dayReward := miner.ExpectedRewardForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, sectorPower, builtin.EpochsInDay) 3795 twentyDayReward := miner.ExpectedRewardForPower(actor.epochRewardSmooth, actor.epochQAPowerSmooth, sectorPower, miner.InitialPledgeProjectionPeriod) 3796 sectorAge := rt.Epoch() - tsector.Activation 3797 expectedFee := miner.PledgePenaltyForTermination(dayReward, sectorAge, twentyDayReward, actor.epochQAPowerSmooth, 3798 sectorPower, actor.epochRewardSmooth, big.Zero(), 0) 3799 3800 sectors := bitfield.NewFromSet([]uint64{uint64(sector1)}) 3801 actor.terminateSectors(rt, sectors, expectedFee) 3802 3803 // Wait WPoStProofChallengePeriod epochs so we can compact the sector. 3804 advanceToEpochWithCron(rt, actor, rt.Epoch()+miner.WPoStDisputeWindow) 3805 3806 // compacting partition will remove sector1 but retain sector 2, 3 and 4. 3807 partId := uint64(0) 3808 deadlineId := uint64(0) 3809 partitions := bitfield.NewFromSet([]uint64{partId}) 3810 actor.compactPartitions(rt, deadlineId, partitions) 3811 3812 st := getState(rt) 3813 assertSectorExists(rt.AdtStore(), st, sector2, partId, deadlineId) 3814 assertSectorExists(rt.AdtStore(), st, sector3, partId, deadlineId) 3815 assertSectorExists(rt.AdtStore(), st, sector4, partId, deadlineId) 3816 3817 assertSectorNotFound(rt.AdtStore(), st, sector1) 3818 actor.checkState(rt) 3819 }) 3820 3821 t.Run("fail to compact partitions with faults", func(T *testing.T) { 3822 rt := builder.Build(t) 3823 actor.constructAndVerify(rt) 3824 3825 rt.SetEpoch(200) 3826 // create 2 sectors in partition 0 3827 info := actor.commitAndProveSectors(rt, 2, defaultSectorExpiration, [][]abi.DealID{{10}, {20}}, true) 3828 advanceAndSubmitPoSts(rt, actor, info...) // prove and activate power. 3829 3830 // fault sector1 3831 actor.declareFaults(rt, info[0]) 3832 3833 // Wait WPoStProofChallengePeriod epochs so we can compact the sector. 3834 advanceToEpochWithCron(rt, actor, rt.Epoch()+miner.WPoStDisputeWindow) 3835 3836 partId := uint64(0) 3837 deadlineId := uint64(0) 3838 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "failed to remove partitions from deadline 0: while removing partitions: cannot remove partition 0: has faults", func() { 3839 partitions := bitfield.NewFromSet([]uint64{partId}) 3840 actor.compactPartitions(rt, deadlineId, partitions) 3841 }) 3842 actor.checkState(rt) 3843 }) 3844 3845 t.Run("fails to compact partitions with unproven sectors", func(T *testing.T) { 3846 rt := builder.Build(t) 3847 actor.constructAndVerify(rt) 3848 3849 // Wait until deadline 0 (the one to which we'll assign the 3850 // sector) has elapsed. That'll let us commit, prove, then wait 3851 // finality epochs. 3852 st := getState(rt) 3853 deadlineEpoch := miner.NewDeadlineInfo(st.ProvingPeriodStart, 0, rt.Epoch()).NextNotElapsed().NextOpen() 3854 rt.SetEpoch(deadlineEpoch) 3855 3856 // create 2 sectors in partition 0 3857 actor.commitAndProveSectors(rt, 2, defaultSectorExpiration, [][]abi.DealID{{10}, {20}}, true) 3858 3859 // Wait WPoStProofChallengePeriod epochs so we can compact the sector. 3860 advanceToEpochWithCron(rt, actor, rt.Epoch()+miner.WPoStDisputeWindow) 3861 3862 partId := uint64(0) 3863 deadlineId := uint64(0) 3864 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "failed to remove partitions from deadline 0: while removing partitions: cannot remove partition 0: has unproven sectors", func() { 3865 partitions := bitfield.NewFromSet([]uint64{partId}) 3866 actor.compactPartitions(rt, deadlineId, partitions) 3867 }) 3868 actor.checkState(rt) 3869 }) 3870 3871 t.Run("fails if deadline is equal to WPoStPeriodDeadlines", func(t *testing.T) { 3872 rt := builder.Build(t) 3873 actor.constructAndVerify(rt) 3874 3875 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "invalid deadline 48", func() { 3876 actor.compactPartitions(rt, miner.WPoStPeriodDeadlines, bitfield.New()) 3877 }) 3878 actor.checkState(rt) 3879 }) 3880 3881 t.Run("fails if deadline is open for challenging", func(t *testing.T) { 3882 rt := builder.Build(t) 3883 actor.constructAndVerify(rt) 3884 3885 rt.SetEpoch(periodOffset) 3886 rt.ExpectAbort(exitcode.ErrForbidden, func() { 3887 actor.compactPartitions(rt, 0, bitfield.New()) 3888 }) 3889 actor.checkState(rt) 3890 }) 3891 3892 t.Run("fails if deadline is next up to be challenged", func(t *testing.T) { 3893 rt := builder.Build(t) 3894 actor.constructAndVerify(rt) 3895 3896 rt.SetEpoch(periodOffset) 3897 rt.ExpectAbort(exitcode.ErrForbidden, func() { 3898 actor.compactPartitions(rt, 1, bitfield.New()) 3899 }) 3900 actor.checkState(rt) 3901 }) 3902 3903 t.Run("the deadline after the next deadline should still be open for compaction", func(t *testing.T) { 3904 rt := builder.Build(t) 3905 actor.constructAndVerify(rt) 3906 3907 rt.SetEpoch(periodOffset) 3908 actor.compactPartitions(rt, 3, bitfield.New()) 3909 actor.checkState(rt) 3910 }) 3911 3912 t.Run("deadlines challenged last proving period should still be in the dispute window", func(t *testing.T) { 3913 rt := builder.Build(t) 3914 actor.constructAndVerify(rt) 3915 3916 rt.SetEpoch(periodOffset) 3917 rt.ExpectAbort(exitcode.ErrForbidden, func() { 3918 actor.compactPartitions(rt, 47, bitfield.New()) 3919 }) 3920 actor.checkState(rt) 3921 }) 3922 3923 disputeEnd := periodOffset + miner.WPoStChallengeWindow + miner.WPoStDisputeWindow - 1 3924 t.Run("compaction should be forbidden during the dispute window", func(t *testing.T) { 3925 rt := builder.Build(t) 3926 actor.constructAndVerify(rt) 3927 3928 rt.SetEpoch(disputeEnd) 3929 rt.ExpectAbort(exitcode.ErrForbidden, func() { 3930 actor.compactPartitions(rt, 0, bitfield.New()) 3931 }) 3932 actor.checkState(rt) 3933 }) 3934 3935 t.Run("compaction should be allowed following the dispute window", func(t *testing.T) { 3936 rt := builder.Build(t) 3937 actor.constructAndVerify(rt) 3938 3939 rt.SetEpoch(disputeEnd + 1) 3940 actor.compactPartitions(rt, 0, bitfield.New()) 3941 actor.checkState(rt) 3942 }) 3943 3944 t.Run("fails if partition count is above limit", func(t *testing.T) { 3945 rt := builder.Build(t) 3946 actor.constructAndVerify(rt) 3947 3948 // partition limit is 4 for the default construction 3949 bf := bitfield.NewFromSet([]uint64{1, 2, 3, 4, 5}) 3950 3951 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 3952 actor.compactPartitions(rt, 1, bf) 3953 }) 3954 actor.checkState(rt) 3955 }) 3956 } 3957 3958 func TestCheckSectorProven(t *testing.T) { 3959 periodOffset := abi.ChainEpoch(100) 3960 3961 t.Run("successfully check sector is proven", func(t *testing.T) { 3962 actor := newHarness(t, periodOffset) 3963 rt := builderForHarness(actor). 3964 WithBalance(bigBalance, big.Zero()). 3965 Build(t) 3966 actor.constructAndVerify(rt) 3967 3968 sectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, [][]abi.DealID{{10}}, true) 3969 3970 actor.checkSectorProven(rt, sectors[0].SectorNumber) 3971 actor.checkState(rt) 3972 }) 3973 3974 t.Run("fails is sector is not found", func(t *testing.T) { 3975 actor := newHarness(t, periodOffset) 3976 rt := builderForHarness(actor). 3977 WithBalance(bigBalance, big.Zero()). 3978 Build(t) 3979 actor.constructAndVerify(rt) 3980 3981 rt.ExpectAbort(exitcode.ErrNotFound, func() { 3982 actor.checkSectorProven(rt, abi.SectorNumber(1)) 3983 }) 3984 actor.checkState(rt) 3985 }) 3986 } 3987 3988 func TestChangeMultiAddrs(t *testing.T) { 3989 periodOffset := abi.ChainEpoch(100) 3990 3991 t.Run("successfully change multiaddrs", func(t *testing.T) { 3992 actor := newHarness(t, periodOffset) 3993 builder := builderForHarness(actor). 3994 WithBalance(bigBalance, big.Zero()) 3995 rt := builder.Build(t) 3996 actor.constructAndVerify(rt) 3997 3998 addr1 := abi.Multiaddrs([]byte("addr1")) 3999 addr2 := abi.Multiaddrs([]byte("addr2")) 4000 4001 actor.changeMultiAddrs(rt, []abi.Multiaddrs{addr1, addr2}) 4002 actor.checkState(rt) 4003 }) 4004 4005 t.Run("clear multiaddrs by passing in empty slice", func(t *testing.T) { 4006 actor := newHarness(t, periodOffset) 4007 builder := builderForHarness(actor). 4008 WithBalance(bigBalance, big.Zero()) 4009 rt := builder.Build(t) 4010 actor.constructAndVerify(rt) 4011 4012 actor.changeMultiAddrs(rt, nil) 4013 actor.checkState(rt) 4014 }) 4015 } 4016 4017 func TestChangeWorkerAddress(t *testing.T) { 4018 periodOffset := abi.ChainEpoch(100) 4019 4020 setupFunc := func() (*mock.Runtime, *actorHarness) { 4021 actor := newHarness(t, periodOffset) 4022 builder := builderForHarness(actor). 4023 WithBalance(bigBalance, big.Zero()) 4024 rt := builder.Build(t) 4025 4026 return rt, actor 4027 } 4028 4029 t.Run("successfully change ONLY the worker address", func(t *testing.T) { 4030 rt, actor := setupFunc() 4031 actor.constructAndVerify(rt) 4032 originalControlAddrs := actor.controlAddrs 4033 4034 newWorker := tutil.NewIDAddr(t, 999) 4035 4036 // set epoch to something close to next deadline so first cron will be before effective date 4037 currentEpoch := abi.ChainEpoch(2970) 4038 rt.SetEpoch(currentEpoch) 4039 4040 effectiveEpoch := currentEpoch + miner.WorkerKeyChangeDelay 4041 actor.changeWorkerAddress(rt, newWorker, effectiveEpoch, originalControlAddrs) 4042 4043 // assert change has been made in state 4044 info := actor.getInfo(rt) 4045 assert.Equal(t, info.PendingWorkerKey.NewWorker, newWorker) 4046 assert.Equal(t, info.PendingWorkerKey.EffectiveAt, effectiveEpoch) 4047 4048 // no change if current epoch is less than effective epoch 4049 st := getState(rt) 4050 deadline := st.DeadlineInfo(rt.Epoch()) 4051 rt.SetEpoch(deadline.PeriodEnd()) 4052 4053 info = actor.getInfo(rt) 4054 require.NotNil(t, info.PendingWorkerKey) 4055 require.EqualValues(t, actor.worker, info.Worker) 4056 4057 // move to deadline containing effectiveEpoch 4058 rt.SetEpoch(effectiveEpoch) 4059 4060 // enact worker change 4061 actor.confirmUpdateWorkerKey(rt) 4062 4063 // assert address has changed 4064 info = actor.getInfo(rt) 4065 assert.Equal(t, newWorker, info.Worker) 4066 4067 // assert control addresses are unchanged 4068 require.NotEmpty(t, info.ControlAddresses) 4069 require.Equal(t, originalControlAddrs, info.ControlAddresses) 4070 actor.checkState(rt) 4071 }) 4072 4073 t.Run("change cannot be overridden", func(t *testing.T) { 4074 rt, actor := setupFunc() 4075 actor.constructAndVerify(rt) 4076 originalControlAddrs := actor.controlAddrs 4077 4078 newWorker1 := tutil.NewIDAddr(t, 999) 4079 newWorker2 := tutil.NewIDAddr(t, 1023) 4080 4081 // set epoch to something close to next deadline so first cron will be before effective date 4082 currentEpoch := abi.ChainEpoch(2970) 4083 rt.SetEpoch(currentEpoch) 4084 4085 effectiveEpoch := currentEpoch + miner.WorkerKeyChangeDelay 4086 actor.changeWorkerAddress(rt, newWorker1, effectiveEpoch, originalControlAddrs) 4087 4088 // no change if current epoch is less than effective epoch 4089 st := getState(rt) 4090 deadline := st.DeadlineInfo(rt.Epoch()) 4091 rt.SetEpoch(deadline.PeriodEnd()) 4092 4093 // attempt to change address again 4094 actor.changeWorkerAddress(rt, newWorker2, rt.Epoch()+miner.WorkerKeyChangeDelay, originalControlAddrs) 4095 4096 // assert change has not been modified 4097 info := actor.getInfo(rt) 4098 assert.Equal(t, info.PendingWorkerKey.NewWorker, newWorker1) 4099 assert.Equal(t, info.PendingWorkerKey.EffectiveAt, effectiveEpoch) 4100 4101 rt.SetEpoch(effectiveEpoch) 4102 actor.confirmUpdateWorkerKey(rt) 4103 4104 // assert original change is effected 4105 info = actor.getInfo(rt) 4106 assert.Equal(t, newWorker1, info.Worker) 4107 actor.checkState(rt) 4108 }) 4109 4110 t.Run("successfully resolve AND change ONLY control addresses", func(t *testing.T) { 4111 rt, actor := setupFunc() 4112 actor.constructAndVerify(rt) 4113 4114 c1Id := tutil.NewIDAddr(t, 555) 4115 4116 c2Id := tutil.NewIDAddr(t, 556) 4117 c2NonId := tutil.NewBLSAddr(t, 999) 4118 rt.AddIDAddress(c2NonId, c2Id) 4119 4120 rt.SetAddressActorType(c1Id, builtin.AccountActorCodeID) 4121 rt.SetAddressActorType(c2Id, builtin.AccountActorCodeID) 4122 4123 actor.changeWorkerAddress(rt, actor.worker, abi.ChainEpoch(-1), []addr.Address{c1Id, c2NonId}) 4124 4125 // assert there is no worker change request and worker key is unchanged 4126 st := getState(rt) 4127 info, err := st.GetInfo(adt.AsStore(rt)) 4128 require.NoError(t, err) 4129 require.Equal(t, actor.worker, info.Worker) 4130 require.Nil(t, info.PendingWorkerKey) 4131 actor.checkState(rt) 4132 }) 4133 4134 t.Run("successfully change both worker AND control addresses", func(t *testing.T) { 4135 rt, actor := setupFunc() 4136 actor.constructAndVerify(rt) 4137 4138 newWorker := tutil.NewIDAddr(t, 999) 4139 4140 c1 := tutil.NewIDAddr(t, 5001) 4141 c2 := tutil.NewIDAddr(t, 5002) 4142 rt.SetAddressActorType(c1, builtin.AccountActorCodeID) 4143 rt.SetAddressActorType(c2, builtin.AccountActorCodeID) 4144 4145 currentEpoch := abi.ChainEpoch(5) 4146 rt.SetEpoch(currentEpoch) 4147 effectiveEpoch := currentEpoch + miner.WorkerKeyChangeDelay 4148 actor.changeWorkerAddress(rt, newWorker, effectiveEpoch, []addr.Address{c1, c2}) 4149 4150 // set current epoch and update worker key 4151 rt.SetEpoch(effectiveEpoch) 4152 actor.confirmUpdateWorkerKey(rt) 4153 4154 // assert both worker and control addresses have changed 4155 st := getState(rt) 4156 info, err := st.GetInfo(adt.AsStore(rt)) 4157 require.NoError(t, err) 4158 require.NotEmpty(t, info.ControlAddresses) 4159 require.Equal(t, []addr.Address{c1, c2}, info.ControlAddresses) 4160 require.Equal(t, newWorker, info.Worker) 4161 actor.checkState(rt) 4162 }) 4163 4164 t.Run("successfully clear all control addresses", func(t *testing.T) { 4165 rt, actor := setupFunc() 4166 actor.constructAndVerify(rt) 4167 4168 actor.changeWorkerAddress(rt, actor.worker, abi.ChainEpoch(-1), nil) 4169 4170 // assert control addresses are cleared 4171 st := getState(rt) 4172 info, err := st.GetInfo(adt.AsStore(rt)) 4173 require.NoError(t, err) 4174 require.Empty(t, info.ControlAddresses) 4175 actor.checkState(rt) 4176 }) 4177 4178 t.Run("fails if control addresses length exceeds maximum limit", func(t *testing.T) { 4179 rt, actor := setupFunc() 4180 actor.constructAndVerify(rt) 4181 4182 controlAddrs := make([]addr.Address, 0, miner.MaxControlAddresses+1) 4183 for i := 0; i <= miner.MaxControlAddresses; i++ { 4184 controlAddrs = append(controlAddrs, tutil.NewIDAddr(t, uint64(i))) 4185 } 4186 4187 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "control addresses length", func() { 4188 actor.changeWorkerAddress(rt, actor.worker, abi.ChainEpoch(-1), controlAddrs) 4189 }) 4190 actor.checkState(rt) 4191 }) 4192 4193 t.Run("fails if unable to resolve control address", func(t *testing.T) { 4194 rt, actor := setupFunc() 4195 actor.constructAndVerify(rt) 4196 c1 := tutil.NewBLSAddr(t, 501) 4197 4198 rt.SetCaller(actor.owner, builtin.AccountActorCodeID) 4199 param := &miner.ChangeWorkerAddressParams{NewControlAddrs: []addr.Address{c1}} 4200 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4201 rt.Call(actor.a.ChangeWorkerAddress, param) 4202 }) 4203 rt.Verify() 4204 actor.checkState(rt) 4205 }) 4206 4207 t.Run("fails if unable to resolve worker address", func(t *testing.T) { 4208 rt, actor := setupFunc() 4209 actor.constructAndVerify(rt) 4210 newWorker := tutil.NewBLSAddr(t, 999) 4211 rt.SetAddressActorType(newWorker, builtin.AccountActorCodeID) 4212 4213 rt.SetCaller(actor.owner, builtin.AccountActorCodeID) 4214 param := &miner.ChangeWorkerAddressParams{NewWorker: newWorker} 4215 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4216 rt.Call(actor.a.ChangeWorkerAddress, param) 4217 }) 4218 rt.Verify() 4219 actor.checkState(rt) 4220 }) 4221 4222 t.Run("fails if worker public key is not BLS", func(t *testing.T) { 4223 rt, actor := setupFunc() 4224 actor.constructAndVerify(rt) 4225 newWorker := tutil.NewIDAddr(t, 999) 4226 rt.SetAddressActorType(newWorker, builtin.AccountActorCodeID) 4227 key := tutil.NewIDAddr(t, 505) 4228 4229 rt.ExpectSend(newWorker, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &key, exitcode.Ok) 4230 4231 rt.SetCaller(actor.owner, builtin.AccountActorCodeID) 4232 param := &miner.ChangeWorkerAddressParams{NewWorker: newWorker} 4233 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4234 rt.Call(actor.a.ChangeWorkerAddress, param) 4235 }) 4236 rt.Verify() 4237 actor.checkState(rt) 4238 }) 4239 4240 t.Run("fails if new worker address does not have a code", func(t *testing.T) { 4241 rt, actor := setupFunc() 4242 actor.constructAndVerify(rt) 4243 newWorker := tutil.NewIDAddr(t, 5001) 4244 4245 rt.SetCaller(actor.owner, builtin.AccountActorCodeID) 4246 param := &miner.ChangeWorkerAddressParams{NewWorker: newWorker} 4247 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4248 rt.Call(actor.a.ChangeWorkerAddress, param) 4249 }) 4250 rt.Verify() 4251 actor.checkState(rt) 4252 }) 4253 4254 t.Run("fails if new worker is not an account actor", func(t *testing.T) { 4255 rt, actor := setupFunc() 4256 actor.constructAndVerify(rt) 4257 newWorker := tutil.NewIDAddr(t, 999) 4258 rt.SetAddressActorType(newWorker, builtin.StorageMinerActorCodeID) 4259 4260 rt.SetCaller(actor.owner, builtin.AccountActorCodeID) 4261 param := &miner.ChangeWorkerAddressParams{NewWorker: newWorker} 4262 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4263 rt.Call(actor.a.ChangeWorkerAddress, param) 4264 }) 4265 rt.Verify() 4266 actor.checkState(rt) 4267 }) 4268 4269 t.Run("fails when caller is not the owner", func(t *testing.T) { 4270 rt, actor := setupFunc() 4271 actor.constructAndVerify(rt) 4272 newWorker := tutil.NewIDAddr(t, 999) 4273 rt.SetAddressActorType(newWorker, builtin.AccountActorCodeID) 4274 4275 rt.ExpectValidateCallerAddr(actor.owner) 4276 rt.ExpectSend(newWorker, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &actor.key, exitcode.Ok) 4277 4278 rt.SetCaller(actor.worker, builtin.AccountActorCodeID) 4279 param := &miner.ChangeWorkerAddressParams{NewWorker: newWorker} 4280 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 4281 rt.Call(actor.a.ChangeWorkerAddress, param) 4282 }) 4283 rt.Verify() 4284 actor.checkState(rt) 4285 }) 4286 } 4287 4288 func TestConfirmUpdateWorkerKey(t *testing.T) { 4289 periodOffset := abi.ChainEpoch(100) 4290 newWorker := tutil.NewIDAddr(t, 999) 4291 currentEpoch := abi.ChainEpoch(5) 4292 actor := newHarness(t, periodOffset) 4293 builder := builderForHarness(actor). 4294 WithBalance(bigBalance, big.Zero()) 4295 4296 t.Run("successfully changes the worker address", func(t *testing.T) { 4297 rt := builder.Build(t) 4298 rt.SetEpoch(currentEpoch) 4299 actor.constructAndVerify(rt) 4300 4301 effectiveEpoch := currentEpoch + miner.WorkerKeyChangeDelay 4302 actor.changeWorkerAddress(rt, newWorker, effectiveEpoch, actor.controlAddrs) 4303 4304 // confirm at effective epoch 4305 rt.SetEpoch(effectiveEpoch) 4306 actor.confirmUpdateWorkerKey(rt) 4307 4308 st := getState(rt) 4309 info, err := st.GetInfo(adt.AsStore(rt)) 4310 require.NoError(t, err) 4311 require.Equal(t, info.Worker, newWorker) 4312 require.Nil(t, info.PendingWorkerKey) 4313 actor.checkState(rt) 4314 }) 4315 4316 t.Run("does nothing before the effective date", func(t *testing.T) { 4317 rt := builder.Build(t) 4318 rt.SetEpoch(currentEpoch) 4319 actor.constructAndVerify(rt) 4320 4321 effectiveEpoch := currentEpoch + miner.WorkerKeyChangeDelay 4322 actor.changeWorkerAddress(rt, newWorker, effectiveEpoch, actor.controlAddrs) 4323 4324 // confirm right before the effective epoch 4325 rt.SetEpoch(effectiveEpoch - 1) 4326 actor.confirmUpdateWorkerKey(rt) 4327 4328 st := getState(rt) 4329 info, err := st.GetInfo(adt.AsStore(rt)) 4330 require.NoError(t, err) 4331 require.Equal(t, actor.worker, info.Worker) 4332 require.NotNil(t, info.PendingWorkerKey) 4333 actor.checkState(rt) 4334 }) 4335 4336 t.Run("does nothing when no update is set", func(t *testing.T) { 4337 rt := builder.Build(t) 4338 rt.SetEpoch(currentEpoch) 4339 actor.constructAndVerify(rt) 4340 4341 actor.confirmUpdateWorkerKey(rt) 4342 4343 st := getState(rt) 4344 info, err := st.GetInfo(adt.AsStore(rt)) 4345 require.NoError(t, err) 4346 require.Equal(t, actor.worker, info.Worker) 4347 require.Nil(t, info.PendingWorkerKey) 4348 actor.checkState(rt) 4349 }) 4350 } 4351 4352 func TestChangeOwnerAddress(t *testing.T) { 4353 actor := newHarness(t, 0) 4354 builder := builderForHarness(actor). 4355 WithBalance(bigBalance, big.Zero()) 4356 newAddr := tutil.NewIDAddr(t, 1001) 4357 otherAddr := tutil.NewIDAddr(t, 1002) 4358 4359 t.Run("successful change", func(t *testing.T) { 4360 rt := builder.Build(t) 4361 actor.constructAndVerify(rt) 4362 4363 rt.SetCaller(actor.owner, builtin.MultisigActorCodeID) 4364 actor.changeOwnerAddress(rt, newAddr) 4365 4366 info := actor.getInfo(rt) 4367 assert.Equal(t, actor.owner, info.Owner) 4368 assert.Equal(t, newAddr, *info.PendingOwnerAddress) 4369 4370 rt.SetCaller(newAddr, builtin.MultisigActorCodeID) 4371 actor.changeOwnerAddress(rt, newAddr) 4372 4373 info = actor.getInfo(rt) 4374 assert.Equal(t, newAddr, info.Owner) 4375 assert.Nil(t, info.PendingOwnerAddress) 4376 }) 4377 4378 t.Run("proposed must be valid", func(t *testing.T) { 4379 rt := builder.Build(t) 4380 actor.constructAndVerify(rt) 4381 4382 nominees := []addr.Address{ 4383 addr.Undef, 4384 tutil.NewSECP256K1Addr(t, "asd"), 4385 tutil.NewBLSAddr(t, 1234), 4386 tutil.NewActorAddr(t, "asd"), 4387 } 4388 rt.SetCaller(actor.owner, builtin.MultisigActorCodeID) 4389 for _, a := range nominees { 4390 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4391 actor.changeOwnerAddress(rt, a) 4392 }) 4393 } 4394 }) 4395 4396 t.Run("withdraw proposal", func(t *testing.T) { 4397 rt := builder.Build(t) 4398 actor.constructAndVerify(rt) 4399 4400 rt.SetCaller(actor.owner, builtin.MultisigActorCodeID) 4401 actor.changeOwnerAddress(rt, newAddr) 4402 4403 // Revert it 4404 actor.changeOwnerAddress(rt, actor.owner) 4405 4406 info := actor.getInfo(rt) 4407 assert.Equal(t, actor.owner, info.Owner) 4408 assert.Nil(t, info.PendingOwnerAddress) 4409 4410 // New address cannot confirm. 4411 rt.SetCaller(newAddr, builtin.MultisigActorCodeID) 4412 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 4413 actor.changeOwnerAddress(rt, newAddr) 4414 }) 4415 }) 4416 4417 t.Run("only owner can propose", func(t *testing.T) { 4418 rt := builder.Build(t) 4419 actor.constructAndVerify(rt) 4420 4421 rt.SetCaller(actor.worker, builtin.AccountActorCodeID) 4422 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 4423 actor.changeOwnerAddress(rt, newAddr) 4424 }) 4425 rt.SetCaller(otherAddr, builtin.MultisigActorCodeID) 4426 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 4427 actor.changeOwnerAddress(rt, newAddr) 4428 }) 4429 }) 4430 4431 t.Run("only owner can change proposal", func(t *testing.T) { 4432 rt := builder.Build(t) 4433 actor.constructAndVerify(rt) 4434 4435 // Make a proposal 4436 rt.SetCaller(actor.owner, builtin.MultisigActorCodeID) 4437 actor.changeOwnerAddress(rt, newAddr) 4438 4439 rt.SetCaller(actor.worker, builtin.AccountActorCodeID) 4440 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 4441 actor.changeOwnerAddress(rt, otherAddr) 4442 }) 4443 rt.SetCaller(otherAddr, builtin.MultisigActorCodeID) 4444 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 4445 actor.changeOwnerAddress(rt, otherAddr) 4446 }) 4447 4448 // Owner can change it 4449 rt.SetCaller(actor.owner, builtin.MultisigActorCodeID) 4450 actor.changeOwnerAddress(rt, otherAddr) 4451 info := actor.getInfo(rt) 4452 assert.Equal(t, actor.owner, info.Owner) 4453 assert.Equal(t, otherAddr, *info.PendingOwnerAddress) 4454 4455 }) 4456 4457 t.Run("only nominee can confirm", func(t *testing.T) { 4458 rt := builder.Build(t) 4459 actor.constructAndVerify(rt) 4460 4461 // Make a proposal 4462 rt.SetCaller(actor.owner, builtin.MultisigActorCodeID) 4463 actor.changeOwnerAddress(rt, newAddr) 4464 4465 // Owner re-proposing same address doesn't confirm it. 4466 actor.changeOwnerAddress(rt, newAddr) 4467 info := actor.getInfo(rt) 4468 assert.Equal(t, actor.owner, info.Owner) 4469 assert.Equal(t, newAddr, *info.PendingOwnerAddress) // Still staged 4470 4471 rt.SetCaller(actor.worker, builtin.AccountActorCodeID) 4472 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 4473 actor.changeOwnerAddress(rt, otherAddr) 4474 }) 4475 rt.SetCaller(otherAddr, builtin.MultisigActorCodeID) 4476 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 4477 actor.changeOwnerAddress(rt, otherAddr) 4478 }) 4479 4480 // New addr can confirm itself 4481 rt.SetCaller(newAddr, builtin.MultisigActorCodeID) 4482 actor.changeOwnerAddress(rt, newAddr) 4483 info = actor.getInfo(rt) 4484 assert.Equal(t, newAddr, info.Owner) 4485 assert.Nil(t, info.PendingOwnerAddress) 4486 }) 4487 4488 t.Run("nominee must confirm self explicitly", func(t *testing.T) { 4489 rt := builder.Build(t) 4490 actor.constructAndVerify(rt) 4491 4492 // Make a proposal 4493 rt.SetCaller(actor.owner, builtin.MultisigActorCodeID) 4494 actor.changeOwnerAddress(rt, newAddr) 4495 4496 rt.SetCaller(newAddr, builtin.MultisigActorCodeID) 4497 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4498 actor.changeOwnerAddress(rt, actor.owner) // Not own address 4499 }) 4500 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4501 actor.changeOwnerAddress(rt, otherAddr) // Not own address 4502 }) 4503 }) 4504 } 4505 4506 func TestReportConsensusFault(t *testing.T) { 4507 periodOffset := abi.ChainEpoch(100) 4508 actor := newHarness(t, periodOffset) 4509 builder := builderForHarness(actor). 4510 WithBalance(bigBalance, big.Zero()) 4511 4512 t.Run("invalid report rejected", func(t *testing.T) { 4513 rt := builder.Build(t) 4514 actor.constructAndVerify(rt) 4515 rt.SetEpoch(abi.ChainEpoch(1)) 4516 4517 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4518 actor.reportConsensusFault(rt, addr.TestAddress, nil) 4519 }) 4520 actor.checkState(rt) 4521 }) 4522 4523 t.Run("mis-targeted report rejected", func(t *testing.T) { 4524 rt := builder.Build(t) 4525 actor.constructAndVerify(rt) 4526 rt.SetEpoch(abi.ChainEpoch(1)) 4527 4528 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4529 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 4530 Target: tutil.NewIDAddr(t, 1234), // Not receiver 4531 Epoch: rt.Epoch() - 1, 4532 Type: runtime.ConsensusFaultDoubleForkMining, 4533 }) 4534 }) 4535 actor.checkState(rt) 4536 }) 4537 4538 t.Run("Report consensus fault pays reward and charges fee", func(t *testing.T) { 4539 rt := builder.Build(t) 4540 actor.constructAndVerify(rt) 4541 precommitEpoch := abi.ChainEpoch(1) 4542 rt.SetEpoch(precommitEpoch) 4543 4544 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 4545 Target: actor.receiver, 4546 Epoch: rt.Epoch() - 1, 4547 Type: runtime.ConsensusFaultDoubleForkMining, 4548 }) 4549 actor.checkState(rt) 4550 }) 4551 4552 t.Run("Report consensus fault updates consensus fault reported field", func(t *testing.T) { 4553 rt := builder.Build(t) 4554 actor.constructAndVerify(rt) 4555 precommitEpoch := abi.ChainEpoch(1) 4556 rt.SetEpoch(precommitEpoch) 4557 4558 startInfo := actor.getInfo(rt) 4559 assert.Equal(t, abi.ChainEpoch(-1), startInfo.ConsensusFaultElapsed) 4560 4561 reportEpoch := abi.ChainEpoch(333) 4562 rt.SetEpoch(reportEpoch) 4563 4564 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 4565 Target: actor.receiver, 4566 Epoch: rt.Epoch() - 1, 4567 Type: runtime.ConsensusFaultDoubleForkMining, 4568 }) 4569 endInfo := actor.getInfo(rt) 4570 assert.Equal(t, reportEpoch+miner.ConsensusFaultIneligibilityDuration, endInfo.ConsensusFaultElapsed) 4571 actor.checkState(rt) 4572 }) 4573 4574 t.Run("Double report of consensus fault fails", func(t *testing.T) { 4575 rt := builder.Build(t) 4576 actor.constructAndVerify(rt) 4577 precommitEpoch := abi.ChainEpoch(1) 4578 rt.SetEpoch(precommitEpoch) 4579 4580 startInfo := actor.getInfo(rt) 4581 assert.Equal(t, abi.ChainEpoch(-1), startInfo.ConsensusFaultElapsed) 4582 4583 reportEpoch := abi.ChainEpoch(333) 4584 rt.SetEpoch(reportEpoch) 4585 4586 fault1 := rt.Epoch() - 1 4587 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 4588 Target: actor.receiver, 4589 Epoch: fault1, 4590 Type: runtime.ConsensusFaultDoubleForkMining, 4591 }) 4592 endInfo := actor.getInfo(rt) 4593 assert.Equal(t, reportEpoch+miner.ConsensusFaultIneligibilityDuration, endInfo.ConsensusFaultElapsed) 4594 4595 // same fault can't be reported twice 4596 rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, "too old", func() { 4597 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 4598 Target: actor.receiver, 4599 Epoch: fault1, 4600 Type: runtime.ConsensusFaultDoubleForkMining, 4601 }) 4602 }) 4603 rt.Reset() 4604 4605 // new consensus faults are forbidden until original has elapsed 4606 rt.SetEpoch(endInfo.ConsensusFaultElapsed) 4607 fault2 := endInfo.ConsensusFaultElapsed - 1 4608 rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, "too old", func() { 4609 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 4610 Target: actor.receiver, 4611 Epoch: fault2, 4612 Type: runtime.ConsensusFaultDoubleForkMining, 4613 }) 4614 }) 4615 rt.Reset() 4616 4617 // a new consensus fault can be reported for blocks once original has expired 4618 rt.SetEpoch(endInfo.ConsensusFaultElapsed + 1) 4619 fault3 := endInfo.ConsensusFaultElapsed 4620 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 4621 Target: actor.receiver, 4622 Epoch: fault3, 4623 Type: runtime.ConsensusFaultDoubleForkMining, 4624 }) 4625 endInfo = actor.getInfo(rt) 4626 assert.Equal(t, rt.Epoch()+miner.ConsensusFaultIneligibilityDuration, endInfo.ConsensusFaultElapsed) 4627 4628 // old fault still cannot be reported after fault interval has elapsed 4629 fault4 := fault1 + 1 4630 rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, "too old", func() { 4631 actor.reportConsensusFault(rt, addr.TestAddress, &runtime.ConsensusFault{ 4632 Target: actor.receiver, 4633 Epoch: fault4, 4634 Type: runtime.ConsensusFaultDoubleForkMining, 4635 }) 4636 }) 4637 actor.checkState(rt) 4638 }) 4639 } 4640 4641 func TestApplyRewards(t *testing.T) { 4642 periodOffset := abi.ChainEpoch(1808) 4643 actor := newHarness(t, periodOffset) 4644 4645 builder := builderForHarness(actor). 4646 WithBalance(bigBalance, big.Zero()) 4647 4648 t.Run("funds are locked", func(t *testing.T) { 4649 rt := builder.Build(t) 4650 actor.constructAndVerify(rt) 4651 4652 rwd := abi.NewTokenAmount(1_000_000) 4653 actor.applyRewards(rt, rwd, big.Zero()) 4654 4655 expected := abi.NewTokenAmount(750_000) 4656 assert.Equal(t, expected, actor.getLockedFunds(rt)) 4657 }) 4658 4659 t.Run("funds vest", func(t *testing.T) { 4660 rt := builder.Build(t) 4661 actor.constructAndVerify(rt) 4662 st := getState(rt) 4663 4664 vestingFunds, err := st.LoadVestingFunds(adt.AsStore(rt)) 4665 require.NoError(t, err) 4666 4667 // Nothing vesting to start 4668 assert.Empty(t, vestingFunds.Funds) 4669 assert.Equal(t, big.Zero(), st.LockedFunds) 4670 4671 // Lock some funds with AddLockedFund 4672 amt := abi.NewTokenAmount(600_000) 4673 actor.applyRewards(rt, amt, big.Zero()) 4674 st = getState(rt) 4675 vestingFunds, err = st.LoadVestingFunds(adt.AsStore(rt)) 4676 require.NoError(t, err) 4677 4678 require.Len(t, vestingFunds.Funds, 180) 4679 4680 // Vested FIL pays out on epochs with expected offset 4681 quantSpec := miner.NewQuantSpec(miner.RewardVestingSpec.Quantization, periodOffset) 4682 4683 currEpoch := rt.Epoch() 4684 for i := range vestingFunds.Funds { 4685 step := miner.RewardVestingSpec.InitialDelay + abi.ChainEpoch(i+1)*miner.RewardVestingSpec.StepDuration 4686 expectedEpoch := quantSpec.QuantizeUp(currEpoch + step) 4687 vf := vestingFunds.Funds[i] 4688 assert.Equal(t, expectedEpoch, vf.Epoch) 4689 } 4690 4691 expectedOffset := periodOffset % miner.RewardVestingSpec.Quantization 4692 for i := range vestingFunds.Funds { 4693 vf := vestingFunds.Funds[i] 4694 require.EqualValues(t, expectedOffset, int64(vf.Epoch)%int64(miner.RewardVestingSpec.Quantization)) 4695 } 4696 4697 st = getState(rt) 4698 lockedAmt, _ := miner.LockedRewardFromReward(amt) 4699 assert.Equal(t, lockedAmt, st.LockedFunds) 4700 // technically applying rewards without first activating cron is an impossible state but convenient for testing 4701 _, msgs := miner.CheckStateInvariants(st, rt.AdtStore(), rt.Balance()) 4702 assert.Equal(t, 1, len(msgs.Messages())) 4703 assert.Contains(t, msgs.Messages()[0], "DeadlineCronActive == false") 4704 }) 4705 4706 t.Run("penalty is burnt", func(t *testing.T) { 4707 rt := builder.Build(t) 4708 actor.constructAndVerify(rt) 4709 4710 rwd := abi.NewTokenAmount(600_000) 4711 penalty := abi.NewTokenAmount(300_000) 4712 rt.SetBalance(big.Add(rt.Balance(), rwd)) 4713 actor.applyRewards(rt, rwd, penalty) 4714 4715 expectedLockAmt, _ := miner.LockedRewardFromReward(rwd) 4716 expectedLockAmt = big.Sub(expectedLockAmt, penalty) 4717 assert.Equal(t, expectedLockAmt, actor.getLockedFunds(rt)) 4718 4719 // technically applying rewards without first activating cron is an impossible state but convenient for testing 4720 st := getState(rt) 4721 _, msgs := miner.CheckStateInvariants(st, rt.AdtStore(), rt.Balance()) 4722 assert.Equal(t, 1, len(msgs.Messages())) 4723 assert.Contains(t, msgs.Messages()[0], "DeadlineCronActive == false") 4724 }) 4725 4726 t.Run("penalty is partially burnt and stored as fee debt", func(t *testing.T) { 4727 rt := builder.Build(t) 4728 actor.constructAndVerify(rt) 4729 st := getState(rt) 4730 assert.Equal(t, big.Zero(), st.FeeDebt) 4731 4732 amt := rt.Balance() 4733 penalty := big.Mul(big.NewInt(3), amt) 4734 reward := amt 4735 4736 // manually update actor balance to include the added funds on reward message 4737 newBalance := big.Add(reward, amt) 4738 rt.SetBalance(newBalance) 4739 4740 rt.SetCaller(builtin.RewardActorAddr, builtin.RewardActorCodeID) 4741 rt.ExpectValidateCallerAddr(builtin.RewardActorAddr) 4742 4743 // pledge change is new reward - reward taken for fee debt 4744 // zero here since all reward goes to debt 4745 // so do not expect pledge update 4746 4747 // burn initial balance + reward = 2*amt 4748 expectBurnt := big.Mul(big.NewInt(2), amt) 4749 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, expectBurnt, nil, exitcode.Ok) 4750 4751 rt.Call(actor.a.ApplyRewards, &builtin.ApplyRewardParams{Reward: reward, Penalty: penalty}) 4752 rt.Verify() 4753 4754 st = getState(rt) 4755 // fee debt = penalty - reward - initial balance = 3*amt - 2*amt = amt 4756 assert.Equal(t, amt, st.FeeDebt) 4757 // technically applying rewards without first activating cron is an impossible state but convenient for testing 4758 actor.checkState(rt) 4759 }) 4760 4761 // The system should not reach this state since fee debt removes mining eligibility 4762 // But if invariants are violated this should work. 4763 t.Run("rewards pay back fee debt ", func(t *testing.T) { 4764 rt := builder.Build(t) 4765 actor.constructAndVerify(rt) 4766 st := getState(rt) 4767 4768 assert.Equal(t, big.Zero(), st.LockedFunds) 4769 4770 amt := rt.Balance() 4771 availableBefore, err := st.GetAvailableBalance(amt) 4772 require.NoError(t, err) 4773 assert.True(t, availableBefore.GreaterThan(big.Zero())) 4774 initFeeDebt := big.Mul(big.NewInt(2), amt) // FeeDebt twice total balance 4775 st.FeeDebt = initFeeDebt 4776 availableAfter, err := st.GetAvailableBalance(amt) 4777 require.NoError(t, err) 4778 assert.True(t, availableAfter.LessThan(big.Zero())) 4779 4780 rt.ReplaceState(st) 4781 4782 reward := big.Mul(big.NewInt(3), amt) 4783 penalty := big.Zero() 4784 // manually update actor balance to include the added funds from outside 4785 newBalance := big.Add(amt, reward) 4786 rt.SetBalance(newBalance) 4787 4788 // pledge change is new reward - reward taken for fee debt 4789 // 3*LockedRewardFactor*amt - 2*amt = remainingLocked 4790 lockedReward, _ := miner.LockedRewardFromReward(reward) 4791 remainingLocked := big.Sub(lockedReward, st.FeeDebt) // note that this would be clamped at 0 if difference above is < 0 4792 pledgeDelta := remainingLocked 4793 rt.SetCaller(builtin.RewardActorAddr, builtin.RewardActorCodeID) 4794 rt.ExpectValidateCallerAddr(builtin.RewardActorAddr) 4795 // expect pledge update 4796 rt.ExpectSend( 4797 builtin.StoragePowerActorAddr, 4798 builtin.MethodsPower.UpdatePledgeTotal, 4799 &pledgeDelta, 4800 abi.NewTokenAmount(0), 4801 nil, 4802 exitcode.Ok, 4803 ) 4804 4805 expectBurnt := st.FeeDebt 4806 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, expectBurnt, nil, exitcode.Ok) 4807 4808 rt.Call(actor.a.ApplyRewards, &builtin.ApplyRewardParams{Reward: reward, Penalty: penalty}) 4809 rt.Verify() 4810 4811 // Set balance to deduct fee 4812 finalBalance := big.Sub(newBalance, expectBurnt) 4813 4814 st = getState(rt) 4815 // balance funds used to pay off fee debt 4816 // available balance should be 2 4817 availableBalance, err := st.GetAvailableBalance(finalBalance) 4818 require.NoError(t, err) 4819 assert.Equal(t, big.Sum(availableBefore, reward, initFeeDebt.Neg(), remainingLocked.Neg()), availableBalance) 4820 assert.True(t, st.IsDebtFree()) 4821 // remaining funds locked in vesting table 4822 assert.Equal(t, remainingLocked, st.LockedFunds) 4823 // technically applying rewards without first activating cron is an impossible state but convenient for testing 4824 _, msgs := miner.CheckStateInvariants(st, rt.AdtStore(), rt.Balance()) 4825 assert.Equal(t, 1, len(msgs.Messages())) 4826 assert.Contains(t, msgs.Messages()[0], "DeadlineCronActive == false") 4827 }) 4828 } 4829 4830 func TestCompactSectorNumbers(t *testing.T) { 4831 periodOffset := abi.ChainEpoch(100) 4832 actor := newHarness(t, periodOffset) 4833 builder := builderForHarness(actor). 4834 WithBalance(bigBalance, big.Zero()) 4835 4836 t.Run("compact sector numbers then pre-commit", func(t *testing.T) { 4837 // Create a sector. 4838 rt := builder.Build(t) 4839 actor.constructAndVerify(rt) 4840 allSectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 4841 4842 targetSno := allSectors[0].SectorNumber 4843 actor.compactSectorNumbers(rt, bf(uint64(targetSno), uint64(targetSno)+1)) 4844 4845 precommitEpoch := rt.Epoch() 4846 deadline := actor.deadline(rt) 4847 expiration := deadline.PeriodEnd() + abi.ChainEpoch(defaultSectorExpiration)*miner.WPoStProvingPeriod 4848 4849 // Allocating masked sector number should fail. 4850 { 4851 precommit := actor.makePreCommit(targetSno+1, precommitEpoch-1, expiration, nil) 4852 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4853 actor.preCommitSector(rt, precommit, preCommitConf{}, false) 4854 }) 4855 } 4856 4857 { 4858 precommit := actor.makePreCommit(targetSno+2, precommitEpoch-1, expiration, nil) 4859 actor.preCommitSector(rt, precommit, preCommitConf{}, false) 4860 } 4861 actor.checkState(rt) 4862 }) 4863 4864 t.Run("owner can also compact sectors", func(t *testing.T) { 4865 // Create a sector. 4866 rt := builder.Build(t) 4867 actor.constructAndVerify(rt) 4868 allSectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 4869 4870 targetSno := allSectors[0].SectorNumber 4871 rt.SetCaller(actor.owner, builtin.AccountActorCodeID) 4872 rt.ExpectValidateCallerAddr(append(actor.controlAddrs, actor.owner, actor.worker)...) 4873 4874 rt.Call(actor.a.CompactSectorNumbers, &miner.CompactSectorNumbersParams{ 4875 MaskSectorNumbers: bf(uint64(targetSno), uint64(targetSno)+1), 4876 }) 4877 rt.Verify() 4878 actor.checkState(rt) 4879 }) 4880 4881 t.Run("one of the control addresses can also compact sectors", func(t *testing.T) { 4882 // Create a sector. 4883 rt := builder.Build(t) 4884 actor.constructAndVerify(rt) 4885 allSectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 4886 4887 targetSno := allSectors[0].SectorNumber 4888 rt.SetCaller(actor.controlAddrs[0], builtin.AccountActorCodeID) 4889 rt.ExpectValidateCallerAddr(append(actor.controlAddrs, actor.owner, actor.worker)...) 4890 4891 rt.Call(actor.a.CompactSectorNumbers, &miner.CompactSectorNumbersParams{ 4892 MaskSectorNumbers: bf(uint64(targetSno), uint64(targetSno)+1), 4893 }) 4894 rt.Verify() 4895 actor.checkState(rt) 4896 }) 4897 4898 t.Run("fail if caller is not among caller worker or control addresses", func(t *testing.T) { 4899 // Create a sector. 4900 rt := builder.Build(t) 4901 actor.constructAndVerify(rt) 4902 allSectors := actor.commitAndProveSectors(rt, 1, defaultSectorExpiration, nil, true) 4903 4904 targetSno := allSectors[0].SectorNumber 4905 rAddr := tutil.NewIDAddr(t, 1005) 4906 rt.SetCaller(rAddr, builtin.AccountActorCodeID) 4907 rt.ExpectValidateCallerAddr(append(actor.controlAddrs, actor.owner, actor.worker)...) 4908 4909 rt.ExpectAbort(exitcode.SysErrForbidden, func() { 4910 rt.Call(actor.a.CompactSectorNumbers, &miner.CompactSectorNumbersParams{ 4911 MaskSectorNumbers: bf(uint64(targetSno), uint64(targetSno)+1), 4912 }) 4913 }) 4914 4915 rt.Verify() 4916 actor.checkState(rt) 4917 }) 4918 4919 t.Run("compacting no sector numbers aborts", func(t *testing.T) { 4920 rt := builder.Build(t) 4921 actor.constructAndVerify(rt) 4922 4923 rt.ExpectAbort(exitcode.ErrIllegalArgument, func() { 4924 // compact nothing 4925 actor.compactSectorNumbers(rt, bf()) 4926 }) 4927 actor.checkState(rt) 4928 }) 4929 } 4930 4931 type actorHarness struct { 4932 a miner.Actor 4933 t testing.TB 4934 4935 receiver addr.Address // The miner actor's own address 4936 owner addr.Address 4937 worker addr.Address 4938 key addr.Address 4939 4940 controlAddrs []addr.Address 4941 4942 sealProofType abi.RegisteredSealProof 4943 windowPostProofType abi.RegisteredPoStProof 4944 sectorSize abi.SectorSize 4945 partitionSize uint64 4946 periodOffset abi.ChainEpoch 4947 nextSectorNo abi.SectorNumber 4948 4949 networkPledge abi.TokenAmount 4950 networkRawPower abi.StoragePower 4951 networkQAPower abi.StoragePower 4952 baselinePower abi.StoragePower 4953 4954 epochRewardSmooth smoothing.FilterEstimate 4955 epochQAPowerSmooth smoothing.FilterEstimate 4956 } 4957 4958 func newHarness(t testing.TB, provingPeriodOffset abi.ChainEpoch) *actorHarness { 4959 owner := tutil.NewIDAddr(t, 100) 4960 worker := tutil.NewIDAddr(t, 101) 4961 4962 controlAddrs := []addr.Address{tutil.NewIDAddr(t, 999), tutil.NewIDAddr(t, 998), tutil.NewIDAddr(t, 997)} 4963 4964 workerKey := tutil.NewBLSAddr(t, 0) 4965 receiver := tutil.NewIDAddr(t, 1000) 4966 rwd := big.Mul(big.NewIntUnsigned(10), big.NewIntUnsigned(1e18)) 4967 pwr := abi.NewStoragePower(1 << 50) 4968 h := &actorHarness{ 4969 t: t, 4970 receiver: receiver, 4971 owner: owner, 4972 worker: worker, 4973 key: workerKey, 4974 4975 controlAddrs: controlAddrs, 4976 4977 // Proof types and metadata initialized in setProofType 4978 periodOffset: provingPeriodOffset, 4979 nextSectorNo: 100, 4980 4981 networkPledge: big.Mul(rwd, big.NewIntUnsigned(1000)), 4982 networkRawPower: pwr, 4983 networkQAPower: pwr, 4984 baselinePower: pwr, 4985 4986 epochRewardSmooth: smoothing.TestingConstantEstimate(rwd), 4987 epochQAPowerSmooth: smoothing.TestingConstantEstimate(pwr), 4988 } 4989 h.setProofType(abi.RegisteredSealProof_StackedDrg32GiBV1_1) 4990 return h 4991 } 4992 4993 func (h *actorHarness) setProofType(proof abi.RegisteredSealProof) { 4994 var err error 4995 h.sealProofType = proof 4996 h.windowPostProofType, err = proof.RegisteredWindowPoStProof() 4997 require.NoError(h.t, err) 4998 h.sectorSize, err = proof.SectorSize() 4999 require.NoError(h.t, err) 5000 h.partitionSize, err = builtin.PoStProofWindowPoStPartitionSectors(h.windowPostProofType) 5001 require.NoError(h.t, err) 5002 } 5003 5004 func (h *actorHarness) constructAndVerify(rt *mock.Runtime) { 5005 params := miner.ConstructorParams{ 5006 OwnerAddr: h.owner, 5007 WorkerAddr: h.worker, 5008 ControlAddrs: h.controlAddrs, 5009 WindowPoStProofType: h.windowPostProofType, 5010 PeerId: testPid, 5011 } 5012 5013 rt.ExpectValidateCallerAddr(builtin.InitActorAddr) 5014 // Fetch worker pubkey. 5015 rt.ExpectSend(h.worker, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &h.key, exitcode.Ok) 5016 // Register proving period cron. 5017 rt.SetCaller(builtin.InitActorAddr, builtin.InitActorCodeID) 5018 ret := rt.Call(h.a.Constructor, ¶ms) 5019 assert.Nil(h.t, ret) 5020 rt.Verify() 5021 } 5022 5023 // 5024 // State access helpers 5025 // 5026 5027 func (h *actorHarness) deadline(rt *mock.Runtime) *dline.Info { 5028 st := getState(rt) 5029 return st.RecordedDeadlineInfo(rt.Epoch()) 5030 } 5031 5032 func (h *actorHarness) currentDeadline(rt *mock.Runtime) *dline.Info { 5033 st := getState(rt) 5034 return st.DeadlineInfo(rt.Epoch()) 5035 } 5036 5037 func (h *actorHarness) getPreCommit(rt *mock.Runtime, sno abi.SectorNumber) *miner.SectorPreCommitOnChainInfo { 5038 st := getState(rt) 5039 pc, found, err := st.GetPrecommittedSector(rt.AdtStore(), sno) 5040 require.NoError(h.t, err) 5041 require.True(h.t, found) 5042 return pc 5043 } 5044 5045 func (h *actorHarness) getSector(rt *mock.Runtime, sno abi.SectorNumber) *miner.SectorOnChainInfo { 5046 st := getState(rt) 5047 sector, found, err := st.GetSector(rt.AdtStore(), sno) 5048 require.NoError(h.t, err) 5049 require.True(h.t, found) 5050 return sector 5051 } 5052 5053 func (h *actorHarness) getInfo(rt *mock.Runtime) *miner.MinerInfo { 5054 var st miner.State 5055 rt.GetState(&st) 5056 info, err := st.GetInfo(rt.AdtStore()) 5057 require.NoError(h.t, err) 5058 return info 5059 } 5060 5061 func (h *actorHarness) getDeadlines(rt *mock.Runtime) *miner.Deadlines { 5062 st := getState(rt) 5063 deadlines, err := st.LoadDeadlines(rt.AdtStore()) 5064 require.NoError(h.t, err) 5065 return deadlines 5066 } 5067 5068 func (h *actorHarness) getDeadline(rt *mock.Runtime, idx uint64) *miner.Deadline { 5069 dls := h.getDeadlines(rt) 5070 deadline, err := dls.LoadDeadline(rt.AdtStore(), idx) 5071 require.NoError(h.t, err) 5072 return deadline 5073 } 5074 5075 func (h *actorHarness) getPartition(rt *mock.Runtime, deadline *miner.Deadline, idx uint64) *miner.Partition { 5076 partition, err := deadline.LoadPartition(rt.AdtStore(), idx) 5077 require.NoError(h.t, err) 5078 return partition 5079 } 5080 5081 func (h *actorHarness) getPartitionSnapshot(rt *mock.Runtime, deadline *miner.Deadline, idx uint64) *miner.Partition { 5082 partition, err := deadline.LoadPartitionSnapshot(rt.AdtStore(), idx) 5083 require.NoError(h.t, err) 5084 return partition 5085 } 5086 5087 func (h *actorHarness) getSubmittedProof(rt *mock.Runtime, deadline *miner.Deadline, idx uint64) *miner.WindowedPoSt { 5088 proofs, err := adt.AsArray(rt.AdtStore(), deadline.OptimisticPoStSubmissionsSnapshot, miner.DeadlineOptimisticPoStSubmissionsAmtBitwidth) 5089 require.NoError(h.t, err) 5090 var post miner.WindowedPoSt 5091 found, err := proofs.Get(idx, &post) 5092 require.NoError(h.t, err) 5093 require.True(h.t, found) 5094 return &post 5095 } 5096 5097 func (h *actorHarness) getDeadlineAndPartition(rt *mock.Runtime, dlIdx, pIdx uint64) (*miner.Deadline, *miner.Partition) { 5098 deadline := h.getDeadline(rt, dlIdx) 5099 partition := h.getPartition(rt, deadline, pIdx) 5100 return deadline, partition 5101 } 5102 5103 func (h *actorHarness) findSector(rt *mock.Runtime, sno abi.SectorNumber) (*miner.Deadline, *miner.Partition) { 5104 var st miner.State 5105 rt.GetState(&st) 5106 deadlines, err := st.LoadDeadlines(rt.AdtStore()) 5107 require.NoError(h.t, err) 5108 dlIdx, pIdx, err := miner.FindSector(rt.AdtStore(), deadlines, sno) 5109 require.NoError(h.t, err) 5110 5111 deadline, err := deadlines.LoadDeadline(rt.AdtStore(), dlIdx) 5112 require.NoError(h.t, err) 5113 partition, err := deadline.LoadPartition(rt.AdtStore(), pIdx) 5114 require.NoError(h.t, err) 5115 return deadline, partition 5116 } 5117 5118 // Collects all sector infos into a map. 5119 func (h *actorHarness) collectSectors(rt *mock.Runtime) map[abi.SectorNumber]*miner.SectorOnChainInfo { 5120 sectors := map[abi.SectorNumber]*miner.SectorOnChainInfo{} 5121 st := getState(rt) 5122 _ = st.ForEachSector(rt.AdtStore(), func(info *miner.SectorOnChainInfo) { 5123 sector := *info 5124 sectors[info.SectorNumber] = §or 5125 }) 5126 return sectors 5127 } 5128 5129 func (h *actorHarness) collectDeadlineExpirations(rt *mock.Runtime, deadline *miner.Deadline) map[abi.ChainEpoch][]uint64 { 5130 queue, err := miner.LoadBitfieldQueue(rt.AdtStore(), deadline.ExpirationsEpochs, miner.NoQuantization, miner.DeadlineExpirationAmtBitwidth) 5131 require.NoError(h.t, err) 5132 expirations := map[abi.ChainEpoch][]uint64{} 5133 _ = queue.ForEach(func(epoch abi.ChainEpoch, bf bitfield.BitField) error { 5134 expanded, err := bf.All(miner.AddressedSectorsMax) 5135 require.NoError(h.t, err) 5136 expirations[epoch] = expanded 5137 return nil 5138 }) 5139 return expirations 5140 } 5141 5142 func (h *actorHarness) collectPartitionExpirations(rt *mock.Runtime, partition *miner.Partition) map[abi.ChainEpoch]*miner.ExpirationSet { 5143 queue, err := miner.LoadExpirationQueue(rt.AdtStore(), partition.ExpirationsEpochs, miner.NoQuantization, miner.PartitionExpirationAmtBitwidth) 5144 require.NoError(h.t, err) 5145 expirations := map[abi.ChainEpoch]*miner.ExpirationSet{} 5146 var es miner.ExpirationSet 5147 _ = queue.ForEach(&es, func(i int64) error { 5148 cpy := es 5149 expirations[abi.ChainEpoch(i)] = &cpy 5150 return nil 5151 }) 5152 return expirations 5153 } 5154 5155 func (h *actorHarness) getLockedFunds(rt *mock.Runtime) abi.TokenAmount { 5156 st := getState(rt) 5157 return st.LockedFunds 5158 } 5159 5160 func (h *actorHarness) checkState(rt *mock.Runtime) { 5161 st := getState(rt) 5162 _, msgs := miner.CheckStateInvariants(st, rt.AdtStore(), rt.Balance()) 5163 assert.True(h.t, msgs.IsEmpty(), strings.Join(msgs.Messages(), "\n")) 5164 } 5165 5166 // 5167 // Actor method calls 5168 // 5169 5170 func (h *actorHarness) changeWorkerAddress(rt *mock.Runtime, newWorker addr.Address, effectiveEpoch abi.ChainEpoch, newControlAddrs []addr.Address) { 5171 rt.SetAddressActorType(newWorker, builtin.AccountActorCodeID) 5172 5173 param := &miner.ChangeWorkerAddressParams{} 5174 param.NewControlAddrs = newControlAddrs 5175 param.NewWorker = newWorker 5176 rt.ExpectSend(newWorker, builtin.MethodsAccount.PubkeyAddress, nil, big.Zero(), &h.key, exitcode.Ok) 5177 5178 rt.ExpectValidateCallerAddr(h.owner) 5179 rt.SetCaller(h.owner, builtin.AccountActorCodeID) 5180 rt.Call(h.a.ChangeWorkerAddress, param) 5181 rt.Verify() 5182 5183 st := getState(rt) 5184 info, err := st.GetInfo(adt.AsStore(rt)) 5185 require.NoError(h.t, err) 5186 5187 var controlAddrs []addr.Address 5188 for _, ca := range newControlAddrs { 5189 resolved, found := rt.GetIdAddr(ca) 5190 require.True(h.t, found) 5191 controlAddrs = append(controlAddrs, resolved) 5192 } 5193 require.EqualValues(h.t, controlAddrs, info.ControlAddresses) 5194 5195 } 5196 5197 func (h *actorHarness) confirmUpdateWorkerKey(rt *mock.Runtime) { 5198 rt.ExpectValidateCallerAddr(h.owner) 5199 rt.SetCaller(h.owner, builtin.AccountActorCodeID) 5200 rt.Call(h.a.ConfirmUpdateWorkerKey, nil) 5201 rt.Verify() 5202 } 5203 5204 func (h *actorHarness) changeOwnerAddress(rt *mock.Runtime, newAddr addr.Address) { 5205 if rt.Caller() == h.owner { 5206 rt.ExpectValidateCallerAddr(h.owner) 5207 } else { 5208 info := h.getInfo(rt) 5209 if info.PendingOwnerAddress != nil { 5210 rt.ExpectValidateCallerAddr(*info.PendingOwnerAddress) 5211 } else { 5212 rt.ExpectValidateCallerAddr(h.owner) 5213 } 5214 } 5215 rt.Call(h.a.ChangeOwnerAddress, &newAddr) 5216 rt.Verify() 5217 } 5218 5219 func (h *actorHarness) checkSectorProven(rt *mock.Runtime, sectorNum abi.SectorNumber) { 5220 param := &miner.CheckSectorProvenParams{SectorNumber: sectorNum} 5221 5222 rt.ExpectValidateCallerAny() 5223 5224 rt.Call(h.a.CheckSectorProven, param) 5225 rt.Verify() 5226 } 5227 5228 func (h *actorHarness) changeMultiAddrs(rt *mock.Runtime, newAddrs []abi.Multiaddrs) { 5229 param := &miner.ChangeMultiaddrsParams{NewMultiaddrs: newAddrs} 5230 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 5231 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5232 5233 rt.Call(h.a.ChangeMultiaddrs, param) 5234 rt.Verify() 5235 5236 // assert addrs has changed 5237 st := getState(rt) 5238 info, err := st.GetInfo(adt.AsStore(rt)) 5239 require.NoError(h.t, err) 5240 require.EqualValues(h.t, newAddrs, info.Multiaddrs) 5241 } 5242 5243 func (h *actorHarness) changePeerID(rt *mock.Runtime, newPID abi.PeerID) { 5244 param := &miner.ChangePeerIDParams{NewID: newPID} 5245 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 5246 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5247 5248 rt.Call(h.a.ChangePeerID, param) 5249 rt.Verify() 5250 st := getState(rt) 5251 info, err := st.GetInfo(adt.AsStore(rt)) 5252 require.NoError(h.t, err) 5253 require.EqualValues(h.t, newPID, info.PeerId) 5254 } 5255 5256 func (h *actorHarness) controlAddresses(rt *mock.Runtime) (owner, worker addr.Address, control []addr.Address) { 5257 rt.ExpectValidateCallerAny() 5258 ret := rt.Call(h.a.ControlAddresses, nil).(*miner.GetControlAddressesReturn) 5259 require.NotNil(h.t, ret) 5260 rt.Verify() 5261 return ret.Owner, ret.Worker, ret.ControlAddrs 5262 } 5263 5264 // Options for preCommitSector behaviour. 5265 // Default zero values should let everything be ok. 5266 type preCommitConf struct { 5267 dealWeight abi.DealWeight 5268 verifiedDealWeight abi.DealWeight 5269 dealSpace abi.SectorSize 5270 pledgeDelta *abi.TokenAmount 5271 } 5272 5273 func (h *actorHarness) preCommitSector(rt *mock.Runtime, params *miner.PreCommitSectorParams, conf preCommitConf, first bool) *miner.SectorPreCommitOnChainInfo { 5274 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5275 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 5276 5277 { 5278 expectQueryNetworkInfo(rt, h) 5279 } 5280 if len(params.DealIDs) > 0 { 5281 // If there are any deal IDs, allocate half the weight to non-verified and half to verified. 5282 vdParams := market.VerifyDealsForActivationParams{ 5283 Sectors: []market.SectorDeals{{ 5284 SectorExpiry: params.Expiration, 5285 DealIDs: params.DealIDs, 5286 }}, 5287 } 5288 5289 if conf.dealWeight.Nil() { 5290 conf.dealWeight = big.Zero() 5291 } 5292 if conf.verifiedDealWeight.Nil() { 5293 conf.verifiedDealWeight = big.Zero() 5294 } 5295 vdReturn := market.VerifyDealsForActivationReturn{ 5296 Sectors: []market.SectorWeights{{ 5297 DealSpace: uint64(conf.dealSpace), 5298 DealWeight: conf.dealWeight, 5299 VerifiedDealWeight: conf.verifiedDealWeight, 5300 }}, 5301 } 5302 rt.ExpectSend(builtin.StorageMarketActorAddr, builtin.MethodsMarket.VerifyDealsForActivation, &vdParams, big.Zero(), &vdReturn, exitcode.Ok) 5303 } 5304 st := getState(rt) 5305 if st.FeeDebt.GreaterThan(big.Zero()) { 5306 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, st.FeeDebt, nil, exitcode.Ok) 5307 } 5308 5309 if first { 5310 dlInfo := miner.NewDeadlineInfoFromOffsetAndEpoch(st.ProvingPeriodStart, rt.Epoch()) 5311 cronParams := makeDeadlineCronEventParams(h.t, dlInfo.Last()) 5312 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.EnrollCronEvent, cronParams, big.Zero(), nil, exitcode.Ok) 5313 } 5314 5315 if conf.pledgeDelta != nil { 5316 if !conf.pledgeDelta.IsZero() { 5317 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, conf.pledgeDelta, big.Zero(), nil, exitcode.Ok) 5318 } 5319 } else if rt.NetworkVersion() < network.Version7 { 5320 pledgeDelta := immediatelyVestingFunds(rt, st).Neg() 5321 if !pledgeDelta.IsZero() { 5322 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &pledgeDelta, big.Zero(), nil, exitcode.Ok) 5323 } 5324 } 5325 5326 rt.Call(h.a.PreCommitSector, params) 5327 rt.Verify() 5328 return h.getPreCommit(rt, params.SectorNumber) 5329 } 5330 5331 // Options for proveCommitSector behaviour. 5332 // Default zero values should let everything be ok. 5333 type proveCommitConf struct { 5334 verifyDealsExit map[abi.SectorNumber]exitcode.ExitCode 5335 vestingPledgeDelta *abi.TokenAmount 5336 } 5337 5338 func (h *actorHarness) proveCommitSector(rt *mock.Runtime, precommit *miner.SectorPreCommitOnChainInfo, params *miner.ProveCommitSectorParams) { 5339 commd := cbg.CborCid(tutil.MakeCID("commd", &market.PieceCIDPrefix)) 5340 sealRand := abi.SealRandomness([]byte{1, 2, 3, 4}) 5341 sealIntRand := abi.InteractiveSealRandomness([]byte{5, 6, 7, 8}) 5342 interactiveEpoch := precommit.PreCommitEpoch + miner.PreCommitChallengeDelay 5343 5344 // Prepare for and receive call to ProveCommitSector 5345 { 5346 cdcParams := market.ComputeDataCommitmentParams{ 5347 DealIDs: precommit.Info.DealIDs, 5348 SectorType: precommit.Info.SealProof, 5349 } 5350 rt.ExpectSend(builtin.StorageMarketActorAddr, builtin.MethodsMarket.ComputeDataCommitment, &cdcParams, big.Zero(), &commd, exitcode.Ok) 5351 } 5352 { 5353 var buf bytes.Buffer 5354 receiver := rt.Receiver() 5355 err := receiver.MarshalCBOR(&buf) 5356 require.NoError(h.t, err) 5357 rt.ExpectGetRandomnessTickets(crypto.DomainSeparationTag_SealRandomness, precommit.Info.SealRandEpoch, buf.Bytes(), abi.Randomness(sealRand)) 5358 rt.ExpectGetRandomnessBeacon(crypto.DomainSeparationTag_InteractiveSealChallengeSeed, interactiveEpoch, buf.Bytes(), abi.Randomness(sealIntRand)) 5359 } 5360 { 5361 actorId, err := addr.IDFromAddress(h.receiver) 5362 require.NoError(h.t, err) 5363 seal := proof.SealVerifyInfo{ 5364 SectorID: abi.SectorID{ 5365 Miner: abi.ActorID(actorId), 5366 Number: precommit.Info.SectorNumber, 5367 }, 5368 SealedCID: precommit.Info.SealedCID, 5369 SealProof: precommit.Info.SealProof, 5370 Proof: params.Proof, 5371 DealIDs: precommit.Info.DealIDs, 5372 Randomness: sealRand, 5373 InteractiveRandomness: sealIntRand, 5374 UnsealedCID: cid.Cid(commd), 5375 } 5376 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.SubmitPoRepForBulkVerify, &seal, abi.NewTokenAmount(0), nil, exitcode.Ok) 5377 } 5378 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5379 rt.ExpectValidateCallerAny() 5380 rt.Call(h.a.ProveCommitSector, params) 5381 rt.Verify() 5382 } 5383 5384 func (h *actorHarness) confirmSectorProofsValid(rt *mock.Runtime, conf proveCommitConf, precommits ...*miner.SectorPreCommitOnChainInfo) { 5385 // expect calls to get network stats 5386 expectQueryNetworkInfo(rt, h) 5387 5388 // Prepare for and receive call to ConfirmSectorProofsValid. 5389 var validPrecommits []*miner.SectorPreCommitOnChainInfo 5390 var allSectorNumbers []abi.SectorNumber 5391 for _, precommit := range precommits { 5392 allSectorNumbers = append(allSectorNumbers, precommit.Info.SectorNumber) 5393 validPrecommits = append(validPrecommits, precommit) 5394 if len(precommit.Info.DealIDs) > 0 { 5395 vdParams := market.ActivateDealsParams{ 5396 DealIDs: precommit.Info.DealIDs, 5397 SectorExpiry: precommit.Info.Expiration, 5398 } 5399 exit, found := conf.verifyDealsExit[precommit.Info.SectorNumber] 5400 if found { 5401 validPrecommits = validPrecommits[:len(validPrecommits)-1] // pop 5402 } else { 5403 exit = exitcode.Ok 5404 } 5405 rt.ExpectSend(builtin.StorageMarketActorAddr, builtin.MethodsMarket.ActivateDeals, &vdParams, big.Zero(), nil, exit) 5406 } 5407 } 5408 5409 // expected pledge is the sum of initial pledges 5410 if len(validPrecommits) > 0 { 5411 expectPledge := big.Zero() 5412 5413 expectQAPower := big.Zero() 5414 expectRawPower := big.Zero() 5415 for _, precommit := range validPrecommits { 5416 precommitOnChain := h.getPreCommit(rt, precommit.Info.SectorNumber) 5417 5418 duration := precommit.Info.Expiration - rt.Epoch() 5419 if duration >= miner.MinSectorExpiration { 5420 qaPowerDelta := miner.QAPowerForWeight(h.sectorSize, duration, precommitOnChain.DealWeight, precommitOnChain.VerifiedDealWeight) 5421 expectQAPower = big.Add(expectQAPower, qaPowerDelta) 5422 expectRawPower = big.Add(expectRawPower, big.NewIntUnsigned(uint64(h.sectorSize))) 5423 pledge := miner.InitialPledgeForPower(qaPowerDelta, h.baselinePower, h.epochRewardSmooth, 5424 h.epochQAPowerSmooth, rt.TotalFilCircSupply()) 5425 5426 // if cc upgrade, pledge is max of new and replaced pledges 5427 if precommitOnChain.Info.ReplaceCapacity { 5428 replaced := h.getSector(rt, precommitOnChain.Info.ReplaceSectorNumber) 5429 pledge = big.Max(pledge, replaced.InitialPledge) 5430 } 5431 5432 expectPledge = big.Add(expectPledge, pledge) 5433 } 5434 } 5435 5436 if conf.vestingPledgeDelta != nil { 5437 expectPledge = big.Add(expectPledge, *conf.vestingPledgeDelta) 5438 } 5439 5440 if !expectPledge.IsZero() { 5441 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &expectPledge, big.Zero(), nil, exitcode.Ok) 5442 } 5443 } 5444 5445 rt.SetCaller(builtin.StoragePowerActorAddr, builtin.StoragePowerActorCodeID) 5446 rt.ExpectValidateCallerAddr(builtin.StoragePowerActorAddr) 5447 rt.Call(h.a.ConfirmSectorProofsValid, &builtin.ConfirmSectorProofsParams{Sectors: allSectorNumbers}) 5448 rt.Verify() 5449 } 5450 5451 func (h *actorHarness) proveCommitSectorAndConfirm(rt *mock.Runtime, precommit *miner.SectorPreCommitOnChainInfo, 5452 params *miner.ProveCommitSectorParams, conf proveCommitConf) *miner.SectorOnChainInfo { 5453 h.proveCommitSector(rt, precommit, params) 5454 h.confirmSectorProofsValid(rt, conf, precommit) 5455 5456 newSector := h.getSector(rt, params.SectorNumber) 5457 return newSector 5458 } 5459 5460 // Pre-commits and then proves a number of sectors. 5461 // The sectors will expire at the end of lifetimePeriods proving periods after now. 5462 // The runtime epoch will be moved forward to the epoch of commitment proofs. 5463 func (h *actorHarness) commitAndProveSectors(rt *mock.Runtime, n int, lifetimePeriods uint64, dealIDs [][]abi.DealID, first bool) []*miner.SectorOnChainInfo { 5464 precommitEpoch := rt.Epoch() 5465 deadline := h.deadline(rt) 5466 expiration := deadline.PeriodEnd() + abi.ChainEpoch(lifetimePeriods)*miner.WPoStProvingPeriod 5467 5468 // Precommit 5469 precommits := make([]*miner.SectorPreCommitOnChainInfo, n) 5470 for i := 0; i < n; i++ { 5471 sectorNo := h.nextSectorNo 5472 var sectorDealIDs []abi.DealID 5473 if dealIDs != nil { 5474 sectorDealIDs = dealIDs[i] 5475 } 5476 params := h.makePreCommit(sectorNo, precommitEpoch-1, expiration, sectorDealIDs) 5477 precommit := h.preCommitSector(rt, params, preCommitConf{}, first && i == 0) 5478 precommits[i] = precommit 5479 h.nextSectorNo++ 5480 } 5481 advanceToEpochWithCron(rt, h, precommitEpoch+miner.PreCommitChallengeDelay+1) 5482 5483 info := []*miner.SectorOnChainInfo{} 5484 for _, pc := range precommits { 5485 sector := h.proveCommitSectorAndConfirm(rt, pc, makeProveCommit(pc.Info.SectorNumber), proveCommitConf{}) 5486 info = append(info, sector) 5487 } 5488 rt.Reset() 5489 return info 5490 } 5491 5492 func (h *actorHarness) compactSectorNumbers(rt *mock.Runtime, bf bitfield.BitField) { 5493 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5494 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 5495 5496 rt.Call(h.a.CompactSectorNumbers, &miner.CompactSectorNumbersParams{ 5497 MaskSectorNumbers: bf, 5498 }) 5499 rt.Verify() 5500 } 5501 5502 func (h *actorHarness) commitAndProveSector(rt *mock.Runtime, sectorNo abi.SectorNumber, lifetimePeriods uint64, dealIDs []abi.DealID) *miner.SectorOnChainInfo { 5503 precommitEpoch := rt.Epoch() 5504 deadline := h.deadline(rt) 5505 expiration := deadline.PeriodEnd() + abi.ChainEpoch(lifetimePeriods)*miner.WPoStProvingPeriod 5506 5507 // Precommit 5508 preCommitParams := h.makePreCommit(sectorNo, precommitEpoch-1, expiration, dealIDs) 5509 precommit := h.preCommitSector(rt, preCommitParams, preCommitConf{}, true) 5510 5511 advanceToEpochWithCron(rt, h, precommitEpoch+miner.PreCommitChallengeDelay+1) 5512 5513 sectorInfo := h.proveCommitSectorAndConfirm(rt, precommit, makeProveCommit(preCommitParams.SectorNumber), proveCommitConf{}) 5514 rt.Reset() 5515 return sectorInfo 5516 } 5517 5518 func (h *actorHarness) commitProveAndUpgradeSector(rt *mock.Runtime, sectorNo, upgradeSectorNo abi.SectorNumber, 5519 lifetimePeriods uint64, dealIDs []abi.DealID, 5520 ) (oldSector *miner.SectorOnChainInfo, newSector *miner.SectorOnChainInfo) { 5521 // Move the current epoch forward so that the first deadline is a stable candidate for both sectors 5522 rt.SetEpoch(h.periodOffset + miner.WPoStChallengeWindow) 5523 5524 // Commit a sector to upgrade 5525 // Use the max sector number to make sure everything works. 5526 oldSector = h.commitAndProveSector(rt, sectorNo, lifetimePeriods, nil) 5527 5528 // advance cron to activate power. 5529 advanceAndSubmitPoSts(rt, h, oldSector) 5530 5531 st := getState(rt) 5532 dlIdx, partIdx, err := st.FindSector(rt.AdtStore(), oldSector.SectorNumber) 5533 require.NoError(h.t, err) 5534 5535 // Reduce the epoch reward so that a new sector's initial pledge would otherwise be lesser. 5536 // It has to be reduced quite a lot to overcome the new sector having more power due to verified deal weight. 5537 h.epochRewardSmooth = smoothing.TestingConstantEstimate(big.Div(h.epochRewardSmooth.Estimate(), big.NewInt(20))) 5538 5539 challengeEpoch := rt.Epoch() - 1 5540 upgradeParams := h.makePreCommit(upgradeSectorNo, challengeEpoch, oldSector.Expiration, dealIDs) 5541 upgradeParams.ReplaceCapacity = true 5542 upgradeParams.ReplaceSectorDeadline = dlIdx 5543 upgradeParams.ReplaceSectorPartition = partIdx 5544 upgradeParams.ReplaceSectorNumber = oldSector.SectorNumber 5545 upgrade := h.preCommitSector(rt, upgradeParams, preCommitConf{ 5546 dealWeight: big.Zero(), 5547 verifiedDealWeight: big.NewInt(int64(h.sectorSize)), 5548 dealSpace: h.sectorSize, 5549 }, false) 5550 5551 // Prove new sector 5552 rt.SetEpoch(upgrade.PreCommitEpoch + miner.PreCommitChallengeDelay + 1) 5553 newSector = h.proveCommitSectorAndConfirm(rt, upgrade, makeProveCommit(upgrade.Info.SectorNumber), proveCommitConf{}) 5554 5555 return oldSector, newSector 5556 } 5557 5558 // Deprecated 5559 func (h *actorHarness) advancePastProvingPeriodWithCron(rt *mock.Runtime) { 5560 st := getState(rt) 5561 deadline := st.DeadlineInfo(rt.Epoch()) 5562 rt.SetEpoch(deadline.PeriodEnd()) 5563 nextCron := deadline.NextPeriodStart() + miner.WPoStProvingPeriod - 1 5564 h.onDeadlineCron(rt, &cronConfig{ 5565 expectedEnrollment: nextCron, 5566 }) 5567 rt.SetEpoch(deadline.NextPeriodStart()) 5568 } 5569 5570 func (h *actorHarness) advancePastDeadlineEndWithCron(rt *mock.Runtime) { 5571 deadline := h.deadline(rt) 5572 rt.SetEpoch(deadline.PeriodEnd()) 5573 nextCron := deadline.Last() + miner.WPoStChallengeWindow 5574 h.onDeadlineCron(rt, &cronConfig{ 5575 expectedEnrollment: nextCron, 5576 }) 5577 rt.SetEpoch(deadline.NextPeriodStart()) 5578 } 5579 5580 type poStDisputeResult struct { 5581 expectedPowerDelta miner.PowerPair 5582 expectedPledgeDelta abi.TokenAmount 5583 expectedPenalty abi.TokenAmount 5584 expectedReward abi.TokenAmount 5585 } 5586 5587 func (h *actorHarness) disputeWindowPoSt(rt *mock.Runtime, deadline *dline.Info, proofIndex uint64, infos []*miner.SectorOnChainInfo, expectSuccess *poStDisputeResult) { 5588 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5589 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 5590 5591 expectQueryNetworkInfo(rt, h) 5592 challengeRand := abi.SealRandomness([]byte{10, 11, 12, 13}) 5593 5594 // only sectors that are not skipped and not existing non-recovered faults will be verified 5595 allIgnored := bf() 5596 dln := h.getDeadline(rt, deadline.Index) 5597 5598 post := h.getSubmittedProof(rt, dln, proofIndex) 5599 5600 var err error 5601 err = post.Partitions.ForEach(func(idx uint64) error { 5602 partition := h.getPartitionSnapshot(rt, dln, idx) 5603 allIgnored, err = bitfield.MergeBitFields(allIgnored, partition.Faults) 5604 require.NoError(h.t, err) 5605 noRecoveries, err := partition.Recoveries.IsEmpty() 5606 require.NoError(h.t, err) 5607 require.True(h.t, noRecoveries) 5608 return nil 5609 }) 5610 require.NoError(h.t, err) 5611 5612 // find the first non-faulty, non-skipped sector in poSt to replace all faulty sectors. 5613 var goodInfo *miner.SectorOnChainInfo 5614 for _, ci := range infos { 5615 contains, err := allIgnored.IsSet(uint64(ci.SectorNumber)) 5616 require.NoError(h.t, err) 5617 if !contains { 5618 goodInfo = ci 5619 break 5620 } 5621 } 5622 require.NotNil(h.t, goodInfo, "stored proof should prove at least one sector") 5623 5624 var buf bytes.Buffer 5625 receiver := rt.Receiver() 5626 err = receiver.MarshalCBOR(&buf) 5627 require.NoError(h.t, err) 5628 5629 rt.ExpectGetRandomnessBeacon(crypto.DomainSeparationTag_WindowedPoStChallengeSeed, deadline.Challenge, buf.Bytes(), abi.Randomness(challengeRand)) 5630 5631 actorId, err := addr.IDFromAddress(h.receiver) 5632 require.NoError(h.t, err) 5633 5634 proofInfos := make([]proof.SectorInfo, len(infos)) 5635 for i, ci := range infos { 5636 si := ci 5637 contains, err := allIgnored.IsSet(uint64(ci.SectorNumber)) 5638 require.NoError(h.t, err) 5639 if contains { 5640 si = goodInfo 5641 } 5642 proofInfos[i] = proof.SectorInfo{ 5643 SealProof: si.SealProof, 5644 SectorNumber: si.SectorNumber, 5645 SealedCID: si.SealedCID, 5646 } 5647 } 5648 5649 vi := proof.WindowPoStVerifyInfo{ 5650 Randomness: abi.PoStRandomness(challengeRand), 5651 Proofs: post.Proofs, 5652 ChallengedSectors: proofInfos, 5653 Prover: abi.ActorID(actorId), 5654 } 5655 var verifResult error 5656 if expectSuccess != nil { 5657 // if we succeed at challenging, proof verification needs to fail. 5658 verifResult = fmt.Errorf("invalid post") 5659 } 5660 rt.ExpectVerifyPoSt(vi, verifResult) 5661 5662 if expectSuccess != nil { 5663 // expect power update 5664 if !expectSuccess.expectedPowerDelta.IsZero() { 5665 claim := &power.UpdateClaimedPowerParams{ 5666 RawByteDelta: expectSuccess.expectedPowerDelta.Raw, 5667 QualityAdjustedDelta: expectSuccess.expectedPowerDelta.QA, 5668 } 5669 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdateClaimedPower, claim, abi.NewTokenAmount(0), 5670 nil, exitcode.Ok) 5671 } 5672 // expect reward 5673 if !expectSuccess.expectedReward.IsZero() { 5674 rt.ExpectSend(h.worker, builtin.MethodSend, nil, expectSuccess.expectedReward, nil, exitcode.Ok) 5675 } 5676 // expect penalty 5677 if !expectSuccess.expectedPenalty.IsZero() { 5678 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, expectSuccess.expectedPenalty, nil, exitcode.Ok) 5679 } 5680 // expect pledge update 5681 if !expectSuccess.expectedPledgeDelta.IsZero() { 5682 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, 5683 &expectSuccess.expectedPledgeDelta, abi.NewTokenAmount(0), nil, exitcode.Ok) 5684 } 5685 } 5686 5687 params := miner.DisputeWindowedPoStParams{ 5688 Deadline: deadline.Index, 5689 PoStIndex: proofIndex, 5690 } 5691 if expectSuccess == nil { 5692 rt.ExpectAbortContainsMessage(exitcode.ErrIllegalArgument, "failed to dispute valid post", func() { 5693 rt.Call(h.a.DisputeWindowedPoSt, ¶ms) 5694 }) 5695 } else { 5696 rt.Call(h.a.DisputeWindowedPoSt, ¶ms) 5697 } 5698 rt.Verify() 5699 } 5700 5701 type poStConfig struct { 5702 expectedPowerDelta miner.PowerPair 5703 verificationError error 5704 } 5705 5706 func (h *actorHarness) submitWindowPoSt(rt *mock.Runtime, deadline *dline.Info, partitions []miner.PoStPartition, infos []*miner.SectorOnChainInfo, poStCfg *poStConfig) { 5707 h.submitWindowPoStRaw(rt, deadline, partitions, infos, makePoStProofs(h.windowPostProofType), poStCfg) 5708 } 5709 5710 func (h *actorHarness) submitWindowPoStRaw(rt *mock.Runtime, deadline *dline.Info, partitions []miner.PoStPartition, infos []*miner.SectorOnChainInfo, proofs []proof.PoStProof, poStCfg *poStConfig) { 5711 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5712 commitRand := abi.Randomness("chaincommitment") 5713 rt.ExpectGetRandomnessTickets(crypto.DomainSeparationTag_PoStChainCommit, deadline.Challenge, nil, commitRand) 5714 5715 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 5716 5717 challengeRand := abi.SealRandomness([]byte{10, 11, 12, 13}) 5718 5719 // only sectors that are not skipped and not existing non-recovered faults will be verified 5720 allIgnored := bf() 5721 allRecovered := bf() 5722 dln := h.getDeadline(rt, deadline.Index) 5723 5724 for _, p := range partitions { 5725 partition := h.getPartition(rt, dln, p.Index) 5726 expectedFaults, err := bitfield.SubtractBitField(partition.Faults, partition.Recoveries) 5727 require.NoError(h.t, err) 5728 allIgnored, err = bitfield.MultiMerge(allIgnored, expectedFaults, p.Skipped) 5729 require.NoError(h.t, err) 5730 recovered, err := bitfield.SubtractBitField(partition.Recoveries, p.Skipped) 5731 require.NoError(h.t, err) 5732 allRecovered, err = bitfield.MergeBitFields(allRecovered, recovered) 5733 require.NoError(h.t, err) 5734 } 5735 optimistic, err := allRecovered.IsEmpty() 5736 require.NoError(h.t, err) 5737 5738 // find the first non-faulty, non-skipped sector in poSt to replace all faulty sectors. 5739 var goodInfo *miner.SectorOnChainInfo 5740 for _, ci := range infos { 5741 contains, err := allIgnored.IsSet(uint64(ci.SectorNumber)) 5742 require.NoError(h.t, err) 5743 if !contains { 5744 goodInfo = ci 5745 break 5746 } 5747 } 5748 5749 // goodInfo == nil indicates all the sectors have been skipped and should PoSt verification should not occur 5750 if !optimistic && goodInfo != nil { 5751 var buf bytes.Buffer 5752 receiver := rt.Receiver() 5753 err := receiver.MarshalCBOR(&buf) 5754 require.NoError(h.t, err) 5755 5756 rt.ExpectGetRandomnessBeacon(crypto.DomainSeparationTag_WindowedPoStChallengeSeed, deadline.Challenge, buf.Bytes(), abi.Randomness(challengeRand)) 5757 5758 actorId, err := addr.IDFromAddress(h.receiver) 5759 require.NoError(h.t, err) 5760 5761 // if not all sectors are skipped 5762 proofInfos := make([]proof.SectorInfo, len(infos)) 5763 for i, ci := range infos { 5764 si := ci 5765 contains, err := allIgnored.IsSet(uint64(ci.SectorNumber)) 5766 require.NoError(h.t, err) 5767 if contains { 5768 si = goodInfo 5769 } 5770 proofInfos[i] = proof.SectorInfo{ 5771 SealProof: si.SealProof, 5772 SectorNumber: si.SectorNumber, 5773 SealedCID: si.SealedCID, 5774 } 5775 } 5776 5777 vi := proof.WindowPoStVerifyInfo{ 5778 Randomness: abi.PoStRandomness(challengeRand), 5779 Proofs: proofs, 5780 ChallengedSectors: proofInfos, 5781 Prover: abi.ActorID(actorId), 5782 } 5783 var verifResult error 5784 if poStCfg != nil { 5785 verifResult = poStCfg.verificationError 5786 } 5787 rt.ExpectVerifyPoSt(vi, verifResult) 5788 } 5789 5790 if poStCfg != nil { 5791 // expect power update 5792 if !poStCfg.expectedPowerDelta.IsZero() { 5793 claim := &power.UpdateClaimedPowerParams{ 5794 RawByteDelta: poStCfg.expectedPowerDelta.Raw, 5795 QualityAdjustedDelta: poStCfg.expectedPowerDelta.QA, 5796 } 5797 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdateClaimedPower, claim, abi.NewTokenAmount(0), 5798 nil, exitcode.Ok) 5799 } 5800 } 5801 5802 params := miner.SubmitWindowedPoStParams{ 5803 Deadline: deadline.Index, 5804 Partitions: partitions, 5805 Proofs: proofs, 5806 ChainCommitEpoch: deadline.Challenge, 5807 ChainCommitRand: commitRand, 5808 } 5809 5810 rt.Call(h.a.SubmitWindowedPoSt, ¶ms) 5811 rt.Verify() 5812 } 5813 5814 func (h *actorHarness) declareFaults(rt *mock.Runtime, faultSectorInfos ...*miner.SectorOnChainInfo) miner.PowerPair { 5815 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5816 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 5817 5818 ss, err := faultSectorInfos[0].SealProof.SectorSize() 5819 require.NoError(h.t, err) 5820 expectedRawDelta, expectedQADelta := powerForSectors(ss, faultSectorInfos) 5821 expectedRawDelta = expectedRawDelta.Neg() 5822 expectedQADelta = expectedQADelta.Neg() 5823 5824 // expect power update 5825 claim := &power.UpdateClaimedPowerParams{ 5826 RawByteDelta: expectedRawDelta, 5827 QualityAdjustedDelta: expectedQADelta, 5828 } 5829 rt.ExpectSend( 5830 builtin.StoragePowerActorAddr, 5831 builtin.MethodsPower.UpdateClaimedPower, 5832 claim, 5833 abi.NewTokenAmount(0), 5834 nil, 5835 exitcode.Ok, 5836 ) 5837 5838 // Calculate params from faulted sector infos 5839 st := getState(rt) 5840 params := makeFaultParamsFromFaultingSectors(h.t, st, rt.AdtStore(), faultSectorInfos) 5841 rt.Call(h.a.DeclareFaults, params) 5842 rt.Verify() 5843 5844 return miner.NewPowerPair(claim.RawByteDelta, claim.QualityAdjustedDelta) 5845 } 5846 5847 func (h *actorHarness) declareRecoveries(rt *mock.Runtime, deadlineIdx uint64, partitionIdx uint64, recoverySectors bitfield.BitField, expectedDebtRepaid abi.TokenAmount) { 5848 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5849 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 5850 5851 if expectedDebtRepaid.GreaterThan(big.Zero()) { 5852 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, expectedDebtRepaid, nil, exitcode.Ok) 5853 } 5854 5855 // Calculate params from faulted sector infos 5856 params := &miner.DeclareFaultsRecoveredParams{Recoveries: []miner.RecoveryDeclaration{{ 5857 Deadline: deadlineIdx, 5858 Partition: partitionIdx, 5859 Sectors: recoverySectors, 5860 }}} 5861 5862 rt.Call(h.a.DeclareFaultsRecovered, params) 5863 rt.Verify() 5864 } 5865 5866 func (h *actorHarness) extendSectors(rt *mock.Runtime, params *miner.ExtendSectorExpirationParams) { 5867 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5868 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 5869 5870 qaDelta := big.Zero() 5871 for _, extension := range params.Extensions { 5872 err := extension.Sectors.ForEach(func(sno uint64) error { 5873 sector := h.getSector(rt, abi.SectorNumber(sno)) 5874 newSector := *sector 5875 newSector.Expiration = extension.NewExpiration 5876 qaDelta = big.Sum(qaDelta, 5877 miner.QAPowerForSector(h.sectorSize, &newSector), 5878 miner.QAPowerForSector(h.sectorSize, sector).Neg(), 5879 ) 5880 return nil 5881 }) 5882 require.NoError(h.t, err) 5883 } 5884 if !qaDelta.IsZero() { 5885 rt.ExpectSend(builtin.StoragePowerActorAddr, 5886 builtin.MethodsPower.UpdateClaimedPower, 5887 &power.UpdateClaimedPowerParams{ 5888 RawByteDelta: big.Zero(), 5889 QualityAdjustedDelta: qaDelta, 5890 }, 5891 abi.NewTokenAmount(0), 5892 nil, 5893 exitcode.Ok, 5894 ) 5895 } 5896 rt.Call(h.a.ExtendSectorExpiration, params) 5897 rt.Verify() 5898 } 5899 5900 func (h *actorHarness) terminateSectors(rt *mock.Runtime, sectors bitfield.BitField, expectedFee abi.TokenAmount) (miner.PowerPair, abi.TokenAmount) { 5901 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 5902 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 5903 5904 dealIDs := []abi.DealID{} 5905 sectorInfos := []*miner.SectorOnChainInfo{} 5906 err := sectors.ForEach(func(secNum uint64) error { 5907 sector := h.getSector(rt, abi.SectorNumber(secNum)) 5908 dealIDs = append(dealIDs, sector.DealIDs...) 5909 5910 sectorInfos = append(sectorInfos, sector) 5911 return nil 5912 }) 5913 require.NoError(h.t, err) 5914 5915 expectQueryNetworkInfo(rt, h) 5916 5917 pledgeDelta := big.Zero() 5918 var sectorPower miner.PowerPair 5919 if big.Zero().LessThan(expectedFee) { 5920 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, expectedFee, nil, exitcode.Ok) 5921 pledgeDelta = big.Sum(pledgeDelta, expectedFee.Neg()) 5922 } 5923 // notify change to initial pledge 5924 if len(sectorInfos) > 0 { 5925 for _, sector := range sectorInfos { 5926 pledgeDelta = big.Add(pledgeDelta, sector.InitialPledge.Neg()) 5927 } 5928 } 5929 if !pledgeDelta.Equals(big.Zero()) { 5930 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &pledgeDelta, big.Zero(), nil, exitcode.Ok) 5931 } 5932 if len(dealIDs) > 0 { 5933 size := len(dealIDs) 5934 if size > cbg.MaxLength { 5935 size = cbg.MaxLength 5936 } 5937 rt.ExpectSend(builtin.StorageMarketActorAddr, builtin.MethodsMarket.OnMinerSectorsTerminate, &market.OnMinerSectorsTerminateParams{ 5938 Epoch: rt.Epoch(), 5939 DealIDs: dealIDs[:size], 5940 }, abi.NewTokenAmount(0), nil, exitcode.Ok) 5941 dealIDs = dealIDs[size:] 5942 } 5943 { 5944 sectorPower = miner.PowerForSectors(h.sectorSize, sectorInfos) 5945 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdateClaimedPower, &power.UpdateClaimedPowerParams{ 5946 RawByteDelta: sectorPower.Raw.Neg(), 5947 QualityAdjustedDelta: sectorPower.QA.Neg(), 5948 }, abi.NewTokenAmount(0), nil, exitcode.Ok) 5949 } 5950 5951 // create declarations 5952 st := getState(rt) 5953 deadlines, err := st.LoadDeadlines(rt.AdtStore()) 5954 require.NoError(h.t, err) 5955 5956 declarations := []miner.TerminationDeclaration{} 5957 err = sectors.ForEach(func(id uint64) error { 5958 dlIdx, pIdx, err := miner.FindSector(rt.AdtStore(), deadlines, abi.SectorNumber(id)) 5959 require.NoError(h.t, err) 5960 5961 declarations = append(declarations, miner.TerminationDeclaration{ 5962 Deadline: dlIdx, 5963 Partition: pIdx, 5964 Sectors: bf(id), 5965 }) 5966 return nil 5967 }) 5968 require.NoError(h.t, err) 5969 5970 params := &miner.TerminateSectorsParams{Terminations: declarations} 5971 rt.Call(h.a.TerminateSectors, params) 5972 rt.Verify() 5973 5974 return sectorPower.Neg(), pledgeDelta 5975 } 5976 5977 func (h *actorHarness) reportConsensusFault(rt *mock.Runtime, from addr.Address, fault *runtime.ConsensusFault) { 5978 rt.SetCaller(from, builtin.AccountActorCodeID) 5979 rt.ExpectValidateCallerType(builtin.CallerTypesSignable...) 5980 params := &miner.ReportConsensusFaultParams{ 5981 BlockHeader1: nil, 5982 BlockHeader2: nil, 5983 BlockHeaderExtra: nil, 5984 } 5985 5986 if fault != nil { 5987 rt.ExpectVerifyConsensusFault(params.BlockHeader1, params.BlockHeader2, params.BlockHeaderExtra, fault, nil) 5988 } else { 5989 rt.ExpectVerifyConsensusFault(params.BlockHeader1, params.BlockHeader2, params.BlockHeaderExtra, nil, fmt.Errorf("no fault")) 5990 } 5991 5992 currentReward := reward.ThisEpochRewardReturn{ 5993 ThisEpochBaselinePower: h.baselinePower, 5994 ThisEpochRewardSmoothed: h.epochRewardSmooth, 5995 } 5996 rt.ExpectSend(builtin.RewardActorAddr, builtin.MethodsReward.ThisEpochReward, nil, big.Zero(), ¤tReward, exitcode.Ok) 5997 5998 penaltyTotal := miner.ConsensusFaultPenalty(h.epochRewardSmooth.Estimate()) 5999 // slash reward 6000 rwd := miner.RewardForConsensusSlashReport(1, penaltyTotal) 6001 rt.ExpectSend(from, builtin.MethodSend, nil, rwd, nil, exitcode.Ok) 6002 6003 // pay fault fee 6004 toBurn := big.Sub(penaltyTotal, rwd) 6005 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, toBurn, nil, exitcode.Ok) 6006 6007 rt.Call(h.a.ReportConsensusFault, params) 6008 rt.Verify() 6009 } 6010 6011 func (h *actorHarness) applyRewards(rt *mock.Runtime, amt, penalty abi.TokenAmount) { 6012 // This harness function does not handle the state where apply rewards is 6013 // on a miner with existing fee debt. This state is not protocol reachable 6014 // because currently fee debt prevents election participation. 6015 // 6016 // We further assume the miner can pay the penalty. If the miner 6017 // goes into debt we can't rely on the harness call 6018 // TODO unify those cases 6019 lockAmt, _ := miner.LockedRewardFromReward(amt) 6020 pledgeDelta := big.Sub(lockAmt, penalty) 6021 6022 rt.SetCaller(builtin.RewardActorAddr, builtin.RewardActorCodeID) 6023 rt.ExpectValidateCallerAddr(builtin.RewardActorAddr) 6024 // expect pledge update 6025 rt.ExpectSend( 6026 builtin.StoragePowerActorAddr, 6027 builtin.MethodsPower.UpdatePledgeTotal, 6028 &pledgeDelta, 6029 abi.NewTokenAmount(0), 6030 nil, 6031 exitcode.Ok, 6032 ) 6033 6034 if penalty.GreaterThan(big.Zero()) { 6035 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, penalty, nil, exitcode.Ok) 6036 } 6037 6038 rt.Call(h.a.ApplyRewards, &builtin.ApplyRewardParams{Reward: amt, Penalty: penalty}) 6039 rt.Verify() 6040 } 6041 6042 type cronConfig struct { 6043 noEnrollment bool // true if expect not to continue enrollment false otherwise 6044 expectedEnrollment abi.ChainEpoch 6045 detectedFaultsPowerDelta *miner.PowerPair 6046 expiredSectorsPowerDelta *miner.PowerPair 6047 expiredSectorsPledgeDelta abi.TokenAmount 6048 continuedFaultsPenalty abi.TokenAmount // Expected amount burnt to pay continued fault penalties. 6049 expiredPrecommitPenalty abi.TokenAmount // Expected amount burnt to pay for expired precommits 6050 repaidFeeDebt abi.TokenAmount // Expected amount burnt to repay fee debt. 6051 penaltyFromUnlocked abi.TokenAmount // Expected reduction in unlocked balance from penalties exceeding vesting funds. 6052 } 6053 6054 func (h *actorHarness) onDeadlineCron(rt *mock.Runtime, config *cronConfig) { 6055 var st miner.State 6056 rt.GetState(&st) 6057 rt.ExpectValidateCallerAddr(builtin.StoragePowerActorAddr) 6058 6059 // Preamble 6060 rwd := reward.ThisEpochRewardReturn{ 6061 ThisEpochBaselinePower: h.baselinePower, 6062 ThisEpochRewardSmoothed: h.epochRewardSmooth, 6063 } 6064 rt.ExpectSend(builtin.RewardActorAddr, builtin.MethodsReward.ThisEpochReward, nil, big.Zero(), &rwd, exitcode.Ok) 6065 networkPower := big.NewIntUnsigned(1 << 50) 6066 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.CurrentTotalPower, nil, big.Zero(), 6067 &power.CurrentTotalPowerReturn{ 6068 RawBytePower: networkPower, 6069 QualityAdjPower: networkPower, 6070 PledgeCollateral: h.networkPledge, 6071 QualityAdjPowerSmoothed: h.epochQAPowerSmooth, 6072 }, 6073 exitcode.Ok) 6074 6075 powerDelta := miner.NewPowerPairZero() 6076 if config.detectedFaultsPowerDelta != nil { 6077 powerDelta = powerDelta.Add(*config.detectedFaultsPowerDelta) 6078 } 6079 if config.expiredSectorsPowerDelta != nil { 6080 powerDelta = powerDelta.Add(*config.expiredSectorsPowerDelta) 6081 } 6082 6083 if !powerDelta.IsZero() { 6084 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdateClaimedPower, &power.UpdateClaimedPowerParams{ 6085 RawByteDelta: powerDelta.Raw, 6086 QualityAdjustedDelta: powerDelta.QA, 6087 }, 6088 abi.NewTokenAmount(0), nil, exitcode.Ok) 6089 } 6090 6091 penaltyTotal := big.Zero() 6092 pledgeDelta := big.Zero() 6093 if !config.continuedFaultsPenalty.NilOrZero() { 6094 penaltyTotal = big.Add(penaltyTotal, config.continuedFaultsPenalty) 6095 } 6096 if !config.repaidFeeDebt.NilOrZero() { 6097 penaltyTotal = big.Add(penaltyTotal, config.repaidFeeDebt) 6098 } 6099 if !config.expiredPrecommitPenalty.NilOrZero() { 6100 penaltyTotal = big.Add(penaltyTotal, config.expiredPrecommitPenalty) 6101 } 6102 if !penaltyTotal.IsZero() { 6103 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, penaltyTotal, nil, exitcode.Ok) 6104 penaltyFromVesting := penaltyTotal 6105 // Outstanding fee debt is only repaid from unlocked balance, not vesting funds. 6106 if !config.repaidFeeDebt.NilOrZero() { 6107 penaltyFromVesting = big.Sub(penaltyFromVesting, config.repaidFeeDebt) 6108 } 6109 // Precommit deposit burns are repaid from PCD account 6110 if !config.expiredPrecommitPenalty.NilOrZero() { 6111 penaltyFromVesting = big.Sub(penaltyFromVesting, config.expiredPrecommitPenalty) 6112 } 6113 // New penalties are paid first from vesting funds but, if exhausted, overflow to unlocked balance. 6114 if !config.penaltyFromUnlocked.NilOrZero() { 6115 penaltyFromVesting = big.Sub(penaltyFromVesting, config.penaltyFromUnlocked) 6116 } 6117 pledgeDelta = big.Sub(pledgeDelta, penaltyFromVesting) 6118 } 6119 6120 if !config.expiredSectorsPledgeDelta.NilOrZero() { 6121 pledgeDelta = big.Add(pledgeDelta, config.expiredSectorsPledgeDelta) 6122 } 6123 6124 pledgeDelta = big.Sub(pledgeDelta, immediatelyVestingFunds(rt, &st)) 6125 6126 if !pledgeDelta.IsZero() { 6127 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &pledgeDelta, big.Zero(), nil, exitcode.Ok) 6128 } 6129 6130 // Re-enrollment for next period. 6131 if !config.noEnrollment { 6132 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.EnrollCronEvent, 6133 makeDeadlineCronEventParams(h.t, config.expectedEnrollment), big.Zero(), nil, exitcode.Ok) 6134 } 6135 6136 rt.SetCaller(builtin.StoragePowerActorAddr, builtin.StoragePowerActorCodeID) 6137 rt.Call(h.a.OnDeferredCronEvent, &miner.CronEventPayload{ 6138 EventType: miner.CronEventProvingDeadline, 6139 }) 6140 rt.Verify() 6141 } 6142 6143 func (h *actorHarness) withdrawFunds(rt *mock.Runtime, amountRequested, amountWithdrawn, expectedDebtRepaid abi.TokenAmount) { 6144 rt.SetCaller(h.owner, builtin.AccountActorCodeID) 6145 rt.ExpectValidateCallerAddr(h.owner) 6146 6147 rt.ExpectSend(h.owner, builtin.MethodSend, nil, amountWithdrawn, nil, exitcode.Ok) 6148 if expectedDebtRepaid.GreaterThan(big.Zero()) { 6149 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, expectedDebtRepaid, nil, exitcode.Ok) 6150 } 6151 rt.Call(h.a.WithdrawBalance, &miner.WithdrawBalanceParams{ 6152 AmountRequested: amountRequested, 6153 }) 6154 6155 rt.Verify() 6156 } 6157 6158 func (h *actorHarness) repayDebt(rt *mock.Runtime, value, expectedRepayedFromVest, expectedRepaidFromBalance abi.TokenAmount) { 6159 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 6160 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 6161 6162 rt.SetBalance(big.Sum(rt.Balance(), value)) 6163 rt.SetReceived(value) 6164 if expectedRepayedFromVest.GreaterThan(big.Zero()) { 6165 pledgeDelta := expectedRepayedFromVest.Neg() 6166 rt.ExpectSend(builtin.StoragePowerActorAddr, builtin.MethodsPower.UpdatePledgeTotal, &pledgeDelta, big.Zero(), nil, exitcode.Ok) 6167 } 6168 6169 totalRepaid := big.Sum(expectedRepayedFromVest, expectedRepaidFromBalance) 6170 if totalRepaid.GreaterThan((big.Zero())) { 6171 rt.ExpectSend(builtin.BurntFundsActorAddr, builtin.MethodSend, nil, totalRepaid, nil, exitcode.Ok) 6172 } 6173 rt.Call(h.a.RepayDebt, nil) 6174 6175 rt.Verify() 6176 } 6177 6178 func (h *actorHarness) compactPartitions(rt *mock.Runtime, deadline uint64, partitions bitfield.BitField) { 6179 param := miner.CompactPartitionsParams{Deadline: deadline, Partitions: partitions} 6180 6181 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 6182 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 6183 6184 rt.Call(h.a.CompactPartitions, ¶m) 6185 rt.Verify() 6186 } 6187 6188 func (h *actorHarness) continuedFaultPenalty(sectors []*miner.SectorOnChainInfo) abi.TokenAmount { 6189 _, qa := powerForSectors(h.sectorSize, sectors) 6190 return miner.PledgePenaltyForContinuedFault(h.epochRewardSmooth, h.epochQAPowerSmooth, qa) 6191 } 6192 6193 func (h *actorHarness) powerPairForSectors(sectors []*miner.SectorOnChainInfo) miner.PowerPair { 6194 rawPower, qaPower := powerForSectors(h.sectorSize, sectors) 6195 return miner.NewPowerPair(rawPower, qaPower) 6196 } 6197 6198 func (h *actorHarness) makePreCommit(sectorNo abi.SectorNumber, challenge, expiration abi.ChainEpoch, dealIDs []abi.DealID) *miner.PreCommitSectorParams { 6199 return &miner.PreCommitSectorParams{ 6200 SealProof: h.sealProofType, 6201 SectorNumber: sectorNo, 6202 SealedCID: tutil.MakeCID("commr", &miner.SealedCIDPrefix), 6203 SealRandEpoch: challenge, 6204 DealIDs: dealIDs, 6205 Expiration: expiration, 6206 } 6207 } 6208 6209 func (h *actorHarness) setPeerID(rt *mock.Runtime, newID abi.PeerID) { 6210 params := miner.ChangePeerIDParams{NewID: newID} 6211 6212 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 6213 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 6214 6215 ret := rt.Call(h.a.ChangePeerID, ¶ms) 6216 assert.Nil(h.t, ret) 6217 rt.Verify() 6218 6219 var st miner.State 6220 rt.GetState(&st) 6221 info, err := st.GetInfo(adt.AsStore(rt)) 6222 require.NoError(h.t, err) 6223 6224 assert.Equal(h.t, newID, info.PeerId) 6225 } 6226 6227 func (h *actorHarness) setMultiaddrs(rt *mock.Runtime, newMultiaddrs ...abi.Multiaddrs) { 6228 params := miner.ChangeMultiaddrsParams{NewMultiaddrs: newMultiaddrs} 6229 6230 rt.SetCaller(h.worker, builtin.AccountActorCodeID) 6231 rt.ExpectValidateCallerAddr(append(h.controlAddrs, h.owner, h.worker)...) 6232 6233 ret := rt.Call(h.a.ChangeMultiaddrs, ¶ms) 6234 assert.Nil(h.t, ret) 6235 rt.Verify() 6236 6237 var st miner.State 6238 rt.GetState(&st) 6239 info, err := st.GetInfo(adt.AsStore(rt)) 6240 require.NoError(h.t, err) 6241 6242 assert.Equal(h.t, newMultiaddrs, info.Multiaddrs) 6243 } 6244 6245 // 6246 // Higher-level orchestration 6247 // 6248 6249 // Completes a deadline by moving the epoch forward to the penultimate one, 6250 // if cron is active calling the deadline cron handler, 6251 // and then advancing to the first epoch in the new deadline. 6252 // If cron is run asserts that the deadline schedules a new cron on the next deadline 6253 func advanceDeadline(rt *mock.Runtime, h *actorHarness, config *cronConfig) *dline.Info { 6254 st := getState(rt) 6255 deadline := miner.NewDeadlineInfoFromOffsetAndEpoch(st.ProvingPeriodStart, rt.Epoch()) 6256 6257 if st.DeadlineCronActive { 6258 rt.SetEpoch(deadline.Last()) 6259 6260 config.expectedEnrollment = deadline.Last() + miner.WPoStChallengeWindow 6261 h.onDeadlineCron(rt, config) 6262 } 6263 rt.SetEpoch(deadline.NextOpen()) 6264 st = getState(rt) 6265 6266 return st.DeadlineInfo(rt.Epoch()) 6267 } 6268 6269 func advanceToEpochWithCron(rt *mock.Runtime, h *actorHarness, e abi.ChainEpoch) { 6270 deadline := h.deadline(rt) 6271 for e > deadline.Last() { 6272 advanceDeadline(rt, h, &cronConfig{}) 6273 deadline = h.deadline(rt) 6274 } 6275 rt.SetEpoch(e) 6276 } 6277 6278 // Advance between 0 and 48 deadlines submitting window posts where necessary to keep 6279 // sectors proven. If sectors is empty this is a noop. If sectors is a singleton this 6280 // will advance to that sector's proving deadline running deadline crons up to and 6281 // including this deadline. If sectors includes a sector assigned to the furthest 6282 // away deadline this will process a whole proving period. 6283 func advanceAndSubmitPoSts(rt *mock.Runtime, h *actorHarness, sectors ...*miner.SectorOnChainInfo) { 6284 st := getState(rt) 6285 6286 sectorArr, err := miner.LoadSectors(rt.AdtStore(), st.Sectors) 6287 require.NoError(h.t, err) 6288 6289 deadlines := map[uint64][]*miner.SectorOnChainInfo{} 6290 for _, sector := range sectors { 6291 dlIdx, _, err := st.FindSector(rt.AdtStore(), sector.SectorNumber) 6292 require.NoError(h.t, err) 6293 deadlines[dlIdx] = append(deadlines[dlIdx], sector) 6294 } 6295 6296 dlinfo := h.currentDeadline(rt) 6297 for len(deadlines) > 0 { 6298 dlSectors, ok := deadlines[dlinfo.Index] 6299 if ok { 6300 sectorNos := bitfield.New() 6301 for _, sector := range dlSectors { 6302 sectorNos.Set(uint64(sector.SectorNumber)) 6303 } 6304 6305 dlArr, err := st.LoadDeadlines(rt.AdtStore()) 6306 require.NoError(h.t, err) 6307 dl, err := dlArr.LoadDeadline(rt.AdtStore(), dlinfo.Index) 6308 require.NoError(h.t, err) 6309 parts, err := dl.PartitionsArray(rt.AdtStore()) 6310 require.NoError(h.t, err) 6311 6312 var partition miner.Partition 6313 partitions := []miner.PoStPartition{} 6314 powerDelta := miner.NewPowerPairZero() 6315 require.NoError(h.t, parts.ForEach(&partition, func(partIdx int64) error { 6316 live, err := partition.LiveSectors() 6317 require.NoError(h.t, err) 6318 toProve, err := bitfield.IntersectBitField(live, sectorNos) 6319 require.NoError(h.t, err) 6320 noProven, err := toProve.IsEmpty() 6321 require.NoError(h.t, err) 6322 if noProven { 6323 // not proving anything in this partition. 6324 return nil 6325 } 6326 6327 toSkip, err := bitfield.SubtractBitField(live, toProve) 6328 require.NoError(h.t, err) 6329 6330 notRecovering, err := bitfield.SubtractBitField(partition.Faults, partition.Recoveries) 6331 require.NoError(h.t, err) 6332 6333 // Don't double-count skips. 6334 toSkip, err = bitfield.SubtractBitField(toSkip, notRecovering) 6335 require.NoError(h.t, err) 6336 6337 skippedProven, err := bitfield.SubtractBitField(toSkip, partition.Unproven) 6338 require.NoError(h.t, err) 6339 6340 skippedProvenSectorInfos, err := sectorArr.Load(skippedProven) 6341 require.NoError(h.t, err) 6342 newFaultyPower := h.powerPairForSectors(skippedProvenSectorInfos) 6343 6344 newProven, err := bitfield.SubtractBitField(partition.Unproven, toSkip) 6345 require.NoError(h.t, err) 6346 6347 newProvenInfos, err := sectorArr.Load(newProven) 6348 require.NoError(h.t, err) 6349 newProvenPower := h.powerPairForSectors(newProvenInfos) 6350 6351 powerDelta = powerDelta.Sub(newFaultyPower) 6352 powerDelta = powerDelta.Add(newProvenPower) 6353 6354 partitions = append(partitions, miner.PoStPartition{Index: uint64(partIdx), Skipped: toSkip}) 6355 return nil 6356 })) 6357 6358 h.submitWindowPoSt(rt, dlinfo, partitions, dlSectors, &poStConfig{ 6359 expectedPowerDelta: powerDelta, 6360 }) 6361 delete(deadlines, dlinfo.Index) 6362 } 6363 6364 advanceDeadline(rt, h, &cronConfig{}) 6365 dlinfo = h.currentDeadline(rt) 6366 } 6367 } 6368 6369 func immediatelyVestingFunds(rt *mock.Runtime, st *miner.State) big.Int { 6370 // Account just the very next vesting funds entry. 6371 var vesting miner.VestingFunds 6372 rt.StoreGet(st.VestingFunds, &vesting) 6373 sum := big.Zero() 6374 for _, v := range vesting.Funds { 6375 if v.Epoch <= rt.Epoch() { 6376 sum = big.Add(sum, v.Amount) 6377 } else { 6378 break 6379 } 6380 } 6381 return sum 6382 } 6383 6384 // 6385 // Construction helpers, etc 6386 // 6387 6388 func builderForHarness(actor *actorHarness) mock.RuntimeBuilder { 6389 rb := mock.NewBuilder(actor.receiver). 6390 WithActorType(actor.owner, builtin.AccountActorCodeID). 6391 WithActorType(actor.worker, builtin.AccountActorCodeID). 6392 WithHasher(fixedHasher(uint64(actor.periodOffset))) 6393 6394 for _, ca := range actor.controlAddrs { 6395 rb = rb.WithActorType(ca, builtin.AccountActorCodeID) 6396 } 6397 6398 return rb 6399 } 6400 6401 func getState(rt *mock.Runtime) *miner.State { 6402 var st miner.State 6403 rt.GetState(&st) 6404 return &st 6405 } 6406 6407 func makeDeadlineCronEventParams(t testing.TB, epoch abi.ChainEpoch) *power.EnrollCronEventParams { 6408 eventPayload := miner.CronEventPayload{EventType: miner.CronEventProvingDeadline} 6409 buf := bytes.Buffer{} 6410 err := eventPayload.MarshalCBOR(&buf) 6411 require.NoError(t, err) 6412 6413 params := &power.EnrollCronEventParams{ 6414 EventEpoch: epoch, 6415 Payload: buf.Bytes(), 6416 } 6417 return params 6418 } 6419 6420 func makeProveCommit(sectorNo abi.SectorNumber) *miner.ProveCommitSectorParams { 6421 return &miner.ProveCommitSectorParams{ 6422 SectorNumber: sectorNo, 6423 Proof: make([]byte, 192), 6424 } 6425 } 6426 6427 func makePoStProofs(registeredPoStProof abi.RegisteredPoStProof) []proof.PoStProof { 6428 proofs := make([]proof.PoStProof, 1) // Number of proofs doesn't depend on partition count 6429 for i := range proofs { 6430 proofs[i].PoStProof = registeredPoStProof 6431 proofs[i].ProofBytes = []byte(fmt.Sprintf("proof%d", i)) 6432 } 6433 return proofs 6434 } 6435 6436 func makeFaultParamsFromFaultingSectors(t testing.TB, st *miner.State, store adt.Store, faultSectorInfos []*miner.SectorOnChainInfo) *miner.DeclareFaultsParams { 6437 deadlines, err := st.LoadDeadlines(store) 6438 require.NoError(t, err) 6439 6440 declarationMap := map[string]*miner.FaultDeclaration{} 6441 for _, sector := range faultSectorInfos { 6442 dlIdx, pIdx, err := miner.FindSector(store, deadlines, sector.SectorNumber) 6443 require.NoError(t, err) 6444 6445 key := fmt.Sprintf("%d:%d", dlIdx, pIdx) 6446 declaration, ok := declarationMap[key] 6447 if !ok { 6448 declaration = &miner.FaultDeclaration{ 6449 Deadline: dlIdx, 6450 Partition: pIdx, 6451 Sectors: bf(), 6452 } 6453 declarationMap[key] = declaration 6454 } 6455 declaration.Sectors.Set(uint64(sector.SectorNumber)) 6456 } 6457 require.NoError(t, err) 6458 6459 var declarations []miner.FaultDeclaration 6460 for _, declaration := range declarationMap { 6461 declarations = append(declarations, *declaration) 6462 } 6463 6464 return &miner.DeclareFaultsParams{Faults: declarations} 6465 } 6466 6467 func sectorInfoAsBitfield(infos []*miner.SectorOnChainInfo) bitfield.BitField { 6468 bf := bitfield.New() 6469 for _, info := range infos { 6470 bf.Set(uint64(info.SectorNumber)) 6471 } 6472 return bf 6473 } 6474 6475 func powerForSectors(sectorSize abi.SectorSize, sectors []*miner.SectorOnChainInfo) (rawBytePower, qaPower big.Int) { 6476 rawBytePower = big.Mul(big.NewIntUnsigned(uint64(sectorSize)), big.NewIntUnsigned(uint64(len(sectors)))) 6477 qaPower = big.Zero() 6478 for _, s := range sectors { 6479 qaPower = big.Add(qaPower, miner.QAPowerForSector(sectorSize, s)) 6480 } 6481 return rawBytePower, qaPower 6482 } 6483 6484 func assertEmptyBitfield(t *testing.T, b bitfield.BitField) { 6485 empty, err := b.IsEmpty() 6486 require.NoError(t, err) 6487 assert.True(t, empty) 6488 } 6489 6490 // Returns a fake hashing function that always arranges the first 8 bytes of the digest to be the binary 6491 // encoding of a target uint64. 6492 func fixedHasher(target uint64) func([]byte) [32]byte { 6493 return func(_ []byte) [32]byte { 6494 var buf bytes.Buffer 6495 err := binary.Write(&buf, binary.BigEndian, target) 6496 if err != nil { 6497 panic(err) 6498 } 6499 var digest [32]byte 6500 copy(digest[:], buf.Bytes()) 6501 return digest 6502 } 6503 } 6504 6505 func expectQueryNetworkInfo(rt *mock.Runtime, h *actorHarness) { 6506 currentPower := power.CurrentTotalPowerReturn{ 6507 RawBytePower: h.networkRawPower, 6508 QualityAdjPower: h.networkQAPower, 6509 PledgeCollateral: h.networkPledge, 6510 QualityAdjPowerSmoothed: h.epochQAPowerSmooth, 6511 } 6512 currentReward := reward.ThisEpochRewardReturn{ 6513 ThisEpochBaselinePower: h.baselinePower, 6514 ThisEpochRewardSmoothed: h.epochRewardSmooth, 6515 } 6516 6517 rt.ExpectSend( 6518 builtin.RewardActorAddr, 6519 builtin.MethodsReward.ThisEpochReward, 6520 nil, 6521 big.Zero(), 6522 ¤tReward, 6523 exitcode.Ok, 6524 ) 6525 6526 rt.ExpectSend( 6527 builtin.StoragePowerActorAddr, 6528 builtin.MethodsPower.CurrentTotalPower, 6529 nil, 6530 big.Zero(), 6531 ¤tPower, 6532 exitcode.Ok, 6533 ) 6534 }