package sync import ( "bytes" "context" "fmt" "testing" "time" lru "github.com/hashicorp/golang-lru" pubsub "github.com/libp2p/go-libp2p-pubsub" pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/prysmaticlabs/go-bitfield" mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" "github.com/prysmaticlabs/prysm/beacon-chain/cache" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" dbtest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing" "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing" "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" ) func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) { t.Skip("Temporarily disabled, fixed in v0.12 branch.") ctx := context.Background() p := p2ptest.NewTestP2P(t) db, _ := dbtest.SetupDB(t) chain := &mockChain.ChainService{ // 1 slot ago. Genesis: time.Now().Add(time.Duration(-1*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second), ValidatorsRoot: [32]byte{'A'}, ValidAttestation: true, } c, err := lru.New(10) if err != nil { t.Fatal(err) } s := &Service{ initialSync: &mockSync.Sync{IsSyncing: false}, p2p: p, db: db, chain: chain, blkRootToPendingAtts: make(map[[32]byte][]*ethpb.SignedAggregateAttestationAndProof), seenAttestationCache: c, stateSummaryCache: cache.NewStateSummaryCache(), } digest, err := s.forkDigest() if err != nil { t.Fatal(err) } blk := ðpb.SignedBeaconBlock{ Block: ðpb.BeaconBlock{ Slot: 1, }, } if err := db.SaveBlock(ctx, blk); err != nil { t.Fatal(err) } validBlockRoot, err := stateutil.BlockRoot(blk.Block) if err != nil { t.Fatal(err) } validators := uint64(64) savedState, keys := testutil.DeterministicGenesisState(t, validators) if err := savedState.SetSlot(1); err != nil { t.Fatal(err) } if err := db.SaveState(context.Background(), savedState, validBlockRoot); err != nil { t.Fatal(err) } chain.State = savedState tests := []struct { name string msg *ethpb.Attestation topic string validAttestationSignature bool want bool }{ { name: "valid attestation signature", msg: ðpb.Attestation{ AggregationBits: bitfield.Bitlist{0b1010}, Data: ðpb.AttestationData{ BeaconBlockRoot: validBlockRoot[:], CommitteeIndex: 0, Slot: 1, Target: ðpb.Checkpoint{ Epoch: 0, Root: validBlockRoot[:], }, }, }, topic: fmt.Sprintf("/eth2/%x/beacon_attestation_1", digest), validAttestationSignature: true, want: true, }, { name: "already seen", msg: ðpb.Attestation{ AggregationBits: bitfield.Bitlist{0b1010}, Data: ðpb.AttestationData{ BeaconBlockRoot: validBlockRoot[:], CommitteeIndex: 0, Slot: 1, Target: ðpb.Checkpoint{}, }, }, topic: fmt.Sprintf("/eth2/%x/beacon_attestation_1", digest), validAttestationSignature: true, want: false, }, { name: "wrong committee index", msg: ðpb.Attestation{ AggregationBits: bitfield.Bitlist{0b1010}, Data: ðpb.AttestationData{ BeaconBlockRoot: validBlockRoot[:], CommitteeIndex: 2, Slot: 1, Target: ðpb.Checkpoint{}, }, }, topic: fmt.Sprintf("/eth2/%x/beacon_attestation_2", digest), validAttestationSignature: true, want: false, }, { name: "already aggregated", msg: ðpb.Attestation{ AggregationBits: bitfield.Bitlist{0b1011}, Data: ðpb.AttestationData{ BeaconBlockRoot: validBlockRoot[:], CommitteeIndex: 1, Slot: 1, Target: ðpb.Checkpoint{}, }, }, topic: fmt.Sprintf("/eth2/%x/beacon_attestation_1", digest), validAttestationSignature: true, want: false, }, { name: "missing block", msg: ðpb.Attestation{ AggregationBits: bitfield.Bitlist{0b1010}, Data: ðpb.AttestationData{ BeaconBlockRoot: bytesutil.PadTo([]byte("missing"), 32), CommitteeIndex: 1, Slot: 1, Target: ðpb.Checkpoint{}, }, }, topic: fmt.Sprintf("/eth2/%x/beacon_attestation_1", digest), validAttestationSignature: true, want: false, }, { name: "invalid attestation", msg: ðpb.Attestation{ AggregationBits: bitfield.Bitlist{0b1010}, Data: ðpb.AttestationData{ BeaconBlockRoot: validBlockRoot[:], CommitteeIndex: 1, Slot: 1, Target: ðpb.Checkpoint{}, }, }, topic: fmt.Sprintf("/eth2/%x/beacon_attestation_1", digest), validAttestationSignature: false, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { chain.ValidAttestation = tt.validAttestationSignature if tt.validAttestationSignature { com, err := helpers.BeaconCommitteeFromState(savedState, tt.msg.Data.Slot, tt.msg.Data.CommitteeIndex) if err != nil { t.Fatal(err) } domain, err := helpers.Domain(savedState.Fork(), tt.msg.Data.Target.Epoch, params.BeaconConfig().DomainBeaconAttester, savedState.GenesisValidatorRoot()) if err != nil { t.Fatal(err) } attRoot, err := helpers.ComputeSigningRoot(tt.msg.Data, domain) if err != nil { t.Fatal(err) } for i := 0; ; i++ { if tt.msg.AggregationBits.BitAt(uint64(i)) { tt.msg.Signature = keys[com[i]].Sign(attRoot[:]).Marshal() break } } } buf := new(bytes.Buffer) _, err := p.Encoding().EncodeGossip(buf, tt.msg) if err != nil { t.Error(err) } m := &pubsub.Message{ Message: &pubsubpb.Message{ Data: buf.Bytes(), TopicIDs: []string{tt.topic}, }, } received := s.validateCommitteeIndexBeaconAttestation(ctx, "" /*peerID*/, m) == pubsub.ValidationAccept if received != tt.want { t.Fatalf("Did not received wanted validation. Got %v, wanted %v", !tt.want, tt.want) } if tt.want && m.ValidatorData == nil { t.Error("Expected validator data to be set") } }) } }