github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/core/blocks/attestation_test.go (about) 1 package blocks_test 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 types "github.com/prysmaticlabs/eth2-types" 9 "github.com/prysmaticlabs/go-bitfield" 10 "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" 11 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 12 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 13 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 14 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 15 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" 16 "github.com/prysmaticlabs/prysm/shared/aggregation" 17 attaggregation "github.com/prysmaticlabs/prysm/shared/aggregation/attestations" 18 "github.com/prysmaticlabs/prysm/shared/attestationutil" 19 "github.com/prysmaticlabs/prysm/shared/bls" 20 "github.com/prysmaticlabs/prysm/shared/bytesutil" 21 "github.com/prysmaticlabs/prysm/shared/params" 22 "github.com/prysmaticlabs/prysm/shared/testutil" 23 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 24 "github.com/prysmaticlabs/prysm/shared/testutil/require" 25 ) 26 27 func TestProcessAttestations_InclusionDelayFailure(t *testing.T) { 28 attestations := []*ethpb.Attestation{ 29 testutil.HydrateAttestation(ðpb.Attestation{ 30 Data: ðpb.AttestationData{ 31 Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)}, 32 Slot: 5, 33 }, 34 }), 35 } 36 b := testutil.NewBeaconBlock() 37 b.Block = ðpb.BeaconBlock{ 38 Body: ðpb.BeaconBlockBody{ 39 Attestations: attestations, 40 }, 41 } 42 beaconState, _ := testutil.DeterministicGenesisState(t, 100) 43 44 want := fmt.Sprintf( 45 "attestation slot %d + inclusion delay %d > state slot %d", 46 attestations[0].Data.Slot, 47 params.BeaconConfig().MinAttestationInclusionDelay, 48 beaconState.Slot(), 49 ) 50 _, err := blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b)) 51 assert.ErrorContains(t, want, err) 52 } 53 54 func TestProcessAttestations_NeitherCurrentNorPrevEpoch(t *testing.T) { 55 att := testutil.HydrateAttestation(ðpb.Attestation{ 56 Data: ðpb.AttestationData{ 57 Source: ðpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")}, 58 Target: ðpb.Checkpoint{Epoch: 0}}}) 59 60 b := testutil.NewBeaconBlock() 61 b.Block = ðpb.BeaconBlock{ 62 Body: ðpb.BeaconBlockBody{ 63 Attestations: []*ethpb.Attestation{att}, 64 }, 65 } 66 beaconState, _ := testutil.DeterministicGenesisState(t, 100) 67 err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().SlotsPerEpoch*4 + params.BeaconConfig().MinAttestationInclusionDelay) 68 require.NoError(t, err) 69 pfc := beaconState.PreviousJustifiedCheckpoint() 70 pfc.Root = []byte("hello-world") 71 require.NoError(t, beaconState.SetPreviousJustifiedCheckpoint(pfc)) 72 require.NoError(t, beaconState.AppendPreviousEpochAttestations(&pb.PendingAttestation{})) 73 74 want := fmt.Sprintf( 75 "expected target epoch (%d) to be the previous epoch (%d) or the current epoch (%d)", 76 att.Data.Target.Epoch, 77 helpers.PrevEpoch(beaconState), 78 helpers.CurrentEpoch(beaconState), 79 ) 80 _, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b)) 81 assert.ErrorContains(t, want, err) 82 } 83 84 func TestProcessAttestations_CurrentEpochFFGDataMismatches(t *testing.T) { 85 attestations := []*ethpb.Attestation{ 86 { 87 Data: ðpb.AttestationData{ 88 Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)}, 89 Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)}, 90 }, 91 AggregationBits: bitfield.Bitlist{0x09}, 92 }, 93 } 94 b := testutil.NewBeaconBlock() 95 b.Block = ðpb.BeaconBlock{ 96 Body: ðpb.BeaconBlockBody{ 97 Attestations: attestations, 98 }, 99 } 100 beaconState, _ := testutil.DeterministicGenesisState(t, 100) 101 require.NoError(t, beaconState.SetSlot(beaconState.Slot()+params.BeaconConfig().MinAttestationInclusionDelay)) 102 cfc := beaconState.CurrentJustifiedCheckpoint() 103 cfc.Root = []byte("hello-world") 104 require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc)) 105 require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{})) 106 107 want := "source check point not equal to current justified checkpoint" 108 _, err := blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b)) 109 assert.ErrorContains(t, want, err) 110 b.Block.Body.Attestations[0].Data.Source.Epoch = helpers.CurrentEpoch(beaconState) 111 b.Block.Body.Attestations[0].Data.Source.Root = []byte{} 112 _, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b)) 113 assert.ErrorContains(t, want, err) 114 } 115 116 func TestProcessAttestations_PrevEpochFFGDataMismatches(t *testing.T) { 117 beaconState, _ := testutil.DeterministicGenesisState(t, 100) 118 119 aggBits := bitfield.NewBitlist(3) 120 aggBits.SetBitAt(0, true) 121 attestations := []*ethpb.Attestation{ 122 { 123 Data: ðpb.AttestationData{ 124 Source: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)}, 125 Target: ðpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)}, 126 Slot: params.BeaconConfig().SlotsPerEpoch, 127 }, 128 AggregationBits: aggBits, 129 }, 130 } 131 b := testutil.NewBeaconBlock() 132 b.Block = ðpb.BeaconBlock{ 133 Body: ðpb.BeaconBlockBody{ 134 Attestations: attestations, 135 }, 136 } 137 138 err := beaconState.SetSlot(beaconState.Slot() + 2*params.BeaconConfig().SlotsPerEpoch) 139 require.NoError(t, err) 140 pfc := beaconState.PreviousJustifiedCheckpoint() 141 pfc.Root = []byte("hello-world") 142 require.NoError(t, beaconState.SetPreviousJustifiedCheckpoint(pfc)) 143 require.NoError(t, beaconState.AppendPreviousEpochAttestations(&pb.PendingAttestation{})) 144 145 want := "source check point not equal to previous justified checkpoint" 146 _, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b)) 147 assert.ErrorContains(t, want, err) 148 b.Block.Body.Attestations[0].Data.Source.Epoch = helpers.PrevEpoch(beaconState) 149 b.Block.Body.Attestations[0].Data.Target.Epoch = helpers.PrevEpoch(beaconState) 150 b.Block.Body.Attestations[0].Data.Source.Root = []byte{} 151 _, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b)) 152 assert.ErrorContains(t, want, err) 153 } 154 155 func TestProcessAttestations_InvalidAggregationBitsLength(t *testing.T) { 156 beaconState, _ := testutil.DeterministicGenesisState(t, 100) 157 158 aggBits := bitfield.NewBitlist(4) 159 att := ðpb.Attestation{ 160 Data: ðpb.AttestationData{ 161 Source: ðpb.Checkpoint{Epoch: 0, Root: []byte("hello-world")}, 162 Target: ðpb.Checkpoint{Epoch: 0}}, 163 AggregationBits: aggBits, 164 } 165 166 b := testutil.NewBeaconBlock() 167 b.Block = ðpb.BeaconBlock{ 168 Body: ðpb.BeaconBlockBody{ 169 Attestations: []*ethpb.Attestation{att}, 170 }, 171 } 172 173 err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay) 174 require.NoError(t, err) 175 176 cfc := beaconState.CurrentJustifiedCheckpoint() 177 cfc.Root = []byte("hello-world") 178 require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc)) 179 require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{})) 180 181 expected := "failed to verify aggregation bitfield: wanted participants bitfield length 3, got: 4" 182 _, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(b)) 183 assert.ErrorContains(t, expected, err) 184 } 185 186 func TestProcessAttestations_OK(t *testing.T) { 187 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 188 189 aggBits := bitfield.NewBitlist(3) 190 aggBits.SetBitAt(0, true) 191 var mockRoot [32]byte 192 copy(mockRoot[:], "hello-world") 193 att := testutil.HydrateAttestation(ðpb.Attestation{ 194 Data: ðpb.AttestationData{ 195 Source: ðpb.Checkpoint{Root: mockRoot[:]}, 196 Target: ðpb.Checkpoint{Root: mockRoot[:]}, 197 }, 198 AggregationBits: aggBits, 199 }) 200 201 cfc := beaconState.CurrentJustifiedCheckpoint() 202 cfc.Root = mockRoot[:] 203 require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc)) 204 require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{})) 205 206 committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex) 207 require.NoError(t, err) 208 attestingIndices, err := attestationutil.AttestingIndices(att.AggregationBits, committee) 209 require.NoError(t, err) 210 sigs := make([]bls.Signature, len(attestingIndices)) 211 for i, indice := range attestingIndices { 212 sb, err := helpers.ComputeDomainAndSign(beaconState, 0, att.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice]) 213 require.NoError(t, err) 214 sig, err := bls.SignatureFromBytes(sb) 215 require.NoError(t, err) 216 sigs[i] = sig 217 } 218 att.Signature = bls.AggregateSignatures(sigs).Marshal() 219 220 block := testutil.NewBeaconBlock() 221 block.Block.Body.Attestations = []*ethpb.Attestation{att} 222 223 err = beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay) 224 require.NoError(t, err) 225 _, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(block)) 226 assert.NoError(t, err) 227 } 228 229 func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) { 230 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 231 data := testutil.HydrateAttestationData(ðpb.AttestationData{ 232 Source: ðpb.Checkpoint{Epoch: 0, Root: bytesutil.PadTo([]byte("hello-world"), 32)}, 233 Target: ðpb.Checkpoint{Epoch: 0, Root: bytesutil.PadTo([]byte("hello-world"), 32)}, 234 }) 235 aggBits1 := bitfield.NewBitlist(3) 236 aggBits1.SetBitAt(0, true) 237 aggBits1.SetBitAt(1, true) 238 att1 := ðpb.Attestation{ 239 Data: data, 240 AggregationBits: aggBits1, 241 } 242 243 cfc := beaconState.CurrentJustifiedCheckpoint() 244 cfc.Root = bytesutil.PadTo([]byte("hello-world"), 32) 245 require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc)) 246 require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{})) 247 248 committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex) 249 require.NoError(t, err) 250 attestingIndices1, err := attestationutil.AttestingIndices(att1.AggregationBits, committee) 251 require.NoError(t, err) 252 sigs := make([]bls.Signature, len(attestingIndices1)) 253 for i, indice := range attestingIndices1 { 254 sb, err := helpers.ComputeDomainAndSign(beaconState, 0, att1.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice]) 255 require.NoError(t, err) 256 sig, err := bls.SignatureFromBytes(sb) 257 require.NoError(t, err) 258 sigs[i] = sig 259 } 260 att1.Signature = bls.AggregateSignatures(sigs).Marshal() 261 262 aggBits2 := bitfield.NewBitlist(3) 263 aggBits2.SetBitAt(1, true) 264 aggBits2.SetBitAt(2, true) 265 att2 := ðpb.Attestation{ 266 Data: data, 267 AggregationBits: aggBits2, 268 } 269 270 committee, err = helpers.BeaconCommitteeFromState(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex) 271 require.NoError(t, err) 272 attestingIndices2, err := attestationutil.AttestingIndices(att2.AggregationBits, committee) 273 require.NoError(t, err) 274 sigs = make([]bls.Signature, len(attestingIndices2)) 275 for i, indice := range attestingIndices2 { 276 sb, err := helpers.ComputeDomainAndSign(beaconState, 0, att2.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice]) 277 require.NoError(t, err) 278 sig, err := bls.SignatureFromBytes(sb) 279 require.NoError(t, err) 280 sigs[i] = sig 281 } 282 att2.Signature = bls.AggregateSignatures(sigs).Marshal() 283 284 _, err = attaggregation.AggregatePair(att1, att2) 285 assert.ErrorContains(t, aggregation.ErrBitsOverlap.Error(), err) 286 } 287 288 func TestProcessAggregatedAttestation_NoOverlappingBits(t *testing.T) { 289 beaconState, privKeys := testutil.DeterministicGenesisState(t, 300) 290 291 var mockRoot [32]byte 292 copy(mockRoot[:], "hello-world") 293 data := testutil.HydrateAttestationData(ðpb.AttestationData{ 294 Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]}, 295 Target: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]}, 296 }) 297 aggBits1 := bitfield.NewBitlist(9) 298 aggBits1.SetBitAt(0, true) 299 aggBits1.SetBitAt(1, true) 300 att1 := ðpb.Attestation{ 301 Data: data, 302 AggregationBits: aggBits1, 303 Signature: make([]byte, 32), 304 } 305 306 cfc := beaconState.CurrentJustifiedCheckpoint() 307 cfc.Root = mockRoot[:] 308 require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(cfc)) 309 require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{})) 310 311 committee, err := helpers.BeaconCommitteeFromState(beaconState, att1.Data.Slot, att1.Data.CommitteeIndex) 312 require.NoError(t, err) 313 attestingIndices1, err := attestationutil.AttestingIndices(att1.AggregationBits, committee) 314 require.NoError(t, err) 315 sigs := make([]bls.Signature, len(attestingIndices1)) 316 for i, indice := range attestingIndices1 { 317 sb, err := helpers.ComputeDomainAndSign(beaconState, 0, data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice]) 318 require.NoError(t, err) 319 sig, err := bls.SignatureFromBytes(sb) 320 require.NoError(t, err) 321 sigs[i] = sig 322 } 323 att1.Signature = bls.AggregateSignatures(sigs).Marshal() 324 325 aggBits2 := bitfield.NewBitlist(9) 326 aggBits2.SetBitAt(2, true) 327 aggBits2.SetBitAt(3, true) 328 att2 := ðpb.Attestation{ 329 Data: data, 330 AggregationBits: aggBits2, 331 Signature: make([]byte, 32), 332 } 333 334 committee, err = helpers.BeaconCommitteeFromState(beaconState, att2.Data.Slot, att2.Data.CommitteeIndex) 335 require.NoError(t, err) 336 attestingIndices2, err := attestationutil.AttestingIndices(att2.AggregationBits, committee) 337 require.NoError(t, err) 338 sigs = make([]bls.Signature, len(attestingIndices2)) 339 for i, indice := range attestingIndices2 { 340 sb, err := helpers.ComputeDomainAndSign(beaconState, 0, att2.Data, params.BeaconConfig().DomainBeaconAttester, privKeys[indice]) 341 require.NoError(t, err) 342 sig, err := bls.SignatureFromBytes(sb) 343 require.NoError(t, err) 344 sigs[i] = sig 345 } 346 att2.Signature = bls.AggregateSignatures(sigs).Marshal() 347 348 aggregatedAtt, err := attaggregation.AggregatePair(att1, att2) 349 require.NoError(t, err) 350 block := testutil.NewBeaconBlock() 351 block.Block.Body.Attestations = []*ethpb.Attestation{aggregatedAtt} 352 353 err = beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay) 354 require.NoError(t, err) 355 356 _, err = blocks.ProcessAttestations(context.Background(), beaconState, wrapper.WrappedPhase0SignedBeaconBlock(block)) 357 assert.NoError(t, err) 358 } 359 360 func TestVerifyAttestationNoVerifySignature_IncorrectSlotTargetEpoch(t *testing.T) { 361 beaconState, _ := testutil.DeterministicGenesisState(t, 1) 362 363 att := testutil.HydrateAttestation(ðpb.Attestation{ 364 Data: ðpb.AttestationData{ 365 Slot: params.BeaconConfig().SlotsPerEpoch, 366 Target: ðpb.Checkpoint{Root: make([]byte, 32)}, 367 }, 368 }) 369 wanted := "slot 32 does not match target epoch 0" 370 err := blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att) 371 assert.ErrorContains(t, wanted, err) 372 } 373 374 func TestProcessAttestationsNoVerify_OK(t *testing.T) { 375 // Attestation with an empty signature 376 377 beaconState, _ := testutil.DeterministicGenesisState(t, 100) 378 379 aggBits := bitfield.NewBitlist(3) 380 aggBits.SetBitAt(1, true) 381 var mockRoot [32]byte 382 copy(mockRoot[:], "hello-world") 383 att := ðpb.Attestation{ 384 Data: ðpb.AttestationData{ 385 Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]}, 386 Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)}, 387 }, 388 AggregationBits: aggBits, 389 } 390 391 zeroSig := [96]byte{} 392 att.Signature = zeroSig[:] 393 394 err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay) 395 require.NoError(t, err) 396 ckp := beaconState.CurrentJustifiedCheckpoint() 397 copy(ckp.Root, "hello-world") 398 require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp)) 399 require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{})) 400 401 _, err = blocks.ProcessAttestationNoVerifySignature(context.TODO(), beaconState, att) 402 assert.NoError(t, err) 403 } 404 405 func TestVerifyAttestationNoVerifySignature_OK(t *testing.T) { 406 // Attestation with an empty signature 407 408 beaconState, _ := testutil.DeterministicGenesisState(t, 100) 409 410 aggBits := bitfield.NewBitlist(3) 411 aggBits.SetBitAt(1, true) 412 var mockRoot [32]byte 413 copy(mockRoot[:], "hello-world") 414 att := ðpb.Attestation{ 415 Data: ðpb.AttestationData{ 416 Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]}, 417 Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)}, 418 }, 419 AggregationBits: aggBits, 420 } 421 422 zeroSig := [96]byte{} 423 att.Signature = zeroSig[:] 424 425 err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay) 426 require.NoError(t, err) 427 ckp := beaconState.CurrentJustifiedCheckpoint() 428 copy(ckp.Root, "hello-world") 429 require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp)) 430 require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{})) 431 432 err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att) 433 assert.NoError(t, err) 434 } 435 436 func TestVerifyAttestationNoVerifySignature_BadAttIdx(t *testing.T) { 437 beaconState, _ := testutil.DeterministicGenesisState(t, 100) 438 aggBits := bitfield.NewBitlist(3) 439 aggBits.SetBitAt(1, true) 440 var mockRoot [32]byte 441 copy(mockRoot[:], "hello-world") 442 att := ðpb.Attestation{ 443 Data: ðpb.AttestationData{ 444 CommitteeIndex: 100, 445 Source: ðpb.Checkpoint{Epoch: 0, Root: mockRoot[:]}, 446 Target: ðpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)}, 447 }, 448 AggregationBits: aggBits, 449 } 450 zeroSig := [96]byte{} 451 att.Signature = zeroSig[:] 452 require.NoError(t, beaconState.SetSlot(beaconState.Slot()+params.BeaconConfig().MinAttestationInclusionDelay)) 453 ckp := beaconState.CurrentJustifiedCheckpoint() 454 copy(ckp.Root, "hello-world") 455 require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp)) 456 require.NoError(t, beaconState.AppendCurrentEpochAttestations(&pb.PendingAttestation{})) 457 err := blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att) 458 require.ErrorContains(t, "committee index 100 >= committee count 1", err) 459 } 460 461 func TestConvertToIndexed_OK(t *testing.T) { 462 helpers.ClearCache() 463 validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch) 464 for i := 0; i < len(validators); i++ { 465 validators[i] = ðpb.Validator{ 466 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 467 } 468 } 469 470 state, err := v1.InitializeFromProto(&pb.BeaconState{ 471 Slot: 5, 472 Validators: validators, 473 RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector), 474 }) 475 require.NoError(t, err) 476 tests := []struct { 477 aggregationBitfield bitfield.Bitlist 478 wantedAttestingIndices []uint64 479 }{ 480 { 481 aggregationBitfield: bitfield.Bitlist{0x07}, 482 wantedAttestingIndices: []uint64{43, 47}, 483 }, 484 { 485 aggregationBitfield: bitfield.Bitlist{0x05}, 486 wantedAttestingIndices: []uint64{47}, 487 }, 488 { 489 aggregationBitfield: bitfield.Bitlist{0x04}, 490 wantedAttestingIndices: []uint64{}, 491 }, 492 } 493 494 var sig [96]byte 495 copy(sig[:], "signed") 496 attestation := testutil.HydrateAttestation(ðpb.Attestation{ 497 Signature: sig[:], 498 }) 499 for _, tt := range tests { 500 attestation.AggregationBits = tt.aggregationBitfield 501 wanted := ðpb.IndexedAttestation{ 502 AttestingIndices: tt.wantedAttestingIndices, 503 Data: attestation.Data, 504 Signature: attestation.Signature, 505 } 506 507 committee, err := helpers.BeaconCommitteeFromState(state, attestation.Data.Slot, attestation.Data.CommitteeIndex) 508 require.NoError(t, err) 509 ia, err := attestationutil.ConvertToIndexed(context.Background(), attestation, committee) 510 require.NoError(t, err) 511 assert.DeepEqual(t, wanted, ia, "Convert attestation to indexed attestation didn't result as wanted") 512 } 513 } 514 515 func TestVerifyIndexedAttestation_OK(t *testing.T) { 516 numOfValidators := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(4)) 517 validators := make([]*ethpb.Validator, numOfValidators) 518 _, keys, err := testutil.DeterministicDepositsAndKeys(numOfValidators) 519 require.NoError(t, err) 520 for i := 0; i < len(validators); i++ { 521 validators[i] = ðpb.Validator{ 522 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 523 PublicKey: keys[i].PublicKey().Marshal(), 524 WithdrawalCredentials: make([]byte, 32), 525 } 526 } 527 528 state, err := v1.InitializeFromProto(&pb.BeaconState{ 529 Slot: 5, 530 Validators: validators, 531 Fork: &pb.Fork{ 532 Epoch: 0, 533 CurrentVersion: params.BeaconConfig().GenesisForkVersion, 534 PreviousVersion: params.BeaconConfig().GenesisForkVersion, 535 }, 536 RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector), 537 }) 538 require.NoError(t, err) 539 tests := []struct { 540 attestation *ethpb.IndexedAttestation 541 }{ 542 {attestation: ðpb.IndexedAttestation{ 543 Data: testutil.HydrateAttestationData(ðpb.AttestationData{ 544 Target: ðpb.Checkpoint{ 545 Epoch: 2, 546 }, 547 Source: ðpb.Checkpoint{}, 548 }), 549 AttestingIndices: []uint64{1}, 550 Signature: make([]byte, 96), 551 }}, 552 {attestation: ðpb.IndexedAttestation{ 553 Data: testutil.HydrateAttestationData(ðpb.AttestationData{ 554 Target: ðpb.Checkpoint{ 555 Epoch: 1, 556 }, 557 }), 558 AttestingIndices: []uint64{47, 99, 101}, 559 Signature: make([]byte, 96), 560 }}, 561 {attestation: ðpb.IndexedAttestation{ 562 Data: testutil.HydrateAttestationData(ðpb.AttestationData{ 563 Target: ðpb.Checkpoint{ 564 Epoch: 4, 565 }, 566 }), 567 AttestingIndices: []uint64{21, 72}, 568 Signature: make([]byte, 96), 569 }}, 570 {attestation: ðpb.IndexedAttestation{ 571 Data: testutil.HydrateAttestationData(ðpb.AttestationData{ 572 Target: ðpb.Checkpoint{ 573 Epoch: 7, 574 }, 575 }), 576 AttestingIndices: []uint64{100, 121, 122}, 577 Signature: make([]byte, 96), 578 }}, 579 } 580 581 for _, tt := range tests { 582 var sig []bls.Signature 583 for _, idx := range tt.attestation.AttestingIndices { 584 sb, err := helpers.ComputeDomainAndSign(state, tt.attestation.Data.Target.Epoch, tt.attestation.Data, params.BeaconConfig().DomainBeaconAttester, keys[idx]) 585 require.NoError(t, err) 586 validatorSig, err := bls.SignatureFromBytes(sb) 587 require.NoError(t, err) 588 sig = append(sig, validatorSig) 589 } 590 aggSig := bls.AggregateSignatures(sig) 591 marshalledSig := aggSig.Marshal() 592 593 tt.attestation.Signature = marshalledSig 594 595 err = blocks.VerifyIndexedAttestation(context.Background(), state, tt.attestation) 596 assert.NoError(t, err, "Failed to verify indexed attestation") 597 } 598 } 599 600 func TestValidateIndexedAttestation_AboveMaxLength(t *testing.T) { 601 indexedAtt1 := ðpb.IndexedAttestation{ 602 AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+5), 603 } 604 605 for i := uint64(0); i < params.BeaconConfig().MaxValidatorsPerCommittee+5; i++ { 606 indexedAtt1.AttestingIndices[i] = i 607 indexedAtt1.Data = ðpb.AttestationData{ 608 Target: ðpb.Checkpoint{ 609 Epoch: types.Epoch(i), 610 }, 611 } 612 } 613 614 want := "validator indices count exceeds MAX_VALIDATORS_PER_COMMITTEE" 615 err := blocks.VerifyIndexedAttestation(context.Background(), &v1.BeaconState{}, indexedAtt1) 616 assert.ErrorContains(t, want, err) 617 } 618 619 func TestValidateIndexedAttestation_BadAttestationsSignatureSet(t *testing.T) { 620 beaconState, keys := testutil.DeterministicGenesisState(t, 128) 621 622 sig := keys[0].Sign([]byte{'t', 'e', 's', 't'}) 623 list := bitfield.Bitlist{0b11111} 624 var atts []*ethpb.Attestation 625 for i := uint64(0); i < 1000; i++ { 626 atts = append(atts, ðpb.Attestation{ 627 Data: ðpb.AttestationData{ 628 CommitteeIndex: 1, 629 Slot: 1, 630 }, 631 Signature: sig.Marshal(), 632 AggregationBits: list, 633 }) 634 } 635 636 want := "nil or missing indexed attestation data" 637 _, err := blocks.AttestationSignatureSet(context.Background(), beaconState, atts) 638 assert.ErrorContains(t, want, err) 639 640 atts = []*ethpb.Attestation{} 641 list = bitfield.Bitlist{0b10000} 642 for i := uint64(0); i < 1000; i++ { 643 atts = append(atts, ðpb.Attestation{ 644 Data: ðpb.AttestationData{ 645 CommitteeIndex: 1, 646 Slot: 1, 647 Target: ðpb.Checkpoint{ 648 Root: []byte{}, 649 }, 650 }, 651 Signature: sig.Marshal(), 652 AggregationBits: list, 653 }) 654 } 655 656 want = "expected non-empty attesting indices" 657 _, err = blocks.AttestationSignatureSet(context.Background(), beaconState, atts) 658 assert.ErrorContains(t, want, err) 659 } 660 661 func TestVerifyAttestations_HandlesPlannedFork(t *testing.T) { 662 // In this test, att1 is from the prior fork and att2 is from the new fork. 663 numOfValidators := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(4)) 664 validators := make([]*ethpb.Validator, numOfValidators) 665 _, keys, err := testutil.DeterministicDepositsAndKeys(numOfValidators) 666 require.NoError(t, err) 667 for i := 0; i < len(validators); i++ { 668 validators[i] = ðpb.Validator{ 669 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 670 PublicKey: keys[i].PublicKey().Marshal(), 671 WithdrawalCredentials: make([]byte, 32), 672 } 673 } 674 675 st, err := testutil.NewBeaconState() 676 require.NoError(t, err) 677 require.NoError(t, st.SetSlot(35)) 678 require.NoError(t, st.SetValidators(validators)) 679 require.NoError(t, st.SetFork(&pb.Fork{ 680 Epoch: 1, 681 CurrentVersion: []byte{0, 1, 2, 3}, 682 PreviousVersion: params.BeaconConfig().GenesisForkVersion, 683 })) 684 685 comm1, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 0 /*committeeIndex*/) 686 require.NoError(t, err) 687 att1 := testutil.HydrateAttestation(ðpb.Attestation{ 688 AggregationBits: bitfield.NewBitlist(uint64(len(comm1))), 689 Data: ðpb.AttestationData{ 690 Slot: 1, 691 }, 692 }) 693 prevDomain, err := helpers.Domain(st.Fork(), st.Fork().Epoch-1, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot()) 694 require.NoError(t, err) 695 root, err := helpers.ComputeSigningRoot(att1.Data, prevDomain) 696 require.NoError(t, err) 697 var sigs []bls.Signature 698 for i, u := range comm1 { 699 att1.AggregationBits.SetBitAt(uint64(i), true) 700 sigs = append(sigs, keys[u].Sign(root[:])) 701 } 702 att1.Signature = bls.AggregateSignatures(sigs).Marshal() 703 704 comm2, err := helpers.BeaconCommitteeFromState(st, 1*params.BeaconConfig().SlotsPerEpoch+1 /*slot*/, 1 /*committeeIndex*/) 705 require.NoError(t, err) 706 att2 := testutil.HydrateAttestation(ðpb.Attestation{ 707 AggregationBits: bitfield.NewBitlist(uint64(len(comm2))), 708 Data: ðpb.AttestationData{ 709 Slot: 1*params.BeaconConfig().SlotsPerEpoch + 1, 710 CommitteeIndex: 1, 711 }, 712 }) 713 currDomain, err := helpers.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot()) 714 require.NoError(t, err) 715 root, err = helpers.ComputeSigningRoot(att2.Data, currDomain) 716 require.NoError(t, err) 717 sigs = nil 718 for i, u := range comm2 { 719 att2.AggregationBits.SetBitAt(uint64(i), true) 720 sigs = append(sigs, keys[u].Sign(root[:])) 721 } 722 att2.Signature = bls.AggregateSignatures(sigs).Marshal() 723 } 724 725 func TestRetrieveAttestationSignatureSet_VerifiesMultipleAttestations(t *testing.T) { 726 ctx := context.Background() 727 numOfValidators := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(4)) 728 validators := make([]*ethpb.Validator, numOfValidators) 729 _, keys, err := testutil.DeterministicDepositsAndKeys(numOfValidators) 730 require.NoError(t, err) 731 for i := 0; i < len(validators); i++ { 732 validators[i] = ðpb.Validator{ 733 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 734 PublicKey: keys[i].PublicKey().Marshal(), 735 WithdrawalCredentials: make([]byte, 32), 736 } 737 } 738 739 st, err := testutil.NewBeaconState() 740 require.NoError(t, err) 741 require.NoError(t, st.SetSlot(5)) 742 require.NoError(t, st.SetValidators(validators)) 743 744 comm1, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 0 /*committeeIndex*/) 745 require.NoError(t, err) 746 att1 := testutil.HydrateAttestation(ðpb.Attestation{ 747 AggregationBits: bitfield.NewBitlist(uint64(len(comm1))), 748 Data: ðpb.AttestationData{ 749 Slot: 1, 750 }, 751 }) 752 domain, err := helpers.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot()) 753 require.NoError(t, err) 754 root, err := helpers.ComputeSigningRoot(att1.Data, domain) 755 require.NoError(t, err) 756 var sigs []bls.Signature 757 for i, u := range comm1 { 758 att1.AggregationBits.SetBitAt(uint64(i), true) 759 sigs = append(sigs, keys[u].Sign(root[:])) 760 } 761 att1.Signature = bls.AggregateSignatures(sigs).Marshal() 762 763 comm2, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 1 /*committeeIndex*/) 764 require.NoError(t, err) 765 att2 := testutil.HydrateAttestation(ðpb.Attestation{ 766 AggregationBits: bitfield.NewBitlist(uint64(len(comm2))), 767 Data: ðpb.AttestationData{ 768 Slot: 1, 769 CommitteeIndex: 1, 770 }, 771 }) 772 root, err = helpers.ComputeSigningRoot(att2.Data, domain) 773 require.NoError(t, err) 774 sigs = nil 775 for i, u := range comm2 { 776 att2.AggregationBits.SetBitAt(uint64(i), true) 777 sigs = append(sigs, keys[u].Sign(root[:])) 778 } 779 att2.Signature = bls.AggregateSignatures(sigs).Marshal() 780 781 set, err := blocks.AttestationSignatureSet(ctx, st, []*ethpb.Attestation{att1, att2}) 782 require.NoError(t, err) 783 verified, err := set.Verify() 784 require.NoError(t, err) 785 assert.Equal(t, true, verified, "Multiple signatures were unable to be verified.") 786 } 787 788 func TestRetrieveAttestationSignatureSet_AcrossFork(t *testing.T) { 789 ctx := context.Background() 790 numOfValidators := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(4)) 791 validators := make([]*ethpb.Validator, numOfValidators) 792 _, keys, err := testutil.DeterministicDepositsAndKeys(numOfValidators) 793 require.NoError(t, err) 794 for i := 0; i < len(validators); i++ { 795 validators[i] = ðpb.Validator{ 796 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 797 PublicKey: keys[i].PublicKey().Marshal(), 798 WithdrawalCredentials: make([]byte, 32), 799 } 800 } 801 802 st, err := testutil.NewBeaconState() 803 require.NoError(t, err) 804 require.NoError(t, st.SetSlot(5)) 805 require.NoError(t, st.SetValidators(validators)) 806 require.NoError(t, st.SetFork(&pb.Fork{Epoch: 1, CurrentVersion: []byte{0, 1, 2, 3}, PreviousVersion: []byte{0, 1, 1, 1}})) 807 808 comm1, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 0 /*committeeIndex*/) 809 require.NoError(t, err) 810 att1 := testutil.HydrateAttestation(ðpb.Attestation{ 811 AggregationBits: bitfield.NewBitlist(uint64(len(comm1))), 812 Data: ðpb.AttestationData{ 813 Slot: 1, 814 }, 815 }) 816 domain, err := helpers.Domain(st.Fork(), st.Fork().Epoch, params.BeaconConfig().DomainBeaconAttester, st.GenesisValidatorRoot()) 817 require.NoError(t, err) 818 root, err := helpers.ComputeSigningRoot(att1.Data, domain) 819 require.NoError(t, err) 820 var sigs []bls.Signature 821 for i, u := range comm1 { 822 att1.AggregationBits.SetBitAt(uint64(i), true) 823 sigs = append(sigs, keys[u].Sign(root[:])) 824 } 825 att1.Signature = bls.AggregateSignatures(sigs).Marshal() 826 827 comm2, err := helpers.BeaconCommitteeFromState(st, 1 /*slot*/, 1 /*committeeIndex*/) 828 require.NoError(t, err) 829 att2 := testutil.HydrateAttestation(ðpb.Attestation{ 830 AggregationBits: bitfield.NewBitlist(uint64(len(comm2))), 831 Data: ðpb.AttestationData{ 832 Slot: 1, 833 CommitteeIndex: 1, 834 }, 835 }) 836 root, err = helpers.ComputeSigningRoot(att2.Data, domain) 837 require.NoError(t, err) 838 sigs = nil 839 for i, u := range comm2 { 840 att2.AggregationBits.SetBitAt(uint64(i), true) 841 sigs = append(sigs, keys[u].Sign(root[:])) 842 } 843 att2.Signature = bls.AggregateSignatures(sigs).Marshal() 844 845 _, err = blocks.AttestationSignatureSet(ctx, st, []*ethpb.Attestation{att1, att2}) 846 require.NoError(t, err) 847 }