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  }