mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 13:28:01 -05:00
Improvement to Fee Recipient UX (#11307)
* updating mock * adding new internal api * adding generated code * converting validator index to pubkey * adding new API endpoint * fixing mock related new API * fixing unit tests * preventing failure on startup, replacing with warnings * improving log message * changing warn log to error log * fixing error formatting * improve log on beacon node side on startup * fixing deepsource issue * improving logs * fixing unit tests * fixing more tests * adding error check * adding in new case for fee recipient to avoid conflicts on changing beacon node suggested fee recipient * adding default fee recipient check for gas limit as well * adding improved unit tests * accidently checked in tmp folder * adding more unit tests * fixing gas limit unit test * Update validator/rpc/standard_api_test.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/rpc/standard_api_test.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/rpc/standard_api_test.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update beacon-chain/node/config.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update beacon-chain/node/config.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update proto/prysm/v1alpha1/validator.proto Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/rpc/standard_api.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update validator/client/runner.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * addressing comments * updating proto generated files * fixing linting and addressign review comments * fixing unit test * improve error handling * accidently added tmp folder * improving function error returns * realizing i am wrapping error incorrectly * fixing unit test * addressing review comment * fixing linting * fixing unit test * improving ux around enable builder Co-authored-by: Radosław Kapka <rkapka@wp.pl> Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/pkg/errors"
|
||||
fastssz "github.com/prysmaticlabs/fastssz"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/beacon-chain/flags"
|
||||
@@ -158,17 +157,22 @@ func configureExecutionSetting(cliCtx *cli.Context) error {
|
||||
}
|
||||
|
||||
if !cliCtx.IsSet(flags.SuggestedFeeRecipient.Name) {
|
||||
log.Warnf("In order to receive transaction fees from proposing blocks, " +
|
||||
"you must provide flag --" + flags.SuggestedFeeRecipient.Name + " with a valid ethereum address when starting your beacon node. " +
|
||||
"Please see our documentation for more information on this requirement (https://docs.prylabs.network/docs/execution-node/fee-recipient).")
|
||||
return nil
|
||||
}
|
||||
|
||||
c := params.BeaconConfig().Copy()
|
||||
ha := cliCtx.String(flags.SuggestedFeeRecipient.Name)
|
||||
if !common.IsHexAddress(ha) {
|
||||
return fmt.Errorf("%s is not a valid fee recipient address", ha)
|
||||
log.Warnf("%s is not a valid fee recipient address, setting suggested-fee-recipient failed", ha)
|
||||
return nil
|
||||
}
|
||||
mixedcaseAddress, err := common.NewMixedcaseAddressFromString(ha)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not decode fee recipient %s", ha)
|
||||
log.WithError(err).Error(fmt.Sprintf("Could not decode fee recipient %s, setting suggested-fee-recipient failed", ha))
|
||||
return nil
|
||||
}
|
||||
checksumAddress := common.HexToAddress(ha)
|
||||
if !mixedcaseAddress.ValidChecksum() {
|
||||
@@ -178,6 +182,8 @@ func configureExecutionSetting(cliCtx *cli.Context) error {
|
||||
"to prevent spelling mistakes in your fee recipient Ethereum address", ha, checksumAddress.Hex())
|
||||
}
|
||||
c.DefaultFeeRecipient = checksumAddress
|
||||
log.Infof("Default fee recipient is set to %s, recipient may be overwritten from validator client and persist in db."+
|
||||
" Default fee recipient will be used as a fall back", checksumAddress.Hex())
|
||||
return params.SetActive(c)
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,8 @@ func TestConfigureExecutionSetting(t *testing.T) {
|
||||
require.NoError(t, set.Set(flags.SuggestedFeeRecipient.Name, "0xB"))
|
||||
cliCtx := cli.NewContext(&app, set, nil)
|
||||
err := configureExecutionSetting(cliCtx)
|
||||
require.ErrorContains(t, "0xB is not a valid fee recipient address", err)
|
||||
assert.LogsContain(t, hook, "0xB is not a valid fee recipient address")
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, set.Set(flags.SuggestedFeeRecipient.Name, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))
|
||||
cliCtx = cli.NewContext(&app, set, nil)
|
||||
|
||||
@@ -42,6 +42,8 @@ func TestNodeClose_OK(t *testing.T) {
|
||||
set.String("p2p-encoding", "ssz", "p2p encoding scheme")
|
||||
set.Bool("demo-config", true, "demo configuration")
|
||||
set.String("deposit-contract", "0x0000000000000000000000000000000000000000", "deposit contract address")
|
||||
set.String("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A", "fee recipient")
|
||||
require.NoError(t, set.Set("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A"))
|
||||
cmd.ValidatorMonitorIndicesFlag.Value = &cli.IntSlice{}
|
||||
cmd.ValidatorMonitorIndicesFlag.Value.SetInt(1)
|
||||
ctx := cli.NewContext(&app, set, nil)
|
||||
@@ -60,6 +62,9 @@ func TestNodeStart_Ok(t *testing.T) {
|
||||
tmp := fmt.Sprintf("%s/datadirtest2", t.TempDir())
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("datadir", tmp, "node data directory")
|
||||
set.String("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A", "fee recipient")
|
||||
require.NoError(t, set.Set("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A"))
|
||||
|
||||
ctx := cli.NewContext(&app, set, nil)
|
||||
node, err := New(ctx, WithBlockchainFlagOptions([]blockchain.Option{}),
|
||||
WithBuilderFlagOptions([]builder.Option{}),
|
||||
@@ -83,6 +88,8 @@ func TestNodeStart_Ok_registerDeterministicGenesisService(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("datadir", tmp, "node data directory")
|
||||
set.Uint64(flags.InteropNumValidatorsFlag.Name, numValidators, "")
|
||||
set.String("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A", "fee recipient")
|
||||
require.NoError(t, set.Set("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A"))
|
||||
genesisState, _, err := interop.GenerateGenesisState(context.Background(), 0, numValidators)
|
||||
require.NoError(t, err, "Could not generate genesis beacon state")
|
||||
for i := uint64(1); i < 2; i++ {
|
||||
@@ -136,7 +143,8 @@ func TestClearDB(t *testing.T) {
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String("datadir", tmp, "node data directory")
|
||||
set.Bool(cmd.ForceClearDB.Name, true, "force clear db")
|
||||
|
||||
set.String("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A", "fee recipient")
|
||||
require.NoError(t, set.Set("suggested-fee-recipient", "0x6e35733c5af9B61374A128e6F85f553aF09ff89A"))
|
||||
context := cli.NewContext(&app, set, nil)
|
||||
_, err = New(context, WithExecutionChainOptions([]execution.Option{
|
||||
execution.WithHttpEndpoint(endpoint),
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -118,6 +119,42 @@ func (vs *Server) PrepareBeaconProposer(
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
// GetFeeRecipientByPubKey returns a fee recipient from the beacon node's settings or db based on a given public key
|
||||
func (vs *Server) GetFeeRecipientByPubKey(ctx context.Context, request *ethpb.FeeRecipientByPubKeyRequest) (*ethpb.FeeRecipientByPubKeyResponse, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.GetFeeRecipientByPublicKey")
|
||||
defer span.End()
|
||||
if request == nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "request was empty")
|
||||
}
|
||||
|
||||
resp, err := vs.ValidatorIndex(ctx, ðpb.ValidatorIndexRequest{PublicKey: request.PublicKey})
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "Could not find validator index") {
|
||||
return ðpb.FeeRecipientByPubKeyResponse{
|
||||
FeeRecipient: params.BeaconConfig().DefaultFeeRecipient.Bytes(),
|
||||
}, nil
|
||||
} else {
|
||||
log.WithError(err).Error("An error occurred while retrieving validator index")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
address, err := vs.BeaconDB.FeeRecipientByValidatorID(ctx, resp.GetIndex())
|
||||
if err != nil {
|
||||
if errors.Is(err, kv.ErrNotFoundFeeRecipient) {
|
||||
return ðpb.FeeRecipientByPubKeyResponse{
|
||||
FeeRecipient: params.BeaconConfig().DefaultFeeRecipient.Bytes(),
|
||||
}, nil
|
||||
} else {
|
||||
log.WithError(err).Error("An error occurred while retrieving fee recipient from db")
|
||||
return nil, status.Errorf(codes.Internal, err.Error())
|
||||
}
|
||||
}
|
||||
return ðpb.FeeRecipientByPubKeyResponse{
|
||||
FeeRecipient: address.Bytes(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (vs *Server) proposeGenericBeaconBlock(ctx context.Context, blk interfaces.SignedBeaconBlock) (*ethpb.ProposeResponse, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "ProposerServer.proposeGenericBeaconBlock")
|
||||
defer span.End()
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
mock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
|
||||
@@ -2453,3 +2454,43 @@ func majorityVoteBoundaryTime(slot types.Slot) (uint64, uint64) {
|
||||
|
||||
return earliestValidTime, latestValidTime
|
||||
}
|
||||
|
||||
func TestProposer_GetFeeRecipientByPubKey(t *testing.T) {
|
||||
db := dbutil.SetupDB(t)
|
||||
ctx := context.Background()
|
||||
numDeposits := uint64(64)
|
||||
beaconState, _ := util.DeterministicGenesisState(t, numDeposits)
|
||||
bsRoot, err := beaconState.HashTreeRoot(ctx)
|
||||
require.NoError(t, err)
|
||||
proposerServer := &Server{
|
||||
BeaconDB: db,
|
||||
HeadFetcher: &mock.ChainService{Root: bsRoot[:], State: beaconState},
|
||||
}
|
||||
pubkey, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
|
||||
require.NoError(t, err)
|
||||
resp, err := proposerServer.GetFeeRecipientByPubKey(ctx, ðpb.FeeRecipientByPubKeyRequest{
|
||||
PublicKey: pubkey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, params.BeaconConfig().DefaultFeeRecipient.Hex(), hexutil.Encode(resp.FeeRecipient))
|
||||
params.BeaconConfig().DefaultFeeRecipient = common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9728D9")
|
||||
resp, err = proposerServer.GetFeeRecipientByPubKey(ctx, ðpb.FeeRecipientByPubKeyRequest{
|
||||
PublicKey: beaconState.Validators()[0].PublicKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, params.BeaconConfig().DefaultFeeRecipient.Hex(), common.BytesToAddress(resp.FeeRecipient).Hex())
|
||||
index, err := proposerServer.ValidatorIndex(ctx, ðpb.ValidatorIndexRequest{
|
||||
PublicKey: beaconState.Validators()[0].PublicKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = proposerServer.BeaconDB.SaveFeeRecipientsByValidatorIDs(ctx, []types.ValidatorIndex{index.Index}, []common.Address{common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e9728D8")})
|
||||
require.NoError(t, err)
|
||||
resp, err = proposerServer.GetFeeRecipientByPubKey(ctx, ðpb.FeeRecipientByPubKeyRequest{
|
||||
PublicKey: beaconState.Validators()[0].PublicKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e9728D8").Hex(), common.BytesToAddress(resp.FeeRecipient).Hex())
|
||||
}
|
||||
|
||||
876
proto/prysm/v1alpha1/validator.pb.go
generated
876
proto/prysm/v1alpha1/validator.pb.go
generated
File diff suppressed because it is too large
Load Diff
@@ -394,6 +394,40 @@ func local_request_BeaconNodeValidator_PrepareBeaconProposer_0(ctx context.Conte
|
||||
|
||||
}
|
||||
|
||||
func request_BeaconNodeValidator_GetFeeRecipientByPubKey_0(ctx context.Context, marshaler runtime.Marshaler, client BeaconNodeValidatorClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq FeeRecipientByPubKeyRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetFeeRecipientByPubKey(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_BeaconNodeValidator_GetFeeRecipientByPubKey_0(ctx context.Context, marshaler runtime.Marshaler, server BeaconNodeValidatorServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq FeeRecipientByPubKeyRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetFeeRecipientByPubKey(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_BeaconNodeValidator_GetAttestationData_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
@@ -1065,6 +1099,29 @@ func RegisterBeaconNodeValidatorHandlerServer(ctx context.Context, mux *runtime.
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BeaconNodeValidator_GetFeeRecipientByPubKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/ethereum.eth.v1alpha1.BeaconNodeValidator/GetFeeRecipientByPubKey")
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BeaconNodeValidator_GetFeeRecipientByPubKey_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BeaconNodeValidator_GetFeeRecipientByPubKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_BeaconNodeValidator_GetAttestationData_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -1632,6 +1689,26 @@ func RegisterBeaconNodeValidatorHandlerClient(ctx context.Context, mux *runtime.
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BeaconNodeValidator_GetFeeRecipientByPubKey_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/ethereum.eth.v1alpha1.BeaconNodeValidator/GetFeeRecipientByPubKey")
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BeaconNodeValidator_GetFeeRecipientByPubKey_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BeaconNodeValidator_GetFeeRecipientByPubKey_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_BeaconNodeValidator_GetAttestationData_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -1938,6 +2015,8 @@ var (
|
||||
|
||||
pattern_BeaconNodeValidator_PrepareBeaconProposer_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"eth", "v1alpha1", "validator", "prepare_beacon_proposer"}, ""))
|
||||
|
||||
pattern_BeaconNodeValidator_GetFeeRecipientByPubKey_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"eth", "v1alpha1", "validator", "fee_recipient_by_pub_key"}, ""))
|
||||
|
||||
pattern_BeaconNodeValidator_GetAttestationData_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"eth", "v1alpha1", "validator", "attestation"}, ""))
|
||||
|
||||
pattern_BeaconNodeValidator_ProposeAttestation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"eth", "v1alpha1", "validator", "attestation"}, ""))
|
||||
@@ -1990,6 +2069,8 @@ var (
|
||||
|
||||
forward_BeaconNodeValidator_PrepareBeaconProposer_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BeaconNodeValidator_GetFeeRecipientByPubKey_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BeaconNodeValidator_GetAttestationData_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BeaconNodeValidator_ProposeAttestation_0 = runtime.ForwardResponseMessage
|
||||
|
||||
@@ -168,6 +168,14 @@ service BeaconNodeValidator {
|
||||
};
|
||||
}
|
||||
|
||||
// GetFeeRecipientByPubKey returns a fee recipient from the beacon node's settings or db based on a given public key
|
||||
rpc GetFeeRecipientByPubKey(FeeRecipientByPubKeyRequest) returns (FeeRecipientByPubKeyResponse){
|
||||
option (google.api.http) = {
|
||||
post: "/eth/v1alpha1/validator/fee_recipient_by_pub_key"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
// Retrieves the latest valid attestation data to be attested on the beacon chain.
|
||||
//
|
||||
// The server returns the latest valid data which represents the correct vote
|
||||
@@ -764,4 +772,12 @@ message PrepareBeaconProposerRequest {
|
||||
uint64 validator_index = 2 [(ethereum.eth.ext.cast_type) = "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives.ValidatorIndex"];
|
||||
}
|
||||
repeated FeeRecipientContainer recipients = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message FeeRecipientByPubKeyRequest {
|
||||
bytes public_key = 1 [(ethereum.eth.ext.ssz_size) = "48", (ethereum.eth.ext.spec_name) = "pubkey"];
|
||||
}
|
||||
|
||||
message FeeRecipientByPubKeyResponse {
|
||||
bytes fee_recipient = 1 [(ethereum.eth.ext.ssz_size) = "20"];
|
||||
}
|
||||
|
||||
20
testing/mock/beacon_validator_client_mock.go
generated
20
testing/mock/beacon_validator_client_mock.go
generated
@@ -238,6 +238,26 @@ func (mr *MockBeaconNodeValidatorClientMockRecorder) PrepareBeaconProposer(arg0,
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrepareBeaconProposer", reflect.TypeOf((*MockBeaconNodeValidatorClient)(nil).PrepareBeaconProposer), varargs...)
|
||||
}
|
||||
|
||||
// GetFeeRecipientByPubKey mocks base method.
|
||||
func (m *MockBeaconNodeValidatorClient) GetFeeRecipientByPubKey(arg0 context.Context, arg1 *eth.FeeRecipientByPubKeyRequest, arg2 ...grpc.CallOption) (*eth.FeeRecipientByPubKeyResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "GetFeeRecipientByPublicKey", varargs...)
|
||||
ret0, _ := ret[0].(*eth.FeeRecipientByPubKeyResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetFeeRecipientByPubKey indicates an expected call of GetFeeRecipientByPubKey.
|
||||
func (mr *MockBeaconNodeValidatorClientMockRecorder) GetFeeRecipientByPubKey(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeeRecipientByPublicKey", reflect.TypeOf((*MockBeaconNodeValidatorClient)(nil).GetFeeRecipientByPubKey), varargs...)
|
||||
}
|
||||
|
||||
// ProposeAttestation mocks base method.
|
||||
func (m *MockBeaconNodeValidatorClient) ProposeAttestation(arg0 context.Context, arg1 *eth.Attestation, arg2 ...grpc.CallOption) (*eth.AttestResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -178,6 +178,11 @@ func (_ MockValidator) CheckDoppelGanger(_ context.Context) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// PushProposerSettings for mocking
|
||||
func (MockValidator) HasProposerSettings() bool {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// PushProposerSettings for mocking
|
||||
func (_ MockValidator) PushProposerSettings(_ context.Context, _ keymanager.IKeymanager) error {
|
||||
panic("implement me")
|
||||
|
||||
@@ -32,6 +32,7 @@ go_library(
|
||||
"//beacon-chain/core/altair:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//cache/lru:go_default_library",
|
||||
"//cmd/validator/flags:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
|
||||
@@ -60,6 +60,7 @@ type Validator interface {
|
||||
ReceiveBlocks(ctx context.Context, connectionErrorChannel chan<- error)
|
||||
HandleKeyReload(ctx context.Context, newKeys [][fieldparams.BLSPubkeyLength]byte) (bool, error)
|
||||
CheckDoppelGanger(ctx context.Context) error
|
||||
HasProposerSettings() bool
|
||||
PushProposerSettings(ctx context.Context, km keymanager.IKeymanager) error
|
||||
SignValidatorRegistrationRequest(ctx context.Context, signer SigningFunc, newValidatorRegistration *ethpb.ValidatorRegistrationV1) (*ethpb.SignedValidatorRegistrationV1, error)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
@@ -55,13 +56,21 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
}
|
||||
sub := km.SubscribeAccountChanges(accountsChangedChan)
|
||||
// Set properties on the beacon node like the fee recipient for validators that are being used & active.
|
||||
if err := v.PushProposerSettings(ctx, km); err != nil {
|
||||
if errors.Is(err, ErrBuilderValidatorRegistration) {
|
||||
log.WithError(err).Warn("Push proposer settings error")
|
||||
} else {
|
||||
log.WithError(err).Fatal("Failed to update proposer settings") // allow fatal. skipcq
|
||||
if v.HasProposerSettings() {
|
||||
log.Infof("Provided proposer settings will periodically update settings such as fee recipient"+
|
||||
" in the beacon node and custom builder ( if --%s)", flags.EnableBuilderFlag.Name)
|
||||
if err := v.PushProposerSettings(ctx, km); err != nil {
|
||||
if errors.Is(err, ErrBuilderValidatorRegistration) {
|
||||
log.WithError(err).Warn("Push proposer settings error")
|
||||
} else {
|
||||
log.WithError(err).Fatal("Failed to update proposer settings") // allow fatal. skipcq
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Info("Proposer settings such as fee recipient are not defined in the validator client" +
|
||||
" and will continue to use settings provided in the beacon node.")
|
||||
}
|
||||
|
||||
for {
|
||||
_, cancel := context.WithCancel(ctx)
|
||||
ctx, span := trace.StartSpan(ctx, "validator.processSlot")
|
||||
@@ -118,7 +127,7 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
continue
|
||||
}
|
||||
|
||||
if slots.IsEpochStart(slot) {
|
||||
if slots.IsEpochStart(slot) && v.HasProposerSettings() {
|
||||
go func() {
|
||||
//deadline set for next epoch rounded up
|
||||
if err := v.PushProposerSettings(ctx, km); err != nil {
|
||||
|
||||
@@ -247,6 +247,11 @@ func (fv *FakeValidator) HandleKeyReload(_ context.Context, newKeys [][fieldpara
|
||||
func (_ *FakeValidator) SubmitSignedContributionAndProof(_ context.Context, _ types.Slot, _ [fieldparams.BLSPubkeyLength]byte) {
|
||||
}
|
||||
|
||||
// HasProposerSettings for mocking
|
||||
func (*FakeValidator) HasProposerSettings() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// PushProposerSettings for mocking
|
||||
func (fv *FakeValidator) PushProposerSettings(_ context.Context, _ keymanager.IKeymanager) error {
|
||||
if fv.ProposerSettingsErr != nil {
|
||||
|
||||
@@ -956,21 +956,12 @@ func (v *validator) logDuties(slot types.Slot, duties []*ethpb.DutiesResponse_Du
|
||||
}
|
||||
}
|
||||
|
||||
func (v *validator) HasProposerSettings() bool {
|
||||
return v.ProposerSettings != nil
|
||||
}
|
||||
|
||||
// PushProposerSettings calls the prepareBeaconProposer RPC to set the fee recipient and also the register validator API if using a custom builder.
|
||||
func (v *validator) PushProposerSettings(ctx context.Context, km keymanager.IKeymanager) error {
|
||||
// only used after Bellatrix
|
||||
if v.ProposerSettings == nil {
|
||||
e := params.BeaconConfig().BellatrixForkEpoch
|
||||
if e != math.MaxUint64 && slots.ToEpoch(slots.CurrentSlot(v.genesisTime)) < e {
|
||||
log.Warn("You will need to specify the Ethereum addresses which will receive transaction fee rewards from proposing blocks. " +
|
||||
"This is known as a fee recipient configuration. You can read more about this feature in our documentation portal here (https://docs.prylabs.network/docs/execution-node/fee-recipient)")
|
||||
} else {
|
||||
log.Warn("In order to receive transaction fees from proposing blocks post merge, " +
|
||||
"you must specify a configuration known as a fee recipient config. " +
|
||||
"If it is not provided, transaction fees will be burnt. Please see our documentation for more information on this requirement (https://docs.prylabs.network/docs/execution-node/fee-recipient).")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if km == nil {
|
||||
return errors.New("keymanager is nil when calling PrepareBeaconProposer")
|
||||
}
|
||||
@@ -999,7 +990,7 @@ func (v *validator) PushProposerSettings(ctx context.Context, km keymanager.IKey
|
||||
log.WithFields(logrus.Fields{
|
||||
"pubkeysCount": len(pubkeys),
|
||||
"reqCount": len(proposerReqs),
|
||||
}).Warnln("Prepare proposer request did not success with all pubkeys")
|
||||
}).Debugln("Prepare proposer request did not success with all pubkeys")
|
||||
}
|
||||
if _, err := v.validatorClient.PrepareBeaconProposer(ctx, ðpb.PrepareBeaconProposerRequest{
|
||||
Recipients: proposerReqs,
|
||||
@@ -1121,7 +1112,7 @@ func (v *validator) validatorIndex(ctx context.Context, pubkey [fieldparams.BLSP
|
||||
resp, err := v.validatorClient.ValidatorIndex(ctx, ðpb.ValidatorIndexRequest{PublicKey: pubkey[:]})
|
||||
switch {
|
||||
case status.Code(err) == codes.NotFound:
|
||||
log.Warnf("Could not find validator index for public key %#x. "+
|
||||
log.Debugf("Could not find validator index for public key %#x. "+
|
||||
"Perhaps the validator is not yet active.", pubkey)
|
||||
return 0, false, nil
|
||||
case err != nil:
|
||||
|
||||
@@ -1806,26 +1806,6 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: " Skip if no config",
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 1,
|
||||
Offset: 1,
|
||||
},
|
||||
}
|
||||
err := v.WaitForKeymanagerInitialization(ctx)
|
||||
require.NoError(t, err)
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: " proposer config not nil but fee recipient empty",
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
@@ -1910,26 +1890,6 @@ func TestValidator_PushProposerSettings(t *testing.T) {
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Before Bellatrix returns nil",
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
v := validator{
|
||||
validatorClient: client,
|
||||
db: db,
|
||||
pubkeyToValidatorIndex: make(map[[fieldparams.BLSPubkeyLength]byte]types.ValidatorIndex),
|
||||
signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1),
|
||||
useWeb: false,
|
||||
interopKeysConfig: &local.InteropKeymanagerConfig{
|
||||
NumValidatorKeys: 1,
|
||||
Offset: 1,
|
||||
},
|
||||
}
|
||||
err := v.WaitForKeymanagerInitialization(ctx)
|
||||
require.NoError(t, err)
|
||||
params.BeaconConfig().BellatrixForkEpoch = 123456789
|
||||
return &v
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "register validator batch failed",
|
||||
validatorSetter: func(t *testing.T) *validator {
|
||||
|
||||
@@ -497,26 +497,15 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
|
||||
!cliCtx.IsSet(flags.ProposerSettingsFlag.Name) &&
|
||||
!cliCtx.IsSet(flags.ProposerSettingsURLFlag.Name) {
|
||||
suggestedFee := cliCtx.String(flags.SuggestedFeeRecipientFlag.Name)
|
||||
var vr *validatorServiceConfig.BuilderConfig
|
||||
if cliCtx.Bool(flags.EnableBuilderFlag.Name) {
|
||||
sgl := cliCtx.String(flags.BuilderGasLimitFlag.Name)
|
||||
vr = &validatorServiceConfig.BuilderConfig{
|
||||
Enabled: true,
|
||||
GasLimit: validatorServiceConfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
|
||||
}
|
||||
if sgl != "" {
|
||||
gl, err := strconv.ParseUint(sgl, 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.New("Gas Limit is not a uint64")
|
||||
}
|
||||
vr.GasLimit = reviewGasLimit(validatorServiceConfig.Uint64(gl))
|
||||
}
|
||||
builderConfig, err := BuilderSettingsFromFlags(cliCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fileConfig = &validatorServiceConfig.ProposerSettingsPayload{
|
||||
ProposerConfig: nil,
|
||||
DefaultConfig: &validatorServiceConfig.ProposerOptionPayload{
|
||||
FeeRecipient: suggestedFee,
|
||||
BuilderConfig: vr,
|
||||
BuilderConfig: builderConfig,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -553,6 +542,14 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
|
||||
FeeRecipient: common.HexToAddress(fileConfig.DefaultConfig.FeeRecipient),
|
||||
BuilderConfig: fileConfig.DefaultConfig.BuilderConfig,
|
||||
}
|
||||
if vpSettings.DefaultConfig.BuilderConfig == nil {
|
||||
builderConfig, err := BuilderSettingsFromFlags(cliCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vpSettings.DefaultConfig.BuilderConfig = builderConfig
|
||||
}
|
||||
|
||||
if vpSettings.DefaultConfig.BuilderConfig != nil {
|
||||
vpSettings.DefaultConfig.BuilderConfig.GasLimit = reviewGasLimit(vpSettings.DefaultConfig.BuilderConfig.GasLimit)
|
||||
}
|
||||
@@ -578,6 +575,12 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
|
||||
}
|
||||
if option.BuilderConfig != nil {
|
||||
option.BuilderConfig.GasLimit = reviewGasLimit(option.BuilderConfig.GasLimit)
|
||||
} else {
|
||||
builderConfig, err := BuilderSettingsFromFlags(cliCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
option.BuilderConfig = builderConfig
|
||||
}
|
||||
vpSettings.ProposeConfig[bytesutil.ToBytes48(decodedKey)] = &validatorServiceConfig.ProposerOption{
|
||||
FeeRecipient: common.HexToAddress(option.FeeRecipient),
|
||||
@@ -590,6 +593,26 @@ func proposerSettings(cliCtx *cli.Context) (*validatorServiceConfig.ProposerSett
|
||||
return vpSettings, nil
|
||||
}
|
||||
|
||||
func BuilderSettingsFromFlags(cliCtx *cli.Context) (*validatorServiceConfig.BuilderConfig, error) {
|
||||
if cliCtx.Bool(flags.EnableBuilderFlag.Name) {
|
||||
gasLimit := validatorServiceConfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit)
|
||||
sgl := cliCtx.String(flags.BuilderGasLimitFlag.Name)
|
||||
|
||||
if sgl != "" {
|
||||
gl, err := strconv.ParseUint(sgl, 10, 64)
|
||||
if err != nil {
|
||||
return nil, errors.New("Gas Limit is not a uint64")
|
||||
}
|
||||
gasLimit = reviewGasLimit(validatorServiceConfig.Uint64(gl))
|
||||
}
|
||||
return &validatorServiceConfig.BuilderConfig{
|
||||
Enabled: true,
|
||||
GasLimit: gasLimit,
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func warnNonChecksummedAddress(feeRecipient string) error {
|
||||
mixedcaseAddress, err := common.NewMixedcaseAddressFromString(feeRecipient)
|
||||
if err != nil {
|
||||
|
||||
@@ -462,16 +462,90 @@ func TestProposerSettings(t *testing.T) {
|
||||
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption{
|
||||
bytesutil.ToBytes48(key1): {
|
||||
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
|
||||
BuilderConfig: &validatorserviceconfig.BuilderConfig{
|
||||
Enabled: true,
|
||||
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
|
||||
},
|
||||
},
|
||||
},
|
||||
DefaultConfig: &validatorserviceconfig.ProposerOption{
|
||||
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
|
||||
BuilderConfig: &validatorserviceconfig.BuilderConfig{
|
||||
Enabled: true,
|
||||
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
wantErr: "",
|
||||
validatorRegistrationEnabled: true,
|
||||
},
|
||||
{
|
||||
name: "Enable Builder flag overrides empty config",
|
||||
args: args{
|
||||
proposerSettingsFlagValues: &proposerSettingsFlag{
|
||||
dir: "./testdata/good-prepare-beacon-proposer-config.json",
|
||||
url: "",
|
||||
defaultfee: "",
|
||||
},
|
||||
},
|
||||
want: func() *validatorserviceconfig.ProposerSettings {
|
||||
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
|
||||
require.NoError(t, err)
|
||||
return &validatorserviceconfig.ProposerSettings{
|
||||
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption{
|
||||
bytesutil.ToBytes48(key1): {
|
||||
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
|
||||
BuilderConfig: &validatorserviceconfig.BuilderConfig{
|
||||
Enabled: true,
|
||||
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
|
||||
},
|
||||
},
|
||||
},
|
||||
DefaultConfig: &validatorserviceconfig.ProposerOption{
|
||||
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
|
||||
BuilderConfig: &validatorserviceconfig.BuilderConfig{
|
||||
Enabled: true,
|
||||
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
validatorRegistrationEnabled: true,
|
||||
},
|
||||
{
|
||||
name: "Enable Builder flag does not override completed builder config",
|
||||
args: args{
|
||||
proposerSettingsFlagValues: &proposerSettingsFlag{
|
||||
dir: "./testdata/good-prepare-beacon-proposer-config.yaml",
|
||||
url: "",
|
||||
defaultfee: "",
|
||||
},
|
||||
},
|
||||
want: func() *validatorserviceconfig.ProposerSettings {
|
||||
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
|
||||
require.NoError(t, err)
|
||||
return &validatorserviceconfig.ProposerSettings{
|
||||
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption{
|
||||
bytesutil.ToBytes48(key1): {
|
||||
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
|
||||
BuilderConfig: &validatorserviceconfig.BuilderConfig{
|
||||
Enabled: true,
|
||||
GasLimit: validatorserviceconfig.Uint64(40000000),
|
||||
},
|
||||
},
|
||||
},
|
||||
DefaultConfig: &validatorserviceconfig.ProposerOption{
|
||||
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
|
||||
BuilderConfig: &validatorserviceconfig.BuilderConfig{
|
||||
Enabled: false,
|
||||
GasLimit: validatorserviceconfig.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
validatorRegistrationEnabled: true,
|
||||
},
|
||||
{
|
||||
name: "No flags set means empty config",
|
||||
args: args{
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
validatorServiceConfig "github.com/prysmaticlabs/prysm/v3/config/validator/service"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpbservice "github.com/prysmaticlabs/prysm/v3/proto/eth/service"
|
||||
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/derived"
|
||||
slashingprotection "github.com/prysmaticlabs/prysm/v3/validator/slashing-protection-history"
|
||||
@@ -24,6 +25,8 @@ 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,
|
||||
@@ -448,11 +451,26 @@ func (s *Server) SetGasLimit(ctx context.Context, req *ethpbservice.SetGasLimitR
|
||||
pOption.BuilderConfig = pBuilderConfig
|
||||
|
||||
if s.validatorService.ProposerSettings == nil {
|
||||
s.validatorService.ProposerSettings = &validatorServiceConfig.ProposerSettings{
|
||||
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
|
||||
bytesutil.ToBytes48(validatorKey): &pOption,
|
||||
},
|
||||
DefaultConfig: &defaultOption,
|
||||
// get the default fee recipient defined with an invalid public key from beacon node
|
||||
resp, err := s.beaconNodeValidatorClient.GetFeeRecipientByPubKey(ctx, ð.FeeRecipientByPubKeyRequest{
|
||||
PublicKey: []byte(nonExistantPublicKey),
|
||||
})
|
||||
if resp == nil || len(resp.FeeRecipient) == 0 || err != nil {
|
||||
s.validatorService.ProposerSettings = &validatorServiceConfig.ProposerSettings{
|
||||
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
|
||||
bytesutil.ToBytes48(validatorKey): &pOption,
|
||||
},
|
||||
DefaultConfig: &defaultOption,
|
||||
}
|
||||
} else {
|
||||
s.validatorService.ProposerSettings = &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 {
|
||||
s.validatorService.ProposerSettings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption)
|
||||
@@ -510,7 +528,7 @@ func (s *Server) DeleteGasLimit(ctx context.Context, req *ethpbservice.DeleteGas
|
||||
}
|
||||
|
||||
// ListFeeRecipientByPubkey returns the public key to eth address mapping object to the end user.
|
||||
func (s *Server) ListFeeRecipientByPubkey(_ context.Context, req *ethpbservice.PubkeyRequest) (*ethpbservice.GetFeeRecipientByPubkeyResponse, error) {
|
||||
func (s *Server) ListFeeRecipientByPubkey(ctx context.Context, req *ethpbservice.PubkeyRequest) (*ethpbservice.GetFeeRecipientByPubkeyResponse, error) {
|
||||
if s.validatorService == nil {
|
||||
return nil, status.Error(codes.FailedPrecondition, "Validator service not ready")
|
||||
}
|
||||
@@ -519,34 +537,34 @@ func (s *Server) ListFeeRecipientByPubkey(_ context.Context, req *ethpbservice.P
|
||||
return nil, status.Error(codes.FailedPrecondition, err.Error())
|
||||
}
|
||||
defaultFeeRecipient := params.BeaconConfig().DefaultFeeRecipient.Bytes()
|
||||
if s.validatorService.ProposerSettings == nil {
|
||||
return ðpbservice.GetFeeRecipientByPubkeyResponse{
|
||||
Data: ðpbservice.GetFeeRecipientByPubkeyResponse_FeeRecipient{
|
||||
Pubkey: validatorKey,
|
||||
Ethaddress: defaultFeeRecipient,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
if s.validatorService.ProposerSettings.ProposeConfig != nil {
|
||||
proposerOption, found := s.validatorService.ProposerSettings.ProposeConfig[bytesutil.ToBytes48(validatorKey)]
|
||||
if found {
|
||||
return ðpbservice.GetFeeRecipientByPubkeyResponse{
|
||||
Data: ðpbservice.GetFeeRecipientByPubkeyResponse_FeeRecipient{
|
||||
Pubkey: validatorKey,
|
||||
Ethaddress: proposerOption.FeeRecipient.Bytes(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
if s.validatorService.ProposerSettings.DefaultConfig != nil {
|
||||
defaultFeeRecipient = s.validatorService.ProposerSettings.DefaultConfig.FeeRecipient.Bytes()
|
||||
}
|
||||
return ðpbservice.GetFeeRecipientByPubkeyResponse{
|
||||
finalResp := ðpbservice.GetFeeRecipientByPubkeyResponse{
|
||||
Data: ðpbservice.GetFeeRecipientByPubkeyResponse_FeeRecipient{
|
||||
Pubkey: validatorKey,
|
||||
Ethaddress: defaultFeeRecipient,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
if s.validatorService.ProposerSettings == nil {
|
||||
resp, err := s.beaconNodeValidatorClient.GetFeeRecipientByPubKey(ctx, ð.FeeRecipientByPubKeyRequest{
|
||||
PublicKey: validatorKey,
|
||||
})
|
||||
if resp != nil && len(resp.FeeRecipient) != 0 && err == nil {
|
||||
finalResp.Data.Ethaddress = resp.FeeRecipient
|
||||
}
|
||||
return finalResp, nil
|
||||
}
|
||||
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()
|
||||
return finalResp, nil
|
||||
}
|
||||
}
|
||||
if s.validatorService.ProposerSettings.DefaultConfig != nil {
|
||||
finalResp.Data.Ethaddress = s.validatorService.ProposerSettings.DefaultConfig.FeeRecipient.Bytes()
|
||||
}
|
||||
return finalResp, nil
|
||||
}
|
||||
|
||||
// SetFeeRecipientByPubkey updates the eth address mapped to the public key.
|
||||
@@ -568,12 +586,23 @@ func (s *Server) SetFeeRecipientByPubkey(ctx context.Context, req *ethpbservice.
|
||||
pOption.FeeRecipient = common.BytesToAddress(req.Ethaddress)
|
||||
switch {
|
||||
case s.validatorService.ProposerSettings == nil:
|
||||
s.validatorService.ProposerSettings = &validatorServiceConfig.ProposerSettings{
|
||||
// get the default fee recipient defined with an invalid public key from beacon node
|
||||
resp, err := s.beaconNodeValidatorClient.GetFeeRecipientByPubKey(ctx, ð.FeeRecipientByPubKeyRequest{
|
||||
PublicKey: []byte(nonExistantPublicKey),
|
||||
})
|
||||
settings := &validatorServiceConfig.ProposerSettings{
|
||||
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
|
||||
bytesutil.ToBytes48(validatorKey): &pOption,
|
||||
},
|
||||
DefaultConfig: &defaultOption,
|
||||
}
|
||||
if resp == nil || len(resp.FeeRecipient) == 0 || err != nil {
|
||||
settings.DefaultConfig = &defaultOption
|
||||
} else {
|
||||
settings.DefaultConfig = &validatorServiceConfig.ProposerOption{
|
||||
FeeRecipient: common.BytesToAddress(resp.FeeRecipient),
|
||||
}
|
||||
}
|
||||
s.validatorService.ProposerSettings = settings
|
||||
case s.validatorService.ProposerSettings.ProposeConfig == nil:
|
||||
pOption.BuilderConfig = s.validatorService.ProposerSettings.DefaultConfig.BuilderConfig
|
||||
s.validatorService.ProposerSettings.ProposeConfig = map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/google/uuid"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
@@ -18,8 +19,10 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpbservice "github.com/prysmaticlabs/prysm/v3/proto/eth/service"
|
||||
eth "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
mock2 "github.com/prysmaticlabs/prysm/v3/testing/mock"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/iface"
|
||||
@@ -704,6 +707,7 @@ func TestServer_ListFeeRecipientByPubkey(t *testing.T) {
|
||||
name string
|
||||
args *validatorserviceconfig.ProposerSettings
|
||||
want *want
|
||||
cached *eth.FeeRecipientByPubKeyResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
@@ -724,23 +728,60 @@ func TestServer_ListFeeRecipientByPubkey(t *testing.T) {
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty settings",
|
||||
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"),
|
||||
},
|
||||
},
|
||||
want: &want{
|
||||
EthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
|
||||
},
|
||||
cached: ð.FeeRecipientByPubKeyResponse{
|
||||
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9").Bytes(),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty settings non cached",
|
||||
args: nil,
|
||||
want: &want{
|
||||
EthAddress: params.BeaconConfig().DefaultFeeRecipient.Hex(),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty settings cached",
|
||||
args: nil,
|
||||
want: &want{
|
||||
EthAddress: common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e97387").Hex(),
|
||||
},
|
||||
wantErr: false,
|
||||
cached: ð.FeeRecipientByPubKeyResponse{
|
||||
FeeRecipient: common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e97387").Bytes(),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
mockValidatorClient := mock2.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
vs, err := client.NewValidatorService(ctx, &client.Config{
|
||||
Validator: &mock.MockValidator{},
|
||||
ProposerSettings: tt.args,
|
||||
})
|
||||
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,
|
||||
validatorService: vs,
|
||||
beaconNodeValidatorClient: mockValidatorClient,
|
||||
}
|
||||
got, err := s.ListFeeRecipientByPubkey(ctx, ðpbservice.PubkeyRequest{Pubkey: byteval})
|
||||
require.NoError(t, err)
|
||||
@@ -749,11 +790,21 @@ func TestServer_ListFeeRecipientByPubkey(t *testing.T) {
|
||||
}
|
||||
}
|
||||
func TestServer_SetFeeRecipientByPubkey(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
beaconClient := mock2.NewMockBeaconNodeValidatorClient(ctrl)
|
||||
ctx := grpc.NewContextWithServerTransportStream(context.Background(), &runtime.ServerTransportStream{})
|
||||
byteval, err := hexutil.Decode("0xaf2e7ba294e03438ea819bd4033c6c1bf6b04320ee2075b77273c08d02f8a61bcc303c2c06bd3713cb442072ae591493")
|
||||
wantAddress := "0x055Fb65722e7b2455012Bfebf6177f1d2e9738d7"
|
||||
cachedAddress := "0x055Fb65722E7b2455012BFEBf6177F1D2e97387"
|
||||
require.NoError(t, err)
|
||||
type want struct {
|
||||
EthAddress string
|
||||
valEthAddress string
|
||||
defaultEthaddress string
|
||||
}
|
||||
type beaconResp struct {
|
||||
resp *eth.FeeRecipientByPubKeyResponse
|
||||
error error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -761,12 +812,66 @@ func TestServer_SetFeeRecipientByPubkey(t *testing.T) {
|
||||
proposerSettings *validatorserviceconfig.ProposerSettings
|
||||
want *want
|
||||
wantErr bool
|
||||
beaconReturn *beaconResp
|
||||
}{
|
||||
{
|
||||
name: "Happy Path Test",
|
||||
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
|
||||
want: &want{
|
||||
EthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
|
||||
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
|
||||
defaultEthaddress: params.BeaconConfig().DefaultFeeRecipient.Hex(),
|
||||
},
|
||||
wantErr: false,
|
||||
beaconReturn: &beaconResp{
|
||||
resp: nil,
|
||||
error: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Happy Path Test Beacon Cached",
|
||||
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
|
||||
want: &want{
|
||||
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
|
||||
defaultEthaddress: common.HexToAddress(cachedAddress).Hex(),
|
||||
},
|
||||
wantErr: false,
|
||||
beaconReturn: &beaconResp{
|
||||
resp: ð.FeeRecipientByPubKeyResponse{
|
||||
FeeRecipient: common.HexToAddress(cachedAddress).Bytes(),
|
||||
},
|
||||
error: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Happy Path Test Beacon Cached preexisting proposer data",
|
||||
args: wantAddress,
|
||||
want: &want{
|
||||
valEthAddress: wantAddress,
|
||||
defaultEthaddress: common.HexToAddress(cachedAddress).Hex(),
|
||||
},
|
||||
proposerSettings: &validatorserviceconfig.ProposerSettings{
|
||||
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
|
||||
bytesutil.ToBytes48(byteval): {
|
||||
FeeRecipient: common.HexToAddress("0x055Fb65722e7b2455012Bfebf6177f1d2e9738d8"),
|
||||
},
|
||||
},
|
||||
DefaultConfig: &validatorserviceconfig.ProposerOption{
|
||||
FeeRecipient: common.HexToAddress(cachedAddress),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Happy Path Test Beacon Cached preexisting default data",
|
||||
args: wantAddress,
|
||||
want: &want{
|
||||
valEthAddress: wantAddress,
|
||||
defaultEthaddress: common.HexToAddress(cachedAddress).Hex(),
|
||||
},
|
||||
proposerSettings: &validatorserviceconfig.ProposerSettings{
|
||||
DefaultConfig: &validatorserviceconfig.ProposerOption{
|
||||
FeeRecipient: common.HexToAddress(cachedAddress),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
@@ -777,13 +882,21 @@ func TestServer_SetFeeRecipientByPubkey(t *testing.T) {
|
||||
Validator: &mock.MockValidator{},
|
||||
ProposerSettings: tt.proposerSettings,
|
||||
})
|
||||
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,
|
||||
validatorService: vs,
|
||||
beaconNodeValidatorClient: beaconClient,
|
||||
}
|
||||
_, err = s.SetFeeRecipientByPubkey(ctx, ðpbservice.SetFeeRecipientByPubkeyRequest{Pubkey: byteval, Ethaddress: common.HexToAddress(tt.args).Bytes()})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want.EthAddress, s.validatorService.ProposerSettings.ProposeConfig[bytesutil.ToBytes48(byteval)].FeeRecipient.Hex())
|
||||
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())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -905,12 +1018,18 @@ func TestServer_GetGasLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_SetGasLimit(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
beaconClient := mock2.NewMockBeaconNodeValidatorClient(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
|
||||
@@ -922,6 +1041,7 @@ func TestServer_SetGasLimit(t *testing.T) {
|
||||
newGasLimit uint64
|
||||
proposerSettings *validatorserviceconfig.ProposerSettings
|
||||
w []want
|
||||
beaconReturn *beaconResp
|
||||
}{
|
||||
{
|
||||
name: "update existing gas limit",
|
||||
@@ -986,7 +1106,25 @@ func TestServer_SetGasLimit(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create new gas limit value for nil proposerSettings",
|
||||
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{
|
||||
want{
|
||||
pubkey: pubkey1,
|
||||
gaslimit: 7777,
|
||||
},
|
||||
},
|
||||
beaconReturn: &beaconResp{
|
||||
resp: ð.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
|
||||
@@ -996,23 +1134,39 @@ func TestServer_SetGasLimit(t *testing.T) {
|
||||
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()
|
||||
vs, err := client.NewValidatorService(ctx, &client.Config{
|
||||
Validator: &mock.MockValidator{},
|
||||
ProposerSettings: tt.proposerSettings,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
s := &Server{
|
||||
validatorService: vs,
|
||||
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, ðpbservice.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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user