mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -05:00
validator client: adding in get duties v2 (#15380)
* adding in get duties v2 * gaz * missed definition * removing comment * updating description
This commit is contained in:
3
changelog/james-prysm_validator-duties-v2.md
Normal file
3
changelog/james-prysm_validator-duties-v2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Added
|
||||
|
||||
- Added feature flag for validator client to use get duties v2.
|
||||
@@ -50,6 +50,7 @@ type Flags struct {
|
||||
EnableHistoricalSpaceRepresentation bool // EnableHistoricalSpaceRepresentation enables the saving of registry validators in separate buckets to save space
|
||||
EnableBeaconRESTApi bool // EnableBeaconRESTApi enables experimental usage of the beacon REST API by the validator when querying a beacon node
|
||||
EnableExperimentalAttestationPool bool // EnableExperimentalAttestationPool enables an experimental attestation pool design.
|
||||
EnableDutiesV2 bool // EnableDutiesV2 sets validator client to use the get Duties V2 endpoint
|
||||
// Logging related toggles.
|
||||
DisableGRPCConnectionLogs bool // Disables logging when a new grpc client has connected.
|
||||
EnableFullSSZDataLogging bool // Enables logging for full ssz data on rejected gossip messages
|
||||
@@ -334,6 +335,10 @@ func ConfigureValidator(ctx *cli.Context) error {
|
||||
logEnabled(EnableBeaconRESTApi)
|
||||
cfg.EnableBeaconRESTApi = true
|
||||
}
|
||||
if ctx.Bool(EnableDutiesV2.Name) {
|
||||
logEnabled(EnableDutiesV2)
|
||||
cfg.EnableDutiesV2 = true
|
||||
}
|
||||
cfg.KeystoreImportDebounceInterval = ctx.Duration(dynamicKeyReloadDebounceInterval.Name)
|
||||
Init(cfg)
|
||||
return nil
|
||||
|
||||
@@ -188,6 +188,12 @@ var (
|
||||
Name: "blacklist-roots",
|
||||
Usage: "A comma-separatted list of 0x-prefixed hexstrings. Declares blocks with the given blockroots to be invalid. It downscores peers that send these blocks.",
|
||||
}
|
||||
|
||||
// EnableDutiesV2 sets the validator client to use the get duties v2 grpc endpoint
|
||||
EnableDutiesV2 = &cli.BoolFlag{
|
||||
Name: "enable-duties-v2",
|
||||
Usage: "Forces use of get duties v2 endpoint.",
|
||||
}
|
||||
)
|
||||
|
||||
// devModeFlags holds list of flags that are set when development mode is on.
|
||||
@@ -208,6 +214,7 @@ var ValidatorFlags = append(deprecatedFlags, []cli.Flag{
|
||||
EnableMinimalSlashingProtection,
|
||||
enableDoppelGangerProtection,
|
||||
EnableBeaconRESTApi,
|
||||
EnableDutiesV2,
|
||||
}...)
|
||||
|
||||
// E2EValidatorFlags contains a list of the validator feature flags to be tested in E2E.
|
||||
|
||||
@@ -17,6 +17,7 @@ go_library(
|
||||
"//api/server/structs:go_default_library",
|
||||
"//beacon-chain/rpc/eth/helpers:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/validator:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
@@ -29,6 +30,8 @@ go_library(
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/OffchainLabs/prysm/v6/api/client"
|
||||
eventClient "github.com/OffchainLabs/prysm/v6/api/client/event"
|
||||
"github.com/OffchainLabs/prysm/v6/api/server/structs"
|
||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
||||
@@ -18,6 +19,8 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type grpcValidatorClient struct {
|
||||
@@ -26,16 +29,33 @@ type grpcValidatorClient struct {
|
||||
}
|
||||
|
||||
func (c *grpcValidatorClient) Duties(ctx context.Context, in *ethpb.DutiesRequest) (*ethpb.ValidatorDutiesContainer, error) {
|
||||
dutiesResponse, err := c.beaconNodeValidatorClient.GetDuties(ctx, in)
|
||||
if features.Get().EnableDutiesV2 {
|
||||
dutiesResponse, err := c.beaconNodeValidatorClient.GetDutiesV2(ctx, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if status.Code(err) == codes.Unimplemented {
|
||||
log.Warn("beaconNodeValidatorClient.GetDutiesV2() returned status code unavailable, falling back to GetDuties")
|
||||
return c.getDuties(ctx, in)
|
||||
}
|
||||
return toValidatorDutiesContainer(dutiesResponse)
|
||||
return nil, errors.Wrap(
|
||||
client.ErrConnectionIssue,
|
||||
errors.Wrap(err, "getDutiesV2").Error(),
|
||||
)
|
||||
}
|
||||
return toValidatorDutiesContainerV2(dutiesResponse)
|
||||
}
|
||||
return c.getDuties(ctx, in)
|
||||
}
|
||||
|
||||
func (c *grpcValidatorClient) DutiesV2(ctx context.Context, in *ethpb.DutiesRequest) (*ethpb.ValidatorDutiesContainer, error) {
|
||||
// TODO: update to v2 get duties in separate PR, used to satisfy interface
|
||||
return nil, errors.New("not implemented")
|
||||
// getDuties is calling the v1 of get duties
|
||||
func (c *grpcValidatorClient) getDuties(ctx context.Context, in *ethpb.DutiesRequest) (*ethpb.ValidatorDutiesContainer, error) {
|
||||
dutiesResponse, err := c.beaconNodeValidatorClient.GetDuties(ctx, in)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(
|
||||
client.ErrConnectionIssue,
|
||||
errors.Wrap(err, "getDuties").Error(),
|
||||
)
|
||||
}
|
||||
return toValidatorDutiesContainer(dutiesResponse)
|
||||
}
|
||||
|
||||
func toValidatorDutiesContainer(dutiesResponse *ethpb.DutiesResponse) (*ethpb.ValidatorDutiesContainer, error) {
|
||||
@@ -87,6 +107,46 @@ func toValidatorDuty(duty *ethpb.DutiesResponse_Duty) (*ethpb.ValidatorDuty, err
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toValidatorDutiesContainerV2(dutiesResponse *ethpb.DutiesV2Response) (*ethpb.ValidatorDutiesContainer, error) {
|
||||
currentDuties := make([]*ethpb.ValidatorDuty, len(dutiesResponse.CurrentEpochDuties))
|
||||
for i, cd := range dutiesResponse.CurrentEpochDuties {
|
||||
duty, err := toValidatorDutyV2(cd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
currentDuties[i] = duty
|
||||
}
|
||||
nextDuties := make([]*ethpb.ValidatorDuty, len(dutiesResponse.NextEpochDuties))
|
||||
for i, nd := range dutiesResponse.NextEpochDuties {
|
||||
duty, err := toValidatorDutyV2(nd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nextDuties[i] = duty
|
||||
}
|
||||
return ðpb.ValidatorDutiesContainer{
|
||||
PrevDependentRoot: dutiesResponse.PreviousDutyDependentRoot,
|
||||
CurrDependentRoot: dutiesResponse.CurrentDutyDependentRoot,
|
||||
CurrentEpochDuties: currentDuties,
|
||||
NextEpochDuties: nextDuties,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toValidatorDutyV2(duty *ethpb.DutiesV2Response_Duty) (*ethpb.ValidatorDuty, error) {
|
||||
return ðpb.ValidatorDuty{
|
||||
CommitteeLength: duty.CommitteeLength,
|
||||
CommitteeIndex: duty.CommitteeIndex,
|
||||
CommitteesAtSlot: duty.CommitteesAtSlot, // GRPC doesn't use this value though
|
||||
ValidatorCommitteeIndex: duty.ValidatorCommitteeIndex,
|
||||
AttesterSlot: duty.AttesterSlot,
|
||||
ProposerSlots: duty.ProposerSlots,
|
||||
PublicKey: bytesutil.SafeCopyBytes(duty.PublicKey),
|
||||
Status: duty.Status,
|
||||
ValidatorIndex: duty.ValidatorIndex,
|
||||
IsSyncCommittee: duty.IsSyncCommittee,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *grpcValidatorClient) CheckDoppelGanger(ctx context.Context, in *ethpb.DoppelGangerRequest) (*ethpb.DoppelGangerResponse, error) {
|
||||
return c.beaconNodeValidatorClient.CheckDoppelGanger(ctx, in)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
// toValidatorDutiesContainer is assumed to be available from your package, returning a *v1alpha1.ValidatorDutiesContainer.
|
||||
func TestToValidatorDutiesContainer_HappyPath(t *testing.T) {
|
||||
// Create a mock DutiesResponse with current and next duties.
|
||||
dutiesResp := ð.DutiesResponse{
|
||||
@@ -71,6 +70,59 @@ func TestToValidatorDutiesContainer_HappyPath(t *testing.T) {
|
||||
assert.DeepEqual(t, firstNextDuty.ProposerSlots, expectedNextDuty.ProposerSlots)
|
||||
}
|
||||
|
||||
func TestToValidatorDutiesContainerV2_HappyPath(t *testing.T) {
|
||||
// Create a mock DutiesResponse with current and next duties.
|
||||
dutiesResp := ð.DutiesV2Response{
|
||||
CurrentEpochDuties: []*eth.DutiesV2Response_Duty{
|
||||
{
|
||||
CommitteeLength: 2,
|
||||
CommitteeIndex: 4,
|
||||
ValidatorCommitteeIndex: 1,
|
||||
AttesterSlot: 200,
|
||||
ProposerSlots: []primitives.Slot{400},
|
||||
PublicKey: []byte{0xAA, 0xBB},
|
||||
Status: eth.ValidatorStatus_ACTIVE,
|
||||
ValidatorIndex: 101,
|
||||
IsSyncCommittee: false,
|
||||
CommitteesAtSlot: 2,
|
||||
},
|
||||
},
|
||||
NextEpochDuties: []*eth.DutiesV2Response_Duty{
|
||||
{
|
||||
CommitteeLength: 2,
|
||||
CommitteeIndex: 8,
|
||||
ValidatorCommitteeIndex: 1,
|
||||
AttesterSlot: 600,
|
||||
ProposerSlots: []primitives.Slot{700, 701},
|
||||
PublicKey: []byte{0xCC, 0xDD},
|
||||
Status: eth.ValidatorStatus_ACTIVE,
|
||||
ValidatorIndex: 301,
|
||||
IsSyncCommittee: true,
|
||||
CommitteesAtSlot: 3,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gotContainer, err := toValidatorDutiesContainerV2(dutiesResp)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Validate we have the correct number of duties in current and next epochs.
|
||||
assert.Equal(t, len(gotContainer.CurrentEpochDuties), len(dutiesResp.CurrentEpochDuties))
|
||||
assert.Equal(t, len(gotContainer.NextEpochDuties), len(dutiesResp.NextEpochDuties))
|
||||
|
||||
firstCurrentDuty := gotContainer.CurrentEpochDuties[0]
|
||||
expectedCurrentDuty := dutiesResp.CurrentEpochDuties[0]
|
||||
assert.DeepEqual(t, firstCurrentDuty.PublicKey, expectedCurrentDuty.PublicKey)
|
||||
assert.Equal(t, firstCurrentDuty.ValidatorIndex, expectedCurrentDuty.ValidatorIndex)
|
||||
assert.DeepEqual(t, firstCurrentDuty.ProposerSlots, expectedCurrentDuty.ProposerSlots)
|
||||
|
||||
firstNextDuty := gotContainer.NextEpochDuties[0]
|
||||
expectedNextDuty := dutiesResp.NextEpochDuties[0]
|
||||
assert.DeepEqual(t, firstNextDuty.PublicKey, expectedNextDuty.PublicKey)
|
||||
assert.Equal(t, firstNextDuty.ValidatorIndex, expectedNextDuty.ValidatorIndex)
|
||||
assert.DeepEqual(t, firstNextDuty.ProposerSlots, expectedNextDuty.ProposerSlots)
|
||||
}
|
||||
|
||||
func TestWaitForChainStart_StreamSetupFails(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
Reference in New Issue
Block a user