github.com/prysmaticlabs/prysm@v1.4.4/shared/aggregation/attestations/maxcover_test.go (about) 1 package attestations 2 3 import ( 4 "testing" 5 6 "github.com/prysmaticlabs/go-bitfield" 7 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 8 "github.com/prysmaticlabs/prysm/shared/aggregation" 9 "github.com/prysmaticlabs/prysm/shared/bls" 10 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 11 ) 12 13 func TestAggregateAttestations_MaxCover_NewMaxCover(t *testing.T) { 14 type args struct { 15 atts []*ethpb.Attestation 16 } 17 tests := []struct { 18 name string 19 args args 20 want *aggregation.MaxCoverProblem 21 }{ 22 { 23 name: "nil attestations", 24 args: args{ 25 atts: nil, 26 }, 27 want: &aggregation.MaxCoverProblem{Candidates: []*aggregation.MaxCoverCandidate{}}, 28 }, 29 { 30 name: "no attestations", 31 args: args{ 32 atts: []*ethpb.Attestation{}, 33 }, 34 want: &aggregation.MaxCoverProblem{Candidates: []*aggregation.MaxCoverCandidate{}}, 35 }, 36 { 37 name: "single attestation", 38 args: args{ 39 atts: []*ethpb.Attestation{ 40 {AggregationBits: bitfield.Bitlist{0b00001010, 0b1}}, 41 }, 42 }, 43 want: &aggregation.MaxCoverProblem{ 44 Candidates: aggregation.MaxCoverCandidates{ 45 aggregation.NewMaxCoverCandidate(0, &bitfield.Bitlist{0b00001010, 0b1}), 46 }, 47 }, 48 }, 49 { 50 name: "multiple attestations", 51 args: args{ 52 atts: []*ethpb.Attestation{ 53 {AggregationBits: bitfield.Bitlist{0b00001010, 0b1}}, 54 {AggregationBits: bitfield.Bitlist{0b00101010, 0b1}}, 55 {AggregationBits: bitfield.Bitlist{0b11111010, 0b1}}, 56 {AggregationBits: bitfield.Bitlist{0b00000010, 0b1}}, 57 {AggregationBits: bitfield.Bitlist{0b00000001, 0b1}}, 58 }, 59 }, 60 want: &aggregation.MaxCoverProblem{ 61 Candidates: aggregation.MaxCoverCandidates{ 62 aggregation.NewMaxCoverCandidate(0, &bitfield.Bitlist{0b00001010, 0b1}), 63 aggregation.NewMaxCoverCandidate(1, &bitfield.Bitlist{0b00101010, 0b1}), 64 aggregation.NewMaxCoverCandidate(2, &bitfield.Bitlist{0b11111010, 0b1}), 65 aggregation.NewMaxCoverCandidate(3, &bitfield.Bitlist{0b00000010, 0b1}), 66 aggregation.NewMaxCoverCandidate(4, &bitfield.Bitlist{0b00000001, 0b1}), 67 }, 68 }, 69 }, 70 } 71 for _, tt := range tests { 72 t.Run(tt.name, func(t *testing.T) { 73 assert.DeepEqual(t, tt.want, NewMaxCover(tt.args.atts)) 74 }) 75 } 76 } 77 78 func TestAggregateAttestations_MaxCover_AttList_validate(t *testing.T) { 79 tests := []struct { 80 name string 81 atts attList 82 wantedErr string 83 }{ 84 { 85 name: "nil list", 86 atts: nil, 87 wantedErr: "nil list", 88 }, 89 { 90 name: "empty list", 91 atts: attList{}, 92 wantedErr: "empty list", 93 }, 94 { 95 name: "first bitlist is nil", 96 atts: attList{ðpb.Attestation{}}, 97 wantedErr: "bitlist cannot be nil or empty", 98 }, 99 { 100 name: "non first bitlist is nil", 101 atts: attList{ 102 ðpb.Attestation{AggregationBits: bitfield.NewBitlist(64)}, 103 ðpb.Attestation{}, 104 }, 105 wantedErr: "bitlist cannot be nil or empty", 106 }, 107 { 108 name: "first bitlist is empty", 109 atts: attList{ 110 ðpb.Attestation{AggregationBits: bitfield.Bitlist{}}, 111 }, 112 wantedErr: "bitlist cannot be nil or empty", 113 }, 114 { 115 name: "non first bitlist is empty", 116 atts: attList{ 117 ðpb.Attestation{AggregationBits: bitfield.NewBitlist(64)}, 118 ðpb.Attestation{AggregationBits: bitfield.Bitlist{}}, 119 }, 120 wantedErr: "bitlist cannot be nil or empty", 121 }, 122 { 123 name: "valid bitlists", 124 atts: attList{ 125 ðpb.Attestation{AggregationBits: bitfield.NewBitlist(64)}, 126 ðpb.Attestation{AggregationBits: bitfield.NewBitlist(64)}, 127 ðpb.Attestation{AggregationBits: bitfield.NewBitlist(64)}, 128 ðpb.Attestation{AggregationBits: bitfield.NewBitlist(64)}, 129 }, 130 }, 131 } 132 for _, tt := range tests { 133 t.Run(tt.name, func(t *testing.T) { 134 err := tt.atts.validate() 135 if tt.wantedErr != "" { 136 assert.ErrorContains(t, tt.wantedErr, err) 137 } else { 138 assert.NoError(t, err) 139 } 140 }) 141 } 142 } 143 144 func TestAggregateAttestations_rearrangeProcessedAttestations(t *testing.T) { 145 tests := []struct { 146 name string 147 atts []*ethpb.Attestation 148 keys []int 149 wantAtts []*ethpb.Attestation 150 }{ 151 { 152 name: "nil attestations", 153 }, 154 { 155 name: "single attestation no processed keys", 156 atts: []*ethpb.Attestation{ 157 {}, 158 }, 159 wantAtts: []*ethpb.Attestation{ 160 {}, 161 }, 162 }, 163 { 164 name: "single attestation processed", 165 atts: []*ethpb.Attestation{ 166 {}, 167 }, 168 keys: []int{0}, 169 wantAtts: []*ethpb.Attestation{ 170 nil, 171 }, 172 }, 173 { 174 name: "multiple processed, last attestation marked", 175 atts: []*ethpb.Attestation{ 176 {AggregationBits: bitfield.Bitlist{0x00}}, 177 {AggregationBits: bitfield.Bitlist{0x01}}, 178 {AggregationBits: bitfield.Bitlist{0x02}}, 179 {AggregationBits: bitfield.Bitlist{0x03}}, 180 {AggregationBits: bitfield.Bitlist{0x04}}, 181 }, 182 keys: []int{1, 4}, // Only attestation at index 1, should be moved, att at 4 is already at the end. 183 wantAtts: []*ethpb.Attestation{ 184 {AggregationBits: bitfield.Bitlist{0x00}}, 185 {AggregationBits: bitfield.Bitlist{0x03}}, 186 {AggregationBits: bitfield.Bitlist{0x02}}, 187 nil, nil, 188 }, 189 }, 190 { 191 name: "all processed", 192 atts: []*ethpb.Attestation{ 193 {AggregationBits: bitfield.Bitlist{0x00}}, 194 {AggregationBits: bitfield.Bitlist{0x01}}, 195 {AggregationBits: bitfield.Bitlist{0x02}}, 196 {AggregationBits: bitfield.Bitlist{0x03}}, 197 {AggregationBits: bitfield.Bitlist{0x04}}, 198 }, 199 keys: []int{0, 1, 2, 3, 4}, 200 wantAtts: []*ethpb.Attestation{ 201 nil, nil, nil, nil, nil, 202 }, 203 }, 204 { 205 name: "operate on slice, single attestation marked", 206 atts: []*ethpb.Attestation{ 207 {AggregationBits: bitfield.Bitlist{0x00}}, 208 {AggregationBits: bitfield.Bitlist{0x01}}, 209 {AggregationBits: bitfield.Bitlist{0x02}}, 210 {AggregationBits: bitfield.Bitlist{0x03}}, 211 {AggregationBits: bitfield.Bitlist{0x04}}, 212 // Assuming some attestations have been already marked as nil, during previous rounds: 213 nil, nil, nil, 214 }, 215 keys: []int{2}, 216 wantAtts: []*ethpb.Attestation{ 217 {AggregationBits: bitfield.Bitlist{0x00}}, 218 {AggregationBits: bitfield.Bitlist{0x01}}, 219 {AggregationBits: bitfield.Bitlist{0x04}}, 220 {AggregationBits: bitfield.Bitlist{0x03}}, 221 nil, nil, nil, nil, 222 }, 223 }, 224 { 225 name: "operate on slice, non-last attestation marked", 226 atts: []*ethpb.Attestation{ 227 {AggregationBits: bitfield.Bitlist{0x00}}, 228 {AggregationBits: bitfield.Bitlist{0x01}}, 229 {AggregationBits: bitfield.Bitlist{0x02}}, 230 {AggregationBits: bitfield.Bitlist{0x03}}, 231 {AggregationBits: bitfield.Bitlist{0x04}}, 232 {AggregationBits: bitfield.Bitlist{0x05}}, 233 // Assuming some attestations have been already marked as nil, during previous rounds: 234 nil, nil, nil, 235 }, 236 keys: []int{2, 3}, 237 wantAtts: []*ethpb.Attestation{ 238 {AggregationBits: bitfield.Bitlist{0x00}}, 239 {AggregationBits: bitfield.Bitlist{0x01}}, 240 {AggregationBits: bitfield.Bitlist{0x05}}, 241 {AggregationBits: bitfield.Bitlist{0x04}}, 242 nil, nil, nil, nil, nil, 243 }, 244 }, 245 { 246 name: "operate on slice, last attestation marked", 247 atts: []*ethpb.Attestation{ 248 {AggregationBits: bitfield.Bitlist{0x00}}, 249 {AggregationBits: bitfield.Bitlist{0x01}}, 250 {AggregationBits: bitfield.Bitlist{0x02}}, 251 {AggregationBits: bitfield.Bitlist{0x03}}, 252 {AggregationBits: bitfield.Bitlist{0x04}}, 253 // Assuming some attestations have been already marked as nil, during previous rounds: 254 nil, nil, nil, 255 }, 256 keys: []int{2, 4}, 257 wantAtts: []*ethpb.Attestation{ 258 {AggregationBits: bitfield.Bitlist{0x00}}, 259 {AggregationBits: bitfield.Bitlist{0x01}}, 260 {AggregationBits: bitfield.Bitlist{0x03}}, 261 nil, nil, nil, nil, nil, 262 }, 263 }, 264 { 265 name: "many items, many selected, keys unsorted", 266 atts: []*ethpb.Attestation{ 267 {AggregationBits: bitfield.Bitlist{0x00}}, 268 {AggregationBits: bitfield.Bitlist{0x01}}, 269 {AggregationBits: bitfield.Bitlist{0x02}}, 270 {AggregationBits: bitfield.Bitlist{0x03}}, 271 {AggregationBits: bitfield.Bitlist{0x04}}, 272 {AggregationBits: bitfield.Bitlist{0x05}}, 273 {AggregationBits: bitfield.Bitlist{0x06}}, 274 }, 275 keys: []int{4, 1, 2, 5, 6}, 276 wantAtts: []*ethpb.Attestation{ 277 {AggregationBits: bitfield.Bitlist{0x00}}, 278 {AggregationBits: bitfield.Bitlist{0x03}}, 279 nil, nil, nil, nil, nil, 280 }, 281 }, 282 } 283 for _, tt := range tests { 284 t.Run(tt.name, func(t *testing.T) { 285 candidates := make([]*bitfield.Bitlist64, len(tt.atts)) 286 for i := 0; i < len(tt.atts); i++ { 287 if tt.atts[i] != nil { 288 var err error 289 candidates[i], err = tt.atts[i].AggregationBits.ToBitlist64() 290 if err != nil { 291 t.Error(err) 292 } 293 } 294 } 295 rearrangeProcessedAttestations(tt.atts, candidates, tt.keys) 296 assert.DeepEqual(t, tt.atts, tt.wantAtts) 297 }) 298 } 299 } 300 301 func TestAggregateAttestations_aggregateAttestations(t *testing.T) { 302 sign := bls.NewAggregateSignature().Marshal() 303 tests := []struct { 304 name string 305 atts []*ethpb.Attestation 306 wantAtts []*ethpb.Attestation 307 keys []int 308 coverage *bitfield.Bitlist64 309 wantTargetIdx int 310 wantErr string 311 }{ 312 { 313 name: "nil attestation", 314 wantTargetIdx: 0, 315 wantErr: ErrInvalidAttestationCount.Error(), 316 keys: []int{0, 1, 2}, 317 }, 318 { 319 name: "single attestation", 320 atts: []*ethpb.Attestation{ 321 {}, 322 }, 323 wantTargetIdx: 0, 324 wantErr: ErrInvalidAttestationCount.Error(), 325 keys: []int{0, 1, 2}, 326 }, 327 { 328 name: "no keys", 329 wantTargetIdx: 0, 330 wantErr: ErrInvalidAttestationCount.Error(), 331 }, 332 { 333 name: "two attestations, none selected", 334 atts: []*ethpb.Attestation{ 335 {AggregationBits: bitfield.Bitlist{0x00}}, 336 {AggregationBits: bitfield.Bitlist{0x01}}, 337 }, 338 wantTargetIdx: 0, 339 wantErr: ErrInvalidAttestationCount.Error(), 340 keys: []int{}, 341 }, 342 { 343 name: "two attestations, one selected", 344 atts: []*ethpb.Attestation{ 345 {AggregationBits: bitfield.Bitlist{0x00}}, 346 {AggregationBits: bitfield.Bitlist{0x01}}, 347 }, 348 wantTargetIdx: 0, 349 wantErr: ErrInvalidAttestationCount.Error(), 350 keys: []int{0}, 351 }, 352 { 353 name: "two attestations, both selected, empty coverage", 354 atts: []*ethpb.Attestation{ 355 {AggregationBits: bitfield.Bitlist{0b00000001, 0b1}, Signature: sign}, 356 {AggregationBits: bitfield.Bitlist{0b00000110, 0b1}, Signature: sign}, 357 }, 358 wantAtts: []*ethpb.Attestation{ 359 {AggregationBits: bitfield.Bitlist{0b00000111, 0b1}, Signature: sign}, 360 {AggregationBits: bitfield.Bitlist{0b00000110, 0b1}, Signature: sign}, 361 }, 362 wantTargetIdx: 0, 363 wantErr: "invalid or empty coverage", 364 keys: []int{0, 1}, 365 }, 366 { 367 name: "two attestations, both selected", 368 atts: []*ethpb.Attestation{ 369 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000001, 0b1}, Signature: sign}, 370 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000010, 0b1}, Signature: sign}, 371 }, 372 wantAtts: []*ethpb.Attestation{ 373 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000011, 0b1}, Signature: sign}, 374 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000010, 0b1}, Signature: sign}, 375 }, 376 wantTargetIdx: 0, 377 keys: []int{0, 1}, 378 coverage: func() *bitfield.Bitlist64 { 379 b, err := bitfield.NewBitlist64FromBytes(64, []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000011}) 380 if err != nil { 381 t.Fatal(err) 382 } 383 return b 384 }(), 385 }, 386 { 387 name: "many attestations, several selected", 388 atts: []*ethpb.Attestation{ 389 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000001, 0b1}, Signature: sign}, 390 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000010, 0b1}, Signature: sign}, 391 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000100, 0b1}, Signature: sign}, 392 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00001000, 0b1}, Signature: sign}, 393 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00010000, 0b1}, Signature: sign}, 394 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00100000, 0b1}, Signature: sign}, 395 }, 396 wantAtts: []*ethpb.Attestation{ 397 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000001, 0b1}, Signature: sign}, 398 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00010110, 0b1}, Signature: sign}, 399 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00000100, 0b1}, Signature: sign}, 400 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00001000, 0b1}, Signature: sign}, 401 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00010000, 0b1}, Signature: sign}, 402 {AggregationBits: bitfield.Bitlist{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00100000, 0b1}, Signature: sign}, 403 }, 404 wantTargetIdx: 1, 405 keys: []int{1, 2, 4}, 406 coverage: func() *bitfield.Bitlist64 { 407 b, err := bitfield.NewBitlist64FromBytes(64, []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0b00010110}) 408 if err != nil { 409 t.Fatal(err) 410 } 411 return b 412 }(), 413 }, 414 } 415 for _, tt := range tests { 416 t.Run(tt.name, func(t *testing.T) { 417 gotTargetIdx, err := aggregateAttestations(tt.atts, tt.keys, tt.coverage) 418 if tt.wantErr != "" { 419 assert.ErrorContains(t, tt.wantErr, err) 420 return 421 } else { 422 assert.NoError(t, err) 423 } 424 assert.Equal(t, tt.wantTargetIdx, gotTargetIdx) 425 extractBitlists := func(atts []*ethpb.Attestation) []bitfield.Bitlist { 426 bl := make([]bitfield.Bitlist, len(atts)) 427 for i, att := range atts { 428 bl[i] = att.AggregationBits 429 } 430 return bl 431 } 432 assert.DeepEqual(t, extractBitlists(tt.atts), extractBitlists(tt.wantAtts)) 433 }) 434 } 435 }