From 62effe829fb0acca361c90b47ab8463cf05bd662 Mon Sep 17 00:00:00 2001 From: rauljordan Date: Tue, 3 Mar 2020 14:10:20 -0600 Subject: [PATCH 01/13] rem slasher proto --- proto/slashing/slashing.proto | 8 +- slasher/rpc/BUILD.bazel | 20 - slasher/rpc/server.go | 201 +--------- slasher/rpc/server_test.go | 709 ---------------------------------- 4 files changed, 6 insertions(+), 932 deletions(-) delete mode 100644 slasher/rpc/server_test.go diff --git a/proto/slashing/slashing.proto b/proto/slashing/slashing.proto index 1bf086410ea..5ffba3622b2 100644 --- a/proto/slashing/slashing.proto +++ b/proto/slashing/slashing.proto @@ -16,15 +16,9 @@ service Slasher { // was received produces a slashable event. rpc IsSlashableAttestation(ethereum.eth.v1alpha1.IndexedAttestation) returns (AttesterSlashingResponse); - // Gets ProposerSlashing container if the block header that + // Gets ProposerSlashing container if the block that // was received produces a slashable event. rpc IsSlashableBlock(ProposerSlashingRequest) returns (ProposerSlashingResponse); - - // Gets ProposerSlashingResponse container if slashing with the requested status are found in the db. - rpc ProposerSlashings(SlashingStatusRequest) returns (ProposerSlashingResponse); - - // Gets AttesterSlashingResponse container if slashing with the requested status are found in the db. - rpc AttesterSlashings(SlashingStatusRequest) returns (AttesterSlashingResponse); } // CompressedIdxAtt is an indexed attestation with the []byte data root diff --git a/slasher/rpc/BUILD.bazel b/slasher/rpc/BUILD.bazel index 83eceb73f9c..6fe090ff44e 100644 --- a/slasher/rpc/BUILD.bazel +++ b/slasher/rpc/BUILD.bazel @@ -6,30 +6,10 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/slasher/rpc", visibility = ["//visibility:public"], deps = [ - "//beacon-chain/core/helpers:go_default_library", "//proto/slashing:go_default_library", - "//shared/hashutil:go_default_library", "//slasher/db/kv:go_default_library", - "//slasher/db/types:go_default_library", - "//slasher/detection/attestations:go_default_library", - "@com_github_gogo_protobuf//proto:go_default_library", "@com_github_pkg_errors//:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", - "@com_github_sirupsen_logrus//:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = ["server_test.go"], - embed = [":go_default_library"], - deps = [ - "//proto/slashing:go_default_library", - "//shared/params:go_default_library", - "//slasher/db/testing:go_default_library", - "//slasher/db/types:go_default_library", - "@com_github_gogo_protobuf//proto:go_default_library", - "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", ], ) diff --git a/slasher/rpc/server.go b/slasher/rpc/server.go index 76604339c8c..a6b5a55b570 100644 --- a/slasher/rpc/server.go +++ b/slasher/rpc/server.go @@ -2,19 +2,11 @@ package rpc import ( "context" - "fmt" - "sync" - "github.com/gogo/protobuf/proto" "github.com/pkg/errors" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" slashpb "github.com/prysmaticlabs/prysm/proto/slashing" - "github.com/prysmaticlabs/prysm/shared/hashutil" "github.com/prysmaticlabs/prysm/slasher/db/kv" - "github.com/prysmaticlabs/prysm/slasher/db/types" - "github.com/prysmaticlabs/prysm/slasher/detection/attestations" - log "github.com/sirupsen/logrus" ) // Server defines a server implementation of the gRPC Slasher service, @@ -27,194 +19,11 @@ type Server struct { // IsSlashableAttestation returns an attester slashing if the attestation submitted // is a slashable vote. func (ss *Server) IsSlashableAttestation(ctx context.Context, req *ethpb.IndexedAttestation) (*slashpb.AttesterSlashingResponse, error) { - //TODO(#3133): add signature validation - if req.Data == nil { - return nil, fmt.Errorf("cant hash nil data in indexed attestation") - } - if err := ss.SlasherDB.SaveIndexedAttestation(ctx, req); err != nil { - return nil, err - } - indices := req.AttestingIndices - root, err := hashutil.HashProto(req.Data) - if err != nil { - return nil, err - } - attSlashingResp := &slashpb.AttesterSlashingResponse{} - attSlashings := make(chan []*ethpb.AttesterSlashing, len(indices)) - errorChans := make(chan error, len(indices)) - var wg sync.WaitGroup - lastIdx := int64(-1) - for _, idx := range indices { - if int64(idx) <= lastIdx { - return nil, fmt.Errorf("indexed attestation contains repeated or non sorted ids") - } - wg.Add(1) - go func(idx uint64, root [32]byte, req *ethpb.IndexedAttestation) { - atts, err := ss.SlasherDB.DoubleVotes(ctx, idx, root[:], req) - if err != nil { - errorChans <- err - wg.Done() - return - } - if atts != nil && len(atts) > 0 { - attSlashings <- atts - } - atts, err = ss.DetectSurroundVotes(ctx, idx, req) - if err != nil { - errorChans <- err - wg.Done() - return - } - if atts != nil && len(atts) > 0 { - attSlashings <- atts - } - wg.Done() - return - }(idx, root, req) - } - wg.Wait() - close(errorChans) - close(attSlashings) - for e := range errorChans { - if err != nil { - err = fmt.Errorf(err.Error() + " : " + e.Error()) - continue - } - err = e - } - for atts := range attSlashings { - attSlashingResp.AttesterSlashing = append(attSlashingResp.AttesterSlashing, atts...) - } - return attSlashingResp, err + return nil, errors.New("unimplemented") } -// UpdateSpanMaps updates and load all span maps from db. -func (ss *Server) UpdateSpanMaps(ctx context.Context, req *ethpb.IndexedAttestation) error { - indices := req.AttestingIndices - lastIdx := int64(-1) - var wg sync.WaitGroup - er := make(chan error, len(indices)) - for _, idx := range indices { - if int64(idx) <= lastIdx { - er <- fmt.Errorf("indexed attestation contains repeated or non sorted ids") - } - wg.Add(1) - go func(i uint64) { - spanMap, err := ss.SlasherDB.ValidatorSpansMap(ctx, i) - if err != nil { - er <- err - wg.Done() - return - } - if req.Data == nil { - log.Trace("Got indexed attestation with no data") - wg.Done() - return - } - spanMap, _, err = attestations.DetectAndUpdateSpans(ctx, spanMap, req) - if err != nil { - er <- err - wg.Done() - return - } - if err := ss.SlasherDB.SaveValidatorSpansMap(ctx, i, spanMap); err != nil { - er <- err - wg.Done() - return - } - }(idx) - wg.Wait() - } - close(er) - for e := range er { - log.Errorf("Got error while trying to update span maps: %v", e) - } - return nil -} - -// IsSlashableBlock returns a proposer slashing if the block header submitted is -// a slashable proposal. -func (ss *Server) IsSlashableBlock(ctx context.Context, psr *slashpb.ProposerSlashingRequest) (*slashpb.ProposerSlashingResponse, error) { - //TODO(#3133): add signature validation - epoch := helpers.SlotToEpoch(psr.BlockHeader.Header.Slot) - blockHeaders, err := ss.SlasherDB.BlockHeaders(ctx, epoch, psr.ValidatorIndex) - if err != nil { - return nil, errors.Wrap(err, "slasher service error while trying to retrieve blocks") - } - pSlashingsResponse := &slashpb.ProposerSlashingResponse{} - presentInDb := false - for _, bh := range blockHeaders { - if proto.Equal(bh, psr.BlockHeader) { - presentInDb = true - continue - } - pSlashingsResponse.ProposerSlashing = append(pSlashingsResponse.ProposerSlashing, ðpb.ProposerSlashing{ProposerIndex: psr.ValidatorIndex, Header_1: psr.BlockHeader, Header_2: bh}) - } - if len(pSlashingsResponse.ProposerSlashing) == 0 && !presentInDb { - err = ss.SlasherDB.SaveBlockHeader(ctx, epoch, psr.ValidatorIndex, psr.BlockHeader) - if err != nil { - return nil, err - } - } - return pSlashingsResponse, nil -} - -// ProposerSlashings returns proposer slashings if slashing with the requested status are found in the db. -func (ss *Server) ProposerSlashings(ctx context.Context, st *slashpb.SlashingStatusRequest) (*slashpb.ProposerSlashingResponse, error) { - pSlashingsResponse := &slashpb.ProposerSlashingResponse{} - var err error - pSlashingsResponse.ProposerSlashing, err = ss.SlasherDB.ProposalSlashingsByStatus(ctx, types.SlashingStatus(st.Status)) - if err != nil { - return nil, err - } - return pSlashingsResponse, nil -} - -// AttesterSlashings returns attester slashings if slashing with the requested status are found in the db. -func (ss *Server) AttesterSlashings(ctx context.Context, st *slashpb.SlashingStatusRequest) (*slashpb.AttesterSlashingResponse, error) { - aSlashingsResponse := &slashpb.AttesterSlashingResponse{} - var err error - aSlashingsResponse.AttesterSlashing, err = ss.SlasherDB.AttesterSlashings(ctx, types.SlashingStatus(st.Status)) - if err != nil { - return nil, err - } - return aSlashingsResponse, nil -} - -// DetectSurroundVotes is a method used to return the attestation that were detected -// by min max surround detection method. -func (ss *Server) DetectSurroundVotes(ctx context.Context, validatorIdx uint64, req *ethpb.IndexedAttestation) ([]*ethpb.AttesterSlashing, error) { - spanMap, err := ss.SlasherDB.ValidatorSpansMap(ctx, validatorIdx) - if err != nil { - return nil, errors.Wrap(err, "failed to get validator spans map") - } - spanMap, slashableEpoch, err := attestations.DetectAndUpdateSpans(ctx, spanMap, req) - if err != nil { - return nil, errors.Wrap(err, "failed to update spans") - } - if err := ss.SlasherDB.SaveValidatorSpansMap(ctx, validatorIdx, spanMap); err != nil { - return nil, errors.Wrap(err, "failed to save validator spans map") - } - - var as []*ethpb.AttesterSlashing - if slashableEpoch > 0 { - atts, err := ss.SlasherDB.IdxAttsForTargetFromID(ctx, slashableEpoch, validatorIdx) - if err != nil { - return nil, err - } - for _, ia := range atts { - if ia.Data == nil { - continue - } - surrounding := ia.Data.Source.Epoch < req.Data.Source.Epoch && ia.Data.Target.Epoch > req.Data.Target.Epoch - surrounded := ia.Data.Source.Epoch > req.Data.Source.Epoch && ia.Data.Target.Epoch < req.Data.Target.Epoch - if surrounding || surrounded { - as = append(as, ðpb.AttesterSlashing{ - Attestation_1: req, - Attestation_2: ia, - }) - } - } - } - return as, nil +// IsSlashableBlock returns an proposer slashing if the block submitted +// is a double proposal. +func (ss *Server) IsSlashableBlock(ctx context.Context, req *ethpb.BeaconBlock) (*slashpb.ProposerSlashingResponse, error) { + return nil, errors.New("unimplemented") } diff --git a/slasher/rpc/server_test.go b/slasher/rpc/server_test.go deleted file mode 100644 index 6cb1447acea..00000000000 --- a/slasher/rpc/server_test.go +++ /dev/null @@ -1,709 +0,0 @@ -package rpc - -import ( - "context" - "strconv" - "testing" - - "github.com/gogo/protobuf/proto" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - slashpb "github.com/prysmaticlabs/prysm/proto/slashing" - "github.com/prysmaticlabs/prysm/shared/params" - testDB "github.com/prysmaticlabs/prysm/slasher/db/testing" - "github.com/prysmaticlabs/prysm/slasher/db/types" -) - -func TestServer_IsSlashableBlock(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - SlasherDB: db, - } - psr := &slashpb.ProposerSlashingRequest{ - BlockHeader: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 1, - StateRoot: []byte("A"), - }, - }, - ValidatorIndex: 1, - } - psr2 := &slashpb.ProposerSlashingRequest{ - BlockHeader: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 1, - StateRoot: []byte("B"), - }, - }, - ValidatorIndex: 1, - } - - if _, err := slasherServer.IsSlashableBlock(ctx, psr); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableBlock(ctx, psr2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - want := ðpb.ProposerSlashing{ - ProposerIndex: psr.ValidatorIndex, - Header_1: psr2.BlockHeader, - Header_2: psr.BlockHeader, - } - - if len(sr.ProposerSlashing) != 1 { - t.Errorf("Should return 1 slashing proof: %v", sr) - } - if !proto.Equal(sr.ProposerSlashing[0], want) { - t.Errorf("wanted slashing proof: %v got: %v", want, sr.ProposerSlashing[0]) - - } - -} - -func TestServer_IsNotSlashableBlock(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - - slasherServer := &Server{ - SlasherDB: db, - } - psr := &slashpb.ProposerSlashingRequest{ - BlockHeader: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 1, - StateRoot: []byte("A"), - }, - }, - ValidatorIndex: 1, - } - psr2 := &slashpb.ProposerSlashingRequest{ - BlockHeader: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 65, - StateRoot: []byte("B"), - }, - }, - ValidatorIndex: 1, - } - ctx := context.Background() - - if _, err := slasherServer.IsSlashableBlock(ctx, psr); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableBlock(ctx, psr2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - - if len(sr.ProposerSlashing) != 0 { - t.Errorf("Should return 0 slashing proof: %v", sr) - } - -} - -func TestServer_DoubleBlock(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - psr := &slashpb.ProposerSlashingRequest{ - BlockHeader: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 1, - StateRoot: []byte("A"), - }, - }, - ValidatorIndex: 1, - } - - if _, err := slasherServer.IsSlashableBlock(ctx, psr); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableBlock(ctx, psr) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - - if len(sr.ProposerSlashing) != 0 { - t.Errorf("Should return 0 slashing proof: %v", sr) - } - -} - -func TestServer_SameSlotSlashable(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - psr := &slashpb.ProposerSlashingRequest{ - BlockHeader: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 1, - StateRoot: []byte("A"), - }, - }, - ValidatorIndex: 1, - } - psr2 := &slashpb.ProposerSlashingRequest{ - BlockHeader: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 1, - StateRoot: []byte("B"), - }, - }, - ValidatorIndex: 1, - } - want := ðpb.ProposerSlashing{ - ProposerIndex: psr.ValidatorIndex, - Header_1: psr2.BlockHeader, - Header_2: psr.BlockHeader, - } - - if _, err := slasherServer.IsSlashableBlock(ctx, psr); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableBlock(ctx, psr2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - - if len(sr.ProposerSlashing) != 1 { - t.Errorf("Should return 1 slashing proof: %v", sr) - } - if !proto.Equal(sr.ProposerSlashing[0], want) { - t.Errorf("wanted slashing proof: %v got: %v", want, sr.ProposerSlashing[0]) - - } - if err := slasherServer.SlasherDB.SaveProposerSlashing(ctx, types.Active, sr.ProposerSlashing[0]); err != nil { - t.Errorf("Could not call db method: %v", err) - } - if sr, err = slasherServer.ProposerSlashings(ctx, &slashpb.SlashingStatusRequest{Status: slashpb.SlashingStatusRequest_Active}); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - ar, err := slasherServer.AttesterSlashings(ctx, &slashpb.SlashingStatusRequest{Status: slashpb.SlashingStatusRequest_Active}) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - if len(ar.AttesterSlashing) > 0 { - t.Errorf("Attester slashings with status 'active' should not be present in testDB.") - } - emptySlashingResponse, err := slasherServer.ProposerSlashings(ctx, &slashpb.SlashingStatusRequest{Status: slashpb.SlashingStatusRequest_Included}) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - if len(emptySlashingResponse.ProposerSlashing) > 0 { - t.Error("Proposer slashings with status 'included' should not be present in db") - } - if !proto.Equal(sr.ProposerSlashing[0], want) { - t.Errorf("Wanted slashing proof: %v got: %v", want, sr.ProposerSlashing[0]) - } -} - -func TestServer_SlashDoubleAttestation(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig2"), - Data: ðpb.AttestationData{ - Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block1"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - }, - } - ia2 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig1"), - Data: ðpb.AttestationData{ - Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block2"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - }, - } - want := ðpb.AttesterSlashing{ - Attestation_1: ia2, - Attestation_2: ia1, - } - - if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableAttestation(ctx, ia2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - - if len(sr.AttesterSlashing) != 1 { - t.Errorf("Should return 1 slashing proof: %v", sr) - } - if !proto.Equal(sr.AttesterSlashing[0], want) { - t.Errorf("Wanted slashing proof: %v got: %v", want, sr.AttesterSlashing[0]) - - } -} - -func TestServer_SlashTripleAttestation(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig1"), - Data: ðpb.AttestationData{ - Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block1"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - }, - } - ia2 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig2"), - Data: ðpb.AttestationData{ - Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block2"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - }, - } - ia3 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig3"), - Data: ðpb.AttestationData{ - Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block3"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - }, - } - want1 := ðpb.AttesterSlashing{ - Attestation_1: ia3, - Attestation_2: ia1, - } - want2 := ðpb.AttesterSlashing{ - Attestation_1: ia3, - Attestation_2: ia2, - } - - if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - _, err := slasherServer.IsSlashableAttestation(ctx, ia2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableAttestation(ctx, ia3) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - if len(sr.AttesterSlashing) != 2 { - t.Errorf("Should return 1 slashing proof: %v", sr) - } - if !proto.Equal(sr.AttesterSlashing[0], want1) { - t.Errorf("Wanted slashing proof: %v got: %v", want1, sr.AttesterSlashing[0]) - - } - if !proto.Equal(sr.AttesterSlashing[1], want2) { - t.Errorf("Wanted slashing proof: %v got: %v", want2, sr.AttesterSlashing[0]) - - } -} - -func TestServer_DontSlashSameAttestation(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig1"), - Data: ðpb.AttestationData{ - Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block1"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - }, - } - - if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableAttestation(ctx, ia1) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - - if len(sr.AttesterSlashing) != 0 { - t.Errorf("Should not return slashing proof for same attestation: %v", sr) - } -} - -func TestServer_DontSlashDifferentTargetAttestation(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig2"), - Data: ðpb.AttestationData{ - Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block1"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - }, - } - ia2 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig1"), - Data: ðpb.AttestationData{ - Slot: 4*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block2"), - Source: ðpb.Checkpoint{Epoch: 3}, - Target: ðpb.Checkpoint{Epoch: 4}, - }, - } - - if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableAttestation(ctx, ia2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - - if len(sr.AttesterSlashing) != 0 { - t.Errorf("Should not return slashing proof for different epoch attestation: %v", sr) - } -} - -func TestServer_DontSlashSameAttestationData(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - ad := ðpb.AttestationData{ - Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block1"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig2"), - Data: ad, - } - ia2 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig1"), - Data: ad, - } - - if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableAttestation(ctx, ia2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - - if len(sr.AttesterSlashing) != 0 { - t.Errorf("Should not return slashing proof for same data: %v", sr) - } -} - -func TestServer_SlashSurroundedAttestation(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig2"), - Data: ðpb.AttestationData{ - Slot: 4*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block1"), - Source: ðpb.Checkpoint{Epoch: 1}, - Target: ðpb.Checkpoint{Epoch: 4}, - }, - } - ia2 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig1"), - Data: ðpb.AttestationData{ - Slot: 4*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block2"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - }, - } - want := ðpb.AttesterSlashing{ - Attestation_1: ia2, - Attestation_2: ia1, - } - - if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableAttestation(ctx, ia2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - if len(sr.AttesterSlashing) != 1 { - t.Fatalf("Should return 1 slashing proof: %v", sr.AttesterSlashing) - } - if !proto.Equal(sr.AttesterSlashing[0], want) { - t.Errorf("Wanted slashing proof: %v got: %v", want, sr.AttesterSlashing[0]) - - } -} - -func TestServer_SlashSurroundAttestation(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig2"), - Data: ðpb.AttestationData{ - Slot: 4*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block1"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 3}, - }, - } - ia2 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig1"), - Data: ðpb.AttestationData{ - Slot: 4*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block2"), - Source: ðpb.Checkpoint{Epoch: 1}, - Target: ðpb.Checkpoint{Epoch: 4}, - }, - } - want := ðpb.AttesterSlashing{ - Attestation_1: ia2, - Attestation_2: ia1, - } - - if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableAttestation(ctx, ia2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - if len(sr.AttesterSlashing) != 1 { - t.Fatalf("Should return 1 slashing proof: %v", sr.AttesterSlashing) - } - if !proto.Equal(sr.AttesterSlashing[0], want) { - t.Errorf("Wanted slashing proof: %v got: %v", want, sr.AttesterSlashing[0]) - - } - if err := slasherServer.SlasherDB.SaveAttesterSlashing(ctx, types.Active, sr.AttesterSlashing[0]); err != nil { - t.Errorf("Could not call db method: %v", err) - } - pr, err := slasherServer.ProposerSlashings(ctx, &slashpb.SlashingStatusRequest{Status: slashpb.SlashingStatusRequest_Active}) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - if len(pr.ProposerSlashing) > 0 { - t.Errorf("Attester slashings with status 'active' should not be present in testDB.") - } - if sr, err = slasherServer.AttesterSlashings(ctx, &slashpb.SlashingStatusRequest{Status: slashpb.SlashingStatusRequest_Active}); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - emptySlashingResponse, err := slasherServer.AttesterSlashings(ctx, &slashpb.SlashingStatusRequest{Status: slashpb.SlashingStatusRequest_Included}) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - if len(emptySlashingResponse.AttesterSlashing) > 0 { - t.Error("Attester slashings with status 'included' should not be present in db") - } - if !proto.Equal(sr.AttesterSlashing[0], want) { - t.Errorf("Wanted slashing proof: %v got: %v", want, sr.AttesterSlashing[0]) - } -} - -func TestServer_DontSlashValidAttestations(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig2"), - Data: ðpb.AttestationData{ - Slot: 5*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block1"), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 4}, - }, - } - ia2 := ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0}, - Signature: []byte("sig1"), - Data: ðpb.AttestationData{ - Slot: 5*params.BeaconConfig().SlotsPerEpoch + 1, - CommitteeIndex: 0, - BeaconBlockRoot: []byte("block2"), - Source: ðpb.Checkpoint{Epoch: 3}, - Target: ðpb.Checkpoint{Epoch: 5}, - }, - } - - if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - sr, err := slasherServer.IsSlashableAttestation(ctx, ia2) - if err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - if len(sr.AttesterSlashing) != 0 { - t.Errorf("Should not return slashing proof for same data: %v", sr) - } -} - -func TestServer_Store_100_Attestations(t *testing.T) { - t.Skip("undergoing slasher redesign") - db := testDB.SetupSlasherDB(t, false) - defer testDB.TeardownSlasherDB(t, db) - ctx := context.Background() - slasherServer := &Server{ - ctx: ctx, - SlasherDB: db, - } - var cb []uint64 - for i := uint64(0); i < 100; i++ { - cb = append(cb, i) - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: cb, - Data: ðpb.AttestationData{ - CommitteeIndex: 0, - BeaconBlockRoot: make([]byte, 32), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 4}, - }, - } - for i := uint64(0); i < 100; i++ { - ia1.Data.Target.Epoch = i + 1 - ia1.Data.Source.Epoch = i - t.Logf("In Loop: %d", i) - ia1.Data.Slot = (i + 1) * params.BeaconConfig().SlotsPerEpoch - root := []byte(strconv.Itoa(int(i))) - ia1.Data.BeaconBlockRoot = append(root, ia1.Data.BeaconBlockRoot[len(root):]...) - if _, err := slasherServer.IsSlashableAttestation(ctx, ia1); err != nil { - t.Errorf("Could not call RPC method: %v", err) - } - } - - s, err := db.Size() - if err != nil { - t.Error(err) - } - t.Logf("DB size is: %d", s) -} - -func BenchmarkCheckAttestations(b *testing.B) { - db := testDB.SetupSlasherDB(b, true) - defer testDB.TeardownSlasherDB(b, db) - context := context.Background() - - slasherServer := &Server{ - ctx: context, - SlasherDB: db, - } - var cb []uint64 - for i := uint64(0); i < 100; i++ { - cb = append(cb, i) - } - ia1 := ðpb.IndexedAttestation{ - AttestingIndices: cb, - Signature: make([]byte, 96), - Data: ðpb.AttestationData{ - CommitteeIndex: 0, - BeaconBlockRoot: make([]byte, 32), - Source: ðpb.Checkpoint{Epoch: 2}, - Target: ðpb.Checkpoint{Epoch: 4}, - }, - } - b.ResetTimer() - for i := uint64(0); i < uint64(b.N); i++ { - ia1.Data.Target.Epoch = i + 1 - ia1.Data.Source.Epoch = i - ia1.Data.Slot = (i + 1) * params.BeaconConfig().SlotsPerEpoch - root := []byte(strconv.Itoa(int(i))) - ia1.Data.BeaconBlockRoot = append(root, ia1.Data.BeaconBlockRoot[len(root):]...) - if _, err := slasherServer.IsSlashableAttestation(context, ia1); err != nil { - b.Errorf("Could not call RPC method: %v", err) - } - } -} From 3931e0d1f7e74859ef88fa56c8910cd77493f081 Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 12:19:17 -0500 Subject: [PATCH 02/13] verify slashing --- beacon-chain/operations/slashings/service.go | 21 ++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/beacon-chain/operations/slashings/service.go b/beacon-chain/operations/slashings/service.go index f9543e3bfd2..de0d75a1c31 100644 --- a/beacon-chain/operations/slashings/service.go +++ b/beacon-chain/operations/slashings/service.go @@ -1,11 +1,15 @@ package slashings import ( + "context" "errors" "fmt" "sort" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "go.opencensus.io/trace" + + "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" "github.com/prysmaticlabs/prysm/shared/params" @@ -23,9 +27,11 @@ func NewPool() *Pool { // PendingAttesterSlashings returns attester slashings that are able to be included into a block. // This method will not return more than the block enforced MaxAttesterSlashings. -func (p *Pool) PendingAttesterSlashings() []*ethpb.AttesterSlashing { +func (p *Pool) PendingAttesterSlashings(ctx context.Context, st *beaconstate.BeaconState) []*ethpb.AttesterSlashing { p.lock.RLock() defer p.lock.RUnlock() + ctx, span := trace.StartSpan(ctx, "operations.PendingAttesterSlashing") + defer span.End() // Update prom metric. numPendingAttesterSlashings.Set(float64(len(p.pendingAttesterSlashing))) @@ -44,7 +50,10 @@ func (p *Pool) PendingAttesterSlashings() []*ethpb.AttesterSlashing { for _, idx := range slashedVal { included[idx] = true } - pending = append(pending, attSlashing) + + if err := blocks.VerifyAttesterSlashing(ctx, st, attSlashing); err == nil { + pending = append(pending, attSlashing) + } } return pending @@ -52,9 +61,11 @@ func (p *Pool) PendingAttesterSlashings() []*ethpb.AttesterSlashing { // PendingProposerSlashings returns proposer slashings that are able to be included into a block. // This method will not return more than the block enforced MaxProposerSlashings. -func (p *Pool) PendingProposerSlashings() []*ethpb.ProposerSlashing { +func (p *Pool) PendingProposerSlashings(ctx context.Context, st *beaconstate.BeaconState) []*ethpb.ProposerSlashing { p.lock.RLock() defer p.lock.RUnlock() + ctx, span := trace.StartSpan(ctx, "operations.PendingProposerSlashing") + defer span.End() // Update prom metric. numPendingProposerSlashings.Set(float64(len(p.pendingProposerSlashing))) @@ -64,7 +75,9 @@ func (p *Pool) PendingProposerSlashings() []*ethpb.ProposerSlashing { if i >= int(params.BeaconConfig().MaxProposerSlashings) { break } - pending = append(pending, slashing) + if err := blocks.VerifyProposerSlashing(st, slashing); err == nil { + pending = append(pending, slashing) + } } return pending } From 55486a1fc70e3f1a8bae39e3e5d76b71aa01189e Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 12:43:37 -0500 Subject: [PATCH 03/13] added in test for pending att slashing --- beacon-chain/operations/slashings/BUILD.bazel | 3 + beacon-chain/operations/slashings/service.go | 6 + .../slashings/service_attester_test.go | 164 +++++++++--------- beacon-chain/rpc/validator/proposer.go | 4 +- 4 files changed, 97 insertions(+), 80 deletions(-) diff --git a/beacon-chain/operations/slashings/BUILD.bazel b/beacon-chain/operations/slashings/BUILD.bazel index bcea792ed69..c6a4c6b9be9 100644 --- a/beacon-chain/operations/slashings/BUILD.bazel +++ b/beacon-chain/operations/slashings/BUILD.bazel @@ -11,6 +11,7 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings", visibility = ["//beacon-chain:__subpackages__"], deps = [ + "//beacon-chain/core/blocks:go_default_library", "//beacon-chain/core/helpers:go_default_library", "//beacon-chain/state:go_default_library", "//shared/params:go_default_library", @@ -18,6 +19,7 @@ go_library( "@com_github_prometheus_client_golang//prometheus:go_default_library", "@com_github_prometheus_client_golang//prometheus/promauto:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", + "@io_opencensus_go//trace:go_default_library", ], ) @@ -33,6 +35,7 @@ go_test( "//beacon-chain/state:go_default_library", "//proto/beacon/p2p/v1:go_default_library", "//shared/params:go_default_library", + "//shared/testutil:go_default_library", "@com_github_gogo_protobuf//proto:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", ], diff --git a/beacon-chain/operations/slashings/service.go b/beacon-chain/operations/slashings/service.go index de0d75a1c31..071a49352dd 100644 --- a/beacon-chain/operations/slashings/service.go +++ b/beacon-chain/operations/slashings/service.go @@ -53,6 +53,9 @@ func (p *Pool) PendingAttesterSlashings(ctx context.Context, st *beaconstate.Bea if err := blocks.VerifyAttesterSlashing(ctx, st, attSlashing); err == nil { pending = append(pending, attSlashing) + } else { + // Else, we clear the attester slashing from the pool. + p.pendingAttesterSlashing = append(p.pendingAttesterSlashing[:i], p.pendingAttesterSlashing[i+1:]...) } } @@ -77,6 +80,9 @@ func (p *Pool) PendingProposerSlashings(ctx context.Context, st *beaconstate.Bea } if err := blocks.VerifyProposerSlashing(st, slashing); err == nil { pending = append(pending, slashing) + } else { + // Else, we clear the proposer slashing from the pool. + p.pendingProposerSlashing = append(p.pendingProposerSlashing[:i], p.pendingProposerSlashing[i+1:]...) } } return pending diff --git a/beacon-chain/operations/slashings/service_attester_test.go b/beacon-chain/operations/slashings/service_attester_test.go index 3ca0067afea..711487d5d97 100644 --- a/beacon-chain/operations/slashings/service_attester_test.go +++ b/beacon-chain/operations/slashings/service_attester_test.go @@ -1,6 +1,7 @@ package slashings import ( + "context" "reflect" "strings" "testing" @@ -10,6 +11,7 @@ import ( beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" p2ppb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" + "github.com/prysmaticlabs/prysm/shared/testutil" ) func attesterSlashingForValIdx(valIdx ...uint64) *ethpb.AttesterSlashing { @@ -450,6 +452,20 @@ func TestPool_PendingAttesterSlashings(t *testing.T) { type fields struct { pending []*PendingAttesterSlashing } + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + pendingSlashings := make([]*PendingAttesterSlashing, 20) + slashings := make([]*ethpb.AttesterSlashing, 20) + for i := 0; i < len(pendingSlashings); i++ { + sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + pendingSlashings[i] = &PendingAttesterSlashing{ + attesterSlashing: sl, + validatorToSlash: uint64(i), + } + slashings[i] = sl + } tests := []struct { name string fields fields @@ -465,34 +481,23 @@ func TestPool_PendingAttesterSlashings(t *testing.T) { { name: "All eligible", fields: fields{ - pending: generateNPendingSlashings(1), + pending: pendingSlashings[0:], }, - want: generateNAttSlashings(1), + want: slashings[0:], }, { name: "Multiple indices", fields: fields{ - pending: []*PendingAttesterSlashing{ - pendingSlashingForValIdx(1, 5, 8), - }, - }, - want: []*ethpb.AttesterSlashing{ - attesterSlashingForValIdx(1, 5, 8), + pending: pendingSlashings[3:6], }, + want: slashings[3:6], }, { name: "All eligible, over max", fields: fields{ - pending: generateNPendingSlashings(6), + pending: pendingSlashings, }, - want: generateNAttSlashings(1), - }, - { - name: "No duplicate slashings for grouped", - fields: fields{ - pending: generateNPendingSlashings(16), - }, - want: generateNAttSlashings(1), + want: slashings[:params.BeaconConfig().MaxAttesterSlashings], }, } for _, tt := range tests { @@ -500,70 +505,73 @@ func TestPool_PendingAttesterSlashings(t *testing.T) { p := &Pool{ pendingAttesterSlashing: tt.fields.pending, } - if got := p.PendingAttesterSlashings(); !reflect.DeepEqual(tt.want, got) { + if got := p.PendingAttesterSlashings( + context.Background(), + beaconState, + ); !reflect.DeepEqual(tt.want, got) { t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", tt.want, got) } }) } } -func TestPool_PendingAttesterSlashings_2Max(t *testing.T) { - conf := params.BeaconConfig() - conf.MaxAttesterSlashings = 2 - params.OverrideBeaconConfig(conf) - - type fields struct { - pending []*PendingAttesterSlashing - } - tests := []struct { - name string - fields fields - want []*ethpb.AttesterSlashing - }{ - { - name: "No duplicates with grouped att slashings", - fields: fields{ - pending: []*PendingAttesterSlashing{ - { - attesterSlashing: attesterSlashingForValIdx(4, 12, 40), - validatorToSlash: 4, - }, - { - attesterSlashing: attesterSlashingForValIdx(6, 8, 24), - validatorToSlash: 6, - }, - { - attesterSlashing: attesterSlashingForValIdx(6, 8, 24), - validatorToSlash: 8, - }, - { - attesterSlashing: attesterSlashingForValIdx(4, 12, 40), - validatorToSlash: 12, - }, - { - attesterSlashing: attesterSlashingForValIdx(6, 8, 24), - validatorToSlash: 24, - }, - { - attesterSlashing: attesterSlashingForValIdx(4, 12, 40), - validatorToSlash: 40, - }, - }, - }, - want: []*ethpb.AttesterSlashing{ - attesterSlashingForValIdx(4, 12, 40), - attesterSlashingForValIdx(6, 8, 24), - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - p := &Pool{ - pendingAttesterSlashing: tt.fields.pending, - } - if got := p.PendingAttesterSlashings(); !reflect.DeepEqual(tt.want, got) { - t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", tt.want, got) - } - }) - } -} +//func TestPool_PendingAttesterSlashings_2Max(t *testing.T) { +// conf := params.BeaconConfig() +// conf.MaxAttesterSlashings = 2 +// params.OverrideBeaconConfig(conf) +// +// type fields struct { +// pending []*PendingAttesterSlashing +// } +// tests := []struct { +// name string +// fields fields +// want []*ethpb.AttesterSlashing +// }{ +// { +// name: "No duplicates with grouped att slashings", +// fields: fields{ +// pending: []*PendingAttesterSlashing{ +// { +// attesterSlashing: attesterSlashingForValIdx(4, 12, 40), +// validatorToSlash: 4, +// }, +// { +// attesterSlashing: attesterSlashingForValIdx(6, 8, 24), +// validatorToSlash: 6, +// }, +// { +// attesterSlashing: attesterSlashingForValIdx(6, 8, 24), +// validatorToSlash: 8, +// }, +// { +// attesterSlashing: attesterSlashingForValIdx(4, 12, 40), +// validatorToSlash: 12, +// }, +// { +// attesterSlashing: attesterSlashingForValIdx(6, 8, 24), +// validatorToSlash: 24, +// }, +// { +// attesterSlashing: attesterSlashingForValIdx(4, 12, 40), +// validatorToSlash: 40, +// }, +// }, +// }, +// want: []*ethpb.AttesterSlashing{ +// attesterSlashingForValIdx(4, 12, 40), +// attesterSlashingForValIdx(6, 8, 24), +// }, +// }, +// } +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// p := &Pool{ +// pendingAttesterSlashing: tt.fields.pending, +// } +// if got := p.PendingAttesterSlashings(); !reflect.DeepEqual(tt.want, got) { +// t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", tt.want, got) +// } +// }) +// } +//} diff --git a/beacon-chain/rpc/validator/proposer.go b/beacon-chain/rpc/validator/proposer.go index 0bbc3f87272..6e9165e1dc3 100644 --- a/beacon-chain/rpc/validator/proposer.go +++ b/beacon-chain/rpc/validator/proposer.go @@ -89,8 +89,8 @@ func (vs *Server) GetBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb Deposits: deposits, Attestations: atts, RandaoReveal: req.RandaoReveal, - ProposerSlashings: vs.SlashingsPool.PendingProposerSlashings(), - AttesterSlashings: vs.SlashingsPool.PendingAttesterSlashings(), + ProposerSlashings: vs.SlashingsPool.PendingProposerSlashings(ctx, head), + AttesterSlashings: vs.SlashingsPool.PendingAttesterSlashings(ctx, head), VoluntaryExits: vs.ExitPool.PendingExits(head, req.Slot), Graffiti: graffiti[:], }, From 83474154e5a6a85f158da8067600bace4dadcfd7 Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 14:07:32 -0500 Subject: [PATCH 04/13] tests starting to apss --- .../slashings/service_attester_test.go | 109 +++++++----------- .../slashings/service_proposer_test.go | 90 +++++++-------- 2 files changed, 84 insertions(+), 115 deletions(-) diff --git a/beacon-chain/operations/slashings/service_attester_test.go b/beacon-chain/operations/slashings/service_attester_test.go index 711487d5d97..03b6e0dda67 100644 --- a/beacon-chain/operations/slashings/service_attester_test.go +++ b/beacon-chain/operations/slashings/service_attester_test.go @@ -481,23 +481,16 @@ func TestPool_PendingAttesterSlashings(t *testing.T) { { name: "All eligible", fields: fields{ - pending: pendingSlashings[0:], + pending: pendingSlashings, }, - want: slashings[0:], + want: slashings[0:1], }, { name: "Multiple indices", fields: fields{ pending: pendingSlashings[3:6], }, - want: slashings[3:6], - }, - { - name: "All eligible, over max", - fields: fields{ - pending: pendingSlashings, - }, - want: slashings[:params.BeaconConfig().MaxAttesterSlashings], + want: slashings[3:4], }, } for _, tt := range tests { @@ -515,63 +508,39 @@ func TestPool_PendingAttesterSlashings(t *testing.T) { } } -//func TestPool_PendingAttesterSlashings_2Max(t *testing.T) { -// conf := params.BeaconConfig() -// conf.MaxAttesterSlashings = 2 -// params.OverrideBeaconConfig(conf) -// -// type fields struct { -// pending []*PendingAttesterSlashing -// } -// tests := []struct { -// name string -// fields fields -// want []*ethpb.AttesterSlashing -// }{ -// { -// name: "No duplicates with grouped att slashings", -// fields: fields{ -// pending: []*PendingAttesterSlashing{ -// { -// attesterSlashing: attesterSlashingForValIdx(4, 12, 40), -// validatorToSlash: 4, -// }, -// { -// attesterSlashing: attesterSlashingForValIdx(6, 8, 24), -// validatorToSlash: 6, -// }, -// { -// attesterSlashing: attesterSlashingForValIdx(6, 8, 24), -// validatorToSlash: 8, -// }, -// { -// attesterSlashing: attesterSlashingForValIdx(4, 12, 40), -// validatorToSlash: 12, -// }, -// { -// attesterSlashing: attesterSlashingForValIdx(6, 8, 24), -// validatorToSlash: 24, -// }, -// { -// attesterSlashing: attesterSlashingForValIdx(4, 12, 40), -// validatorToSlash: 40, -// }, -// }, -// }, -// want: []*ethpb.AttesterSlashing{ -// attesterSlashingForValIdx(4, 12, 40), -// attesterSlashingForValIdx(6, 8, 24), -// }, -// }, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// p := &Pool{ -// pendingAttesterSlashing: tt.fields.pending, -// } -// if got := p.PendingAttesterSlashings(); !reflect.DeepEqual(tt.want, got) { -// t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", tt.want, got) -// } -// }) -// } -//} +func TestPool_PendingAttesterSlashings_NoDuplicates(t *testing.T) { + conf := params.BeaconConfig() + conf.MaxAttesterSlashings = 2 + params.OverrideBeaconConfig(conf) + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + pendingSlashings := make([]*PendingAttesterSlashing, 3) + slashings := make([]*ethpb.AttesterSlashing, 3) + for i := 0; i < 2; i++ { + sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + pendingSlashings[i] = &PendingAttesterSlashing{ + attesterSlashing: sl, + validatorToSlash: uint64(i), + } + slashings[i] = sl + } + // We duplicate the last slashing. + pendingSlashings[2] = pendingSlashings[1] + slashings[2] = slashings[1] + p := &Pool{ + pendingAttesterSlashing: pendingSlashings, + } + want := slashings[0:2] + if got := p.PendingAttesterSlashings( + context.Background(), + beaconState, + ); !reflect.DeepEqual(want, got) { + t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", want, got) + } +} + +func TestPool_PendingAttesterSlashings_SigFailsVerify_ClearPool(t *testing.T) { + +} diff --git a/beacon-chain/operations/slashings/service_proposer_test.go b/beacon-chain/operations/slashings/service_proposer_test.go index 209b3c24c59..f43d5bd6c49 100644 --- a/beacon-chain/operations/slashings/service_proposer_test.go +++ b/beacon-chain/operations/slashings/service_proposer_test.go @@ -332,48 +332,48 @@ func TestPool_MarkIncludedProposerSlashing(t *testing.T) { } } -func TestPool_PendingProposerSlashings(t *testing.T) { - type fields struct { - pending []*ethpb.ProposerSlashing - } - type args struct { - validatorToSlash uint64 - } - tests := []struct { - name string - fields fields - want []*ethpb.ProposerSlashing - }{ - { - name: "Empty list", - fields: fields{ - pending: []*ethpb.ProposerSlashing{}, - }, - want: []*ethpb.ProposerSlashing{}, - }, - { - name: "All eligible", - fields: fields{ - pending: generateNProposerSlashings(6), - }, - want: generateNProposerSlashings(6), - }, - { - name: "All eligible, more than max", - fields: fields{ - pending: generateNProposerSlashings(24), - }, - want: generateNProposerSlashings(16), - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - p := &Pool{ - pendingProposerSlashing: tt.fields.pending, - } - if got := p.PendingProposerSlashings(); !reflect.DeepEqual(got, tt.want) { - t.Errorf("PendingProposerSlashings() = %v, want %v", got, tt.want) - } - }) - } -} +//func TestPool_PendingProposerSlashings(t *testing.T) { +// type fields struct { +// pending []*ethpb.ProposerSlashing +// } +// type args struct { +// validatorToSlash uint64 +// } +// tests := []struct { +// name string +// fields fields +// want []*ethpb.ProposerSlashing +// }{ +// { +// name: "Empty list", +// fields: fields{ +// pending: []*ethpb.ProposerSlashing{}, +// }, +// want: []*ethpb.ProposerSlashing{}, +// }, +// { +// name: "All eligible", +// fields: fields{ +// pending: generateNProposerSlashings(6), +// }, +// want: generateNProposerSlashings(6), +// }, +// { +// name: "All eligible, more than max", +// fields: fields{ +// pending: generateNProposerSlashings(24), +// }, +// want: generateNProposerSlashings(16), +// }, +// } +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// p := &Pool{ +// pendingProposerSlashing: tt.fields.pending, +// } +// if got := p.PendingProposerSlashings(); !reflect.DeepEqual(got, tt.want) { +// t.Errorf("PendingProposerSlashings() = %v, want %v", got, tt.want) +// } +// }) +// } +//} From 8bdfc40450a2663a19cc31e4b246dec2a6b4778f Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 14:18:49 -0500 Subject: [PATCH 05/13] sig failed verify regression test --- .../slashings/service_attester_test.go | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/beacon-chain/operations/slashings/service_attester_test.go b/beacon-chain/operations/slashings/service_attester_test.go index 03b6e0dda67..cfacd7c545c 100644 --- a/beacon-chain/operations/slashings/service_attester_test.go +++ b/beacon-chain/operations/slashings/service_attester_test.go @@ -542,5 +542,41 @@ func TestPool_PendingAttesterSlashings_NoDuplicates(t *testing.T) { } func TestPool_PendingAttesterSlashings_SigFailsVerify_ClearPool(t *testing.T) { - + conf := params.BeaconConfig() + conf.MaxAttesterSlashings = 2 + params.OverrideBeaconConfig(conf) + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + pendingSlashings := make([]*PendingAttesterSlashing, 2) + slashings := make([]*ethpb.AttesterSlashing, 2) + for i := 0; i < 2; i++ { + sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + pendingSlashings[i] = &PendingAttesterSlashing{ + attesterSlashing: sl, + validatorToSlash: uint64(i), + } + slashings[i] = sl + } + // We mess up the signature of the second slashing. + badSig := make([]byte, 96) + copy(badSig, "muahaha") + pendingSlashings[1].attesterSlashing.Attestation_1.Signature = badSig + slashings[1].Attestation_1.Signature = badSig + p := &Pool{ + pendingAttesterSlashing: pendingSlashings, + } + // We only want a single attester slashing to remain. + want := slashings[0:1] + if got := p.PendingAttesterSlashings( + context.Background(), + beaconState, + ); !reflect.DeepEqual(want, got) { + t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", want, got) + } + // We expect to only have 1 pending attester slashing in the pool. + if len(p.pendingAttesterSlashing) != 1 { + t.Error("Expected failed attester slashing to have been cleared from pool") + } } From 7f87a9b7bda18cb1b8e809dfac4590f35118fa6f Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 14:32:26 -0500 Subject: [PATCH 06/13] tests passing for ops pool --- beacon-chain/operations/slashings/metrics.go | 12 ++ beacon-chain/operations/slashings/service.go | 2 + .../slashings/service_proposer_test.go | 135 ++++++++++++------ 3 files changed, 104 insertions(+), 45 deletions(-) diff --git a/beacon-chain/operations/slashings/metrics.go b/beacon-chain/operations/slashings/metrics.go index 1ecaea787f1..471b623e98f 100644 --- a/beacon-chain/operations/slashings/metrics.go +++ b/beacon-chain/operations/slashings/metrics.go @@ -6,6 +6,12 @@ import ( ) var ( + numPendingAttesterSlashingFailedSigVerify = promauto.NewCounter( + prometheus.CounterOpts{ + Name: "pending_attester_slashing_fail_sig_verify_total", + Help: "Times an pending attester slashing fails sig verification", + }, + ) numPendingAttesterSlashings = promauto.NewGauge( prometheus.GaugeOpts{ Name: "num_pending_attester_slashings", @@ -24,6 +30,12 @@ var ( Help: "Times an attester slashing for an already slashed validator is received", }, ) + numPendingProposerSlashingFailedSigVerify = promauto.NewCounter( + prometheus.CounterOpts{ + Name: "pending_proposer_slashing_fail_sig_verify_total", + Help: "Times an pending proposer slashing fails sig verification", + }, + ) numPendingProposerSlashings = promauto.NewGauge( prometheus.GaugeOpts{ Name: "num_pending_proposer_slashings", diff --git a/beacon-chain/operations/slashings/service.go b/beacon-chain/operations/slashings/service.go index 071a49352dd..f7aa4e914a6 100644 --- a/beacon-chain/operations/slashings/service.go +++ b/beacon-chain/operations/slashings/service.go @@ -54,6 +54,7 @@ func (p *Pool) PendingAttesterSlashings(ctx context.Context, st *beaconstate.Bea if err := blocks.VerifyAttesterSlashing(ctx, st, attSlashing); err == nil { pending = append(pending, attSlashing) } else { + numPendingAttesterSlashingFailedSigVerify.Inc() // Else, we clear the attester slashing from the pool. p.pendingAttesterSlashing = append(p.pendingAttesterSlashing[:i], p.pendingAttesterSlashing[i+1:]...) } @@ -81,6 +82,7 @@ func (p *Pool) PendingProposerSlashings(ctx context.Context, st *beaconstate.Bea if err := blocks.VerifyProposerSlashing(st, slashing); err == nil { pending = append(pending, slashing) } else { + numPendingProposerSlashingFailedSigVerify.Inc() // Else, we clear the proposer slashing from the pool. p.pendingProposerSlashing = append(p.pendingProposerSlashing[:i], p.pendingProposerSlashing[i+1:]...) } diff --git a/beacon-chain/operations/slashings/service_proposer_test.go b/beacon-chain/operations/slashings/service_proposer_test.go index f43d5bd6c49..b31f7124db7 100644 --- a/beacon-chain/operations/slashings/service_proposer_test.go +++ b/beacon-chain/operations/slashings/service_proposer_test.go @@ -1,6 +1,7 @@ package slashings import ( + "context" "reflect" "strings" "testing" @@ -10,6 +11,7 @@ import ( beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" p2ppb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" "github.com/prysmaticlabs/prysm/shared/params" + "github.com/prysmaticlabs/prysm/shared/testutil" ) func proposerSlashingForValIdx(valIdx uint64) *ethpb.ProposerSlashing { @@ -332,48 +334,91 @@ func TestPool_MarkIncludedProposerSlashing(t *testing.T) { } } -//func TestPool_PendingProposerSlashings(t *testing.T) { -// type fields struct { -// pending []*ethpb.ProposerSlashing -// } -// type args struct { -// validatorToSlash uint64 -// } -// tests := []struct { -// name string -// fields fields -// want []*ethpb.ProposerSlashing -// }{ -// { -// name: "Empty list", -// fields: fields{ -// pending: []*ethpb.ProposerSlashing{}, -// }, -// want: []*ethpb.ProposerSlashing{}, -// }, -// { -// name: "All eligible", -// fields: fields{ -// pending: generateNProposerSlashings(6), -// }, -// want: generateNProposerSlashings(6), -// }, -// { -// name: "All eligible, more than max", -// fields: fields{ -// pending: generateNProposerSlashings(24), -// }, -// want: generateNProposerSlashings(16), -// }, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// p := &Pool{ -// pendingProposerSlashing: tt.fields.pending, -// } -// if got := p.PendingProposerSlashings(); !reflect.DeepEqual(got, tt.want) { -// t.Errorf("PendingProposerSlashings() = %v, want %v", got, tt.want) -// } -// }) -// } -//} +func TestPool_PendingProposerSlashings(t *testing.T) { + type fields struct { + pending []*ethpb.ProposerSlashing + } + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + slashings := make([]*ethpb.ProposerSlashing, 20) + for i := 0; i < len(slashings); i++ { + sl, err := testutil.GenerateProposerSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + slashings[i] = sl + } + tests := []struct { + name string + fields fields + want []*ethpb.ProposerSlashing + }{ + { + name: "Empty list", + fields: fields{ + pending: []*ethpb.ProposerSlashing{}, + }, + want: []*ethpb.ProposerSlashing{}, + }, + { + name: "All eligible", + fields: fields{ + pending: slashings[:params.BeaconConfig().MaxProposerSlashings], + }, + want: slashings[:params.BeaconConfig().MaxProposerSlashings], + }, + { + name: "Multiple indices", + fields: fields{ + pending: slashings[3:6], + }, + want: slashings[3:6], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Pool{ + pendingProposerSlashing: tt.fields.pending, + } + if got := p.PendingProposerSlashings( + context.Background(), + beaconState, + ); !reflect.DeepEqual(tt.want, got) { + t.Errorf("Unexpected return from PendingProposerSlashings, wanted %v, received %v", tt.want, got) + } + }) + } +} + +func TestPool_PendingProposerSlashings_SigFailsVerify_ClearPool(t *testing.T) { + conf := params.BeaconConfig() + conf.MaxAttesterSlashings = 2 + params.OverrideBeaconConfig(conf) + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + slashings := make([]*ethpb.ProposerSlashing, 2) + for i := 0; i < 2; i++ { + sl, err := testutil.GenerateProposerSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + slashings[i] = sl + } + // We mess up the signature of the second slashing. + badSig := make([]byte, 96) + copy(badSig, "muahaha") + slashings[1].Header_1.Signature = badSig + p := &Pool{ + pendingProposerSlashing: slashings, + } + // We only want a single slashing to remain. + want := slashings[0:1] + if got := p.PendingProposerSlashings( + context.Background(), + beaconState, + ); !reflect.DeepEqual(want, got) { + t.Errorf("Unexpected return from PendingProposerSlashings, wanted %v, received %v", want, got) + } + // We expect to only have 1 pending proposer slashing in the pool. + if len(p.pendingProposerSlashing) != 1 { + t.Error("Expected failed proposer slashing to have been cleared from pool") + } +} From c287271a231594c9c57925ef3a147221f2fbd864 Mon Sep 17 00:00:00 2001 From: Raul Jordan Date: Wed, 11 Mar 2020 14:34:29 -0500 Subject: [PATCH 07/13] Update beacon-chain/operations/slashings/service.go --- beacon-chain/operations/slashings/service.go | 1 - 1 file changed, 1 deletion(-) diff --git a/beacon-chain/operations/slashings/service.go b/beacon-chain/operations/slashings/service.go index f7aa4e914a6..a635b84e4c3 100644 --- a/beacon-chain/operations/slashings/service.go +++ b/beacon-chain/operations/slashings/service.go @@ -8,7 +8,6 @@ import ( ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "go.opencensus.io/trace" - "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" From a588e8851186f4e16dbf5511dda6cb2b35ce774a Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 16:29:02 -0500 Subject: [PATCH 08/13] verify on insert --- beacon-chain/operations/slashings/service.go | 52 ++-- .../slashings/service_attester_test.go | 294 +++++++----------- .../slashings/service_proposer_test.go | 167 +++++----- 3 files changed, 234 insertions(+), 279 deletions(-) diff --git a/beacon-chain/operations/slashings/service.go b/beacon-chain/operations/slashings/service.go index a635b84e4c3..b3a011ab808 100644 --- a/beacon-chain/operations/slashings/service.go +++ b/beacon-chain/operations/slashings/service.go @@ -2,17 +2,17 @@ package slashings import ( "context" - "errors" "fmt" "sort" + "github.com/pkg/errors" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "go.opencensus.io/trace" "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/sliceutil" + "go.opencensus.io/trace" ) // NewPool returns an initialized attester slashing and proposer slashing pool. @@ -26,7 +26,7 @@ func NewPool() *Pool { // PendingAttesterSlashings returns attester slashings that are able to be included into a block. // This method will not return more than the block enforced MaxAttesterSlashings. -func (p *Pool) PendingAttesterSlashings(ctx context.Context, st *beaconstate.BeaconState) []*ethpb.AttesterSlashing { +func (p *Pool) PendingAttesterSlashings(ctx context.Context) []*ethpb.AttesterSlashing { p.lock.RLock() defer p.lock.RUnlock() ctx, span := trace.StartSpan(ctx, "operations.PendingAttesterSlashing") @@ -42,6 +42,7 @@ func (p *Pool) PendingAttesterSlashings(ctx context.Context, st *beaconstate.Bea break } if included[slashing.validatorToSlash] { + p.pendingAttesterSlashing = append(p.pendingAttesterSlashing[:i], p.pendingAttesterSlashing[i+1:]...) continue } attSlashing := slashing.attesterSlashing @@ -50,13 +51,7 @@ func (p *Pool) PendingAttesterSlashings(ctx context.Context, st *beaconstate.Bea included[idx] = true } - if err := blocks.VerifyAttesterSlashing(ctx, st, attSlashing); err == nil { - pending = append(pending, attSlashing) - } else { - numPendingAttesterSlashingFailedSigVerify.Inc() - // Else, we clear the attester slashing from the pool. - p.pendingAttesterSlashing = append(p.pendingAttesterSlashing[:i], p.pendingAttesterSlashing[i+1:]...) - } + pending = append(pending, attSlashing) } return pending @@ -64,7 +59,7 @@ func (p *Pool) PendingAttesterSlashings(ctx context.Context, st *beaconstate.Bea // PendingProposerSlashings returns proposer slashings that are able to be included into a block. // This method will not return more than the block enforced MaxProposerSlashings. -func (p *Pool) PendingProposerSlashings(ctx context.Context, st *beaconstate.BeaconState) []*ethpb.ProposerSlashing { +func (p *Pool) PendingProposerSlashings(ctx context.Context) []*ethpb.ProposerSlashing { p.lock.RLock() defer p.lock.RUnlock() ctx, span := trace.StartSpan(ctx, "operations.PendingProposerSlashing") @@ -78,22 +73,27 @@ func (p *Pool) PendingProposerSlashings(ctx context.Context, st *beaconstate.Bea if i >= int(params.BeaconConfig().MaxProposerSlashings) { break } - if err := blocks.VerifyProposerSlashing(st, slashing); err == nil { - pending = append(pending, slashing) - } else { - numPendingProposerSlashingFailedSigVerify.Inc() - // Else, we clear the proposer slashing from the pool. - p.pendingProposerSlashing = append(p.pendingProposerSlashing[:i], p.pendingProposerSlashing[i+1:]...) - } + pending = append(pending, slashing) } return pending } // InsertAttesterSlashing into the pool. This method is a no-op if the attester slashing already exists in the pool, // has been included into a block recently, or the validator is already exited. -func (p *Pool) InsertAttesterSlashing(state *beaconstate.BeaconState, slashing *ethpb.AttesterSlashing) error { +func (p *Pool) InsertAttesterSlashing( + ctx context.Context, + state *beaconstate.BeaconState, + slashing *ethpb.AttesterSlashing, +) error { p.lock.Lock() defer p.lock.Unlock() + ctx, span := trace.StartSpan(ctx, "operations.InsertAttesterSlashing") + defer span.End() + + if err := blocks.VerifyAttesterSlashing(ctx, state, slashing); err != nil { + numPendingAttesterSlashingFailedSigVerify.Inc() + return errors.Wrap(err, "could not verify attester slashing") + } slashedVal := sliceutil.IntersectionUint64(slashing.Attestation_1.AttestingIndices, slashing.Attestation_2.AttestingIndices) for _, val := range slashedVal { @@ -135,9 +135,21 @@ func (p *Pool) InsertAttesterSlashing(state *beaconstate.BeaconState, slashing * // InsertProposerSlashing into the pool. This method is a no-op if the pending slashing already exists, // has been included recently, the validator is already exited, or the validator was already slashed. -func (p *Pool) InsertProposerSlashing(state *beaconstate.BeaconState, slashing *ethpb.ProposerSlashing) error { +func (p *Pool) InsertProposerSlashing( + ctx context.Context, + state *beaconstate.BeaconState, + slashing *ethpb.ProposerSlashing, +) error { p.lock.Lock() defer p.lock.Unlock() + ctx, span := trace.StartSpan(ctx, "operations.InsertProposerSlashing") + defer span.End() + + if err := blocks.VerifyProposerSlashing(state, slashing); err != nil { + numPendingAttesterSlashingFailedSigVerify.Inc() + return errors.Wrap(err, "could not verify proposer slashing") + } + idx := slashing.ProposerIndex ok, err := p.validatorSlashingPreconditionCheck(state, idx) if err != nil { diff --git a/beacon-chain/operations/slashings/service_attester_test.go b/beacon-chain/operations/slashings/service_attester_test.go index cfacd7c545c..eac28626880 100644 --- a/beacon-chain/operations/slashings/service_attester_test.go +++ b/beacon-chain/operations/slashings/service_attester_test.go @@ -32,25 +32,6 @@ func pendingSlashingForValIdx(valIdx ...uint64) *PendingAttesterSlashing { } } -func generateNPendingSlashings(n uint64) []*PendingAttesterSlashing { - pendingAttSlashings := make([]*PendingAttesterSlashing, n) - for i := uint64(0); i < n; i++ { - pendingAttSlashings[i] = &PendingAttesterSlashing{ - attesterSlashing: attesterSlashingForValIdx(i), - validatorToSlash: i, - } - } - return pendingAttSlashings -} - -func generateNAttSlashings(n uint64) []*ethpb.AttesterSlashing { - attSlashings := make([]*ethpb.AttesterSlashing, n) - for i := uint64(0); i < n; i++ { - attSlashings[i] = attesterSlashingForValIdx(i) - } - return attSlashings -} - func TestPool_InsertAttesterSlashing(t *testing.T) { type fields struct { pending []*PendingAttesterSlashing @@ -59,8 +40,52 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { err string } type args struct { - slashing *ethpb.AttesterSlashing + slashings []*ethpb.AttesterSlashing + } + + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + pendingSlashings := make([]*PendingAttesterSlashing, 20) + slashings := make([]*ethpb.AttesterSlashing, 20) + for i := 0; i < len(pendingSlashings); i++ { + sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + pendingSlashings[i] = &PendingAttesterSlashing{ + attesterSlashing: sl, + validatorToSlash: uint64(i), + } + slashings[i] = sl + } + + // We mark the following validators with some preconditions. + validators := []*ethpb.Validator{ + { // 0 + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + }, + { // 1 + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + }, + { // 2 - Already exited. + ExitEpoch: 15, + }, + { // 3 + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + }, + { // 4 - Will be exited. + ExitEpoch: 17, + }, + { // 5 - Slashed. + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + Slashed: true, + }, + } + for i := 0; i < len(validators); i++ { + if err := beaconState.UpdateValidatorAtIndex(uint64(i), validators[i]); err != nil { + t.Fatal(err) + } } + tests := []struct { name string fields fields @@ -75,12 +100,12 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { included: make(map[uint64]bool), }, args: args{ - slashing: attesterSlashingForValIdx(1), + slashings: slashings[0:1], }, want: []*PendingAttesterSlashing{ { - attesterSlashing: attesterSlashingForValIdx(1), - validatorToSlash: 1, + attesterSlashing: slashings[0], + validatorToSlash: 0, }, }, }, @@ -91,134 +116,55 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { included: make(map[uint64]bool), }, args: args{ - slashing: ðpb.AttesterSlashing{ - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0, 1}, - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0, 1}, - }, - }, - }, - want: []*PendingAttesterSlashing{ - { - attesterSlashing: ðpb.AttesterSlashing{ - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0, 1}, - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0, 1}, - }, - }, - validatorToSlash: 0, - }, - { - attesterSlashing: ðpb.AttesterSlashing{ - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0, 1}, - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{0, 1}, - }, - }, - validatorToSlash: 1, - }, - }, - }, - { - name: "Empty list two validators slashed out of three", - fields: fields{ - pending: make([]*PendingAttesterSlashing, 0), - included: make(map[uint64]bool), - }, - args: args{ - slashing: ðpb.AttesterSlashing{ - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{1, 2, 3}, - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{1, 3}, - }, - }, - }, - want: []*PendingAttesterSlashing{ - { - attesterSlashing: ðpb.AttesterSlashing{ - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{1, 2, 3}, - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{1, 3}, - }, - }, - validatorToSlash: 1, - }, - { - attesterSlashing: ðpb.AttesterSlashing{ - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{1, 2, 3}, - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{1, 3}, - }, - }, - validatorToSlash: 3, - }, + slashings: slashings[0:2], }, + want: pendingSlashings[0:2], }, { name: "Duplicate identical slashing", fields: fields{ pending: []*PendingAttesterSlashing{ - - pendingSlashingForValIdx(1), + pendingSlashings[1], }, included: make(map[uint64]bool), }, args: args{ - slashing: attesterSlashingForValIdx(1), - }, - want: []*PendingAttesterSlashing{ - - pendingSlashingForValIdx(1), + slashings: slashings[1:2], }, + want: pendingSlashings[1:2], }, { - name: "Slashing for exited validator", + name: "Slashing for already slashed validator", fields: fields{ pending: []*PendingAttesterSlashing{}, included: make(map[uint64]bool), }, args: args{ - slashing: attesterSlashingForValIdx(2), + slashings: slashings[5:6], }, want: []*PendingAttesterSlashing{}, }, { - name: "Slashing for futuristic exited validator", + name: "Slashing for exited validator", fields: fields{ pending: []*PendingAttesterSlashing{}, included: make(map[uint64]bool), }, args: args{ - slashing: attesterSlashingForValIdx(4), - }, - want: []*PendingAttesterSlashing{ - pendingSlashingForValIdx(4), + slashings: slashings[2:3], }, + want: []*PendingAttesterSlashing{}, }, { - name: "Slashing for slashed validator", + name: "Slashing for futuristic exited validator", fields: fields{ pending: []*PendingAttesterSlashing{}, included: make(map[uint64]bool), - wantErr: true, - err: "cannot be slashed", }, args: args{ - slashing: attesterSlashingForValIdx(5), + slashings: slashings[4:5], }, - want: []*PendingAttesterSlashing{}, + want: pendingSlashings[4:5], }, { name: "Already included", @@ -229,7 +175,7 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { }, }, args: args{ - slashing: attesterSlashingForValIdx(1), + slashings: slashings[1:2], }, want: []*PendingAttesterSlashing{}, }, @@ -237,36 +183,15 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { name: "Maintains sorted order", fields: fields{ pending: []*PendingAttesterSlashing{ - pendingSlashingForValIdx(0), - pendingSlashingForValIdx(2), + pendingSlashings[0], + pendingSlashings[2], }, included: make(map[uint64]bool), }, args: args{ - slashing: attesterSlashingForValIdx(1), + slashings: slashings[1:2], }, - want: generateNPendingSlashings(3), - }, - } - validators := []*ethpb.Validator{ - { // 0 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 1 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 2 - Already exited. - ExitEpoch: 15, - }, - { // 3 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 4 - Will be exited. - ExitEpoch: 17, - }, - { // 5 - Slashed. - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - Slashed: true, + want: pendingSlashings[0:3], }, } for _, tt := range tests { @@ -282,7 +207,9 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { if err != nil { t.Fatal(err) } - err = p.InsertAttesterSlashing(s, tt.args.slashing) + for i := 0; i < len(tt.args.slashings); i++ { + err = p.InsertAttesterSlashing(context.Background(), s, tt.args.slashings[i]) + } if err != nil && tt.fields.wantErr && !strings.Contains(err.Error(), tt.fields.err) { t.Fatalf("Wanted err: %v, received %v", tt.fields.err, err) } @@ -311,6 +238,47 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { } } +func TestPool_InsertAttesterSlashing_SigFailsVerify_ClearPool(t *testing.T) { + conf := params.BeaconConfig() + conf.MaxAttesterSlashings = 2 + params.OverrideBeaconConfig(conf) + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + pendingSlashings := make([]*PendingAttesterSlashing, 2) + slashings := make([]*ethpb.AttesterSlashing, 2) + for i := 0; i < 2; i++ { + sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + pendingSlashings[i] = &PendingAttesterSlashing{ + attesterSlashing: sl, + validatorToSlash: uint64(i), + } + slashings[i] = sl + } + // We mess up the signature of the second slashing. + badSig := make([]byte, 96) + copy(badSig, "muahaha") + pendingSlashings[1].attesterSlashing.Attestation_1.Signature = badSig + slashings[1].Attestation_1.Signature = badSig + p := &Pool{ + pendingAttesterSlashing: pendingSlashings, + } + for i := 0; i < len(slashings); i++ { + if err := p.InsertAttesterSlashing( + context.Background(), + beaconState, + slashings[i], + ); err != nil { + t.Fatal(err) + } + } + // We expect to only have 1 pending attester slashing in the pool. + if len(p.pendingAttesterSlashing) != 1 { + t.Error("Expected failed attester slashing to have been cleared from pool") + } +} + func TestPool_MarkIncludedAttesterSlashing(t *testing.T) { type fields struct { pending []*PendingAttesterSlashing @@ -500,7 +468,6 @@ func TestPool_PendingAttesterSlashings(t *testing.T) { } if got := p.PendingAttesterSlashings( context.Background(), - beaconState, ); !reflect.DeepEqual(tt.want, got) { t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", tt.want, got) } @@ -535,48 +502,7 @@ func TestPool_PendingAttesterSlashings_NoDuplicates(t *testing.T) { want := slashings[0:2] if got := p.PendingAttesterSlashings( context.Background(), - beaconState, ); !reflect.DeepEqual(want, got) { t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", want, got) } } - -func TestPool_PendingAttesterSlashings_SigFailsVerify_ClearPool(t *testing.T) { - conf := params.BeaconConfig() - conf.MaxAttesterSlashings = 2 - params.OverrideBeaconConfig(conf) - beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) - pendingSlashings := make([]*PendingAttesterSlashing, 2) - slashings := make([]*ethpb.AttesterSlashing, 2) - for i := 0; i < 2; i++ { - sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) - if err != nil { - t.Fatal(err) - } - pendingSlashings[i] = &PendingAttesterSlashing{ - attesterSlashing: sl, - validatorToSlash: uint64(i), - } - slashings[i] = sl - } - // We mess up the signature of the second slashing. - badSig := make([]byte, 96) - copy(badSig, "muahaha") - pendingSlashings[1].attesterSlashing.Attestation_1.Signature = badSig - slashings[1].Attestation_1.Signature = badSig - p := &Pool{ - pendingAttesterSlashing: pendingSlashings, - } - // We only want a single attester slashing to remain. - want := slashings[0:1] - if got := p.PendingAttesterSlashings( - context.Background(), - beaconState, - ); !reflect.DeepEqual(want, got) { - t.Errorf("Unexpected return from PendingAttesterSlashings, wanted %v, received %v", want, got) - } - // We expect to only have 1 pending attester slashing in the pool. - if len(p.pendingAttesterSlashing) != 1 { - t.Error("Expected failed attester slashing to have been cleared from pool") - } -} diff --git a/beacon-chain/operations/slashings/service_proposer_test.go b/beacon-chain/operations/slashings/service_proposer_test.go index b31f7124db7..c0ee0b447ed 100644 --- a/beacon-chain/operations/slashings/service_proposer_test.go +++ b/beacon-chain/operations/slashings/service_proposer_test.go @@ -36,8 +36,47 @@ func TestPool_InsertProposerSlashing(t *testing.T) { included map[uint64]bool } type args struct { - slashing *ethpb.ProposerSlashing + slashings []*ethpb.ProposerSlashing } + + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + slashings := make([]*ethpb.ProposerSlashing, 20) + for i := 0; i < len(slashings); i++ { + sl, err := testutil.GenerateProposerSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + slashings[i] = sl + } + + // We mark the following validators with some preconditions. + validators := []*ethpb.Validator{ + { // 0 + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + }, + { // 1 + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + }, + { // 2 - Already exited. + ExitEpoch: 15, + }, + { // 3 + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + }, + { // 4 - Will be exited. + ExitEpoch: 17, + }, + { // 5 - Slashed. + ExitEpoch: params.BeaconConfig().FarFutureEpoch, + Slashed: true, + }, + } + for i := 0; i < len(validators); i++ { + if err := beaconState.UpdateValidatorAtIndex(uint64(i), validators[i]); err != nil { + t.Fatal(err) + } + } + tests := []struct { name string fields fields @@ -51,22 +90,22 @@ func TestPool_InsertProposerSlashing(t *testing.T) { included: make(map[uint64]bool), }, args: args{ - slashing: proposerSlashingForValIdx(0), + slashings: slashings[0:1], }, - want: generateNProposerSlashings(1), + want: slashings[0:1], }, { name: "Duplicate identical slashing", fields: fields{ - pending: generateNProposerSlashings(1), + pending: slashings[0:1], included: make(map[uint64]bool), wantErr: true, err: "slashing object already exists in pending proposer slashings", }, args: args{ - slashing: proposerSlashingForValIdx(0), + slashings: slashings[0:1], }, - want: generateNProposerSlashings(1), + want: slashings[0:1], }, { name: "Slashing for exited validator", @@ -77,7 +116,7 @@ func TestPool_InsertProposerSlashing(t *testing.T) { err: "cannot be slashed", }, args: args{ - slashing: proposerSlashingForValIdx(2), + slashings: slashings[2:3], }, want: []*ethpb.ProposerSlashing{}, }, @@ -88,11 +127,9 @@ func TestPool_InsertProposerSlashing(t *testing.T) { included: make(map[uint64]bool), }, args: args{ - slashing: proposerSlashingForValIdx(4), - }, - want: []*ethpb.ProposerSlashing{ - proposerSlashingForValIdx(4), + slashings: slashings[4:5], }, + want: slashings[4:5], }, { name: "Slashing for slashed validator", @@ -103,7 +140,7 @@ func TestPool_InsertProposerSlashing(t *testing.T) { err: "cannot be slashed", }, args: args{ - slashing: proposerSlashingForValIdx(5), + slashings: slashings[5:6], }, want: []*ethpb.ProposerSlashing{}, }, @@ -118,7 +155,7 @@ func TestPool_InsertProposerSlashing(t *testing.T) { err: "cannot be slashed", }, args: args{ - slashing: proposerSlashingForValIdx(1), + slashings: slashings[1:2], }, want: []*ethpb.ProposerSlashing{}, }, @@ -126,42 +163,21 @@ func TestPool_InsertProposerSlashing(t *testing.T) { name: "Maintains sorted order", fields: fields{ pending: []*ethpb.ProposerSlashing{ - proposerSlashingForValIdx(0), - proposerSlashingForValIdx(4), + slashings[0], + slashings[2], }, included: make(map[uint64]bool), }, args: args{ - slashing: proposerSlashingForValIdx(1), + slashings: slashings[1:2], }, want: []*ethpb.ProposerSlashing{ - proposerSlashingForValIdx(0), - proposerSlashingForValIdx(1), - proposerSlashingForValIdx(4), + slashings[0], + slashings[1], + slashings[2], }, }, } - validators := []*ethpb.Validator{ - { // 0 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 1 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 2 - Already exited. - ExitEpoch: 15, - }, - { // 3 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 4 - Will be exited. - ExitEpoch: 17, - }, - { // 5 - Slashed. - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - Slashed: true, - }, - } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { p := &Pool{ @@ -175,7 +191,9 @@ func TestPool_InsertProposerSlashing(t *testing.T) { if err != nil { t.Fatal(err) } - err = p.InsertProposerSlashing(beaconState, tt.args.slashing) + for i := 0; i < len(tt.args.slashings); i++ { + err = p.InsertProposerSlashing(context.Background(), beaconState, tt.args.slashings[i]) + } if err != nil && tt.fields.wantErr && !strings.Contains(err.Error(), tt.fields.err) { t.Fatalf("Wanted err: %v, received %v", tt.fields.err, err) } @@ -381,7 +399,6 @@ func TestPool_PendingProposerSlashings(t *testing.T) { } if got := p.PendingProposerSlashings( context.Background(), - beaconState, ); !reflect.DeepEqual(tt.want, got) { t.Errorf("Unexpected return from PendingProposerSlashings, wanted %v, received %v", tt.want, got) } @@ -389,36 +406,36 @@ func TestPool_PendingProposerSlashings(t *testing.T) { } } -func TestPool_PendingProposerSlashings_SigFailsVerify_ClearPool(t *testing.T) { - conf := params.BeaconConfig() - conf.MaxAttesterSlashings = 2 - params.OverrideBeaconConfig(conf) - beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) - slashings := make([]*ethpb.ProposerSlashing, 2) - for i := 0; i < 2; i++ { - sl, err := testutil.GenerateProposerSlashingForValidator(beaconState, privKeys[i], uint64(i)) - if err != nil { - t.Fatal(err) - } - slashings[i] = sl - } - // We mess up the signature of the second slashing. - badSig := make([]byte, 96) - copy(badSig, "muahaha") - slashings[1].Header_1.Signature = badSig - p := &Pool{ - pendingProposerSlashing: slashings, - } - // We only want a single slashing to remain. - want := slashings[0:1] - if got := p.PendingProposerSlashings( - context.Background(), - beaconState, - ); !reflect.DeepEqual(want, got) { - t.Errorf("Unexpected return from PendingProposerSlashings, wanted %v, received %v", want, got) - } - // We expect to only have 1 pending proposer slashing in the pool. - if len(p.pendingProposerSlashing) != 1 { - t.Error("Expected failed proposer slashing to have been cleared from pool") - } -} +//func TestPool_PendingProposerSlashings_SigFailsVerify_ClearPool(t *testing.T) { +// conf := params.BeaconConfig() +// conf.MaxAttesterSlashings = 2 +// params.OverrideBeaconConfig(conf) +// beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) +// slashings := make([]*ethpb.ProposerSlashing, 2) +// for i := 0; i < 2; i++ { +// sl, err := testutil.GenerateProposerSlashingForValidator(beaconState, privKeys[i], uint64(i)) +// if err != nil { +// t.Fatal(err) +// } +// slashings[i] = sl +// } +// // We mess up the signature of the second slashing. +// badSig := make([]byte, 96) +// copy(badSig, "muahaha") +// slashings[1].Header_1.Signature = badSig +// p := &Pool{ +// pendingProposerSlashing: slashings, +// } +// // We only want a single slashing to remain. +// want := slashings[0:1] +// if got := p.PendingProposerSlashings( +// context.Background(), +// beaconState, +// ); !reflect.DeepEqual(want, got) { +// t.Errorf("Unexpected return from PendingProposerSlashings, wanted %v, received %v", want, got) +// } +// // We expect to only have 1 pending proposer slashing in the pool. +// if len(p.pendingProposerSlashing) != 1 { +// t.Error("Expected failed proposer slashing to have been cleared from pool") +// } +//} From 71d91ce822de36081ac0b00068343a883dbca96d Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 16:51:24 -0500 Subject: [PATCH 09/13] tests starting to pass --- beacon-chain/operations/slashings/BUILD.bazel | 1 + .../slashings/service_attester_test.go | 248 +++++++++--------- .../slashings/service_proposer_test.go | 8 - 3 files changed, 119 insertions(+), 138 deletions(-) diff --git a/beacon-chain/operations/slashings/BUILD.bazel b/beacon-chain/operations/slashings/BUILD.bazel index c6a4c6b9be9..fb28cad5833 100644 --- a/beacon-chain/operations/slashings/BUILD.bazel +++ b/beacon-chain/operations/slashings/BUILD.bazel @@ -16,6 +16,7 @@ go_library( "//beacon-chain/state:go_default_library", "//shared/params:go_default_library", "//shared/sliceutil:go_default_library", + "@com_github_pkg_errors//:go_default_library", "@com_github_prometheus_client_golang//prometheus:go_default_library", "@com_github_prometheus_client_golang//prometheus/promauto:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", diff --git a/beacon-chain/operations/slashings/service_attester_test.go b/beacon-chain/operations/slashings/service_attester_test.go index eac28626880..58d6f0413b6 100644 --- a/beacon-chain/operations/slashings/service_attester_test.go +++ b/beacon-chain/operations/slashings/service_attester_test.go @@ -8,8 +8,7 @@ import ( "github.com/gogo/protobuf/proto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" - p2ppb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" ) @@ -60,25 +59,16 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { // We mark the following validators with some preconditions. validators := []*ethpb.Validator{ - { // 0 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 1 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 2 - Already exited. - ExitEpoch: 15, - }, - { // 3 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 4 - Will be exited. - ExitEpoch: 17, - }, - { // 5 - Slashed. - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - Slashed: true, - }, + //{ // 2 - Already exited. + // ExitEpoch: 15, + //}, + //{ // 4 - Will be exited. + // ExitEpoch: 17, + //}, + //{ // 5 - Slashed. + // ExitEpoch: params.BeaconConfig().FarFutureEpoch, + // Slashed: true, + //}, } for i := 0; i < len(validators); i++ { if err := beaconState.UpdateValidatorAtIndex(uint64(i), validators[i]); err != nil { @@ -133,66 +123,66 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { }, want: pendingSlashings[1:2], }, - { - name: "Slashing for already slashed validator", - fields: fields{ - pending: []*PendingAttesterSlashing{}, - included: make(map[uint64]bool), - }, - args: args{ - slashings: slashings[5:6], - }, - want: []*PendingAttesterSlashing{}, - }, - { - name: "Slashing for exited validator", - fields: fields{ - pending: []*PendingAttesterSlashing{}, - included: make(map[uint64]bool), - }, - args: args{ - slashings: slashings[2:3], - }, - want: []*PendingAttesterSlashing{}, - }, - { - name: "Slashing for futuristic exited validator", - fields: fields{ - pending: []*PendingAttesterSlashing{}, - included: make(map[uint64]bool), - }, - args: args{ - slashings: slashings[4:5], - }, - want: pendingSlashings[4:5], - }, - { - name: "Already included", - fields: fields{ - pending: []*PendingAttesterSlashing{}, - included: map[uint64]bool{ - 1: true, - }, - }, - args: args{ - slashings: slashings[1:2], - }, - want: []*PendingAttesterSlashing{}, - }, - { - name: "Maintains sorted order", - fields: fields{ - pending: []*PendingAttesterSlashing{ - pendingSlashings[0], - pendingSlashings[2], - }, - included: make(map[uint64]bool), - }, - args: args{ - slashings: slashings[1:2], - }, - want: pendingSlashings[0:3], - }, + //{ + // name: "Slashing for already slashed validator", + // fields: fields{ + // pending: []*PendingAttesterSlashing{}, + // included: make(map[uint64]bool), + // }, + // args: args{ + // slashings: slashings[5:6], + // }, + // want: []*PendingAttesterSlashing{}, + //}, + //{ + // name: "Slashing for exited validator", + // fields: fields{ + // pending: []*PendingAttesterSlashing{}, + // included: make(map[uint64]bool), + // }, + // args: args{ + // slashings: slashings[2:3], + // }, + // want: []*PendingAttesterSlashing{}, + //}, + //{ + // name: "Slashing for futuristic exited validator", + // fields: fields{ + // pending: []*PendingAttesterSlashing{}, + // included: make(map[uint64]bool), + // }, + // args: args{ + // slashings: slashings[4:5], + // }, + // want: pendingSlashings[4:5], + //}, + //{ + // name: "Already included", + // fields: fields{ + // pending: []*PendingAttesterSlashing{}, + // included: map[uint64]bool{ + // 1: true, + // }, + // }, + // args: args{ + // slashings: slashings[1:2], + // }, + // want: []*PendingAttesterSlashing{}, + //}, + //{ + // name: "Maintains sorted order", + // fields: fields{ + // pending: []*PendingAttesterSlashing{ + // pendingSlashings[0], + // pendingSlashings[2], + // }, + // included: make(map[uint64]bool), + // }, + // args: args{ + // slashings: slashings[1:2], + // }, + // want: pendingSlashings[0:3], + //}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -200,21 +190,19 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { pendingAttesterSlashing: tt.fields.pending, included: tt.fields.included, } - s, err := beaconstate.InitializeFromProtoUnsafe(&p2ppb.BeaconState{ - Slot: 16 * params.BeaconConfig().SlotsPerEpoch, - Validators: validators, - }) - if err != nil { - t.Fatal(err) - } + var err error for i := 0; i < len(tt.args.slashings); i++ { - err = p.InsertAttesterSlashing(context.Background(), s, tt.args.slashings[i]) + err = p.InsertAttesterSlashing(context.Background(), beaconState, tt.args.slashings[i]) } if err != nil && tt.fields.wantErr && !strings.Contains(err.Error(), tt.fields.err) { t.Fatalf("Wanted err: %v, received %v", tt.fields.err, err) } if len(p.pendingAttesterSlashing) != len(tt.want) { - t.Fatalf("Mismatched lengths of pending list. Got %d, wanted %d.", len(p.pendingAttesterSlashing), len(tt.want)) + t.Fatalf( + "Mismatched lengths of pending list. Got %d, wanted %d.", + len(p.pendingAttesterSlashing), + len(tt.want), + ) } for i := range p.pendingAttesterSlashing { if p.pendingAttesterSlashing[i].validatorToSlash != tt.want[i].validatorToSlash { @@ -238,46 +226,46 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { } } -func TestPool_InsertAttesterSlashing_SigFailsVerify_ClearPool(t *testing.T) { - conf := params.BeaconConfig() - conf.MaxAttesterSlashings = 2 - params.OverrideBeaconConfig(conf) - beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) - pendingSlashings := make([]*PendingAttesterSlashing, 2) - slashings := make([]*ethpb.AttesterSlashing, 2) - for i := 0; i < 2; i++ { - sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) - if err != nil { - t.Fatal(err) - } - pendingSlashings[i] = &PendingAttesterSlashing{ - attesterSlashing: sl, - validatorToSlash: uint64(i), - } - slashings[i] = sl - } - // We mess up the signature of the second slashing. - badSig := make([]byte, 96) - copy(badSig, "muahaha") - pendingSlashings[1].attesterSlashing.Attestation_1.Signature = badSig - slashings[1].Attestation_1.Signature = badSig - p := &Pool{ - pendingAttesterSlashing: pendingSlashings, - } - for i := 0; i < len(slashings); i++ { - if err := p.InsertAttesterSlashing( - context.Background(), - beaconState, - slashings[i], - ); err != nil { - t.Fatal(err) - } - } - // We expect to only have 1 pending attester slashing in the pool. - if len(p.pendingAttesterSlashing) != 1 { - t.Error("Expected failed attester slashing to have been cleared from pool") - } -} +//func TestPool_InsertAttesterSlashing_SigFailsVerify_ClearPool(t *testing.T) { +// conf := params.BeaconConfig() +// conf.MaxAttesterSlashings = 2 +// params.OverrideBeaconConfig(conf) +// beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) +// pendingSlashings := make([]*PendingAttesterSlashing, 2) +// slashings := make([]*ethpb.AttesterSlashing, 2) +// for i := 0; i < 2; i++ { +// sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) +// if err != nil { +// t.Fatal(err) +// } +// pendingSlashings[i] = &PendingAttesterSlashing{ +// attesterSlashing: sl, +// validatorToSlash: uint64(i), +// } +// slashings[i] = sl +// } +// // We mess up the signature of the second slashing. +// badSig := make([]byte, 96) +// copy(badSig, "muahaha") +// pendingSlashings[1].attesterSlashing.Attestation_1.Signature = badSig +// slashings[1].Attestation_1.Signature = badSig +// p := &Pool{ +// pendingAttesterSlashing: pendingSlashings, +// } +// for i := 0; i < len(slashings); i++ { +// if err := p.InsertAttesterSlashing( +// context.Background(), +// beaconState, +// slashings[i], +// ); err != nil { +// t.Fatal(err) +// } +// } +// // We expect to only have 1 pending attester slashing in the pool. +// if len(p.pendingAttesterSlashing) != 1 { +// t.Error("Expected failed attester slashing to have been cleared from pool") +// } +//} func TestPool_MarkIncludedAttesterSlashing(t *testing.T) { type fields struct { diff --git a/beacon-chain/operations/slashings/service_proposer_test.go b/beacon-chain/operations/slashings/service_proposer_test.go index c0ee0b447ed..15aeced8efe 100644 --- a/beacon-chain/operations/slashings/service_proposer_test.go +++ b/beacon-chain/operations/slashings/service_proposer_test.go @@ -20,14 +20,6 @@ func proposerSlashingForValIdx(valIdx uint64) *ethpb.ProposerSlashing { } } -func generateNProposerSlashings(n uint64) []*ethpb.ProposerSlashing { - proposerSlashings := make([]*ethpb.ProposerSlashing, n) - for i := uint64(0); i < n; i++ { - proposerSlashings[i] = proposerSlashingForValIdx(i) - } - return proposerSlashings -} - func TestPool_InsertProposerSlashing(t *testing.T) { type fields struct { wantErr bool From 424711178c37e54700d6abd5dd573a97cc5470b5 Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 17:11:17 -0500 Subject: [PATCH 10/13] all code paths fixed --- beacon-chain/operations/slashings/BUILD.bazel | 3 +- .../slashings/service_attester_test.go | 241 +++++++++--------- .../slashings/service_proposer_test.go | 130 +++++----- beacon-chain/rpc/beacon/slashings.go | 4 +- beacon-chain/rpc/validator/proposer.go | 4 +- 5 files changed, 192 insertions(+), 190 deletions(-) diff --git a/beacon-chain/operations/slashings/BUILD.bazel b/beacon-chain/operations/slashings/BUILD.bazel index fb28cad5833..ebb185cd9da 100644 --- a/beacon-chain/operations/slashings/BUILD.bazel +++ b/beacon-chain/operations/slashings/BUILD.bazel @@ -33,8 +33,7 @@ go_test( ], embed = [":go_default_library"], deps = [ - "//beacon-chain/state:go_default_library", - "//proto/beacon/p2p/v1:go_default_library", + "//beacon-chain/core/helpers:go_default_library", "//shared/params:go_default_library", "//shared/testutil:go_default_library", "@com_github_gogo_protobuf//proto:go_default_library", diff --git a/beacon-chain/operations/slashings/service_attester_test.go b/beacon-chain/operations/slashings/service_attester_test.go index 58d6f0413b6..807f2b3a692 100644 --- a/beacon-chain/operations/slashings/service_attester_test.go +++ b/beacon-chain/operations/slashings/service_attester_test.go @@ -8,7 +8,7 @@ import ( "github.com/gogo/protobuf/proto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - + "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" ) @@ -56,24 +56,25 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { } slashings[i] = sl } + if err := beaconState.SetSlot(helpers.StartSlot(1)); err != nil { + t.Fatal(err) + } // We mark the following validators with some preconditions. - validators := []*ethpb.Validator{ - //{ // 2 - Already exited. - // ExitEpoch: 15, - //}, - //{ // 4 - Will be exited. - // ExitEpoch: 17, - //}, - //{ // 5 - Slashed. - // ExitEpoch: params.BeaconConfig().FarFutureEpoch, - // Slashed: true, - //}, + exitedVal, _ := beaconState.ValidatorAtIndex(uint64(2)) + exitedVal.ExitEpoch = 0 + futureExitedVal, _ := beaconState.ValidatorAtIndex(uint64(4)) + futureExitedVal.ExitEpoch = 17 + slashedVal, _ := beaconState.ValidatorAtIndex(uint64(5)) + slashedVal.Slashed = true + if err := beaconState.UpdateValidatorAtIndex(uint64(2), exitedVal); err != nil { + t.Fatal(err) } - for i := 0; i < len(validators); i++ { - if err := beaconState.UpdateValidatorAtIndex(uint64(i), validators[i]); err != nil { - t.Fatal(err) - } + if err := beaconState.UpdateValidatorAtIndex(uint64(4), futureExitedVal); err != nil { + t.Fatal(err) + } + if err := beaconState.UpdateValidatorAtIndex(uint64(5), slashedVal); err != nil { + t.Fatal(err) } tests := []struct { @@ -123,66 +124,66 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { }, want: pendingSlashings[1:2], }, - //{ - // name: "Slashing for already slashed validator", - // fields: fields{ - // pending: []*PendingAttesterSlashing{}, - // included: make(map[uint64]bool), - // }, - // args: args{ - // slashings: slashings[5:6], - // }, - // want: []*PendingAttesterSlashing{}, - //}, - //{ - // name: "Slashing for exited validator", - // fields: fields{ - // pending: []*PendingAttesterSlashing{}, - // included: make(map[uint64]bool), - // }, - // args: args{ - // slashings: slashings[2:3], - // }, - // want: []*PendingAttesterSlashing{}, - //}, - //{ - // name: "Slashing for futuristic exited validator", - // fields: fields{ - // pending: []*PendingAttesterSlashing{}, - // included: make(map[uint64]bool), - // }, - // args: args{ - // slashings: slashings[4:5], - // }, - // want: pendingSlashings[4:5], - //}, - //{ - // name: "Already included", - // fields: fields{ - // pending: []*PendingAttesterSlashing{}, - // included: map[uint64]bool{ - // 1: true, - // }, - // }, - // args: args{ - // slashings: slashings[1:2], - // }, - // want: []*PendingAttesterSlashing{}, - //}, - //{ - // name: "Maintains sorted order", - // fields: fields{ - // pending: []*PendingAttesterSlashing{ - // pendingSlashings[0], - // pendingSlashings[2], - // }, - // included: make(map[uint64]bool), - // }, - // args: args{ - // slashings: slashings[1:2], - // }, - // want: pendingSlashings[0:3], - //}, + { + name: "Slashing for already slashed validator", + fields: fields{ + pending: []*PendingAttesterSlashing{}, + included: make(map[uint64]bool), + }, + args: args{ + slashings: slashings[5:6], + }, + want: []*PendingAttesterSlashing{}, + }, + { + name: "Slashing for exited validator", + fields: fields{ + pending: []*PendingAttesterSlashing{}, + included: make(map[uint64]bool), + }, + args: args{ + slashings: slashings[2:3], + }, + want: []*PendingAttesterSlashing{}, + }, + { + name: "Slashing for futuristic exited validator", + fields: fields{ + pending: []*PendingAttesterSlashing{}, + included: make(map[uint64]bool), + }, + args: args{ + slashings: slashings[4:5], + }, + want: pendingSlashings[4:5], + }, + { + name: "Already included", + fields: fields{ + pending: []*PendingAttesterSlashing{}, + included: map[uint64]bool{ + 1: true, + }, + }, + args: args{ + slashings: slashings[1:2], + }, + want: []*PendingAttesterSlashing{}, + }, + { + name: "Maintains sorted order", + fields: fields{ + pending: []*PendingAttesterSlashing{ + pendingSlashings[0], + pendingSlashings[2], + }, + included: make(map[uint64]bool), + }, + args: args{ + slashings: slashings[1:2], + }, + want: pendingSlashings[0:3], + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -226,46 +227,51 @@ func TestPool_InsertAttesterSlashing(t *testing.T) { } } -//func TestPool_InsertAttesterSlashing_SigFailsVerify_ClearPool(t *testing.T) { -// conf := params.BeaconConfig() -// conf.MaxAttesterSlashings = 2 -// params.OverrideBeaconConfig(conf) -// beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) -// pendingSlashings := make([]*PendingAttesterSlashing, 2) -// slashings := make([]*ethpb.AttesterSlashing, 2) -// for i := 0; i < 2; i++ { -// sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) -// if err != nil { -// t.Fatal(err) -// } -// pendingSlashings[i] = &PendingAttesterSlashing{ -// attesterSlashing: sl, -// validatorToSlash: uint64(i), -// } -// slashings[i] = sl -// } -// // We mess up the signature of the second slashing. -// badSig := make([]byte, 96) -// copy(badSig, "muahaha") -// pendingSlashings[1].attesterSlashing.Attestation_1.Signature = badSig -// slashings[1].Attestation_1.Signature = badSig -// p := &Pool{ -// pendingAttesterSlashing: pendingSlashings, -// } -// for i := 0; i < len(slashings); i++ { -// if err := p.InsertAttesterSlashing( -// context.Background(), -// beaconState, -// slashings[i], -// ); err != nil { -// t.Fatal(err) -// } -// } -// // We expect to only have 1 pending attester slashing in the pool. -// if len(p.pendingAttesterSlashing) != 1 { -// t.Error("Expected failed attester slashing to have been cleared from pool") -// } -//} +func TestPool_InsertAttesterSlashing_SigFailsVerify_ClearPool(t *testing.T) { + conf := params.BeaconConfig() + conf.MaxAttesterSlashings = 2 + params.OverrideBeaconConfig(conf) + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + pendingSlashings := make([]*PendingAttesterSlashing, 2) + slashings := make([]*ethpb.AttesterSlashing, 2) + for i := 0; i < 2; i++ { + sl, err := testutil.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + pendingSlashings[i] = &PendingAttesterSlashing{ + attesterSlashing: sl, + validatorToSlash: uint64(i), + } + slashings[i] = sl + } + // We mess up the signature of the second slashing. + badSig := make([]byte, 96) + copy(badSig, "muahaha") + pendingSlashings[1].attesterSlashing.Attestation_1.Signature = badSig + slashings[1].Attestation_1.Signature = badSig + p := &Pool{ + pendingAttesterSlashing: make([]*PendingAttesterSlashing, 0), + } + if err := p.InsertAttesterSlashing( + context.Background(), + beaconState, + slashings[0], + ); err != nil { + t.Fatal(err) + } + if err := p.InsertAttesterSlashing( + context.Background(), + beaconState, + slashings[1], + ); err == nil { + t.Error("Expected error when inserting slashing with bad sig, got nil") + } + // We expect to only have 1 pending attester slashing in the pool. + if len(p.pendingAttesterSlashing) != 1 { + t.Error("Expected failed attester slashing to have been cleared from pool") + } +} func TestPool_MarkIncludedAttesterSlashing(t *testing.T) { type fields struct { @@ -408,6 +414,9 @@ func TestPool_PendingAttesterSlashings(t *testing.T) { type fields struct { pending []*PendingAttesterSlashing } + conf := params.BeaconConfig() + conf.MaxAttesterSlashings = 1 + params.OverrideBeaconConfig(conf) beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) pendingSlashings := make([]*PendingAttesterSlashing, 20) slashings := make([]*ethpb.AttesterSlashing, 20) diff --git a/beacon-chain/operations/slashings/service_proposer_test.go b/beacon-chain/operations/slashings/service_proposer_test.go index 15aeced8efe..674fdb99a14 100644 --- a/beacon-chain/operations/slashings/service_proposer_test.go +++ b/beacon-chain/operations/slashings/service_proposer_test.go @@ -8,8 +8,8 @@ import ( "github.com/gogo/protobuf/proto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state" - p2ppb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + + "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" ) @@ -41,32 +41,25 @@ func TestPool_InsertProposerSlashing(t *testing.T) { slashings[i] = sl } + if err := beaconState.SetSlot(helpers.StartSlot(1)); err != nil { + t.Fatal(err) + } + // We mark the following validators with some preconditions. - validators := []*ethpb.Validator{ - { // 0 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 1 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 2 - Already exited. - ExitEpoch: 15, - }, - { // 3 - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - }, - { // 4 - Will be exited. - ExitEpoch: 17, - }, - { // 5 - Slashed. - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - Slashed: true, - }, + exitedVal, _ := beaconState.ValidatorAtIndex(uint64(2)) + exitedVal.ExitEpoch = 0 + futureExitedVal, _ := beaconState.ValidatorAtIndex(uint64(4)) + futureExitedVal.ExitEpoch = 17 + slashedVal, _ := beaconState.ValidatorAtIndex(uint64(5)) + slashedVal.Slashed = true + if err := beaconState.UpdateValidatorAtIndex(uint64(2), exitedVal); err != nil { + t.Fatal(err) } - for i := 0; i < len(validators); i++ { - if err := beaconState.UpdateValidatorAtIndex(uint64(i), validators[i]); err != nil { - t.Fatal(err) - } + if err := beaconState.UpdateValidatorAtIndex(uint64(4), futureExitedVal); err != nil { + t.Fatal(err) + } + if err := beaconState.UpdateValidatorAtIndex(uint64(5), slashedVal); err != nil { + t.Fatal(err) } tests := []struct { @@ -129,7 +122,7 @@ func TestPool_InsertProposerSlashing(t *testing.T) { pending: []*ethpb.ProposerSlashing{}, included: make(map[uint64]bool), wantErr: true, - err: "cannot be slashed", + err: "not slashable", }, args: args{ slashings: slashings[5:6], @@ -176,13 +169,7 @@ func TestPool_InsertProposerSlashing(t *testing.T) { pendingProposerSlashing: tt.fields.pending, included: tt.fields.included, } - beaconState, err := beaconstate.InitializeFromProtoUnsafe(&p2ppb.BeaconState{ - Slot: 16 * params.BeaconConfig().SlotsPerEpoch, - Validators: validators, - }) - if err != nil { - t.Fatal(err) - } + var err error for i := 0; i < len(tt.args.slashings); i++ { err = p.InsertProposerSlashing(context.Background(), beaconState, tt.args.slashings[i]) } @@ -212,6 +199,47 @@ func TestPool_InsertProposerSlashing(t *testing.T) { } } +func TestPool_InsertProposerSlashing_SigFailsVerify_ClearPool(t *testing.T) { + conf := params.BeaconConfig() + conf.MaxAttesterSlashings = 2 + params.OverrideBeaconConfig(conf) + beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) + slashings := make([]*ethpb.ProposerSlashing, 2) + for i := 0; i < 2; i++ { + sl, err := testutil.GenerateProposerSlashingForValidator(beaconState, privKeys[i], uint64(i)) + if err != nil { + t.Fatal(err) + } + slashings[i] = sl + } + // We mess up the signature of the second slashing. + badSig := make([]byte, 96) + copy(badSig, "muahaha") + slashings[1].Header_1.Signature = badSig + p := &Pool{ + pendingProposerSlashing: make([]*ethpb.ProposerSlashing, 0), + } + // We only want a single slashing to remain. + if err := p.InsertProposerSlashing( + context.Background(), + beaconState, + slashings[0], + ); err != nil { + t.Fatal(err) + } + if err := p.InsertProposerSlashing( + context.Background(), + beaconState, + slashings[1], + ); err == nil { + t.Error("Expected slashing with bad signature to fail, received nil") + } + // We expect to only have 1 pending proposer slashing in the pool. + if len(p.pendingProposerSlashing) != 1 { + t.Error("Expected failed proposer slashing to have been cleared from pool") + } +} + func TestPool_MarkIncludedProposerSlashing(t *testing.T) { type fields struct { pending []*ethpb.ProposerSlashing @@ -397,37 +425,3 @@ func TestPool_PendingProposerSlashings(t *testing.T) { }) } } - -//func TestPool_PendingProposerSlashings_SigFailsVerify_ClearPool(t *testing.T) { -// conf := params.BeaconConfig() -// conf.MaxAttesterSlashings = 2 -// params.OverrideBeaconConfig(conf) -// beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) -// slashings := make([]*ethpb.ProposerSlashing, 2) -// for i := 0; i < 2; i++ { -// sl, err := testutil.GenerateProposerSlashingForValidator(beaconState, privKeys[i], uint64(i)) -// if err != nil { -// t.Fatal(err) -// } -// slashings[i] = sl -// } -// // We mess up the signature of the second slashing. -// badSig := make([]byte, 96) -// copy(badSig, "muahaha") -// slashings[1].Header_1.Signature = badSig -// p := &Pool{ -// pendingProposerSlashing: slashings, -// } -// // We only want a single slashing to remain. -// want := slashings[0:1] -// if got := p.PendingProposerSlashings( -// context.Background(), -// beaconState, -// ); !reflect.DeepEqual(want, got) { -// t.Errorf("Unexpected return from PendingProposerSlashings, wanted %v, received %v", want, got) -// } -// // We expect to only have 1 pending proposer slashing in the pool. -// if len(p.pendingProposerSlashing) != 1 { -// t.Error("Expected failed proposer slashing to have been cleared from pool") -// } -//} diff --git a/beacon-chain/rpc/beacon/slashings.go b/beacon-chain/rpc/beacon/slashings.go index 2df63200732..50a9ba93b8f 100644 --- a/beacon-chain/rpc/beacon/slashings.go +++ b/beacon-chain/rpc/beacon/slashings.go @@ -20,7 +20,7 @@ func (bs *Server) SubmitProposerSlashing( if err != nil { return nil, status.Errorf(codes.Internal, "Could not retrieve head state: %v", err) } - if err := bs.SlashingsPool.InsertProposerSlashing(beaconState, req); err != nil { + if err := bs.SlashingsPool.InsertProposerSlashing(ctx, beaconState, req); err != nil { return nil, status.Errorf(codes.Internal, "Could not insert proposer slashing into pool: %v", err) } return ðpb.SubmitSlashingResponse{ @@ -39,7 +39,7 @@ func (bs *Server) SubmitAttesterSlashing( if err != nil { return nil, status.Errorf(codes.Internal, "Could not retrieve head state: %v", err) } - if err := bs.SlashingsPool.InsertAttesterSlashing(beaconState, req); err != nil { + if err := bs.SlashingsPool.InsertAttesterSlashing(ctx, beaconState, req); err != nil { return nil, status.Errorf(codes.Internal, "Could not insert attester slashing into pool: %v", err) } slashedIndices := sliceutil.IntersectionUint64(req.Attestation_1.AttestingIndices, req.Attestation_2.AttestingIndices) diff --git a/beacon-chain/rpc/validator/proposer.go b/beacon-chain/rpc/validator/proposer.go index 6e9165e1dc3..fe8a63c3adb 100644 --- a/beacon-chain/rpc/validator/proposer.go +++ b/beacon-chain/rpc/validator/proposer.go @@ -89,8 +89,8 @@ func (vs *Server) GetBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb Deposits: deposits, Attestations: atts, RandaoReveal: req.RandaoReveal, - ProposerSlashings: vs.SlashingsPool.PendingProposerSlashings(ctx, head), - AttesterSlashings: vs.SlashingsPool.PendingAttesterSlashings(ctx, head), + ProposerSlashings: vs.SlashingsPool.PendingProposerSlashings(ctx), + AttesterSlashings: vs.SlashingsPool.PendingAttesterSlashings(ctx), VoluntaryExits: vs.ExitPool.PendingExits(head, req.Slot), Graffiti: graffiti[:], }, From 78c35028387bf728f11dddd07e0bf265bdf200f4 Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 17:12:24 -0500 Subject: [PATCH 11/13] imports --- beacon-chain/operations/slashings/service_proposer_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/beacon-chain/operations/slashings/service_proposer_test.go b/beacon-chain/operations/slashings/service_proposer_test.go index 674fdb99a14..21c3e00cc65 100644 --- a/beacon-chain/operations/slashings/service_proposer_test.go +++ b/beacon-chain/operations/slashings/service_proposer_test.go @@ -8,7 +8,6 @@ import ( "github.com/gogo/protobuf/proto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" From 1aaa2135fe485866835cdafac9f3a8eaa0c2e1a1 Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 17:16:06 -0500 Subject: [PATCH 12/13] fix build --- beacon-chain/rpc/validator/proposer_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/beacon-chain/rpc/validator/proposer_test.go b/beacon-chain/rpc/validator/proposer_test.go index 6e083bc4f85..f017ad618b0 100644 --- a/beacon-chain/rpc/validator/proposer_test.go +++ b/beacon-chain/rpc/validator/proposer_test.go @@ -99,7 +99,7 @@ func TestGetBlock_OK(t *testing.T) { privKeys[0], 0, /* validator index */ ) - if err := proposerServer.SlashingsPool.InsertProposerSlashing(beaconState, proposerSlashing); err != nil { + if err := proposerServer.SlashingsPool.InsertProposerSlashing(context.Background(), beaconState, proposerSlashing); err != nil { t.Fatal(err) } @@ -109,7 +109,7 @@ func TestGetBlock_OK(t *testing.T) { privKeys[1], 1, /* validator index */ ) - if err := proposerServer.SlashingsPool.InsertAttesterSlashing(beaconState, attesterSlashing); err != nil { + if err := proposerServer.SlashingsPool.InsertAttesterSlashing(context.Background(), beaconState, attesterSlashing); err != nil { t.Fatal(err) } From 87dbb4da714fb06795e7a26ca575780b013f998d Mon Sep 17 00:00:00 2001 From: rauljordan Date: Wed, 11 Mar 2020 19:28:02 -0500 Subject: [PATCH 13/13] fix rpc errors --- beacon-chain/rpc/beacon/slashings_test.go | 115 +++++++--------------- 1 file changed, 36 insertions(+), 79 deletions(-) diff --git a/beacon-chain/rpc/beacon/slashings_test.go b/beacon-chain/rpc/beacon/slashings_test.go index c068ecb1772..08fff1fcdd8 100644 --- a/beacon-chain/rpc/beacon/slashings_test.go +++ b/beacon-chain/rpc/beacon/slashings_test.go @@ -2,42 +2,28 @@ package beacon import ( "context" - "strconv" "testing" "github.com/gogo/protobuf/proto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" "github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings" - stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" - pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" - "github.com/prysmaticlabs/prysm/shared/params" + "github.com/prysmaticlabs/prysm/shared/testutil" ) func TestServer_SubmitProposerSlashing(t *testing.T) { ctx := context.Background() - vals := make([]*ethpb.Validator, 10) - for i := 0; i < len(vals); i++ { - key := make([]byte, 48) - copy(key, strconv.Itoa(i)) - vals[i] = ðpb.Validator{ - PublicKey: key[:], - WithdrawalCredentials: make([]byte, 32), - EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, - Slashed: false, - } + st, privs := testutil.DeterministicGenesisState(t, 64) + slashedVal, err := st.ValidatorAtIndex(5) + if err != nil { + t.Fatal(err) } - // We mark the validator at index 5 as already slashed. - vals[5].Slashed = true - - st, err := stateTrie.InitializeFromProto(&pbp2p.BeaconState{ - Slot: 0, - Validators: vals, - }) - if err != nil { + slashedVal.Slashed = true + if err := st.UpdateValidatorAtIndex(5, slashedVal); err != nil { t.Fatal(err) } + bs := &Server{ HeadFetcher: &mock.ChainService{ State: st, @@ -50,27 +36,11 @@ func TestServer_SubmitProposerSlashing(t *testing.T) { wanted := ðpb.SubmitSlashingResponse{ SlashedIndices: []uint64{2}, } - slashing := ðpb.ProposerSlashing{ - ProposerIndex: 2, - Header_1: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 0, - ParentRoot: nil, - StateRoot: nil, - BodyRoot: nil, - }, - Signature: make([]byte, 96), - }, - Header_2: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 0, - ParentRoot: nil, - StateRoot: nil, - BodyRoot: nil, - }, - Signature: make([]byte, 96), - }, + slashing, err := testutil.GenerateProposerSlashingForValidator(st, privs[2], uint64(2)) + if err != nil { + t.Fatal(err) } + res, err := bs.SubmitProposerSlashing(ctx, slashing) if err != nil { t.Fatal(err) @@ -79,9 +49,13 @@ func TestServer_SubmitProposerSlashing(t *testing.T) { t.Errorf("Wanted %v, received %v", wanted, res) } + slashing, err = testutil.GenerateProposerSlashingForValidator(st, privs[5], uint64(5)) + if err != nil { + t.Fatal(err) + } + // We do not want a proposer slashing for an already slashed validator // (the validator at index 5) to be included in the pool. - slashing.ProposerIndex = 5 if _, err := bs.SubmitProposerSlashing(ctx, slashing); err == nil { t.Error("Expected including a proposer slashing for an already slashed validator to fail") } @@ -89,29 +63,19 @@ func TestServer_SubmitProposerSlashing(t *testing.T) { func TestServer_SubmitAttesterSlashing(t *testing.T) { ctx := context.Background() - vals := make([]*ethpb.Validator, 10) - for i := 0; i < len(vals); i++ { - key := make([]byte, 48) - copy(key, strconv.Itoa(i)) - vals[i] = ðpb.Validator{ - PublicKey: key[:], - WithdrawalCredentials: make([]byte, 32), - EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, - Slashed: false, - } - } - // We mark the validators at index 5, 6, 7 as already slashed. - vals[5].Slashed = true - vals[6].Slashed = true - vals[7].Slashed = true - - st, err := stateTrie.InitializeFromProto(&pbp2p.BeaconState{ - Slot: 0, - Validators: vals, - }) + // We mark the validators at index 5, 6 as already slashed. + st, privs := testutil.DeterministicGenesisState(t, 64) + slashedVal, err := st.ValidatorAtIndex(5) if err != nil { t.Fatal(err) } + + // We mark the validator at index 5 as already slashed. + slashedVal.Slashed = true + if err := st.UpdateValidatorAtIndex(5, slashedVal); err != nil { + t.Fatal(err) + } + bs := &Server{ HeadFetcher: &mock.ChainService{ State: st, @@ -119,19 +83,16 @@ func TestServer_SubmitAttesterSlashing(t *testing.T) { SlashingsPool: slashings.NewPool(), } - slashing := ðpb.AttesterSlashing{ - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{1, 2, 3}, - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{2, 3, 4}, - }, + slashing, err := testutil.GenerateAttesterSlashingForValidator(st, privs[2], uint64(2)) + if err != nil { + t.Fatal(err) } + // We want the intersection of the slashing attesting indices // to be slashed, so we expect validators 2 and 3 to be in the response // slashed indices. wanted := ðpb.SubmitSlashingResponse{ - SlashedIndices: []uint64{2, 3}, + SlashedIndices: []uint64{2}, } res, err := bs.SubmitAttesterSlashing(ctx, slashing) if err != nil { @@ -141,16 +102,12 @@ func TestServer_SubmitAttesterSlashing(t *testing.T) { t.Errorf("Wanted %v, received %v", wanted, res) } + slashing, err = testutil.GenerateAttesterSlashingForValidator(st, privs[5], uint64(5)) + if err != nil { + t.Fatal(err) + } // If any of the attesting indices in the slashing object have already // been slashed, we should fail to insert properly into the attester slashing pool. - slashing = ðpb.AttesterSlashing{ - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{5, 6, 7}, - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{6, 7, 8}, - }, - } if _, err := bs.SubmitAttesterSlashing(ctx, slashing); err == nil { t.Error("Expected including a attester slashing for an already slashed validator to fail") }