Improve validator status method (#4032)

* Cleanup validatorStatus

* gaz

* fix tests

* fix tests
This commit is contained in:
Preston Van Loon
2019-11-18 16:47:02 -08:00
committed by GitHub
parent ab756ec094
commit 13207a9de5
4 changed files with 53 additions and 66 deletions

View File

@@ -22,8 +22,10 @@ go_library(
"//proto/eth/v1alpha1:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/params:go_default_library",
"//shared/traceutil:go_default_library",
"@com_github_gogo_protobuf//types:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
"@org_golang_google_grpc//codes:go_default_library",
"@org_golang_google_grpc//status:go_default_library",
],

View File

@@ -149,11 +149,6 @@ func TestWaitForActivation_ValidatorOriginallyExists(t *testing.T) {
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: pubKey1,
},
{
ActivationEpoch: 0,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: pubKey2,
},
},
}
block := blk.NewGenesisBlock([]byte{})

View File

@@ -11,8 +11,12 @@ import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/traceutil"
"go.opencensus.io/trace"
)
var errPubkeyDoesNotExist = errors.New("pubkey does not exist")
// ValidatorStatus returns the validator status of the current epoch.
// The status response can be one of the following:
// PENDING_ACTIVE - validator is waiting to get activated.
@@ -62,54 +66,53 @@ func (vs *Server) multipleValidatorStatus(
}
func (vs *Server) validatorStatus(ctx context.Context, pubKey []byte, headState *pbp2p.BeaconState) *pb.ValidatorStatusResponse {
ctx, span := trace.StartSpan(ctx, "validatorServer.validatorStatus")
defer span.End()
resp := &pb.ValidatorStatusResponse{
Status: pb.ValidatorStatus_UNKNOWN_STATUS,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
}
vStatus, idx, err := vs.retrieveStatusFromState(ctx, pubKey, headState)
if err != nil && err != errPubkeyDoesNotExist {
traceutil.AnnotateError(span, err)
return resp
}
resp.Status = vStatus
if err != errPubkeyDoesNotExist {
resp.ActivationEpoch = headState.Validators[idx].ActivationEpoch
}
// If no connection to ETH1, the deposit block number or position in queue cannot be determined.
if !vs.Eth1InfoFetcher.IsConnectedToETH1() {
vStatus, idx, err := vs.retrieveStatusFromState(ctx, pubKey, headState)
if err != nil {
return &pb.ValidatorStatusResponse{
Status: pb.ValidatorStatus_UNKNOWN_STATUS,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
}
}
statusResp := &pb.ValidatorStatusResponse{
Status: vStatus,
}
if vStatus == pb.ValidatorStatus_ACTIVE {
statusResp.ActivationEpoch = headState.Validators[idx].ActivationEpoch
}
return statusResp
log.Warn("Not connected to ETH1. Cannot determine validator ETH1 deposit block number")
return resp
}
_, eth1BlockNumBigInt := vs.DepositFetcher.DepositByPubkey(ctx, pubKey)
if eth1BlockNumBigInt == nil {
return &pb.ValidatorStatusResponse{
Status: pb.ValidatorStatus_UNKNOWN_STATUS,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
}
if eth1BlockNumBigInt == nil { // No deposit found in ETH1.
return resp
}
statusResp := &pb.ValidatorStatusResponse{
Status: pb.ValidatorStatus_DEPOSIT_RECEIVED,
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
Eth1DepositBlockNumber: eth1BlockNumBigInt.Uint64(),
if resp.Status == pb.ValidatorStatus_UNKNOWN_STATUS {
resp.Status = pb.ValidatorStatus_DEPOSIT_RECEIVED
}
resp.Eth1DepositBlockNumber = eth1BlockNumBigInt.Uint64()
depositBlockSlot, err := vs.depositBlockSlot(ctx, headState.Slot, eth1BlockNumBigInt, headState)
if err != nil {
return statusResp
return resp
}
statusResp.DepositInclusionSlot = depositBlockSlot
vStatus, idx, err := vs.retrieveStatusFromState(ctx, pubKey, headState)
if err != nil {
return statusResp
}
statusResp.Status = vStatus
resp.DepositInclusionSlot = depositBlockSlot
if vStatus == pb.ValidatorStatus_ACTIVE {
statusResp.ActivationEpoch = headState.Validators[idx].ActivationEpoch
return statusResp
// If validator has been activated at any point, they are not in the queue so we can return
// the request early. Additionally, if idx is zero (default return value) then we know this
// validator cannot be in the queue either.
if resp.ActivationEpoch != params.BeaconConfig().FarFutureEpoch || idx == 0 {
return resp
}
var queuePosition uint64
var lastActivatedValidatorIdx uint64
for j := len(headState.Validators) - 1; j >= 0; j-- {
if helpers.IsActiveValidator(headState.Validators[j], helpers.CurrentEpoch(headState)) {
@@ -118,14 +121,11 @@ func (vs *Server) validatorStatus(ctx context.Context, pubKey []byte, headState
}
}
// Our position in the activation queue is the above index - our validator index.
queuePosition = idx - lastActivatedValidatorIdx
return &pb.ValidatorStatusResponse{
Status: vStatus,
Eth1DepositBlockNumber: eth1BlockNumBigInt.Uint64(),
PositionInActivationQueue: queuePosition,
DepositInclusionSlot: depositBlockSlot,
ActivationEpoch: headState.Validators[idx].ActivationEpoch,
if lastActivatedValidatorIdx > idx {
resp.PositionInActivationQueue = idx - lastActivatedValidatorIdx
}
return resp
}
func (vs *Server) retrieveStatusFromState(ctx context.Context, pubKey []byte,
@@ -137,8 +137,8 @@ func (vs *Server) retrieveStatusFromState(ctx context.Context, pubKey []byte,
if err != nil {
return pb.ValidatorStatus(0), 0, err
}
if !ok {
return pb.ValidatorStatus(0), 0, errors.New("pubkey does not exist")
if !ok || int(idx) >= len(headState.Validators) {
return pb.ValidatorStatus(0), 0, errPubkeyDoesNotExist
}
return vs.assignmentStatus(idx, headState), idx, nil
}

View File

@@ -524,6 +524,7 @@ func TestValidatorStatus_UnknownStatus(t *testing.T) {
Slot: 0,
},
},
BeaconDB: db,
}
req := &pb.ValidatorIndexRequest{
PublicKey: pubKey,
@@ -543,27 +544,19 @@ func TestMultipleValidatorStatus_OK(t *testing.T) {
ctx := context.Background()
pubKeys := [][]byte{{'A'}, {'B'}, {'C'}}
if err := db.SaveValidatorIndex(ctx, bytesutil.ToBytes48(pubKeys[0]), 0); err != nil {
t.Fatalf("Could not save validator index: %v", err)
}
if err := db.SaveValidatorIndex(ctx, bytesutil.ToBytes48(pubKeys[1]), 0); err != nil {
t.Fatalf("Could not save validator index: %v", err)
}
beaconState := &pbp2p.BeaconState{
Slot: 4000,
Validators: []*ethpb.Validator{{
ActivationEpoch: 0,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: pubKeys[0]},
Validators: []*ethpb.Validator{
{
ActivationEpoch: 0,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: pubKeys[1]},
PublicKey: pubKeys[0],
},
{
ActivationEpoch: 0,
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
PublicKey: pubKeys[2]},
PublicKey: pubKeys[1],
},
},
}
block := blk.NewGenesisBlock([]byte{})
@@ -606,9 +599,6 @@ func TestMultipleValidatorStatus_OK(t *testing.T) {
if err := db.SaveValidatorIndex(ctx, bytesutil.ToBytes48(pubKeys[1]), 1); err != nil {
t.Fatalf("could not save validator index: %v", err)
}
if err := db.SaveValidatorIndex(ctx, bytesutil.ToBytes48(pubKeys[2]), 2); err != nil {
t.Fatalf("could not save validator index: %v", err)
}
vs := &Server{
BeaconDB: db,
Ctx: context.Background(),
@@ -631,12 +621,12 @@ func TestMultipleValidatorStatus_OK(t *testing.T) {
response[0].PublicKey, response[0].Status.Status.String())
}
if response[1].Status.Status == pb.ValidatorStatus_ACTIVE {
if response[1].Status.Status != pb.ValidatorStatus_ACTIVE {
t.Errorf("Validator with pubkey %#x was activated when not supposed to",
response[1].PublicKey)
}
if response[2].Status.Status != pb.ValidatorStatus_ACTIVE {
if response[2].Status.Status != pb.ValidatorStatus_DEPOSIT_RECEIVED {
t.Errorf("Validator with pubkey %#x is not activated and instead has this status: %s",
response[2].PublicKey, response[2].Status.Status.String())
}