github.com/prysmaticlabs/prysm@v1.4.4/shared/attestationutil/attestation_utils_test.go (about) 1 package attestationutil_test 2 3 import ( 4 "context" 5 "testing" 6 7 types "github.com/prysmaticlabs/eth2-types" 8 "github.com/prysmaticlabs/go-bitfield" 9 eth "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 10 "github.com/prysmaticlabs/prysm/shared/attestationutil" 11 "github.com/prysmaticlabs/prysm/shared/params" 12 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 13 "github.com/prysmaticlabs/prysm/shared/testutil/require" 14 ) 15 16 func TestAttestingIndices(t *testing.T) { 17 type args struct { 18 bf bitfield.Bitfield 19 committee []types.ValidatorIndex 20 } 21 tests := []struct { 22 name string 23 args args 24 want []uint64 25 err string 26 }{ 27 { 28 name: "Full committee attested", 29 args: args{ 30 bf: bitfield.Bitlist{0b1111}, 31 committee: []types.ValidatorIndex{0, 1, 2}, 32 }, 33 want: []uint64{0, 1, 2}, 34 }, 35 { 36 name: "Partial committee attested", 37 args: args{ 38 bf: bitfield.Bitlist{0b1101}, 39 committee: []types.ValidatorIndex{0, 1, 2}, 40 }, 41 want: []uint64{0, 2}, 42 }, 43 { 44 name: "Invalid bit length", 45 args: args{ 46 bf: bitfield.Bitlist{0b11111}, 47 committee: []types.ValidatorIndex{0, 1, 2}, 48 }, 49 err: "bitfield length 4 is not equal to committee length 3", 50 }, 51 } 52 for _, tt := range tests { 53 t.Run(tt.name, func(t *testing.T) { 54 got, err := attestationutil.AttestingIndices(tt.args.bf, tt.args.committee) 55 if tt.err == "" { 56 require.NoError(t, err) 57 assert.DeepEqual(t, tt.want, got) 58 } else { 59 require.ErrorContains(t, tt.err, err) 60 } 61 }) 62 } 63 } 64 65 func TestIsValidAttestationIndices(t *testing.T) { 66 tests := []struct { 67 name string 68 att *eth.IndexedAttestation 69 wantedErr string 70 }{ 71 { 72 name: "Indices should not be nil", 73 att: ð.IndexedAttestation{ 74 Data: ð.AttestationData{ 75 Target: ð.Checkpoint{}, 76 }, 77 Signature: make([]byte, 96), 78 }, 79 wantedErr: "nil or missing indexed attestation data", 80 }, 81 { 82 name: "Indices should be non-empty", 83 att: ð.IndexedAttestation{ 84 AttestingIndices: []uint64{}, 85 Data: ð.AttestationData{ 86 Target: ð.Checkpoint{}, 87 }, 88 Signature: make([]byte, 96), 89 }, 90 wantedErr: "expected non-empty", 91 }, 92 { 93 name: "Greater than max validators per committee", 94 att: ð.IndexedAttestation{ 95 AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+1), 96 Data: ð.AttestationData{ 97 Target: ð.Checkpoint{}, 98 }, 99 Signature: make([]byte, 96), 100 }, 101 wantedErr: "indices count exceeds", 102 }, 103 { 104 name: "Needs to be sorted", 105 att: ð.IndexedAttestation{ 106 AttestingIndices: []uint64{3, 2, 1}, 107 Data: ð.AttestationData{ 108 Target: ð.Checkpoint{}, 109 }, 110 Signature: make([]byte, 96), 111 }, 112 wantedErr: "not uniquely sorted", 113 }, 114 { 115 name: "Valid indices", 116 att: ð.IndexedAttestation{ 117 AttestingIndices: []uint64{1, 2, 3}, 118 Data: ð.AttestationData{ 119 Target: ð.Checkpoint{}, 120 }, 121 Signature: make([]byte, 96), 122 }, 123 }, 124 { 125 name: "Valid indices with length of 2", 126 att: ð.IndexedAttestation{ 127 AttestingIndices: []uint64{1, 2}, 128 Data: ð.AttestationData{ 129 Target: ð.Checkpoint{}, 130 }, 131 Signature: make([]byte, 96), 132 }, 133 }, 134 { 135 name: "Valid indices with length of 1", 136 att: ð.IndexedAttestation{ 137 AttestingIndices: []uint64{1}, 138 Data: ð.AttestationData{ 139 Target: ð.Checkpoint{}, 140 }, 141 Signature: make([]byte, 96), 142 }, 143 }, 144 } 145 for _, tt := range tests { 146 t.Run(tt.name, func(t *testing.T) { 147 err := attestationutil.IsValidAttestationIndices(context.Background(), tt.att) 148 if tt.wantedErr != "" { 149 assert.ErrorContains(t, tt.wantedErr, err) 150 } else { 151 assert.NoError(t, err) 152 } 153 }) 154 } 155 } 156 157 func BenchmarkAttestingIndices_PartialCommittee(b *testing.B) { 158 bf := bitfield.Bitlist{0b11111111, 0b11111111, 0b10000111, 0b11111111, 0b100} 159 committee := []types.ValidatorIndex{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34} 160 161 b.ResetTimer() 162 for i := 0; i < b.N; i++ { 163 _, err := attestationutil.AttestingIndices(bf, committee) 164 require.NoError(b, err) 165 } 166 } 167 168 func BenchmarkIsValidAttestationIndices(b *testing.B) { 169 indices := make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee) 170 for i := 0; i < len(indices); i++ { 171 indices[i] = uint64(i) 172 } 173 att := ð.IndexedAttestation{ 174 AttestingIndices: indices, 175 Data: ð.AttestationData{ 176 Target: ð.Checkpoint{}, 177 }, 178 Signature: make([]byte, 96), 179 } 180 b.ResetTimer() 181 for i := 0; i < b.N; i++ { 182 if err := attestationutil.IsValidAttestationIndices(context.Background(), att); err != nil { 183 require.NoError(b, err) 184 } 185 } 186 } 187 188 func TestAttDataIsEqual(t *testing.T) { 189 type test struct { 190 name string 191 attData1 *eth.AttestationData 192 attData2 *eth.AttestationData 193 equal bool 194 } 195 tests := []test{ 196 { 197 name: "same", 198 attData1: ð.AttestationData{ 199 Slot: 5, 200 CommitteeIndex: 2, 201 BeaconBlockRoot: []byte("great block"), 202 Source: ð.Checkpoint{ 203 Epoch: 4, 204 Root: []byte("good source"), 205 }, 206 Target: ð.Checkpoint{ 207 Epoch: 10, 208 Root: []byte("good target"), 209 }, 210 }, 211 attData2: ð.AttestationData{ 212 Slot: 5, 213 CommitteeIndex: 2, 214 BeaconBlockRoot: []byte("great block"), 215 Source: ð.Checkpoint{ 216 Epoch: 4, 217 Root: []byte("good source"), 218 }, 219 Target: ð.Checkpoint{ 220 Epoch: 10, 221 Root: []byte("good target"), 222 }, 223 }, 224 equal: true, 225 }, 226 { 227 name: "diff slot", 228 attData1: ð.AttestationData{ 229 Slot: 5, 230 CommitteeIndex: 2, 231 BeaconBlockRoot: []byte("great block"), 232 Source: ð.Checkpoint{ 233 Epoch: 4, 234 Root: []byte("good source"), 235 }, 236 Target: ð.Checkpoint{ 237 Epoch: 10, 238 Root: []byte("good target"), 239 }, 240 }, 241 attData2: ð.AttestationData{ 242 Slot: 4, 243 CommitteeIndex: 2, 244 BeaconBlockRoot: []byte("great block"), 245 Source: ð.Checkpoint{ 246 Epoch: 4, 247 Root: []byte("good source"), 248 }, 249 Target: ð.Checkpoint{ 250 Epoch: 10, 251 Root: []byte("good target"), 252 }, 253 }, 254 }, 255 { 256 name: "diff block", 257 attData1: ð.AttestationData{ 258 Slot: 5, 259 CommitteeIndex: 2, 260 BeaconBlockRoot: []byte("good block"), 261 Source: ð.Checkpoint{ 262 Epoch: 4, 263 Root: []byte("good source"), 264 }, 265 Target: ð.Checkpoint{ 266 Epoch: 10, 267 Root: []byte("good target"), 268 }, 269 }, 270 attData2: ð.AttestationData{ 271 Slot: 5, 272 CommitteeIndex: 2, 273 BeaconBlockRoot: []byte("great block"), 274 Source: ð.Checkpoint{ 275 Epoch: 4, 276 Root: []byte("good source"), 277 }, 278 Target: ð.Checkpoint{ 279 Epoch: 10, 280 Root: []byte("good target"), 281 }, 282 }, 283 }, 284 { 285 name: "diff source root", 286 attData1: ð.AttestationData{ 287 Slot: 5, 288 CommitteeIndex: 2, 289 BeaconBlockRoot: []byte("great block"), 290 Source: ð.Checkpoint{ 291 Epoch: 4, 292 Root: []byte("good source"), 293 }, 294 Target: ð.Checkpoint{ 295 Epoch: 10, 296 Root: []byte("good target"), 297 }, 298 }, 299 attData2: ð.AttestationData{ 300 Slot: 5, 301 CommitteeIndex: 2, 302 BeaconBlockRoot: []byte("great block"), 303 Source: ð.Checkpoint{ 304 Epoch: 4, 305 Root: []byte("bad source"), 306 }, 307 Target: ð.Checkpoint{ 308 Epoch: 10, 309 Root: []byte("good target"), 310 }, 311 }, 312 }, 313 } 314 for _, tt := range tests { 315 t.Run(tt.name, func(t *testing.T) { 316 assert.Equal(t, tt.equal, attestationutil.AttDataIsEqual(tt.attData1, tt.attData2)) 317 }) 318 } 319 } 320 321 func TestCheckPtIsEqual(t *testing.T) { 322 type test struct { 323 name string 324 checkPt1 *eth.Checkpoint 325 checkPt2 *eth.Checkpoint 326 equal bool 327 } 328 tests := []test{ 329 { 330 name: "same", 331 checkPt1: ð.Checkpoint{ 332 Epoch: 4, 333 Root: []byte("good source"), 334 }, 335 checkPt2: ð.Checkpoint{ 336 Epoch: 4, 337 Root: []byte("good source"), 338 }, 339 equal: true, 340 }, 341 { 342 name: "diff epoch", 343 checkPt1: ð.Checkpoint{ 344 Epoch: 4, 345 Root: []byte("good source"), 346 }, 347 checkPt2: ð.Checkpoint{ 348 Epoch: 5, 349 Root: []byte("good source"), 350 }, 351 equal: false, 352 }, 353 { 354 name: "diff root", 355 checkPt1: ð.Checkpoint{ 356 Epoch: 4, 357 Root: []byte("good source"), 358 }, 359 checkPt2: ð.Checkpoint{ 360 Epoch: 4, 361 Root: []byte("bad source"), 362 }, 363 equal: false, 364 }, 365 } 366 for _, tt := range tests { 367 t.Run(tt.name, func(t *testing.T) { 368 assert.Equal(t, tt.equal, attestationutil.CheckPointIsEqual(tt.checkPt1, tt.checkPt2)) 369 }) 370 } 371 } 372 373 func BenchmarkAttDataIsEqual(b *testing.B) { 374 attData1 := ð.AttestationData{ 375 Slot: 5, 376 CommitteeIndex: 2, 377 BeaconBlockRoot: []byte("great block"), 378 Source: ð.Checkpoint{ 379 Epoch: 4, 380 Root: []byte("good source"), 381 }, 382 Target: ð.Checkpoint{ 383 Epoch: 10, 384 Root: []byte("good target"), 385 }, 386 } 387 attData2 := ð.AttestationData{ 388 Slot: 5, 389 CommitteeIndex: 2, 390 BeaconBlockRoot: []byte("great block"), 391 Source: ð.Checkpoint{ 392 Epoch: 4, 393 Root: []byte("good source"), 394 }, 395 Target: ð.Checkpoint{ 396 Epoch: 10, 397 Root: []byte("good target"), 398 }, 399 } 400 401 b.Run("fast", func(b *testing.B) { 402 b.ReportAllocs() 403 for i := 0; i < b.N; i++ { 404 assert.Equal(b, true, attestationutil.AttDataIsEqual(attData1, attData2)) 405 } 406 }) 407 408 b.Run("proto.Equal", func(b *testing.B) { 409 b.ReportAllocs() 410 for i := 0; i < b.N; i++ { 411 assert.Equal(b, true, attestationutil.AttDataIsEqual(attData1, attData2)) 412 } 413 }) 414 }