Ensure exits are not for an already exited validator (#4701)

* ensure exits are not for an already exited validator
This commit is contained in:
Preston Van Loon
2020-01-31 17:18:36 -08:00
committed by GitHub
parent 0b2b77c5b0
commit d32493d43b
6 changed files with 30 additions and 9 deletions

View File

@@ -10,6 +10,7 @@ go_library(
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/state:go_default_library",
"//shared/params:go_default_library",
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
],
@@ -21,6 +22,8 @@ go_test(
srcs = ["service_test.go"],
embed = [":go_default_library"],
deps = [
"//beacon-chain/state:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/params:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",

View File

@@ -7,6 +7,7 @@ import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/shared/params"
)
@@ -29,7 +30,7 @@ func NewPool() *Pool {
// PendingExits returns exits that are ready for inclusion at the given slot. This method will not
// return more than the block enforced MaxVoluntaryExits.
func (p *Pool) PendingExits(slot uint64) []*ethpb.SignedVoluntaryExit {
func (p *Pool) PendingExits(state *beaconstate.BeaconState, slot uint64) []*ethpb.SignedVoluntaryExit {
p.lock.RLock()
defer p.lock.RUnlock()
pending := make([]*ethpb.SignedVoluntaryExit, 0)
@@ -37,7 +38,9 @@ func (p *Pool) PendingExits(slot uint64) []*ethpb.SignedVoluntaryExit {
if e.Exit.Epoch > helpers.SlotToEpoch(slot) {
continue
}
pending = append(pending, e)
if v, err := state.ValidatorAtIndexReadOnly(e.Exit.ValidatorIndex); err == nil && v.ExitEpoch() == params.BeaconConfig().FarFutureEpoch {
pending = append(pending, e)
}
}
if len(pending) > int(params.BeaconConfig().MaxVoluntaryExits) {
pending = pending[:params.BeaconConfig().MaxVoluntaryExits]
@@ -47,7 +50,7 @@ func (p *Pool) PendingExits(slot uint64) []*ethpb.SignedVoluntaryExit {
// InsertVoluntaryExit into the pool. This method is a no-op if the pending exit already exists,
// has been included recently, or the validator is already exited.
func (p *Pool) InsertVoluntaryExit(ctx context.Context, validators []*ethpb.Validator, exit *ethpb.SignedVoluntaryExit) {
func (p *Pool) InsertVoluntaryExit(ctx context.Context, state *beaconstate.BeaconState, exit *ethpb.SignedVoluntaryExit) {
p.lock.Lock()
defer p.lock.Unlock()
@@ -57,7 +60,7 @@ func (p *Pool) InsertVoluntaryExit(ctx context.Context, validators []*ethpb.Vali
}
// Has the validator been exited already?
if len(validators) <= int(exit.Exit.ValidatorIndex) || validators[exit.Exit.ValidatorIndex].ExitEpoch != params.BeaconConfig().FarFutureEpoch {
if v, err := state.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex); err != nil || v.ExitEpoch() != params.BeaconConfig().FarFutureEpoch {
return
}

View File

@@ -7,6 +7,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/shared/params"
)
@@ -211,7 +213,11 @@ func TestPool_InsertVoluntaryExit(t *testing.T) {
pending: tt.fields.pending,
included: tt.fields.included,
}
p.InsertVoluntaryExit(ctx, validators, tt.args.exit)
s, err := beaconstate.InitializeFromProtoUnsafe(&p2ppb.BeaconState{Validators: validators})
if err != nil {
t.Fatal(err)
}
p.InsertVoluntaryExit(ctx, s, tt.args.exit)
if len(p.pending) != len(tt.want) {
t.Fatalf("Mismatched lengths of pending list. Got %d, wanted %d.", len(p.pending), len(tt.want))
}
@@ -444,7 +450,11 @@ func TestPool_PendingExits(t *testing.T) {
p := &Pool{
pending: tt.fields.pending,
}
if got := p.PendingExits(tt.args.slot); !reflect.DeepEqual(got, tt.want) {
s, err := beaconstate.InitializeFromProtoUnsafe(&p2ppb.BeaconState{Validators: []*ethpb.Validator{{ExitEpoch: params.BeaconConfig().FarFutureEpoch}}})
if err != nil {
t.Fatal(err)
}
if got := p.PendingExits(s, tt.args.slot); !reflect.DeepEqual(got, tt.want) {
t.Errorf("PendingExits() = %v, want %v", got, tt.want)
}
})

View File

@@ -40,7 +40,7 @@ func (vs *Server) ProposeExit(ctx context.Context, req *ethpb.SignedVoluntaryExi
},
})
vs.ExitPool.InsertVoluntaryExit(ctx, s.Validators(), req)
vs.ExitPool.InsertVoluntaryExit(ctx, s, req)
return &ptypes.Empty{}, vs.P2P.Broadcast(ctx, req)
}

View File

@@ -63,6 +63,11 @@ func (vs *Server) GetBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb
graffiti := bytesutil.ToBytes32(req.Graffiti)
head, err := vs.HeadFetcher.HeadState(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get head state %v", err)
}
blk := &ethpb.BeaconBlock{
Slot: req.Slot,
ParentRoot: parentRoot[:],
@@ -75,7 +80,7 @@ func (vs *Server) GetBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb
// TODO(2766): Implement rest of the retrievals for beacon block operations
ProposerSlashings: []*ethpb.ProposerSlashing{},
AttesterSlashings: []*ethpb.AttesterSlashing{},
VoluntaryExits: vs.ExitPool.PendingExits(req.Slot),
VoluntaryExits: vs.ExitPool.PendingExits(head, req.Slot),
Graffiti: graffiti[:],
},
}

View File

@@ -12,7 +12,7 @@ func (r *Service) voluntaryExitSubscriber(ctx context.Context, msg proto.Message
if err != nil {
return err
}
r.exitPool.InsertVoluntaryExit(ctx, s.Validators(), msg.(*ethpb.SignedVoluntaryExit))
r.exitPool.InsertVoluntaryExit(ctx, s, msg.(*ethpb.SignedVoluntaryExit))
return nil
}