mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 13:28:01 -05:00
Include Slashing Submission Endpoints + Slashing Pool in Beacon Node (#4858)
* add to workspace * impl * include tests for func * fix broken build * test passing, found 2 bugs * add errors package * added in mockgen * we check for insertion into the pool based on attester slashings * test passing * proper test * Update beacon-chain/rpc/beacon/slashings.go * Update beacon-chain/rpc/beacon/slashings_test.go
This commit is contained in:
@@ -1272,7 +1272,7 @@ go_repository(
|
||||
|
||||
go_repository(
|
||||
name = "com_github_prysmaticlabs_ethereumapis",
|
||||
commit = "79d7a99b999d1873431b2ae56f1e6ea6e730242f",
|
||||
commit = "b7452dde4ca361809def4ed5924ab3cb7ad1299a",
|
||||
importpath = "github.com/prysmaticlabs/ethereumapis",
|
||||
patch_args = ["-p1"],
|
||||
patches = [
|
||||
|
||||
@@ -19,6 +19,7 @@ go_library(
|
||||
"//beacon-chain/gateway:go_default_library",
|
||||
"//beacon-chain/interop-cold-start:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/operations/voluntaryexits:go_default_library",
|
||||
"//beacon-chain/p2p:go_default_library",
|
||||
"//beacon-chain/powchain:go_default_library",
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/gateway"
|
||||
interopcoldstart "github.com/prysmaticlabs/prysm/beacon-chain/interop-cold-start"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
@@ -62,6 +63,7 @@ type BeaconNode struct {
|
||||
db db.Database
|
||||
attestationPool attestations.Pool
|
||||
exitPool *voluntaryexits.Pool
|
||||
slashingsPool *slashings.Pool
|
||||
depositCache *depositcache.DepositCache
|
||||
stateFeed *event.Feed
|
||||
blockFeed *event.Feed
|
||||
@@ -109,6 +111,7 @@ func NewBeaconNode(ctx *cli.Context) (*BeaconNode, error) {
|
||||
opFeed: new(event.Feed),
|
||||
attestationPool: attestations.NewPool(),
|
||||
exitPool: voluntaryexits.NewPool(),
|
||||
slashingsPool: slashings.NewPool(),
|
||||
}
|
||||
|
||||
if err := beacon.startDB(ctx); err != nil {
|
||||
@@ -497,6 +500,7 @@ func (b *BeaconNode) registerRPCService(ctx *cli.Context) error {
|
||||
GenesisTimeFetcher: chainService,
|
||||
AttestationsPool: b.attestationPool,
|
||||
ExitPool: b.exitPool,
|
||||
SlashingsPool: b.slashingsPool,
|
||||
POWChainService: web3Service,
|
||||
ChainStartFetcher: chainStartFetcher,
|
||||
MockEth1Votes: mockEth1DataVotes,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package slashings
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
@@ -77,7 +79,7 @@ func (p *Pool) InsertAttesterSlashing(state *beaconstate.BeaconState, slashing *
|
||||
// has been recently included in the pool of slashings, do not process this new
|
||||
// slashing.
|
||||
if !ok {
|
||||
return nil
|
||||
return fmt.Errorf("validator at index %d cannot be slashed", val)
|
||||
}
|
||||
|
||||
// Check if the validator already exists in the list of slashings.
|
||||
@@ -117,7 +119,7 @@ func (p *Pool) InsertProposerSlashing(state *beaconstate.BeaconState, slashing *
|
||||
// has been recently included in the pool of slashings, do not process this new
|
||||
// slashing.
|
||||
if !ok {
|
||||
return nil
|
||||
return fmt.Errorf("validator at index %d cannot be slashed", idx)
|
||||
}
|
||||
|
||||
// Check if the validator already exists in the list of slashings.
|
||||
@@ -126,7 +128,7 @@ func (p *Pool) InsertProposerSlashing(state *beaconstate.BeaconState, slashing *
|
||||
return p.pendingProposerSlashing[i].ProposerIndex == slashing.ProposerIndex
|
||||
})
|
||||
if found != len(p.pendingProposerSlashing) {
|
||||
return nil
|
||||
return errors.New("slashing object already exists in pending proposer slashings")
|
||||
}
|
||||
|
||||
// Insert into pending list and sort again.
|
||||
@@ -194,11 +196,7 @@ func (p *Pool) validatorSlashingPreconditionCheck(
|
||||
return false, nil
|
||||
}
|
||||
// Checking if the validator has already been slashed.
|
||||
slashedValidators := state.Slashings()
|
||||
found := sort.Search(len(slashedValidators), func(i int) bool {
|
||||
return slashedValidators[i] == valIdx
|
||||
})
|
||||
if found != len(slashedValidators) {
|
||||
if validator.Slashed() {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
|
||||
@@ -2,6 +2,7 @@ package slashings
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
@@ -52,6 +53,8 @@ func TestPool_InsertAttesterSlashing(t *testing.T) {
|
||||
type fields struct {
|
||||
pending []*PendingAttesterSlashing
|
||||
included map[uint64]bool
|
||||
wantErr bool
|
||||
err string
|
||||
}
|
||||
type args struct {
|
||||
slashing *ethpb.AttesterSlashing
|
||||
@@ -179,7 +182,7 @@ func TestPool_InsertAttesterSlashing(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Slashing for exited validator ",
|
||||
name: "Slashing for exited validator",
|
||||
fields: fields{
|
||||
pending: []*PendingAttesterSlashing{},
|
||||
included: make(map[uint64]bool),
|
||||
@@ -190,7 +193,7 @@ func TestPool_InsertAttesterSlashing(t *testing.T) {
|
||||
want: []*PendingAttesterSlashing{},
|
||||
},
|
||||
{
|
||||
name: "Slashing for futuristic exited validator ",
|
||||
name: "Slashing for futuristic exited validator",
|
||||
fields: fields{
|
||||
pending: []*PendingAttesterSlashing{},
|
||||
included: make(map[uint64]bool),
|
||||
@@ -203,10 +206,12 @@ func TestPool_InsertAttesterSlashing(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Slashing for slashed validator ",
|
||||
name: "Slashing for slashed validator",
|
||||
fields: fields{
|
||||
pending: []*PendingAttesterSlashing{},
|
||||
included: make(map[uint64]bool),
|
||||
wantErr: true,
|
||||
err: "cannot be slashed",
|
||||
},
|
||||
args: args{
|
||||
slashing: attesterSlashingForValIdx(5),
|
||||
@@ -259,6 +264,7 @@ func TestPool_InsertAttesterSlashing(t *testing.T) {
|
||||
},
|
||||
{ // 5 - Slashed.
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -267,13 +273,17 @@ func TestPool_InsertAttesterSlashing(t *testing.T) {
|
||||
pendingAttesterSlashing: tt.fields.pending,
|
||||
included: tt.fields.included,
|
||||
}
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(&p2ppb.BeaconState{Validators: validators})
|
||||
s, err := beaconstate.InitializeFromProtoUnsafe(&p2ppb.BeaconState{
|
||||
Slot: 16 * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: validators,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s.SetSlot(16 * params.BeaconConfig().SlotsPerEpoch)
|
||||
s.SetSlashings([]uint64{5})
|
||||
p.InsertAttesterSlashing(s, tt.args.slashing)
|
||||
err = p.InsertAttesterSlashing(s, tt.args.slashing)
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package slashings
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
@@ -27,6 +28,8 @@ func generateNProposerSlashings(n uint64) []*ethpb.ProposerSlashing {
|
||||
|
||||
func TestPool_InsertProposerSlashing(t *testing.T) {
|
||||
type fields struct {
|
||||
wantErr bool
|
||||
err string
|
||||
pending []*ethpb.ProposerSlashing
|
||||
included map[uint64]bool
|
||||
}
|
||||
@@ -90,6 +93,8 @@ func TestPool_InsertProposerSlashing(t *testing.T) {
|
||||
fields: fields{
|
||||
pending: []*ethpb.ProposerSlashing{},
|
||||
included: make(map[uint64]bool),
|
||||
wantErr: true,
|
||||
err: "cannot be slashed",
|
||||
},
|
||||
args: args{
|
||||
slashing: proposerSlashingForValIdx(5),
|
||||
@@ -103,6 +108,8 @@ func TestPool_InsertProposerSlashing(t *testing.T) {
|
||||
included: map[uint64]bool{
|
||||
1: true,
|
||||
},
|
||||
wantErr: true,
|
||||
err: "cannot be slashed",
|
||||
},
|
||||
args: args{
|
||||
slashing: proposerSlashingForValIdx(1),
|
||||
@@ -146,6 +153,7 @@ func TestPool_InsertProposerSlashing(t *testing.T) {
|
||||
},
|
||||
{ // 5 - Slashed.
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
Slashed: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -154,13 +162,17 @@ func TestPool_InsertProposerSlashing(t *testing.T) {
|
||||
pendingProposerSlashing: tt.fields.pending,
|
||||
included: tt.fields.included,
|
||||
}
|
||||
beaconState, err := beaconstate.InitializeFromProtoUnsafe(&p2ppb.BeaconState{Validators: validators})
|
||||
beaconState, err := beaconstate.InitializeFromProtoUnsafe(&p2ppb.BeaconState{
|
||||
Slot: 16 * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: validators,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.SetSlot(16 * params.BeaconConfig().SlotsPerEpoch)
|
||||
beaconState.SetSlashings([]uint64{5})
|
||||
p.InsertProposerSlashing(beaconState, tt.args.slashing)
|
||||
err = p.InsertProposerSlashing(beaconState, tt.args.slashing)
|
||||
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.pendingProposerSlashing) != len(tt.want) {
|
||||
t.Fatalf("Mismatched lengths of pending list. Got %d, wanted %d.", len(p.pendingProposerSlashing), len(tt.want))
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ go_library(
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/operations/voluntaryexits:go_default_library",
|
||||
"//beacon-chain/p2p:go_default_library",
|
||||
"//beacon-chain/powchain:go_default_library",
|
||||
|
||||
@@ -9,6 +9,7 @@ go_library(
|
||||
"committees.go",
|
||||
"config.go",
|
||||
"server.go",
|
||||
"slashings.go",
|
||||
"validators.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/rpc/beacon",
|
||||
@@ -26,12 +27,14 @@ go_library(
|
||||
"//beacon-chain/db/filters:go_default_library",
|
||||
"//beacon-chain/flags:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/powchain:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/pagination:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"//shared/slotutil:go_default_library",
|
||||
"@com_github_gogo_protobuf//types:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
@@ -50,6 +53,7 @@ go_test(
|
||||
"blocks_test.go",
|
||||
"committees_test.go",
|
||||
"config_test.go",
|
||||
"slashings_test.go",
|
||||
"validators_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
@@ -65,6 +69,7 @@ go_test(
|
||||
"//beacon-chain/db/testing:go_default_library",
|
||||
"//beacon-chain/flags:go_default_library",
|
||||
"//beacon-chain/operations/attestations:go_default_library",
|
||||
"//beacon-chain/operations/slashings:go_default_library",
|
||||
"//beacon-chain/rpc/testing:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
|
||||
@@ -119,7 +119,7 @@ func (bs *Server) StreamAttestations(
|
||||
for {
|
||||
select {
|
||||
case <-bs.SlotTicker.C():
|
||||
atts := bs.Pool.AggregatedAttestations()
|
||||
atts := bs.AttestationsPool.AggregatedAttestations()
|
||||
for i := 0; i < len(atts); i++ {
|
||||
if err := stream.Send(atts[i]); err != nil {
|
||||
return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err)
|
||||
@@ -153,7 +153,7 @@ func (bs *Server) AttestationPool(
|
||||
flags.Get().MaxPageSize,
|
||||
)
|
||||
}
|
||||
atts := bs.Pool.AggregatedAttestations()
|
||||
atts := bs.AttestationsPool.AggregatedAttestations()
|
||||
numAtts := len(atts)
|
||||
if numAtts == 0 {
|
||||
return ðpb.AttestationPoolResponse{
|
||||
|
||||
@@ -551,7 +551,7 @@ func TestServer_AttestationPool_Pagination_ExceedsMaxPageSize(t *testing.T) {
|
||||
func TestServer_AttestationPool_Pagination_OutOfRange(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
bs := &Server{
|
||||
Pool: attestations.NewPool(),
|
||||
AttestationsPool: attestations.NewPool(),
|
||||
}
|
||||
|
||||
atts := []*ethpb.Attestation{
|
||||
@@ -559,7 +559,7 @@ func TestServer_AttestationPool_Pagination_OutOfRange(t *testing.T) {
|
||||
{Data: ðpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b1101}},
|
||||
{Data: ðpb.AttestationData{Slot: 3}, AggregationBits: bitfield.Bitlist{0b1101}},
|
||||
}
|
||||
if err := bs.Pool.SaveAggregatedAttestations(atts); err != nil {
|
||||
if err := bs.AttestationsPool.SaveAggregatedAttestations(atts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -576,7 +576,7 @@ func TestServer_AttestationPool_Pagination_OutOfRange(t *testing.T) {
|
||||
func TestServer_AttestationPool_Pagination_DefaultPageSize(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
bs := &Server{
|
||||
Pool: attestations.NewPool(),
|
||||
AttestationsPool: attestations.NewPool(),
|
||||
}
|
||||
|
||||
atts := make([]*ethpb.Attestation, params.BeaconConfig().DefaultPageSize+1)
|
||||
@@ -586,7 +586,7 @@ func TestServer_AttestationPool_Pagination_DefaultPageSize(t *testing.T) {
|
||||
AggregationBits: bitfield.Bitlist{0b1101},
|
||||
}
|
||||
}
|
||||
if err := bs.Pool.SaveAggregatedAttestations(atts); err != nil {
|
||||
if err := bs.AttestationsPool.SaveAggregatedAttestations(atts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -610,7 +610,7 @@ func TestServer_AttestationPool_Pagination_DefaultPageSize(t *testing.T) {
|
||||
func TestServer_AttestationPool_Pagination_CustomPageSize(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
bs := &Server{
|
||||
Pool: attestations.NewPool(),
|
||||
AttestationsPool: attestations.NewPool(),
|
||||
}
|
||||
|
||||
numAtts := 100
|
||||
@@ -621,7 +621,7 @@ func TestServer_AttestationPool_Pagination_CustomPageSize(t *testing.T) {
|
||||
AggregationBits: bitfield.Bitlist{0b1101},
|
||||
}
|
||||
}
|
||||
if err := bs.Pool.SaveAggregatedAttestations(atts); err != nil {
|
||||
if err := bs.AttestationsPool.SaveAggregatedAttestations(atts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tests := []struct {
|
||||
@@ -716,9 +716,9 @@ func TestServer_StreamAttestations_OnSlotTick(t *testing.T) {
|
||||
Channel: make(chan uint64),
|
||||
}
|
||||
server := &Server{
|
||||
Ctx: ctx,
|
||||
SlotTicker: ticker,
|
||||
Pool: attestations.NewPool(),
|
||||
Ctx: ctx,
|
||||
SlotTicker: ticker,
|
||||
AttestationsPool: attestations.NewPool(),
|
||||
}
|
||||
|
||||
atts := []*ethpb.Attestation{
|
||||
@@ -726,7 +726,7 @@ func TestServer_StreamAttestations_OnSlotTick(t *testing.T) {
|
||||
{Data: ðpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b1101}},
|
||||
{Data: ðpb.AttestationData{Slot: 3}, AggregationBits: bitfield.Bitlist{0b1101}},
|
||||
}
|
||||
if err := server.Pool.SaveAggregatedAttestations(atts); err != nil {
|
||||
if err := server.AttestationsPool.SaveAggregatedAttestations(atts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
@@ -27,7 +28,8 @@ type Server struct {
|
||||
ParticipationFetcher blockchain.ParticipationFetcher
|
||||
StateNotifier statefeed.Notifier
|
||||
BlockNotifier blockfeed.Notifier
|
||||
Pool attestations.Pool
|
||||
AttestationsPool attestations.Pool
|
||||
SlashingsPool *slashings.Pool
|
||||
IncomingAttestation chan *ethpb.Attestation
|
||||
CanonicalStateChan chan *pbp2p.BeaconState
|
||||
ChainStartChan chan time.Time
|
||||
|
||||
49
beacon-chain/rpc/beacon/slashings.go
Normal file
49
beacon-chain/rpc/beacon/slashings.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package beacon
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
)
|
||||
|
||||
// SubmitProposerSlashing receives a proposer slashing object via
|
||||
// RPC and injects it into the beacon node's operations pool.
|
||||
// Submission into this pool does not guarantee inclusion into a beacon block.
|
||||
func (bs *Server) SubmitProposerSlashing(
|
||||
ctx context.Context,
|
||||
req *ethpb.ProposerSlashing,
|
||||
) (*ethpb.SubmitSlashingResponse, error) {
|
||||
beaconState, err := bs.HeadFetcher.HeadState(ctx)
|
||||
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 {
|
||||
return nil, status.Errorf(codes.Internal, "Could not insert proposer slashing into pool: %v", err)
|
||||
}
|
||||
return ðpb.SubmitSlashingResponse{
|
||||
SlashedIndices: []uint64{req.ProposerIndex},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SubmitAttesterSlashing receives an attester slashing object via
|
||||
// RPC and injects it into the beacon node's operations pool.
|
||||
// Submission into this pool does not guarantee inclusion into a beacon block.
|
||||
func (bs *Server) SubmitAttesterSlashing(
|
||||
ctx context.Context,
|
||||
req *ethpb.AttesterSlashing,
|
||||
) (*ethpb.SubmitSlashingResponse, error) {
|
||||
beaconState, err := bs.HeadFetcher.HeadState(ctx)
|
||||
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 {
|
||||
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)
|
||||
return ðpb.SubmitSlashingResponse{
|
||||
SlashedIndices: slashedIndices,
|
||||
}, nil
|
||||
}
|
||||
157
beacon-chain/rpc/beacon/slashings_test.go
Normal file
157
beacon-chain/rpc/beacon/slashings_test.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package beacon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
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"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bs := &Server{
|
||||
HeadFetcher: &mock.ChainService{
|
||||
State: st,
|
||||
},
|
||||
SlashingsPool: slashings.NewPool(),
|
||||
}
|
||||
|
||||
// We want a proposer slashing for validator with index 2 to
|
||||
// be included in the pool.
|
||||
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),
|
||||
},
|
||||
}
|
||||
res, err := bs.SubmitProposerSlashing(ctx, slashing)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !proto.Equal(wanted, res) {
|
||||
t.Errorf("Wanted %v, received %v", wanted, res)
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bs := &Server{
|
||||
HeadFetcher: &mock.ChainService{
|
||||
State: st,
|
||||
},
|
||||
SlashingsPool: slashings.NewPool(),
|
||||
}
|
||||
|
||||
slashing := ðpb.AttesterSlashing{
|
||||
Attestation_1: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{1, 2, 3},
|
||||
},
|
||||
Attestation_2: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{2, 3, 4},
|
||||
},
|
||||
}
|
||||
// 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},
|
||||
}
|
||||
res, err := bs.SubmitAttesterSlashing(ctx, slashing)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !proto.Equal(wanted, res) {
|
||||
t.Errorf("Wanted %v, received %v", wanted, res)
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
@@ -67,6 +68,7 @@ type Service struct {
|
||||
mockEth1Votes bool
|
||||
attestationsPool attestations.Pool
|
||||
exitPool *voluntaryexits.Pool
|
||||
slashingsPool *slashings.Pool
|
||||
syncService sync.Checker
|
||||
host string
|
||||
port string
|
||||
@@ -110,6 +112,7 @@ type Config struct {
|
||||
MockEth1Votes bool
|
||||
AttestationsPool attestations.Pool
|
||||
ExitPool *voluntaryexits.Pool
|
||||
SlashingsPool *slashings.Pool
|
||||
SyncService sync.Checker
|
||||
Broadcaster p2p.Broadcaster
|
||||
PeersFetcher p2p.PeersProvider
|
||||
@@ -144,6 +147,7 @@ func NewService(ctx context.Context, cfg *Config) *Service {
|
||||
mockEth1Votes: cfg.MockEth1Votes,
|
||||
attestationsPool: cfg.AttestationsPool,
|
||||
exitPool: cfg.ExitPool,
|
||||
slashingsPool: cfg.SlashingsPool,
|
||||
syncService: cfg.SyncService,
|
||||
host: cfg.Host,
|
||||
port: cfg.Port,
|
||||
@@ -241,7 +245,8 @@ func (s *Service) Start() {
|
||||
beaconChainServer := &beacon.Server{
|
||||
Ctx: s.ctx,
|
||||
BeaconDB: s.beaconDB,
|
||||
Pool: s.attestationsPool,
|
||||
AttestationsPool: s.attestationsPool,
|
||||
SlashingsPool: s.slashingsPool,
|
||||
HeadFetcher: s.headFetcher,
|
||||
FinalizationFetcher: s.finalizationFetcher,
|
||||
ParticipationFetcher: s.participationFetcher,
|
||||
|
||||
40
shared/mock/beacon_chain_service_mock.go
generated
40
shared/mock/beacon_chain_service_mock.go
generated
@@ -397,6 +397,46 @@ func (mr *MockBeaconChainClientMockRecorder) StreamValidatorsInfo(arg0 interface
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StreamValidatorsInfo", reflect.TypeOf((*MockBeaconChainClient)(nil).StreamValidatorsInfo), varargs...)
|
||||
}
|
||||
|
||||
// SubmitAttesterSlashing mocks base method
|
||||
func (m *MockBeaconChainClient) SubmitAttesterSlashing(arg0 context.Context, arg1 *v1alpha1.AttesterSlashing, arg2 ...grpc.CallOption) (*v1alpha1.SubmitSlashingResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "SubmitAttesterSlashing", varargs...)
|
||||
ret0, _ := ret[0].(*v1alpha1.SubmitSlashingResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SubmitAttesterSlashing indicates an expected call of SubmitAttesterSlashing
|
||||
func (mr *MockBeaconChainClientMockRecorder) SubmitAttesterSlashing(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitAttesterSlashing", reflect.TypeOf((*MockBeaconChainClient)(nil).SubmitAttesterSlashing), varargs...)
|
||||
}
|
||||
|
||||
// SubmitProposerSlashing mocks base method
|
||||
func (m *MockBeaconChainClient) SubmitProposerSlashing(arg0 context.Context, arg1 *v1alpha1.ProposerSlashing, arg2 ...grpc.CallOption) (*v1alpha1.SubmitSlashingResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "SubmitProposerSlashing", varargs...)
|
||||
ret0, _ := ret[0].(*v1alpha1.SubmitSlashingResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SubmitProposerSlashing indicates an expected call of SubmitProposerSlashing
|
||||
func (mr *MockBeaconChainClientMockRecorder) SubmitProposerSlashing(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitProposerSlashing", reflect.TypeOf((*MockBeaconChainClient)(nil).SubmitProposerSlashing), varargs...)
|
||||
}
|
||||
|
||||
// MockBeaconChain_StreamChainHeadClient is a mock of BeaconChain_StreamChainHeadClient interface
|
||||
type MockBeaconChain_StreamChainHeadClient struct {
|
||||
ctrl *gomock.Controller
|
||||
|
||||
@@ -262,7 +262,7 @@ index 2ce5c34..4cbb276 100644
|
||||
+ bytes signature = 3 [(gogoproto.moretags) = "ssz-size:\"96\""];
|
||||
}
|
||||
diff --git a/eth/v1alpha1/beacon_chain.proto b/eth/v1alpha1/beacon_chain.proto
|
||||
index 5ee000f..0f5f69c 100644
|
||||
index cdac301..945f8b5 100644
|
||||
--- a/eth/v1alpha1/beacon_chain.proto
|
||||
+++ b/eth/v1alpha1/beacon_chain.proto
|
||||
@@ -15,6 +15,7 @@ syntax = "proto3";
|
||||
@@ -273,7 +273,7 @@ index 5ee000f..0f5f69c 100644
|
||||
import "google/api/annotations.proto";
|
||||
import "google/protobuf/empty.proto";
|
||||
import "google/protobuf/any.proto";
|
||||
@@ -344,7 +345,7 @@ message ChainHead {
|
||||
@@ -358,7 +359,7 @@ message ChainHead {
|
||||
uint64 head_epoch = 2;
|
||||
|
||||
// 32 byte merkle tree root of the canonical head block in the beacon node.
|
||||
@@ -282,7 +282,7 @@ index 5ee000f..0f5f69c 100644
|
||||
|
||||
// Most recent slot that contains the finalized block.
|
||||
uint64 finalized_slot = 4;
|
||||
@@ -353,7 +354,7 @@ message ChainHead {
|
||||
@@ -367,7 +368,7 @@ message ChainHead {
|
||||
uint64 finalized_epoch = 5;
|
||||
|
||||
// Most recent 32 byte finalized block root.
|
||||
@@ -291,7 +291,7 @@ index 5ee000f..0f5f69c 100644
|
||||
|
||||
// Most recent slot that contains the justified block.
|
||||
uint64 justified_slot = 7;
|
||||
@@ -362,7 +363,7 @@ message ChainHead {
|
||||
@@ -376,7 +377,7 @@ message ChainHead {
|
||||
uint64 justified_epoch = 8;
|
||||
|
||||
// Most recent 32 byte justified block root.
|
||||
@@ -300,7 +300,7 @@ index 5ee000f..0f5f69c 100644
|
||||
|
||||
// Most recent slot that contains the previous justified block.
|
||||
uint64 previous_justified_slot = 10;
|
||||
@@ -371,7 +372,7 @@ message ChainHead {
|
||||
@@ -385,7 +386,7 @@ message ChainHead {
|
||||
uint64 previous_justified_epoch = 11;
|
||||
|
||||
// Previous 32 byte justified block root.
|
||||
@@ -309,7 +309,7 @@ index 5ee000f..0f5f69c 100644
|
||||
}
|
||||
|
||||
message ListCommitteesRequest {
|
||||
@@ -416,7 +417,7 @@ message ListValidatorBalancesRequest {
|
||||
@@ -430,7 +431,7 @@ message ListValidatorBalancesRequest {
|
||||
|
||||
// Validator 48 byte BLS public keys to filter validators for the given
|
||||
// epoch.
|
||||
@@ -318,7 +318,7 @@ index 5ee000f..0f5f69c 100644
|
||||
|
||||
// Validator indices to filter validators for the given epoch.
|
||||
repeated uint64 indices = 4;
|
||||
@@ -437,7 +438,7 @@ message ValidatorBalances {
|
||||
@@ -451,7 +452,7 @@ message ValidatorBalances {
|
||||
|
||||
message Balance {
|
||||
// Validator's 48 byte BLS public key.
|
||||
@@ -327,7 +327,7 @@ index 5ee000f..0f5f69c 100644
|
||||
|
||||
// Validator's index in the validator set.
|
||||
uint64 index = 2;
|
||||
@@ -486,7 +487,7 @@ message GetValidatorRequest {
|
||||
@@ -500,7 +501,7 @@ message GetValidatorRequest {
|
||||
uint64 index = 1;
|
||||
|
||||
// 48 byte validator public key.
|
||||
@@ -336,7 +336,7 @@ index 5ee000f..0f5f69c 100644
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,26 +529,25 @@ message ActiveSetChanges {
|
||||
@@ -542,26 +543,25 @@ message ActiveSetChanges {
|
||||
uint64 epoch = 1;
|
||||
|
||||
// 48 byte validator public keys that have been activated in the given epoch.
|
||||
@@ -369,7 +369,7 @@ index 5ee000f..0f5f69c 100644
|
||||
|
||||
// Indices of validators ejected in the given epoch.
|
||||
repeated uint64 ejected_indices = 9;
|
||||
@@ -597,11 +597,11 @@ message ValidatorQueue {
|
||||
@@ -611,11 +611,11 @@ message ValidatorQueue {
|
||||
|
||||
// Ordered list of 48 byte public keys awaiting activation. 0th index is the
|
||||
// next key to be processed.
|
||||
@@ -383,7 +383,7 @@ index 5ee000f..0f5f69c 100644
|
||||
}
|
||||
|
||||
message ListValidatorAssignmentsRequest {
|
||||
@@ -613,7 +613,7 @@ message ListValidatorAssignmentsRequest {
|
||||
@@ -627,7 +627,7 @@ message ListValidatorAssignmentsRequest {
|
||||
bool genesis = 2;
|
||||
}
|
||||
// 48 byte validator public keys to filter assignments for the given epoch.
|
||||
@@ -392,7 +392,7 @@ index 5ee000f..0f5f69c 100644
|
||||
|
||||
// Validator indicies to filter assignments for the given epoch.
|
||||
repeated uint64 indices = 4;
|
||||
@@ -648,7 +648,7 @@ message ValidatorAssignments {
|
||||
@@ -662,7 +662,7 @@ message ValidatorAssignments {
|
||||
uint64 proposer_slot = 4;
|
||||
|
||||
// 48 byte BLS public key.
|
||||
|
||||
Reference in New Issue
Block a user