ETH2 APIs: Handle invalid validator status as error (#8946)

* Handle invalid validator status as error

* Change text

* Fix review comments

* Remove nil status check

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
Ivan Martinez
2021-05-27 02:44:36 -04:00
committed by GitHub
parent d5f4385525
commit e97f6cfdbf
2 changed files with 108 additions and 43 deletions

View File

@@ -59,8 +59,14 @@ func (bs *Server) ListValidators(ctx context.Context, req *ethpb.StateValidators
epoch := helpers.SlotToEpoch(state.Slot())
filteredVals := make([]*ethpb.ValidatorContainer, 0, len(valContainers))
for _, vc := range valContainers {
valStatus := validatorStatus(vc.Validator, epoch)
valSubStatus := validatorSubStatus(vc.Validator, epoch)
valStatus, err := validatorStatus(vc.Validator, epoch)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get validator status: %v", err)
}
valSubStatus, err := validatorSubStatus(vc.Validator, epoch)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get validator sub status: %v", err)
}
if filterStatus[valStatus] || filterStatus[valSubStatus] {
filteredVals = append(filteredVals, vc)
}
@@ -150,10 +156,14 @@ func valContainersByRequestIds(state iface.BeaconState, validatorIds [][]byte) (
valContainers = make([]*ethpb.ValidatorContainer, len(allValidators))
for i, validator := range allValidators {
v1Validator := migration.V1Alpha1ValidatorToV1(validator)
subStatus, err := validatorSubStatus(v1Validator, epoch)
if err != nil {
return nil, fmt.Errorf("could not get validator sub status: %v", err)
}
valContainers[i] = &ethpb.ValidatorContainer{
Index: types.ValidatorIndex(i),
Balance: allBalances[i],
Status: validatorSubStatus(v1Validator, epoch),
Status: subStatus,
Validator: v1Validator,
}
}
@@ -175,10 +185,14 @@ func valContainersByRequestIds(state iface.BeaconState, validatorIds [][]byte) (
valIndex = types.ValidatorIndex(index)
}
v1Validator := migration.V1Alpha1ValidatorToV1(allValidators[valIndex])
subStatus, err := validatorSubStatus(v1Validator, epoch)
if err != nil {
return nil, fmt.Errorf("could not get validator sub status: %v", err)
}
valContainers[i] = &ethpb.ValidatorContainer{
Index: valIndex,
Balance: allBalances[valIndex],
Status: validatorSubStatus(v1Validator, epoch),
Status: subStatus,
Validator: v1Validator,
}
}
@@ -186,59 +200,63 @@ func valContainersByRequestIds(state iface.BeaconState, validatorIds [][]byte) (
return valContainers, nil
}
func validatorStatus(validator *ethpb.Validator, epoch types.Epoch) ethpb.ValidatorStatus {
switch validatorSubStatus(validator, epoch) {
case ethpb.ValidatorStatus_PENDING_INITIALIZED, ethpb.ValidatorStatus_PENDING_QUEUED:
return ethpb.ValidatorStatus_PENDING
case ethpb.ValidatorStatus_ACTIVE_ONGOING, ethpb.ValidatorStatus_ACTIVE_SLASHED, ethpb.ValidatorStatus_ACTIVE_EXITING:
return ethpb.ValidatorStatus_ACTIVE
case ethpb.ValidatorStatus_EXITED_UNSLASHED, ethpb.ValidatorStatus_EXITED_SLASHED:
return ethpb.ValidatorStatus_EXITED
case ethpb.ValidatorStatus_WITHDRAWAL_POSSIBLE, ethpb.ValidatorStatus_WITHDRAWAL_DONE:
return ethpb.ValidatorStatus_WITHDRAWAL
func validatorStatus(validator *ethpb.Validator, epoch types.Epoch) (ethpb.ValidatorStatus, error) {
valStatus, err := validatorSubStatus(validator, epoch)
if err != nil {
return 0, errors.Wrap(err, "could not get sub status")
}
return 0
switch valStatus {
case ethpb.ValidatorStatus_PENDING_INITIALIZED, ethpb.ValidatorStatus_PENDING_QUEUED:
return ethpb.ValidatorStatus_PENDING, nil
case ethpb.ValidatorStatus_ACTIVE_ONGOING, ethpb.ValidatorStatus_ACTIVE_SLASHED, ethpb.ValidatorStatus_ACTIVE_EXITING:
return ethpb.ValidatorStatus_ACTIVE, nil
case ethpb.ValidatorStatus_EXITED_UNSLASHED, ethpb.ValidatorStatus_EXITED_SLASHED:
return ethpb.ValidatorStatus_EXITED, nil
case ethpb.ValidatorStatus_WITHDRAWAL_POSSIBLE, ethpb.ValidatorStatus_WITHDRAWAL_DONE:
return ethpb.ValidatorStatus_WITHDRAWAL, nil
}
return 0, errors.New("invalid validator state")
}
func validatorSubStatus(validator *ethpb.Validator, epoch types.Epoch) ethpb.ValidatorStatus {
func validatorSubStatus(validator *ethpb.Validator, epoch types.Epoch) (ethpb.ValidatorStatus, error) {
farFutureEpoch := params.BeaconConfig().FarFutureEpoch
// Pending.
if validator.ActivationEpoch > epoch {
if validator.ActivationEligibilityEpoch == farFutureEpoch {
return ethpb.ValidatorStatus_PENDING_INITIALIZED
} else if validator.ActivationEligibilityEpoch < farFutureEpoch && validator.ActivationEpoch > epoch {
return ethpb.ValidatorStatus_PENDING_QUEUED
return ethpb.ValidatorStatus_PENDING_INITIALIZED, nil
} else if validator.ActivationEligibilityEpoch < farFutureEpoch {
return ethpb.ValidatorStatus_PENDING_QUEUED, nil
}
}
// Active.
if validator.ActivationEpoch <= epoch && epoch < validator.ExitEpoch {
if validator.ExitEpoch == farFutureEpoch {
return ethpb.ValidatorStatus_ACTIVE_ONGOING
return ethpb.ValidatorStatus_ACTIVE_ONGOING, nil
} else if validator.ExitEpoch < farFutureEpoch {
if validator.Slashed {
return ethpb.ValidatorStatus_ACTIVE_SLASHED
return ethpb.ValidatorStatus_ACTIVE_SLASHED, nil
}
return ethpb.ValidatorStatus_ACTIVE_EXITING
return ethpb.ValidatorStatus_ACTIVE_EXITING, nil
}
}
// Exited.
if validator.ExitEpoch <= epoch && epoch < validator.WithdrawableEpoch {
if validator.Slashed {
return ethpb.ValidatorStatus_EXITED_SLASHED
return ethpb.ValidatorStatus_EXITED_SLASHED, nil
}
return ethpb.ValidatorStatus_EXITED_UNSLASHED
return ethpb.ValidatorStatus_EXITED_UNSLASHED, nil
}
if validator.WithdrawableEpoch <= epoch {
if validator.EffectiveBalance != 0 {
return ethpb.ValidatorStatus_WITHDRAWAL_POSSIBLE
return ethpb.ValidatorStatus_WITHDRAWAL_POSSIBLE, nil
} else {
return ethpb.ValidatorStatus_WITHDRAWAL_DONE
return ethpb.ValidatorStatus_WITHDRAWAL_DONE, nil
}
}
return 0
return 0, errors.New("invalid validator state")
}

View File

@@ -220,36 +220,48 @@ func TestListValidators_Status(t *testing.T) {
farFutureEpoch := params.BeaconConfig().FarFutureEpoch
validators := []*ethpb_alpha.Validator{
// Pending initialized.
{
ActivationEpoch: farFutureEpoch,
ActivationEligibilityEpoch: farFutureEpoch,
},
// Pending queued.
{
ActivationEpoch: 10,
ActivationEligibilityEpoch: 4,
},
// Active ongoing.
{
ActivationEpoch: 0,
ExitEpoch: farFutureEpoch,
},
// Active slashed.
{
ActivationEpoch: 0,
ExitEpoch: 30,
Slashed: true,
},
// Active exiting.
{
ActivationEpoch: 3,
ExitEpoch: 30,
Slashed: false,
},
// Exit slashed (at epoch 35).
{
ActivationEpoch: 3,
ExitEpoch: 30,
WithdrawableEpoch: 40,
Slashed: true,
},
// Exit unslashed (at epoch 35).
{
ActivationEpoch: 3,
ExitEpoch: 30,
WithdrawableEpoch: 40,
Slashed: false,
},
// Withdrawable (at epoch 45).
{
ActivationEpoch: 3,
ExitEpoch: 30,
@@ -257,6 +269,7 @@ func TestListValidators_Status(t *testing.T) {
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
Slashed: false,
},
// Withdrawal done (at epoch 45).
{
ActivationEpoch: 3,
ExitEpoch: 30,
@@ -284,7 +297,8 @@ func TestListValidators_Status(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, len(resp.Data), 8192+2 /* 2 active */)
for _, datum := range resp.Data {
status := validatorStatus(datum.Validator, 0)
status, err := validatorStatus(datum.Validator, 0)
require.NoError(t, err)
require.Equal(
t,
true,
@@ -314,7 +328,8 @@ func TestListValidators_Status(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, len(resp.Data), 8192+1 /* 1 active_ongoing */)
for _, datum := range resp.Data {
status := validatorSubStatus(datum.Validator, 0)
status, err := validatorSubStatus(datum.Validator, 0)
require.NoError(t, err)
require.Equal(
t,
true,
@@ -343,7 +358,8 @@ func TestListValidators_Status(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 4 /* 4 exited */, len(resp.Data))
for _, datum := range resp.Data {
status := validatorStatus(datum.Validator, 35)
status, err := validatorStatus(datum.Validator, 35)
require.NoError(t, err)
require.Equal(
t,
true,
@@ -371,7 +387,8 @@ func TestListValidators_Status(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 4 /* 4 exited */, len(resp.Data))
for _, datum := range resp.Data {
status := validatorSubStatus(datum.Validator, 35)
status, err := validatorSubStatus(datum.Validator, 35)
require.NoError(t, err)
require.Equal(
t,
true,
@@ -399,8 +416,10 @@ func TestListValidators_Status(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 2 /* 1 pending, 1 exited */, len(resp.Data))
for _, datum := range resp.Data {
status := validatorStatus(datum.Validator, 35)
subStatus := validatorSubStatus(datum.Validator, 35)
status, err := validatorStatus(datum.Validator, 35)
require.NoError(t, err)
subStatus, err := validatorSubStatus(datum.Validator, 35)
require.NoError(t, err)
require.Equal(
t,
true,
@@ -650,9 +669,10 @@ func Test_validatorStatus(t *testing.T) {
epoch types.Epoch
}
tests := []struct {
name string
args args
want ethpb.ValidatorStatus
name string
args args
want ethpb.ValidatorStatus
wantErr bool
}{
{
name: "pending initialized",
@@ -665,6 +685,17 @@ func Test_validatorStatus(t *testing.T) {
},
want: ethpb.ValidatorStatus_PENDING,
},
{
name: "pending queued",
args: args{
validator: &ethpb.Validator{
ActivationEpoch: 10,
ActivationEligibilityEpoch: 2,
},
epoch: types.Epoch(5),
},
want: ethpb.ValidatorStatus_PENDING,
},
{
name: "active ongoing",
args: args{
@@ -757,8 +788,10 @@ func Test_validatorStatus(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := validatorStatus(tt.args.validator, tt.args.epoch); got != tt.want {
t.Errorf("validatorStatus() = %v, want %v", got, tt.want)
got, err := validatorStatus(tt.args.validator, tt.args.epoch)
require.NoError(t, err)
if got != tt.want {
t.Errorf("validatorStatus() got = %v, want %v", got, tt.want)
}
})
}
@@ -772,9 +805,10 @@ func Test_validatorSubStatus(t *testing.T) {
epoch types.Epoch
}
tests := []struct {
name string
args args
want ethpb.ValidatorStatus
name string
args args
want ethpb.ValidatorStatus
wantErr bool
}{
{
name: "pending initialized",
@@ -787,6 +821,17 @@ func Test_validatorSubStatus(t *testing.T) {
},
want: ethpb.ValidatorStatus_PENDING_INITIALIZED,
},
{
name: "pending queued",
args: args{
validator: &ethpb.Validator{
ActivationEpoch: 10,
ActivationEligibilityEpoch: 2,
},
epoch: types.Epoch(5),
},
want: ethpb.ValidatorStatus_PENDING_QUEUED,
},
{
name: "active ongoing",
args: args{
@@ -879,8 +924,10 @@ func Test_validatorSubStatus(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := validatorSubStatus(tt.args.validator, tt.args.epoch); got != tt.want {
t.Errorf("validatorSubStatus() = %v, want %v", got, tt.want)
got, err := validatorSubStatus(tt.args.validator, tt.args.epoch)
require.NoError(t, err)
if got != tt.want {
t.Errorf("validatorSubStatus() got = %v, want %v", got, tt.want)
}
})
}