github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/miner/bitfield_queue_test.go (about) 1 package miner_test 2 3 import ( 4 "testing" 5 6 "github.com/filecoin-project/go-address" 7 "github.com/filecoin-project/go-bitfield" 8 "github.com/filecoin-project/go-state-types/abi" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 12 "github.com/filecoin-project/specs-actors/v4/actors/builtin/miner" 13 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 14 "github.com/filecoin-project/specs-actors/v4/support/mock" 15 ) 16 17 const testAmtBitwidth = 3 18 19 func TestBitfieldQueue(t *testing.T) { 20 t.Run("adds values to empty queue", func(t *testing.T) { 21 queue := emptyBitfieldQueue(t, testAmtBitwidth) 22 23 values := []uint64{1, 2, 3, 4} 24 epoch := abi.ChainEpoch(42) 25 require.NoError(t, queue.AddToQueueValues(epoch, values...)) 26 27 ExpectBQ(). 28 Add(epoch, values...). 29 Equals(t, queue) 30 }) 31 32 t.Run("adds bitfield to empty queue", func(t *testing.T) { 33 queue := emptyBitfieldQueue(t, testAmtBitwidth) 34 35 values := []uint64{1, 2, 3, 4} 36 epoch := abi.ChainEpoch(42) 37 38 require.NoError(t, queue.AddToQueue(epoch, bitfield.NewFromSet(values))) 39 40 ExpectBQ(). 41 Add(epoch, values...). 42 Equals(t, queue) 43 }) 44 45 t.Run("quantizes added epochs according to quantization spec", func(t *testing.T) { 46 queue := emptyBitfieldQueueWithQuantizing(t, miner.NewQuantSpec(5, 3), testAmtBitwidth) 47 48 for _, val := range []uint64{0, 2, 3, 4, 7, 8, 9} { 49 require.NoError(t, queue.AddToQueueValues(abi.ChainEpoch(val), val)) 50 } 51 52 // expect values to only be set on quantization boundaries 53 ExpectBQ(). 54 Add(abi.ChainEpoch(3), 0, 2, 3). 55 Add(abi.ChainEpoch(8), 4, 7, 8). 56 Add(abi.ChainEpoch(13), 9). 57 Equals(t, queue) 58 }) 59 60 t.Run("quantizes added epochs according to quantization spec", func(t *testing.T) { 61 queue := emptyBitfieldQueueWithQuantizing(t, miner.NewQuantSpec(5, 3), testAmtBitwidth) 62 63 for _, val := range []uint64{0, 2, 3, 4, 7, 8, 9} { 64 err := queue.AddToQueueValues(abi.ChainEpoch(val), val) 65 require.NoError(t, err) 66 } 67 68 // expect values to only be set on quantization boundaries 69 ExpectBQ(). 70 Add(abi.ChainEpoch(3), 0, 2, 3). 71 Add(abi.ChainEpoch(8), 4, 7, 8). 72 Add(abi.ChainEpoch(13), 9). 73 Equals(t, queue) 74 }) 75 76 t.Run("merges values withing same epoch", func(t *testing.T) { 77 queue := emptyBitfieldQueue(t, testAmtBitwidth) 78 79 epoch := abi.ChainEpoch(42) 80 81 require.NoError(t, queue.AddToQueueValues(epoch, 1, 3)) 82 require.NoError(t, queue.AddToQueueValues(epoch, 2, 4)) 83 84 ExpectBQ(). 85 Add(epoch, 1, 2, 3, 4). 86 Equals(t, queue) 87 }) 88 89 t.Run("adds values to different epochs", func(t *testing.T) { 90 queue := emptyBitfieldQueue(t, testAmtBitwidth) 91 92 epoch1 := abi.ChainEpoch(42) 93 epoch2 := abi.ChainEpoch(93) 94 95 require.NoError(t, queue.AddToQueueValues(epoch1, 1, 3)) 96 require.NoError(t, queue.AddToQueueValues(epoch2, 2, 4)) 97 98 ExpectBQ(). 99 Add(epoch1, 1, 3). 100 Add(epoch2, 2, 4). 101 Equals(t, queue) 102 }) 103 104 t.Run("PouUntil from empty queue returns empty bitfield", func(t *testing.T) { 105 queue := emptyBitfieldQueue(t, testAmtBitwidth) 106 107 // TODO: broken pending https://github.com/filecoin-project/go-amt-ipld/issues/18 108 //emptyQueue, err := queue.Root() 109 //require.NoError(t, err) 110 111 next, modified, err := queue.PopUntil(42) 112 require.NoError(t, err) 113 assert.False(t, modified) 114 115 // no values are returned 116 count, err := next.Count() 117 require.NoError(t, err) 118 assert.Equal(t, 0, int(count)) 119 120 // queue is still empty 121 //root, err := queue.Root() 122 //assert.Equal(t, emptyQueue, root) 123 }) 124 125 t.Run("PopUntil does nothing if 'until' parameter before first value", func(t *testing.T) { 126 queue := emptyBitfieldQueue(t, testAmtBitwidth) 127 128 epoch1 := abi.ChainEpoch(42) 129 epoch2 := abi.ChainEpoch(93) 130 131 require.NoError(t, queue.AddToQueueValues(epoch1, 1, 3)) 132 require.NoError(t, queue.AddToQueueValues(epoch2, 2, 4)) 133 134 next, modified, err := queue.PopUntil(epoch1 - 1) 135 assert.False(t, modified) 136 require.NoError(t, err) 137 assert.False(t, modified) 138 139 // no values are returned 140 count, err := next.Count() 141 require.NoError(t, err) 142 assert.Equal(t, 0, int(count)) 143 144 // queue remains the same 145 ExpectBQ(). 146 Add(epoch1, 1, 3). 147 Add(epoch2, 2, 4). 148 Equals(t, queue) 149 }) 150 151 t.Run("PopUntil removes and returns entries before and including target epoch", func(t *testing.T) { 152 queue := emptyBitfieldQueue(t, testAmtBitwidth) 153 154 epoch1 := abi.ChainEpoch(42) 155 epoch2 := abi.ChainEpoch(93) 156 epoch3 := abi.ChainEpoch(94) 157 epoch4 := abi.ChainEpoch(203) 158 159 require.NoError(t, queue.AddToQueueValues(epoch1, 1, 3)) 160 require.NoError(t, queue.AddToQueueValues(epoch2, 5)) 161 require.NoError(t, queue.AddToQueueValues(epoch3, 6, 7, 8)) 162 require.NoError(t, queue.AddToQueueValues(epoch4, 2, 4)) 163 164 // Required to ensure queue is in a sane state for PopUntil 165 _, err := queue.Root() 166 require.NoError(t, err) 167 168 next, modified, err := queue.PopUntil(epoch2) 169 require.NoError(t, err) 170 // modified should be true to indicate queue has changed 171 assert.True(t, modified) 172 173 // values from first two epochs are returned 174 assertBitfieldEquals(t, next, 1, 3, 5) 175 176 // queue only contains remaining values 177 ExpectBQ(). 178 Add(epoch3, 6, 7, 8). 179 Add(epoch4, 2, 4). 180 Equals(t, queue) 181 182 // subsequent call to epoch less than next does nothing. 183 next, modified, err = queue.PopUntil(epoch3 - 1) 184 require.NoError(t, err) 185 assert.False(t, modified) 186 187 // no values are returned 188 assertBitfieldEquals(t, next, []uint64{}...) 189 190 // queue only contains remaining values 191 ExpectBQ(). 192 Add(epoch3, 6, 7, 8). 193 Add(epoch4, 2, 4). 194 Equals(t, queue) 195 196 // popping the rest of the queue gets the rest of the values 197 next, modified, err = queue.PopUntil(epoch4) 198 require.NoError(t, err) 199 assert.True(t, modified) 200 201 // rest of values are returned 202 assertBitfieldEquals(t, next, 2, 4, 6, 7, 8) 203 204 // queue is now empty 205 ExpectBQ(). 206 Equals(t, queue) 207 }) 208 209 t.Run("cuts elements", func(t *testing.T) { 210 queue := emptyBitfieldQueue(t, testAmtBitwidth) 211 212 epoch1 := abi.ChainEpoch(42) 213 epoch2 := abi.ChainEpoch(93) 214 215 require.NoError(t, queue.AddToQueueValues(epoch1, 1, 2, 3, 4, 99)) 216 require.NoError(t, queue.AddToQueueValues(epoch2, 5, 6)) 217 218 require.NoError(t, queue.Cut(bitfield.NewFromSet([]uint64{2, 4, 5, 6}))) 219 220 ExpectBQ(). 221 Add(epoch1, 1, 2, 95). // 3 shifts down to 2, 99 down to 95 222 Equals(t, queue) 223 }) 224 225 t.Run("adds empty bitfield to queue", func(t *testing.T) { 226 queue := emptyBitfieldQueue(t, testAmtBitwidth) 227 228 epoch := abi.ChainEpoch(42) 229 require.NoError(t, queue.AddToQueue(epoch, bf())) 230 231 // ensures we don't add an empty entry. 232 ExpectBQ().Equals(t, queue) 233 }) 234 235 } 236 237 func emptyBitfieldQueueWithQuantizing(t *testing.T, quant miner.QuantSpec, bitwidth int) miner.BitfieldQueue { 238 rt := mock.NewBuilder(address.Undef).Build(t) 239 store := adt.AsStore(rt) 240 emptyArray, err := adt.StoreEmptyArray(store, bitwidth) 241 require.NoError(t, err) 242 243 queue, err := miner.LoadBitfieldQueue(store, emptyArray, quant, bitwidth) 244 require.NoError(t, err) 245 return queue 246 } 247 248 func emptyBitfieldQueue(t *testing.T, bitwidth int) miner.BitfieldQueue { 249 return emptyBitfieldQueueWithQuantizing(t, miner.NoQuantization, bitwidth) 250 } 251 252 type bqExpectation struct { 253 expected map[abi.ChainEpoch][]uint64 254 } 255 256 func ExpectBQ() *bqExpectation { 257 return &bqExpectation{expected: make(map[abi.ChainEpoch][]uint64)} 258 } 259 260 func (bqe *bqExpectation) Add(epoch abi.ChainEpoch, values ...uint64) *bqExpectation { 261 bqe.expected[epoch] = values 262 return bqe 263 } 264 265 func (bqe *bqExpectation) Equals(t *testing.T, q miner.BitfieldQueue) { 266 // ensure cached changes are ready to be iterated 267 _, err := q.Root() 268 require.NoError(t, err) 269 270 assert.Equal(t, uint64(len(bqe.expected)), q.Length()) 271 272 err = q.ForEach(func(epoch abi.ChainEpoch, bf bitfield.BitField) error { 273 values, ok := bqe.expected[epoch] 274 require.True(t, ok) 275 276 assertBitfieldEquals(t, bf, values...) 277 return nil 278 }) 279 require.NoError(t, err) 280 }