Fix #11948 and reduces call to GetFeeRecipientByPubKey only in ListFeeRecipientByPubkey in nothing is defined in VC (#11970)

* Fix #11948 and reduces call to `GetFeeRecipientByPubKey` only in `ListFeeRecipientByPubkey` in nothing is defined in VC

* Fix typo
This commit is contained in:
Manu NALEPA
2023-02-14 05:53:54 +01:00
committed by GitHub
parent 791110f795
commit 93298dfc56
14 changed files with 1414 additions and 288 deletions

View File

@@ -25,8 +25,6 @@ import (
"google.golang.org/grpc/status"
)
const nonExistantPublicKey = "0x0"
// ListKeystores implements the standard validator key management API.
func (s *Server) ListKeystores(
ctx context.Context, _ *empty.Empty,
@@ -426,52 +424,44 @@ func (s *Server) SetGasLimit(ctx context.Context, req *ethpbservice.SetGasLimitR
if s.validatorService == nil {
return nil, status.Error(codes.FailedPrecondition, "Validator service not ready")
}
validatorKey := req.Pubkey
if err := validatePublicKey(validatorKey); err != nil {
return nil, status.Error(codes.FailedPrecondition, err.Error())
}
defaultOption := validatorServiceConfig.DefaultProposerOption()
var pBuilderConfig *validatorServiceConfig.BuilderConfig
if s.validatorService.ProposerSettings() != nil &&
s.validatorService.ProposerSettings().DefaultConfig != nil &&
s.validatorService.ProposerSettings().DefaultConfig.BuilderConfig != nil {
// Make a copy of BuildConfig from DefaultConfig (thus "*" then "&"), so when we change GasLimit, we do not mess up with
// Make a copy of BuilderConfig from DefaultConfig (thus "*" then "&"), so when we change GasLimit, we do not mess up with
// "DefaultConfig.BuilderConfig".
bo := *s.validatorService.ProposerSettings().DefaultConfig.BuilderConfig
pBuilderConfig = &bo
pBuilderConfig.GasLimit = validatorServiceConfig.Uint64(req.GasLimit)
} else {
// No default BuildConfig to copy from, just create one and set "GasLimit", but keep "Enabled" to "false".
pBuilderConfig = &validatorServiceConfig.BuilderConfig{Enabled: false, GasLimit: validatorServiceConfig.Uint64(req.GasLimit)}
// No default BuilderConfig to copy from, just create one and set "GasLimit", but keep "Enabled" to "false".
pBuilderConfig = &validatorServiceConfig.BuilderConfig{
Enabled: false,
GasLimit: validatorServiceConfig.Uint64(req.GasLimit),
Relays: []string{},
}
}
pOption := validatorServiceConfig.DefaultProposerOption()
// "pOption.BuildConfig" is nil from "validatorServiceConfig.DefaultProposerOption()", so set it.
pOption.BuilderConfig = pBuilderConfig
pOption := validatorServiceConfig.ProposerOption{
FeeRecipientConfig: nil,
BuilderConfig: pBuilderConfig,
}
if s.validatorService.ProposerSettings() == nil {
// get the default fee recipient defined with an invalid public key from beacon node
resp, err := s.beaconNodeValidatorClient.GetFeeRecipientByPubKey(ctx, &eth.FeeRecipientByPubKeyRequest{
PublicKey: []byte(nonExistantPublicKey),
s.validatorService.SetProposerSettings(&validatorServiceConfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(validatorKey): &pOption,
},
DefaultConfig: nil,
})
if resp == nil || len(resp.FeeRecipient) == 0 || err != nil {
s.validatorService.SetProposerSettings(&validatorServiceConfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(validatorKey): &pOption,
},
DefaultConfig: &defaultOption,
})
} else {
s.validatorService.SetProposerSettings(&validatorServiceConfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(validatorKey): &pOption,
},
DefaultConfig: &validatorServiceConfig.ProposerOption{
FeeRecipient: common.BytesToAddress(resp.FeeRecipient),
},
})
}
} else if s.validatorService.ProposerSettings().ProposeConfig == nil {
settings := s.validatorService.ProposerSettings()
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption)
@@ -479,6 +469,7 @@ func (s *Server) SetGasLimit(ctx context.Context, req *ethpbservice.SetGasLimitR
s.validatorService.SetProposerSettings(settings)
} else {
proposerOption, found := s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(validatorKey)]
if found {
if proposerOption.BuilderConfig == nil {
proposerOption.BuilderConfig = pBuilderConfig
@@ -489,10 +480,12 @@ func (s *Server) SetGasLimit(ctx context.Context, req *ethpbservice.SetGasLimitR
s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(validatorKey)] = &pOption
}
}
// override the 200 success with 202 according to the specs
if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", "202")); err != nil {
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set custom success code header: %v", err)
}
return &empty.Empty{}, nil
}
@@ -534,38 +527,49 @@ func (s *Server) ListFeeRecipientByPubkey(ctx context.Context, req *ethpbservice
if s.validatorService == nil {
return nil, status.Error(codes.FailedPrecondition, "Validator service not ready")
}
validatorKey := req.Pubkey
if err := validatePublicKey(validatorKey); err != nil {
return nil, status.Error(codes.FailedPrecondition, err.Error())
}
defaultFeeRecipient := params.BeaconConfig().DefaultFeeRecipient.Bytes()
finalResp := &ethpbservice.GetFeeRecipientByPubkeyResponse{
Data: &ethpbservice.GetFeeRecipientByPubkeyResponse_FeeRecipient{
Pubkey: validatorKey,
Ethaddress: defaultFeeRecipient,
Ethaddress: params.BeaconConfig().DefaultFeeRecipient.Bytes(),
},
}
// If no proposer settings is set, use beacon node default (if possible)
if s.validatorService.ProposerSettings() == nil {
resp, err := s.beaconNodeValidatorClient.GetFeeRecipientByPubKey(ctx, &eth.FeeRecipientByPubKeyRequest{
PublicKey: validatorKey,
})
if resp != nil && len(resp.FeeRecipient) != 0 && err == nil {
finalResp.Data.Ethaddress = resp.FeeRecipient
}
return finalResp, nil
}
// If fee recipient is defined for this specific pubkey in proposer configuration, use it
if s.validatorService.ProposerSettings().ProposeConfig != nil {
hexv := hexutil.Encode(validatorKey)
fmt.Println(hexv)
proposerOption, found := s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(validatorKey)]
if found {
finalResp.Data.Ethaddress = proposerOption.FeeRecipient.Bytes()
if found && proposerOption.FeeRecipientConfig != nil {
finalResp.Data.Ethaddress = proposerOption.FeeRecipientConfig.FeeRecipient.Bytes()
return finalResp, nil
}
}
if s.validatorService.ProposerSettings().DefaultConfig != nil {
finalResp.Data.Ethaddress = s.validatorService.ProposerSettings().DefaultConfig.FeeRecipient.Bytes()
// If fee recipient is defined in default configuration, use it
if s.validatorService.ProposerSettings().DefaultConfig != nil && s.validatorService.ProposerSettings().DefaultConfig.FeeRecipientConfig != nil {
finalResp.Data.Ethaddress = s.validatorService.ProposerSettings().DefaultConfig.FeeRecipientConfig.FeeRecipient.Bytes()
return finalResp, nil
}
// Default case
return finalResp, nil
}
@@ -574,53 +578,75 @@ func (s *Server) SetFeeRecipientByPubkey(ctx context.Context, req *ethpbservice.
if s.validatorService == nil {
return nil, status.Error(codes.FailedPrecondition, "Validator service not ready")
}
validatorKey := req.Pubkey
feeRecipient := common.BytesToAddress(req.Ethaddress)
if err := validatePublicKey(validatorKey); err != nil {
return nil, status.Error(codes.FailedPrecondition, err.Error())
}
defaultOption := validatorServiceConfig.DefaultProposerOption()
encoded := hexutil.Encode(req.Ethaddress)
if !common.IsHexAddress(encoded) {
return nil, status.Error(
codes.InvalidArgument, "Fee recipient is not a valid Ethereum address")
}
pOption := validatorServiceConfig.DefaultProposerOption()
pOption.FeeRecipient = common.BytesToAddress(req.Ethaddress)
switch {
case s.validatorService.ProposerSettings() == nil:
// get the default fee recipient defined with an invalid public key from beacon node
resp, err := s.beaconNodeValidatorClient.GetFeeRecipientByPubKey(ctx, &eth.FeeRecipientByPubKeyRequest{
PublicKey: []byte(nonExistantPublicKey),
})
settings := &validatorServiceConfig.ProposerSettings{
s.validatorService.SetProposerSettings(&validatorServiceConfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(validatorKey): &pOption,
bytesutil.ToBytes48(validatorKey): {
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: feeRecipient,
},
BuilderConfig: nil,
},
},
DefaultConfig: nil,
})
case s.validatorService.ProposerSettings().ProposeConfig == nil:
builderConfig := &validatorServiceConfig.BuilderConfig{}
settings := s.validatorService.ProposerSettings()
if settings.DefaultConfig != nil {
builderConfig = settings.DefaultConfig.BuilderConfig
}
settings.ProposeConfig = map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(validatorKey): {
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: feeRecipient,
},
BuilderConfig: builderConfig,
},
}
if resp == nil || len(resp.FeeRecipient) == 0 || err != nil {
settings.DefaultConfig = &defaultOption
} else {
settings.DefaultConfig = &validatorServiceConfig.ProposerOption{
FeeRecipient: common.BytesToAddress(resp.FeeRecipient),
}
}
s.validatorService.SetProposerSettings(settings)
case s.validatorService.ProposerSettings().ProposeConfig == nil:
settings := s.validatorService.ProposerSettings()
pOption.BuilderConfig = settings.DefaultConfig.BuilderConfig
settings.ProposeConfig = map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
bytesutil.ToBytes48(validatorKey): &pOption,
}
s.validatorService.SetProposerSettings(settings)
default:
proposerOption, found := s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(validatorKey)]
if found {
proposerOption.FeeRecipient = common.BytesToAddress(req.Ethaddress)
if found && proposerOption != nil {
proposerOption.FeeRecipientConfig = &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: feeRecipient,
}
} else {
settings := s.validatorService.ProposerSettings()
pOption.BuilderConfig = settings.DefaultConfig.BuilderConfig
settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)] = &pOption
var builderConfig = &validatorServiceConfig.BuilderConfig{}
if settings.DefaultConfig != nil {
builderConfig = settings.DefaultConfig.BuilderConfig
}
settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)] = &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: feeRecipient,
},
BuilderConfig: builderConfig,
}
s.validatorService.SetProposerSettings(settings)
}
}
@@ -636,20 +662,22 @@ func (s *Server) DeleteFeeRecipientByPubkey(ctx context.Context, req *ethpbservi
if s.validatorService == nil {
return nil, status.Error(codes.FailedPrecondition, "Validator service not ready")
}
validatorKey := req.Pubkey
if err := validatePublicKey(validatorKey); err != nil {
return nil, status.Error(codes.FailedPrecondition, err.Error())
}
defaultFeeRecipient := params.BeaconConfig().DefaultFeeRecipient
if s.validatorService.ProposerSettings() != nil && s.validatorService.ProposerSettings().DefaultConfig != nil {
defaultFeeRecipient = s.validatorService.ProposerSettings().DefaultConfig.FeeRecipient
}
if s.validatorService.ProposerSettings() != nil && s.validatorService.ProposerSettings().ProposeConfig != nil {
proposerOption, found := s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(validatorKey)]
settings := s.validatorService.ProposerSettings()
if settings != nil && settings.ProposeConfig != nil {
proposerOption, found := settings.ProposeConfig[bytesutil.ToBytes48(validatorKey)]
if found {
proposerOption.FeeRecipient = defaultFeeRecipient
proposerOption.FeeRecipientConfig = nil
}
}
// override the 200 success with 204 according to the specs
if err := grpc.SetHeader(ctx, metadata.Pairs("x-http-code", "204")); err != nil {
return &empty.Empty{}, status.Errorf(codes.Internal, "Could not set custom success code header: %v", err)

View File

@@ -13,6 +13,7 @@ import (
"github.com/golang/protobuf/ptypes/empty"
"github.com/google/uuid"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/pkg/errors"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v3/config/validator/service"
@@ -711,34 +712,8 @@ func TestServer_ListFeeRecipientByPubkey(t *testing.T) {
wantErr bool
}{
{
name: "Happy Path Test",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(byteval): {
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
want: &want{
EthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
},
{
name: "happy path test cached",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(byteval): {
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
name: "ProposerSettings is nil",
args: nil,
want: &want{
EthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
@@ -748,57 +723,167 @@ func TestServer_ListFeeRecipientByPubkey(t *testing.T) {
wantErr: false,
},
{
name: "empty settings non cached",
name: "ProposerSettings is nil - Beacon node error",
args: nil,
want: &want{
EthAddress: params.BeaconConfig().DefaultFeeRecipient.Hex(),
EthAddress: "0x0000000000000000000000000000000000000000",
},
cached: nil,
wantErr: true,
},
{
name: "ProposerSettings.ProposeConfig.FeeRecipientConfig defined for pubkey",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(byteval): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
},
},
},
want: &want{
EthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
},
{
name: "empty settings cached",
args: nil,
name: "ProposerSettings.ProposeConfig.FeeRecipientConfig NOT defined for pubkey and ProposerSettings.DefaultConfig.FeeRecipientConfig defined",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
},
want: &want{
EthAddress: common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e97387").Hex(),
EthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
cached: &eth.FeeRecipientByPubKeyResponse{
FeeRecipient: common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e97387").Bytes(),
},
{
name: "ProposerSettings.ProposeConfig.FeeRecipientConfig NOT defined for pubkey and ProposerSettings.DefaultConfig is nil",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{},
DefaultConfig: nil,
},
want: &want{
EthAddress: "0x0000000000000000000000000000000000000000",
},
wantErr: false,
},
{
name: "ProposerSettings.ProposeConfig is nil and ProposerSettings.DefaultConfig is nil",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: nil,
DefaultConfig: nil,
},
want: &want{
EthAddress: "0x0000000000000000000000000000000000000000",
},
wantErr: false,
},
{
name: "ProposerSettings.ProposeConfig is nil and ProposerSettings.DefaultConfig.FeeRecipientConfig is nil",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: nil,
},
},
want: &want{
EthAddress: "0x0000000000000000000000000000000000000000",
},
wantErr: false,
},
{
name: "ProposerSettings.ProposerConfig.FeeRecipientConfig NOT defined for pubkey, ProposerSettings.DefaultConfig.FeeRecipientConfig defined",
args: &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
},
want: &want{
EthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
mockValidatorClient := mock2.NewMockValidatorClient(ctrl)
m := &mock.MockValidator{}
m.SetProposerSettings(tt.args)
if tt.args == nil {
var err error = nil
if tt.wantErr {
err = errors.New("custom error")
}
mockValidatorClient.EXPECT().GetFeeRecipientByPubKey(gomock.Any(), gomock.Any()).Return(tt.cached, err)
}
vs, err := client.NewValidatorService(ctx, &client.Config{
Validator: m,
})
require.NoError(t, err)
if tt.args == nil || tt.args.ProposeConfig == nil {
mockValidatorClient.EXPECT().GetFeeRecipientByPubKey(gomock.Any(), gomock.Any()).Return(tt.cached, nil)
}
s := &Server{
validatorService: vs,
beaconNodeValidatorClient: mockValidatorClient,
}
got, err := s.ListFeeRecipientByPubkey(ctx, &ethpbservice.PubkeyRequest{Pubkey: byteval})
require.NoError(t, err)
assert.Equal(t, tt.want.EthAddress, common.BytesToAddress(got.Data.Ethaddress).Hex())
})
}
}
func TestServer_SetFeeRecipientByPubkey(t *testing.T) {
func TestServer_ListFeeRecipientByPubkey_ValidatorServiceNil(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
s := &Server{}
_, err := s.ListFeeRecipientByPubkey(ctx, nil)
require.ErrorContains(t, "Validator service not ready", err)
}
func TestServer_ListFeeRecipientByPubkey_InvalidPubKey(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
s := &Server{
validatorService: &client.ValidatorService{},
}
req := &ethpbservice.PubkeyRequest{
Pubkey: []byte{},
}
_, err := s.ListFeeRecipientByPubkey(ctx, req)
require.ErrorContains(t, "not a valid bls public key", err)
}
func TestServer_FeeRecipientByPubkey(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
beaconClient := mock2.NewMockValidatorClient(ctrl)
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
byteval, err := hexutil.Decode("0xaf2e7ba294e03438ea819bd4033c6c1bf6b04320ee2075b77273c08d02f8a61bcc303c2c06bd3713cb442072ae591493")
wantAddress := "0x055Fb65722e7b2455012Bfebf6177f1d2e9738d7"
cachedAddress := "0x055Fb65722E7b2455012BFEBf6177F1D2e97387"
require.NoError(t, err)
type want struct {
valEthAddress string
defaultEthaddress string
@@ -816,11 +901,11 @@ func TestServer_SetFeeRecipientByPubkey(t *testing.T) {
beaconReturn *beaconResp
}{
{
name: "Happy Path Test",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
name: "ProposerSetting is nil",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: nil,
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
defaultEthaddress: params.BeaconConfig().DefaultFeeRecipient.Hex(),
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
beaconReturn: &beaconResp{
@@ -829,80 +914,168 @@ func TestServer_SetFeeRecipientByPubkey(t *testing.T) {
},
},
{
name: "Happy Path Test Beacon Cached",
name: "ProposerSetting.ProposeConfig is nil",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: nil,
},
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
defaultEthaddress: common.HexToAddress(cachedAddress).Hex(),
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
beaconReturn: &beaconResp{
resp: &eth.FeeRecipientByPubKeyResponse{
FeeRecipient: common.HexToAddress(cachedAddress).Bytes(),
},
resp: nil,
error: nil,
},
},
{
name: "Happy Path Test Beacon Cached preexisting proposer data",
args: wantAddress,
want: &want{
valEthAddress: wantAddress,
defaultEthaddress: common.HexToAddress(cachedAddress).Hex(),
},
name: "ProposerSetting.ProposeConfig is nil AND ProposerSetting.Defaultconfig is defined",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(byteval): {
FeeRecipient: common.HexToAddress("0x055Fb65722e7b2455012Bfebf6177f1d2e9738d8"),
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipient: common.HexToAddress(cachedAddress),
},
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{},
},
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
beaconReturn: &beaconResp{
resp: nil,
error: nil,
},
},
{
name: "Happy Path Test Beacon Cached preexisting default data",
args: wantAddress,
want: &want{
valEthAddress: wantAddress,
defaultEthaddress: common.HexToAddress(cachedAddress).Hex(),
},
name: "ProposerSetting.ProposeConfig is defined for pubkey",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipient: common.HexToAddress(cachedAddress),
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(byteval): {},
},
},
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
beaconReturn: &beaconResp{
resp: nil,
error: nil,
},
},
{
name: "ProposerSetting.ProposeConfig not defined for pubkey",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{},
},
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
beaconReturn: &beaconResp{
resp: nil,
error: nil,
},
},
{
name: "ProposerSetting.ProposeConfig is nil for pubkey",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(byteval): nil,
},
},
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
beaconReturn: &beaconResp{
resp: nil,
error: nil,
},
},
{
name: "ProposerSetting.ProposeConfig is nil for pubkey AND DefaultConfig is not nil",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(byteval): nil,
},
DefaultConfig: &validatorserviceconfig.ProposerOption{},
},
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
},
wantErr: false,
beaconReturn: &beaconResp{
resp: nil,
error: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m := &mock.MockValidator{}
m.SetProposerSettings(tt.proposerSettings)
vs, err := client.NewValidatorService(ctx, &client.Config{
Validator: m,
})
if tt.beaconReturn != nil {
beaconClient.EXPECT().GetFeeRecipientByPubKey(
gomock.Any(),
gomock.Any(),
).Return(tt.beaconReturn.resp, tt.beaconReturn.error)
}
require.NoError(t, err)
s := &Server{
validatorService: vs,
beaconNodeValidatorClient: beaconClient,
}
_, err = s.SetFeeRecipientByPubkey(ctx, &ethpbservice.SetFeeRecipientByPubkeyRequest{Pubkey: byteval, Ethaddress: common.HexToAddress(tt.args).Bytes()})
require.NoError(t, err)
assert.Equal(t, tt.want.valEthAddress, s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(byteval)].FeeRecipient.Hex())
assert.Equal(t, tt.want.defaultEthaddress, s.validatorService.ProposerSettings().DefaultConfig.FeeRecipient.Hex())
assert.Equal(t, tt.want.valEthAddress, s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(byteval)].FeeRecipientConfig.FeeRecipient.Hex())
})
}
}
func TestServer_SetFeeRecipientByPubkey_ValidatorServiceNil(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
s := &Server{}
_, err := s.SetFeeRecipientByPubkey(ctx, nil)
require.ErrorContains(t, "Validator service not ready", err)
}
func TestServer_SetFeeRecipientByPubkey_InvalidPubKey(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
s := &Server{
validatorService: &client.ValidatorService{},
}
req := &ethpbservice.SetFeeRecipientByPubkeyRequest{
Pubkey: []byte{},
}
_, err := s.SetFeeRecipientByPubkey(ctx, req)
require.ErrorContains(t, "not a valid bls public key", err)
}
func TestServer_SetGasLimit_InvalidFeeRecipient(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
byteval, err := hexutil.Decode("0xaf2e7ba294e03438ea819bd4033c6c1bf6b04320ee2075b77273c08d02f8a61bcc303c2c06bd3713cb442072ae591493")
require.NoError(t, err)
s := &Server{
validatorService: &client.ValidatorService{},
}
req := &ethpbservice.SetFeeRecipientByPubkeyRequest{
Pubkey: byteval,
}
_, err = s.SetFeeRecipientByPubkey(ctx, req)
require.ErrorContains(t, "Fee recipient is not a valid Ethereum address", err)
}
func TestServer_DeleteFeeRecipientByPubkey(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
byteval, err := hexutil.Decode("0xaf2e7ba294e03438ea819bd4033c6c1bf6b04320ee2075b77273c08d02f8a61bcc303c2c06bd3713cb442072ae591493")
@@ -921,11 +1094,15 @@ func TestServer_DeleteFeeRecipientByPubkey(t *testing.T) {
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(byteval): {
FeeRecipient: common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e9738D5"),
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e9738D5"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
},
want: &want{
@@ -947,11 +1124,35 @@ func TestServer_DeleteFeeRecipientByPubkey(t *testing.T) {
}
_, err = s.DeleteFeeRecipientByPubkey(ctx, &ethpbservice.PubkeyRequest{Pubkey: byteval})
require.NoError(t, err)
assert.Equal(t, tt.want.EthAddress, s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(byteval)].FeeRecipient.Hex())
assert.Equal(t, true, s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(byteval)].FeeRecipientConfig == nil)
})
}
}
func TestServer_DeleteFeeRecipientByPubkey_ValidatorServiceNil(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
s := &Server{}
_, err := s.DeleteFeeRecipientByPubkey(ctx, nil)
require.ErrorContains(t, "Validator service not ready", err)
}
func TestServer_DeleteFeeRecipientByPubkey_InvalidPubKey(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
s := &Server{
validatorService: &client.ValidatorService{},
}
req := &ethpbservice.PubkeyRequest{
Pubkey: []byte{},
}
_, err := s.DeleteFeeRecipientByPubkey(ctx, req)
require.ErrorContains(t, "not a valid bls public key", err)
}
func TestServer_GetGasLimit(t *testing.T) {
ctx := context.Background()
byteval, err := hexutil.Decode("0xaf2e7ba294e03438ea819bd4033c6c1bf6b04320ee2075b77273c08d02f8a61bcc303c2c06bd3713cb442072ae591493")
@@ -1024,16 +1225,20 @@ func TestServer_GetGasLimit(t *testing.T) {
func TestServer_SetGasLimit(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
beaconClient := mock2.NewMockValidatorClient(ctrl)
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
pubkey1, err := hexutil.Decode("0xaf2e7ba294e03438ea819bd4033c6c1bf6b04320ee2075b77273c08d02f8a61bcc303c2c06bd3713cb442072ae591493")
pubkey2, err2 := hexutil.Decode("0xbedefeaa94e03438ea819bd4033c6c1bf6b04320ee2075b77273c08d02f8a61bcc303c2cdddddddddddddddddddddddd")
require.NoError(t, err)
require.NoError(t, err2)
type beaconResp struct {
resp *eth.FeeRecipientByPubKeyResponse
error error
}
type want struct {
pubkey []byte
gaslimit uint64
@@ -1048,17 +1253,40 @@ func TestServer_SetGasLimit(t *testing.T) {
beaconReturn *beaconResp
}{
{
name: "update existing gas limit",
name: "ProposerSettings is nil",
pubkey: pubkey1,
newGasLimit: 9999,
proposerSettings: nil,
w: []want{
{
pubkey: pubkey1,
gaslimit: 9999,
},
},
},
{
name: "ProposerSettings.ProposeConfig is nil AND ProposerSettings.DefaultConfig is nil",
pubkey: pubkey1,
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: 123456789},
},
ProposeConfig: nil,
DefaultConfig: nil,
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 9999,
},
},
},
{
name: "ProposerSettings.ProposeConfig is nil AND ProposerSettings.DefaultConfig.BuilderConfig is nil",
pubkey: pubkey1,
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: 987654321},
BuilderConfig: nil,
},
},
w: []want{
@@ -1069,113 +1297,145 @@ func TestServer_SetGasLimit(t *testing.T) {
},
},
{
name: "insert a new gas limit",
pubkey: pubkey2,
newGasLimit: 8888,
name: "ProposerSettings.ProposeConfig is defined for pubkey, BuilderConfig is nil AND ProposerSettings.DefaultConfig is nil",
pubkey: pubkey1,
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: 123456789},
BuilderConfig: nil,
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: 987654321},
},
DefaultConfig: nil,
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 123456789,
gaslimit: 9999,
},
},
},
{
name: "ProposerSettings.ProposeConfig is defined for pubkey, BuilderConfig is defined AND ProposerSettings.DefaultConfig is nil",
pubkey: pubkey1,
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{},
},
},
DefaultConfig: nil,
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 9999,
},
},
},
{
name: "ProposerSettings.ProposeConfig is NOT defined for pubkey, BuilderConfig is defined AND ProposerSettings.DefaultConfig is nil",
pubkey: pubkey2,
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{
GasLimit: 12345,
},
},
},
DefaultConfig: nil,
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 12345,
},
{
pubkey: pubkey2,
gaslimit: 8888,
gaslimit: 9999,
},
},
},
{
name: "create new gas limit value for nil ProposerSettings.ProposeConfig",
name: "ProposerSettings.ProposeConfig is defined for pubkey, BuilderConfig is nil AND ProposerSettings.DefaultConfig.BuilderConfig is defined",
pubkey: pubkey1,
newGasLimit: 8888,
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: nil,
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: 987654321},
BuilderConfig: &validatorserviceconfig.BuilderConfig{},
},
},
w: []want{
{
pubkey: pubkey1,
gaslimit: 8888,
gaslimit: 9999,
},
},
},
{
name: "create new gas limit value for nil proposerSettings with beacon node fee recipient",
pubkey: pubkey1,
newGasLimit: 7777,
// proposerSettings is not set - we need to create proposerSettings and set gaslimit properly
w: []want{
{
pubkey: pubkey1,
gaslimit: 7777,
},
},
beaconReturn: &beaconResp{
resp: &eth.FeeRecipientByPubKeyResponse{
FeeRecipient: common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e97387").Bytes(),
},
error: nil,
},
},
{
name: "create new gas limit value for nil proposerSettings without beacon node fee recipient",
pubkey: pubkey1,
newGasLimit: 7777,
// proposerSettings is not set - we need to create proposerSettings and set gaslimit properly
w: []want{
{
pubkey: pubkey1,
gaslimit: 7777,
},
},
beaconReturn: &beaconResp{
resp: nil,
error: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
feeRecipient := params.BeaconConfig().DefaultFeeRecipient.Hex()
m := &mock.MockValidator{}
m.SetProposerSettings(tt.proposerSettings)
vs, err := client.NewValidatorService(ctx, &client.Config{
Validator: m,
})
require.NoError(t, err)
s := &Server{
validatorService: vs,
beaconNodeValidatorClient: beaconClient,
}
if tt.beaconReturn != nil {
beaconClient.EXPECT().GetFeeRecipientByPubKey(
gomock.Any(),
gomock.Any(),
).Return(tt.beaconReturn.resp, tt.beaconReturn.error)
if tt.beaconReturn.resp != nil {
feeRecipient = common.BytesToAddress(tt.beaconReturn.resp.FeeRecipient).Hex()
}
}
_, err = s.SetGasLimit(ctx, &ethpbservice.SetGasLimitRequest{Pubkey: tt.pubkey, GasLimit: tt.newGasLimit})
require.NoError(t, err)
for _, w := range tt.w {
assert.Equal(t, w.gaslimit, uint64(s.validatorService.ProposerSettings().ProposeConfig[bytesutil.ToBytes48(w.pubkey)].BuilderConfig.GasLimit))
}
assert.Equal(t, s.validatorService.ProposerSettings().DefaultConfig.FeeRecipient.Hex(), feeRecipient)
})
}
}
func TestServer_SetGasLimit_ValidatorServiceNil(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
s := &Server{}
_, err := s.SetGasLimit(ctx, nil)
require.ErrorContains(t, "Validator service not ready", err)
}
func TestServer_SetGasLimit_InvalidPubKey(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
s := &Server{
validatorService: &client.ValidatorService{},
}
req := &ethpbservice.SetGasLimitRequest{
Pubkey: []byte{},
}
_, err := s.SetGasLimit(ctx, req)
require.ErrorContains(t, "not a valid bls public key", err)
}
func TestServer_DeleteGasLimit(t *testing.T) {
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
pubkey1, err := hexutil.Decode("0xaf2e7ba294e03438ea819bd4033c6c1bf6b04320ee2075b77273c08d02f8a61bcc303c2c06bd3713cb442072ae591493")