github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/miner/expiration_queue_test.go (about) 1 package miner_test 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/filecoin-project/go-address" 8 "github.com/filecoin-project/go-bitfield" 9 "github.com/filecoin-project/go-state-types/abi" 10 "github.com/filecoin-project/go-state-types/big" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" 15 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 16 "github.com/filecoin-project/specs-actors/v4/support/mock" 17 tutil "github.com/filecoin-project/specs-actors/v4/support/testing" 18 ) 19 20 func TestExpirationSet(t *testing.T) { 21 onTimeSectors := bitfield.NewFromSet([]uint64{5, 8, 9}) 22 earlySectors := bitfield.NewFromSet([]uint64{2, 3}) 23 onTimePledge := abi.NewTokenAmount(1000) 24 activePower := miner.NewPowerPair(abi.NewStoragePower(1<<13), abi.NewStoragePower(1<<14)) 25 faultyPower := miner.NewPowerPair(abi.NewStoragePower(1<<11), abi.NewStoragePower(1<<12)) 26 27 t.Run("adds sectors and power to empty set", func(t *testing.T) { 28 set := miner.NewExpirationSetEmpty() 29 30 err := set.Add(onTimeSectors, earlySectors, onTimePledge, activePower, faultyPower) 31 require.NoError(t, err) 32 33 assertBitfieldEquals(t, set.OnTimeSectors, 5, 8, 9) 34 assertBitfieldEquals(t, set.EarlySectors, 2, 3) 35 assert.Equal(t, onTimePledge, set.OnTimePledge) 36 assert.True(t, activePower.Equals(set.ActivePower)) 37 assert.True(t, faultyPower.Equals(set.FaultyPower)) 38 39 count, err := set.Count() 40 require.NoError(t, err) 41 assert.EqualValues(t, 5, count) 42 }) 43 44 t.Run("adds sectors and power to non-empty set", func(t *testing.T) { 45 set := miner.NewExpirationSet(onTimeSectors, earlySectors, onTimePledge, activePower, faultyPower) 46 47 err := set.Add( 48 bitfield.NewFromSet([]uint64{6, 7, 11}), 49 bitfield.NewFromSet([]uint64{1, 4}), 50 abi.NewTokenAmount(300), 51 miner.NewPowerPair(abi.NewStoragePower(3*(1<<13)), abi.NewStoragePower(3*(1<<14))), 52 miner.NewPowerPair(abi.NewStoragePower(3*(1<<11)), abi.NewStoragePower(3*(1<<12))), 53 ) 54 require.NoError(t, err) 55 56 assertBitfieldEquals(t, set.OnTimeSectors, 5, 6, 7, 8, 9, 11) 57 assertBitfieldEquals(t, set.EarlySectors, 1, 2, 3, 4) 58 assert.Equal(t, abi.NewTokenAmount(1300), set.OnTimePledge) 59 active := miner.NewPowerPair(abi.NewStoragePower(1<<15), abi.NewStoragePower(1<<16)) 60 assert.True(t, active.Equals(set.ActivePower)) 61 faulty := miner.NewPowerPair(abi.NewStoragePower(1<<13), abi.NewStoragePower(1<<14)) 62 assert.True(t, faulty.Equals(set.FaultyPower)) 63 }) 64 65 t.Run("removes sectors and power set", func(t *testing.T) { 66 set := miner.NewExpirationSet(onTimeSectors, earlySectors, onTimePledge, activePower, faultyPower) 67 68 err := set.Remove( 69 bitfield.NewFromSet([]uint64{9}), 70 bitfield.NewFromSet([]uint64{2}), 71 abi.NewTokenAmount(800), 72 miner.NewPowerPair(abi.NewStoragePower(3*(1<<11)), abi.NewStoragePower(3*(1<<12))), 73 miner.NewPowerPair(abi.NewStoragePower(3*(1<<9)), abi.NewStoragePower(3*(1<<10))), 74 ) 75 require.NoError(t, err) 76 77 assertBitfieldEquals(t, set.OnTimeSectors, 5, 8) 78 assertBitfieldEquals(t, set.EarlySectors, 3) 79 assert.Equal(t, abi.NewTokenAmount(200), set.OnTimePledge) 80 active := miner.NewPowerPair(abi.NewStoragePower(1<<11), abi.NewStoragePower(1<<12)) 81 assert.True(t, active.Equals(set.ActivePower)) 82 faulty := miner.NewPowerPair(abi.NewStoragePower(1<<9), abi.NewStoragePower(1<<10)) 83 assert.True(t, faulty.Equals(set.FaultyPower)) 84 }) 85 86 t.Run("remove fails when pledge underflows", func(t *testing.T) { 87 set := miner.NewExpirationSet(onTimeSectors, earlySectors, onTimePledge, activePower, faultyPower) 88 89 err := set.Remove( 90 bitfield.NewFromSet([]uint64{9}), 91 bitfield.NewFromSet([]uint64{2}), 92 abi.NewTokenAmount(1200), 93 miner.NewPowerPair(abi.NewStoragePower(3*(1<<11)), abi.NewStoragePower(3*(1<<12))), 94 miner.NewPowerPair(abi.NewStoragePower(3*(1<<9)), abi.NewStoragePower(3*(1<<10))), 95 ) 96 require.Error(t, err) 97 assert.Contains(t, err.Error(), "pledge underflow") 98 }) 99 100 t.Run("remove fails to remove sectors it does not contain", func(t *testing.T) { 101 set := miner.NewExpirationSet(onTimeSectors, earlySectors, onTimePledge, activePower, faultyPower) 102 103 // remove unknown active sector 12 104 err := set.Remove( 105 bitfield.NewFromSet([]uint64{12}), 106 bitfield.NewFromSet([]uint64{}), 107 abi.NewTokenAmount(0), 108 miner.NewPowerPair(abi.NewStoragePower(3*(1<<11)), abi.NewStoragePower(3*(1<<12))), 109 miner.NewPowerPair(abi.NewStoragePower(3*(1<<9)), abi.NewStoragePower(3*(1<<10))), 110 ) 111 require.Error(t, err) 112 assert.Contains(t, err.Error(), "not contained") 113 114 // remove faulty sector 8, that is active in the set 115 err = set.Remove( 116 bitfield.NewFromSet([]uint64{0}), 117 bitfield.NewFromSet([]uint64{8}), 118 abi.NewTokenAmount(0), 119 miner.NewPowerPair(abi.NewStoragePower(3*(1<<11)), abi.NewStoragePower(3*(1<<12))), 120 miner.NewPowerPair(abi.NewStoragePower(3*(1<<9)), abi.NewStoragePower(3*(1<<10))), 121 ) 122 require.Error(t, err) 123 assert.Contains(t, err.Error(), "not contained") 124 }) 125 126 t.Run("remove fails when active or fault qa power underflows", func(t *testing.T) { 127 set := miner.NewExpirationSet(onTimeSectors, earlySectors, onTimePledge, activePower, faultyPower) 128 129 // active removed power > active power 130 err := set.Remove( 131 bitfield.NewFromSet([]uint64{9}), 132 bitfield.NewFromSet([]uint64{2}), 133 abi.NewTokenAmount(200), 134 miner.NewPowerPair(abi.NewStoragePower(3*(1<<12)), abi.NewStoragePower(3*(1<<13))), 135 miner.NewPowerPair(abi.NewStoragePower(3*(1<<9)), abi.NewStoragePower(3*(1<<10))), 136 ) 137 require.Error(t, err) 138 assert.Contains(t, err.Error(), "power underflow") 139 140 set = miner.NewExpirationSet(onTimeSectors, earlySectors, onTimePledge, activePower, faultyPower) 141 142 // faulty removed power > faulty power 143 err = set.Remove( 144 bitfield.NewFromSet([]uint64{9}), 145 bitfield.NewFromSet([]uint64{2}), 146 abi.NewTokenAmount(200), 147 miner.NewPowerPair(abi.NewStoragePower(3*(1<<11)), abi.NewStoragePower(3*(1<<12))), 148 miner.NewPowerPair(abi.NewStoragePower(3*(1<<10)), abi.NewStoragePower(3*(1<<11))), 149 ) 150 require.Error(t, err) 151 assert.Contains(t, err.Error(), "power underflow") 152 }) 153 154 t.Run("set is empty when all sectors removed", func(t *testing.T) { 155 set := miner.NewExpirationSetEmpty() 156 157 empty, err := set.IsEmpty() 158 require.NoError(t, err) 159 assert.True(t, empty) 160 161 count, err := set.Count() 162 require.NoError(t, err) 163 assert.Zero(t, count) 164 165 err = set.Add(onTimeSectors, earlySectors, onTimePledge, activePower, faultyPower) 166 require.NoError(t, err) 167 168 empty, err = set.IsEmpty() 169 require.NoError(t, err) 170 assert.False(t, empty) 171 172 err = set.Remove(onTimeSectors, earlySectors, onTimePledge, activePower, faultyPower) 173 require.NoError(t, err) 174 175 empty, err = set.IsEmpty() 176 require.NoError(t, err) 177 assert.True(t, empty) 178 179 count, err = set.Count() 180 require.NoError(t, err) 181 assert.Zero(t, count) 182 }) 183 } 184 185 func TestExpirationQueue(t *testing.T) { 186 sectors := []*miner.SectorOnChainInfo{ 187 testSector(2, 1, 50, 60, 1000), 188 testSector(3, 2, 51, 61, 1001), 189 testSector(7, 3, 52, 62, 1002), 190 testSector(8, 4, 53, 63, 1003), 191 testSector(11, 5, 54, 64, 1004), 192 testSector(13, 6, 55, 65, 1005), 193 } 194 sectorSize := abi.SectorSize(32 * 1 << 30) 195 196 t.Run("added sectors can be popped off queue", func(t *testing.T) { 197 queue := emptyExpirationQueue(t) 198 secNums, power, pledge, err := queue.AddActiveSectors(sectors, sectorSize) 199 require.NoError(t, err) 200 assertBitfieldEquals(t, secNums, 1, 2, 3, 4, 5, 6) 201 assert.True(t, power.Equals(miner.PowerForSectors(sectorSize, sectors))) 202 assert.Equal(t, abi.NewTokenAmount(6015), pledge) 203 204 // default test quantizing of 1 means every sector is in its own expriation set 205 assert.Equal(t, len(sectors), int(queue.Length())) 206 207 _, err = queue.Root() 208 require.NoError(t, err) 209 210 // pop off sectors up to and including epoch 8 211 set, err := queue.PopUntil(7) 212 require.NoError(t, err) 213 214 // only 3 sectors remain 215 assert.Equal(t, 3, int(queue.Length())) 216 217 assertBitfieldEquals(t, set.OnTimeSectors, 1, 2, 3) 218 assertBitfieldEmpty(t, set.EarlySectors) 219 220 activePower := miner.PowerForSectors(sectorSize, sectors[:3]) 221 faultyPower := miner.NewPowerPairZero() 222 223 assert.Equal(t, big.NewInt(3003), set.OnTimePledge) // sum of first 3 sector pledges 224 assert.True(t, activePower.Equals(set.ActivePower)) 225 assert.True(t, faultyPower.Equals(set.FaultyPower)) 226 227 // pop off rest up to and including epoch 8 228 set, err = queue.PopUntil(20) 229 require.NoError(t, err) 230 231 assertBitfieldEquals(t, set.OnTimeSectors, 4, 5, 6) 232 assertBitfieldEmpty(t, set.EarlySectors) 233 234 assert.Equal(t, big.NewInt(3012), set.OnTimePledge) // sum of last 3 sector pledges 235 assert.True(t, set.ActivePower.Equals(miner.PowerForSectors(sectorSize, sectors[3:]))) 236 assert.True(t, set.FaultyPower.Equals(miner.NewPowerPairZero())) 237 238 // queue is now empty 239 assert.Equal(t, 0, int(queue.Length())) 240 }) 241 242 t.Run("quantizes added sectors by expiration", func(t *testing.T) { 243 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(5, 3), testAmtBitwidth) 244 secNums, power, pledge, err := queue.AddActiveSectors(sectors, sectorSize) 245 require.NoError(t, err) 246 assertBitfieldEquals(t, secNums, 1, 2, 3, 4, 5, 6) 247 assert.True(t, power.Equals(miner.PowerForSectors(sectorSize, sectors))) 248 assert.Equal(t, abi.NewTokenAmount(6015), pledge) 249 250 // work around caching issues in amt 251 _, err = queue.Root() 252 require.NoError(t, err) 253 254 // quantizing spec means sectors should be grouped into 3 sets expiring at 3, 8 and 13 255 assert.Equal(t, 3, int(queue.Length())) 256 257 // set popped before first quantized sector should be empty 258 set, err := queue.PopUntil(2) 259 require.NoError(t, err) 260 assertBitfieldEmpty(t, set.OnTimeSectors) 261 assert.Equal(t, 3, int(queue.Length())) 262 263 // first 2 sectors will be in first set popped off at quantization offset (3) 264 set, err = queue.PopUntil(3) 265 require.NoError(t, err) 266 assertBitfieldEquals(t, set.OnTimeSectors, 1, 2) 267 assert.Equal(t, 2, int(queue.Length())) 268 269 _, err = queue.Root() 270 require.NoError(t, err) 271 272 // no sectors will be popped off in quantization interval 273 set, err = queue.PopUntil(7) 274 require.NoError(t, err) 275 assertBitfieldEmpty(t, set.OnTimeSectors) 276 assert.Equal(t, 2, int(queue.Length())) 277 278 // next 2 sectors will be in first set popped off after quantization interval (8) 279 set, err = queue.PopUntil(8) 280 require.NoError(t, err) 281 assertBitfieldEquals(t, set.OnTimeSectors, 3, 4) 282 assert.Equal(t, 1, int(queue.Length())) 283 284 _, err = queue.Root() 285 require.NoError(t, err) 286 287 // no sectors will be popped off in quantization interval 288 set, err = queue.PopUntil(12) 289 require.NoError(t, err) 290 assertBitfieldEmpty(t, set.OnTimeSectors) 291 assert.Equal(t, 1, int(queue.Length())) 292 293 // rest of sectors will be in first set popped off after quantization interval (13) 294 set, err = queue.PopUntil(13) 295 require.NoError(t, err) 296 assertBitfieldEquals(t, set.OnTimeSectors, 5, 6) 297 assert.Equal(t, 0, int(queue.Length())) 298 }) 299 300 t.Run("reschedules sectors to expire later", func(t *testing.T) { 301 queue := emptyExpirationQueue(t) 302 _, _, _, err := queue.AddActiveSectors(sectors, sectorSize) 303 require.NoError(t, err) 304 305 _, err = queue.Root() 306 require.NoError(t, err) 307 308 err = queue.RescheduleExpirations(abi.ChainEpoch(20), sectors[:3], sectorSize) 309 require.NoError(t, err) 310 311 _, err = queue.Root() 312 require.NoError(t, err) 313 314 // expect 3 rescheduled sectors to be bundled into 1 set 315 assert.Equal(t, 4, int(queue.Length())) 316 317 // rescheduled sectors are no longer scheduled before epoch 8 318 set, err := queue.PopUntil(7) 319 require.NoError(t, err) 320 assertBitfieldEmpty(t, set.OnTimeSectors) 321 assert.Equal(t, 4, int(queue.Length())) 322 323 // pop off sectors before new expiration and expect only the rescheduled set to remain 324 _, err = queue.PopUntil(19) 325 require.NoError(t, err) 326 assert.Equal(t, 1, int(queue.Length())) 327 328 // pop off rescheduled sectors 329 set, err = queue.PopUntil(20) 330 require.NoError(t, err) 331 assert.Equal(t, 0, int(queue.Length())) 332 333 // expect all sector stats from first 3 sectors to belong to new expiration set 334 assertBitfieldEquals(t, set.OnTimeSectors, 1, 2, 3) 335 assertBitfieldEmpty(t, set.EarlySectors) 336 337 assert.Equal(t, big.NewInt(3003), set.OnTimePledge) 338 assert.True(t, set.ActivePower.Equals(miner.PowerForSectors(sectorSize, sectors[:3]))) 339 assert.True(t, set.FaultyPower.Equals(miner.NewPowerPairZero())) 340 }) 341 342 t.Run("reschedules sectors as faults", func(t *testing.T) { 343 // Create 3 expiration sets with 2 sectors apiece 344 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 345 _, _, _, err := queue.AddActiveSectors(sectors, sectorSize) 346 require.NoError(t, err) 347 348 _, err = queue.Root() 349 require.NoError(t, err) 350 351 // Fault middle sectors to expire at epoch 6 352 // This faults one sector from the first set, all of the second set and one from the third. 353 // Faulting at epoch 6 means the first 3 will expire on time, but the last will be early and 354 // moved to the second set 355 powerDelta, err := queue.RescheduleAsFaults(abi.ChainEpoch(6), sectors[1:5], sectorSize) 356 require.NoError(t, err) 357 assert.True(t, powerDelta.Equals(miner.PowerForSectors(sectorSize, sectors[1:5]))) 358 359 _, err = queue.Root() 360 require.NoError(t, err) 361 362 // expect first set to contain first two sectors but with the seconds power moved to faulty power 363 requireNoExpirationGroupsBefore(t, 5, queue) 364 set, err := queue.PopUntil(5) 365 require.NoError(t, err) 366 367 assertBitfieldEquals(t, set.OnTimeSectors, 1, 2) 368 assertBitfieldEmpty(t, set.EarlySectors) 369 370 assert.Equal(t, big.NewInt(2001), set.OnTimePledge) 371 assert.True(t, set.ActivePower.Equals(miner.PowerForSectors(sectorSize, sectors[0:1]))) 372 assert.True(t, set.FaultyPower.Equals(miner.PowerForSectors(sectorSize, sectors[1:2]))) 373 374 // expect the second set to have all faulty power and now contain 5th sector as an early sector 375 requireNoExpirationGroupsBefore(t, 9, queue) 376 set, err = queue.PopUntil(9) 377 require.NoError(t, err) 378 379 assertBitfieldEquals(t, set.OnTimeSectors, 3, 4) 380 assertBitfieldEquals(t, set.EarlySectors, 5) 381 382 // pledge is kept from original 2 sectors. Pledge from new early sector is NOT added. 383 assert.Equal(t, big.NewInt(2005), set.OnTimePledge) 384 385 assert.True(t, set.ActivePower.Equals(miner.NewPowerPairZero())) 386 assert.True(t, set.FaultyPower.Equals(miner.PowerForSectors(sectorSize, sectors[2:5]))) 387 388 // expect last set to only contain non faulty sector 389 requireNoExpirationGroupsBefore(t, 13, queue) 390 set, err = queue.PopUntil(13) 391 require.NoError(t, err) 392 393 assertBitfieldEquals(t, set.OnTimeSectors, 6) 394 assertBitfieldEmpty(t, set.EarlySectors) 395 396 // Pledge from sector moved from this set is dropped 397 assert.Equal(t, big.NewInt(1005), set.OnTimePledge) 398 399 assert.True(t, set.ActivePower.Equals(miner.PowerForSectors(sectorSize, sectors[5:]))) 400 assert.True(t, set.FaultyPower.Equals(miner.NewPowerPairZero())) 401 }) 402 403 t.Run("reschedules all sectors as faults", func(t *testing.T) { 404 // Create expiration 3 sets with 2 sectors apiece 405 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 406 _, _, _, err := queue.AddActiveSectors(sectors, sectorSize) 407 require.NoError(t, err) 408 409 _, err = queue.Root() 410 require.NoError(t, err) 411 412 // Fault all sectors 413 // This converts the first 2 sets to faults and adds the 3rd set as early sectors to the second set 414 err = queue.RescheduleAllAsFaults(abi.ChainEpoch(6)) 415 require.NoError(t, err) 416 417 _, err = queue.Root() 418 require.NoError(t, err) 419 420 // expect first set to contain first two sectors but with the seconds power moved to faulty power 421 requireNoExpirationGroupsBefore(t, 5, queue) 422 set, err := queue.PopUntil(5) 423 require.NoError(t, err) 424 425 assertBitfieldEquals(t, set.OnTimeSectors, 1, 2) // sectors are unmoved 426 assertBitfieldEmpty(t, set.EarlySectors) 427 428 assert.Equal(t, big.NewInt(2001), set.OnTimePledge) // pledge is same 429 430 // active power is converted to fault power 431 assert.True(t, set.ActivePower.Equals(miner.NewPowerPairZero())) 432 assert.True(t, set.FaultyPower.Equals(miner.PowerForSectors(sectorSize, sectors[:2]))) 433 434 // expect the second set to have all faulty power and now contain 5th and 6th sectors as an early sectors 435 requireNoExpirationGroupsBefore(t, 9, queue) 436 set, err = queue.PopUntil(9) 437 require.NoError(t, err) 438 439 assertBitfieldEquals(t, set.OnTimeSectors, 3, 4) 440 assertBitfieldEquals(t, set.EarlySectors, 5, 6) 441 442 // pledge is kept from original 2 sectors. Pledge from new early sectors is NOT added. 443 assert.Equal(t, big.NewInt(2005), set.OnTimePledge) 444 445 // fault power is all power for sectors previously in the first and second sets 446 assert.True(t, set.ActivePower.Equals(miner.NewPowerPairZero())) 447 assert.True(t, set.FaultyPower.Equals(miner.PowerForSectors(sectorSize, sectors[2:]))) 448 449 // expect last set to only contain non faulty sector 450 requireNoExpirationGroupsBefore(t, 13, queue) 451 set, err = queue.PopUntil(13) 452 require.NoError(t, err) 453 454 assertBitfieldEmpty(t, set.OnTimeSectors) 455 assertBitfieldEmpty(t, set.EarlySectors) 456 457 // all pledge is dropped 458 assert.Equal(t, big.Zero(), set.OnTimePledge) 459 460 assert.True(t, set.ActivePower.Equals(miner.NewPowerPairZero())) 461 assert.True(t, set.FaultyPower.Equals(miner.NewPowerPairZero())) 462 }) 463 464 t.Run("reschedule expirations then reschedule as fault", func(t *testing.T) { 465 // Create expiration 3 sets with 2 sectors apiece 466 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 467 _, _, _, err := queue.AddActiveSectors(sectors, sectorSize) 468 require.NoError(t, err) 469 470 _, err = queue.Root() 471 require.NoError(t, err) 472 473 // reschedule 2 from second group to first 474 toReschedule := []*miner.SectorOnChainInfo{sectors[2]} 475 err = queue.RescheduleExpirations(2, toReschedule, sectorSize) 476 require.NoError(t, err) 477 478 // now reschedule one sector in first group and another in second group as faults to expire in first set 479 faults := []*miner.SectorOnChainInfo{sectors[1], sectors[2]} 480 power, err := queue.RescheduleAsFaults(4, faults, sectorSize) 481 require.NoError(t, err) 482 483 expectedPower := miner.PowerForSectors(sectorSize, faults) 484 assert.Equal(t, expectedPower, power) 485 486 // expect 0, 1, 2, 3 in first group 487 set, err := queue.PopUntil(5) 488 require.NoError(t, err) 489 assertBitfieldEquals(t, set.OnTimeSectors, 1, 2, 3) 490 assert.Equal(t, miner.PowerForSectors(sectorSize, []*miner.SectorOnChainInfo{sectors[0]}), set.ActivePower) 491 assert.Equal(t, expectedPower, set.FaultyPower) 492 493 // expect rest to come later 494 set, err = queue.PopUntil(20) 495 require.NoError(t, err) 496 assertBitfieldEquals(t, set.OnTimeSectors, 4, 5, 6) 497 assert.Equal(t, miner.PowerForSectors(sectorSize, []*miner.SectorOnChainInfo{sectors[3], sectors[4], sectors[5]}), set.ActivePower) 498 assert.Equal(t, miner.NewPowerPairZero(), set.FaultyPower) 499 }) 500 501 t.Run("reschedule recover restores all sector stats", func(t *testing.T) { 502 // Create expiration 3 sets with 2 sectors apiece 503 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 504 _, _, _, err := queue.AddActiveSectors(sectors, sectorSize) 505 require.NoError(t, err) 506 507 _, err = queue.Root() 508 require.NoError(t, err) 509 510 // Fault middle sectors to expire at epoch 6 to put sectors in a state 511 // described in "reschedules sectors as faults" 512 _, err = queue.RescheduleAsFaults(abi.ChainEpoch(6), sectors[1:5], sectorSize) 513 require.NoError(t, err) 514 515 _, err = queue.Root() 516 require.NoError(t, err) 517 518 // mark faulted sectors as recovered 519 recovered, err := queue.RescheduleRecovered(sectors[1:5], sectorSize) 520 require.NoError(t, err) 521 assert.True(t, recovered.Equals(miner.PowerForSectors(sectorSize, sectors[1:5]))) 522 523 // expect first set to contain first two sectors with active power 524 requireNoExpirationGroupsBefore(t, 5, queue) 525 set, err := queue.PopUntil(5) 526 require.NoError(t, err) 527 528 assertBitfieldEquals(t, set.OnTimeSectors, 1, 2) 529 assertBitfieldEmpty(t, set.EarlySectors) 530 531 // pledge from both sectors 532 assert.Equal(t, big.NewInt(2001), set.OnTimePledge) 533 534 assert.True(t, set.ActivePower.Equals(miner.PowerForSectors(sectorSize, sectors[:2]))) 535 assert.True(t, set.FaultyPower.Equals(miner.NewPowerPairZero())) 536 537 // expect second set to have lost early sector 5 and have active power just from 3 and 4 538 requireNoExpirationGroupsBefore(t, 9, queue) 539 set, err = queue.PopUntil(9) 540 require.NoError(t, err) 541 542 assertBitfieldEquals(t, set.OnTimeSectors, 3, 4) 543 assertBitfieldEmpty(t, set.EarlySectors) 544 545 // pledge is kept from original 2 sectors 546 assert.Equal(t, big.NewInt(2005), set.OnTimePledge) 547 548 assert.True(t, set.ActivePower.Equals(miner.PowerForSectors(sectorSize, sectors[2:4]))) 549 assert.True(t, set.FaultyPower.Equals(miner.NewPowerPairZero())) 550 551 // expect sector 5 to be returned to last setu 552 requireNoExpirationGroupsBefore(t, 13, queue) 553 set, err = queue.PopUntil(13) 554 require.NoError(t, err) 555 556 assertBitfieldEquals(t, set.OnTimeSectors, 5, 6) 557 assertBitfieldEmpty(t, set.EarlySectors) 558 559 // Pledge from sector 5 is restored 560 assert.Equal(t, big.NewInt(2009), set.OnTimePledge) 561 562 assert.True(t, set.ActivePower.Equals(miner.PowerForSectors(sectorSize, sectors[4:]))) 563 assert.True(t, set.FaultyPower.Equals(miner.NewPowerPairZero())) 564 }) 565 566 t.Run("replaces sectors with new sectors", func(t *testing.T) { 567 // Create expiration 3 sets 568 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 569 570 // add sectors to each set 571 _, _, _, err := queue.AddActiveSectors([]*miner.SectorOnChainInfo{sectors[0], sectors[1], sectors[3], sectors[5]}, sectorSize) 572 require.NoError(t, err) 573 574 _, err = queue.Root() 575 require.NoError(t, err) 576 577 // remove all from first set, replace second set, and append to third 578 toRemove := []*miner.SectorOnChainInfo{sectors[0], sectors[1], sectors[3]} 579 toAdd := []*miner.SectorOnChainInfo{sectors[2], sectors[4]} 580 removed, added, powerDelta, pledgeDelta, err := queue.ReplaceSectors( 581 toRemove, 582 toAdd, 583 sectorSize) 584 require.NoError(t, err) 585 assertBitfieldEquals(t, removed, 1, 2, 4) 586 assertBitfieldEquals(t, added, 3, 5) 587 addedPower := miner.PowerForSectors(sectorSize, toAdd) 588 assert.True(t, powerDelta.Equals(addedPower.Sub(miner.PowerForSectors(sectorSize, toRemove)))) 589 assert.Equal(t, abi.NewTokenAmount(1002+1004-1000-1001-1003), pledgeDelta) 590 591 // first set is gone 592 requireNoExpirationGroupsBefore(t, 9, queue) 593 594 // second set is replaced 595 set, err := queue.PopUntil(9) 596 require.NoError(t, err) 597 598 assertBitfieldEquals(t, set.OnTimeSectors, 3) 599 assertBitfieldEmpty(t, set.EarlySectors) 600 601 // pledge and power is only from sector 3 602 assert.Equal(t, big.NewInt(1002), set.OnTimePledge) 603 assert.True(t, set.ActivePower.Equals(miner.PowerForSectors(sectorSize, sectors[2:3]))) 604 assert.True(t, set.FaultyPower.Equals(miner.NewPowerPairZero())) 605 606 // last set appends sector 6 607 requireNoExpirationGroupsBefore(t, 13, queue) 608 set, err = queue.PopUntil(13) 609 require.NoError(t, err) 610 611 assertBitfieldEquals(t, set.OnTimeSectors, 5, 6) 612 assertBitfieldEmpty(t, set.EarlySectors) 613 614 // pledge and power are some of old and new sectors 615 assert.Equal(t, big.NewInt(2009), set.OnTimePledge) 616 assert.True(t, set.ActivePower.Equals(miner.PowerForSectors(sectorSize, sectors[4:]))) 617 assert.True(t, set.FaultyPower.Equals(miner.NewPowerPairZero())) 618 }) 619 620 t.Run("removes sectors", func(t *testing.T) { 621 // add all sectors into 3 sets 622 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 623 _, _, _, err := queue.AddActiveSectors(sectors, sectorSize) 624 require.NoError(t, err) 625 626 _, err = queue.Root() 627 require.NoError(t, err) 628 629 // put queue in a state where some sectors are early and some are faulty 630 _, err = queue.RescheduleAsFaults(abi.ChainEpoch(6), sectors[1:6], sectorSize) 631 require.NoError(t, err) 632 633 _, err = queue.Root() 634 require.NoError(t, err) 635 636 // remove an active sector from first set, faulty sector and early faulty sector from second set, 637 toRemove := []*miner.SectorOnChainInfo{sectors[0], sectors[3], sectors[4], sectors[5]} 638 639 // and only sector from last set 640 faults := bitfield.NewFromSet([]uint64{4, 5, 6}) 641 642 // label the last as recovering 643 recovering := bitfield.NewFromSet([]uint64{6}) 644 removed, recoveringPower, err := queue.RemoveSectors(toRemove, faults, recovering, sectorSize) 645 require.NoError(t, err) 646 647 // assert all return values are correct 648 assertBitfieldEquals(t, removed.OnTimeSectors, 1, 4) 649 assertBitfieldEquals(t, removed.EarlySectors, 5, 6) 650 assert.Equal(t, abi.NewTokenAmount(1000+1003), removed.OnTimePledge) // only on-time sectors 651 assert.True(t, removed.ActivePower.Equals(miner.PowerForSectors(sectorSize, []*miner.SectorOnChainInfo{sectors[0]}))) 652 assert.True(t, removed.FaultyPower.Equals(miner.PowerForSectors(sectorSize, sectors[3:6]))) 653 assert.True(t, recoveringPower.Equals(miner.PowerForSectors(sectorSize, sectors[5:6]))) 654 655 // assert queue state is as expected 656 657 // only faulty sector 2 is found in first set 658 requireNoExpirationGroupsBefore(t, 5, queue) 659 set, err := queue.PopUntil(5) 660 require.NoError(t, err) 661 662 assertBitfieldEquals(t, set.OnTimeSectors, 2) 663 assertBitfieldEmpty(t, set.EarlySectors) 664 assert.Equal(t, abi.NewTokenAmount(1001), set.OnTimePledge) 665 assert.True(t, set.ActivePower.Equals(miner.NewPowerPairZero())) 666 assert.True(t, set.FaultyPower.Equals(miner.PowerForSectors(sectorSize, sectors[1:2]))) 667 668 // only faulty on-time sector 3 is found in second set 669 requireNoExpirationGroupsBefore(t, 9, queue) 670 set, err = queue.PopUntil(9) 671 require.NoError(t, err) 672 673 assertBitfieldEquals(t, set.OnTimeSectors, 3) 674 assertBitfieldEmpty(t, set.EarlySectors) 675 assert.Equal(t, abi.NewTokenAmount(1002), set.OnTimePledge) 676 assert.True(t, set.ActivePower.Equals(miner.NewPowerPairZero())) 677 assert.True(t, set.FaultyPower.Equals(miner.PowerForSectors(sectorSize, sectors[2:3]))) 678 679 // no further sets remain 680 requireNoExpirationGroupsBefore(t, 20, queue) 681 }) 682 683 t.Run("adding no sectors leaves the queue empty", func(t *testing.T) { 684 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 685 _, _, _, err := queue.AddActiveSectors(nil, sectorSize) 686 require.NoError(t, err) 687 assert.Zero(t, queue.Length()) 688 }) 689 690 t.Run("rescheduling no expirations leaves the queue empty", func(t *testing.T) { 691 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 692 err := queue.RescheduleExpirations(10, nil, sectorSize) 693 require.NoError(t, err) 694 assert.Zero(t, queue.Length()) 695 }) 696 697 t.Run("rescheduling no expirations as faults leaves the queue empty", func(t *testing.T) { 698 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 699 700 _, _, _, err := queue.AddActiveSectors(sectors, sectorSize) 701 require.NoError(t, err) 702 703 // all sectors already expire before epoch 15, nothing should change. 704 length := queue.Length() 705 _, err = queue.RescheduleAsFaults(15, sectors, sectorSize) 706 require.NoError(t, err) 707 assert.Equal(t, length, queue.Length()) 708 }) 709 710 t.Run("rescheduling all expirations as faults leaves the queue empty if it was empty", func(t *testing.T) { 711 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 712 713 _, _, _, err := queue.AddActiveSectors(sectors, sectorSize) 714 require.NoError(t, err) 715 716 // all sectors already expire before epoch 15, nothing should change. 717 length := queue.Length() 718 err = queue.RescheduleAllAsFaults(15) 719 require.NoError(t, err) 720 assert.Equal(t, length, queue.Length()) 721 }) 722 723 t.Run("rescheduling no sectors as recovered leaves the queue empty", func(t *testing.T) { 724 queue := emptyExpirationQueueWithQuantizing(t, miner.NewQuantSpec(4, 1), testAmtBitwidth) 725 _, err := queue.RescheduleRecovered(nil, sectorSize) 726 require.NoError(t, err) 727 assert.Zero(t, queue.Length()) 728 }) 729 } 730 731 func testSector(expiration, number, weight, vweight, pledge int64) *miner.SectorOnChainInfo { 732 return &miner.SectorOnChainInfo{ 733 Expiration: abi.ChainEpoch(expiration), 734 SectorNumber: abi.SectorNumber(number), 735 DealWeight: big.NewInt(weight), 736 VerifiedDealWeight: big.NewInt(vweight), 737 InitialPledge: abi.NewTokenAmount(pledge), 738 SealedCID: tutil.MakeCID(fmt.Sprintf("commR-%d", number), &miner.SealedCIDPrefix), 739 } 740 } 741 742 func requireNoExpirationGroupsBefore(t *testing.T, epoch abi.ChainEpoch, queue miner.ExpirationQueue) { 743 _, err := queue.Root() 744 require.NoError(t, err) 745 746 set, err := queue.PopUntil(epoch - 1) 747 require.NoError(t, err) 748 empty, err := set.IsEmpty() 749 require.NoError(t, err) 750 require.True(t, empty) 751 } 752 753 func emptyExpirationQueueWithQuantizing(t *testing.T, quant miner.QuantSpec, bitwidth int) miner.ExpirationQueue { 754 rt := mock.NewBuilder(address.Undef).Build(t) 755 store := adt.AsStore(rt) 756 emptyArray, err := adt.StoreEmptyArray(store, testAmtBitwidth) 757 require.NoError(t, err) 758 759 queue, err := miner.LoadExpirationQueue(store, emptyArray, quant, bitwidth) 760 require.NoError(t, err) 761 return queue 762 } 763 764 func emptyExpirationQueue(t *testing.T) miner.ExpirationQueue { 765 return emptyExpirationQueueWithQuantizing(t, miner.NoQuantization, testAmtBitwidth) 766 }