refactoring how proposer settings load into validator client (#13645)

* refactoring how proposer settings load

* fixing tests and moving test data

* fixing linting and adding comments

* accidently removed a function, adding it back in

* fixing usage of dependency

* gaz

* fixing package visibility

* gaz

* iface config gaz

* adding visibility for db

* fix ineffectual assignment to err

* adding in log for when the builder is set but ignored due to no fee recipient

* Update config/validator/service/proposer_settings.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update config/validator/service/proposer_settings.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update validator/client/validator.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update config/validator/service/proposer_settings.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update config/proposer/loader.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update config/proposer/loader.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update config/proposer/loader.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update config/proposer/loader.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update config/proposer/loader.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update config/validator/service/proposer_settings.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update config/util.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* some of the review feedback

* more review comments

* adding more test coverage

* Update config/proposer/loader.go

Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>

* Update config/proposer/loader.go

Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>

* Update config/proposer/loader.go

Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>

* Update config/proposer/loader.go

Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>

* updating based on feedback

* renaming variable

* fixing unhandled errors

* fixing tests

* gaz

* adding in gaslimit log

* fixing log

* some more review comments

* renaming and moving proposer settings file

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
Co-authored-by: Manu NALEPA <enalepa@offchainlabs.com>
This commit is contained in:
james-prysm 2024-03-04 09:12:11 -06:00 committed by GitHub
parent 3df7a1f067
commit d6fb8c29c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
43 changed files with 1823 additions and 1446 deletions

View File

@ -10,6 +10,7 @@ go_library(
visibility = [
"//cmd/prysmctl:__subpackages__",
"//cmd/validator:__subpackages__",
"//config:__subpackages__",
"//testing/endtoend:__subpackages__",
"//validator:__subpackages__",
],

View File

@ -1,3 +1,5 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
config_setting(
name = "mainnet",
flag_values = {
@ -11,3 +13,28 @@ config_setting(
"//proto:network": "minimal",
},
)
go_library(
name = "go_default_library",
srcs = ["util.go"],
importpath = "github.com/prysmaticlabs/prysm/v5/config",
visibility = ["//visibility:public"],
deps = [
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@io_k8s_apimachinery//pkg/util/yaml:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["util_test.go"],
embed = [":go_default_library"],
deps = [
"//config/params:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],
)

View File

@ -2,10 +2,11 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["proposer_settings.go"],
importpath = "github.com/prysmaticlabs/prysm/v5/config/validator/service",
srcs = ["settings.go"],
importpath = "github.com/prysmaticlabs/prysm/v5/config/proposer",
visibility = ["//visibility:public"],
deps = [
"//config:go_default_library",
"//config/fieldparams:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
@ -18,7 +19,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["proposer_settings_test.go"],
srcs = ["settings_test.go"],
embed = [":go_default_library"],
deps = [
"//config/fieldparams:go_default_library",

View File

@ -0,0 +1,45 @@
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
go_test(
name = "go_default_test",
size = "small",
srcs = ["loader_test.go"],
data = glob(["testdata/**"]),
embed = [":go_default_library"],
deps = [
"//cmd/validator/flags:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//validator/db/iface:go_default_library",
"//validator/db/testing:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["loader.go"],
importpath = "github.com/prysmaticlabs/prysm/v5/config/proposer/loader",
visibility = ["//visibility:public"],
deps = [
"//cmd/validator/flags:go_default_library",
"//config:go_default_library",
"//config/params:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/validator:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//validator/db/iface:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
],
)

View File

@ -0,0 +1,283 @@
package loader
import (
"fmt"
"strconv"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/cmd/validator/flags"
"github.com/prysmaticlabs/prysm/v5/config"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/validator"
validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client"
"github.com/prysmaticlabs/prysm/v5/validator/db/iface"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
type settingsType int
const (
none settingsType = iota
defaultFlag
fileFlag
urlFlag
onlyDB
)
type settingsLoader struct {
loadMethods []settingsType
existsInDB bool
db iface.ValidatorDB
options *flagOptions
}
type flagOptions struct {
builderConfig *proposer.BuilderConfig
gasLimit *validator.Uint64
}
// SettingsLoaderOption sets additional options that affect the proposer settings
type SettingsLoaderOption func(cliCtx *cli.Context, psl *settingsLoader) error
// WithBuilderConfig applies the --enable-builder flag to proposer settings
func WithBuilderConfig() SettingsLoaderOption {
return func(cliCtx *cli.Context, psl *settingsLoader) error {
if cliCtx.Bool(flags.EnableBuilderFlag.Name) {
psl.options.builderConfig = &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
}
}
return nil
}
}
// WithGasLimit applies the --suggested-gas-limit flag to proposer settings
func WithGasLimit() SettingsLoaderOption {
return func(cliCtx *cli.Context, psl *settingsLoader) error {
sgl := cliCtx.String(flags.BuilderGasLimitFlag.Name)
if sgl != "" {
gl, err := strconv.ParseUint(sgl, 10, 64)
if err != nil {
return errors.Errorf("Value set by --%s is not a uint64", flags.BuilderGasLimitFlag.Name)
}
if gl == 0 {
log.Warnf("Gas limit was intentionally set to 0, this will be replaced with the default gas limit of %d", params.BeaconConfig().DefaultBuilderGasLimit)
}
rgl := reviewGasLimit(validator.Uint64(gl))
psl.options.gasLimit = &rgl
}
return nil
}
}
// NewProposerSettingsLoader returns a new proposer settings loader that can process the proposer settings based on flag options
func NewProposerSettingsLoader(cliCtx *cli.Context, db iface.ValidatorDB, opts ...SettingsLoaderOption) (*settingsLoader, error) {
if cliCtx.IsSet(flags.ProposerSettingsFlag.Name) && cliCtx.IsSet(flags.ProposerSettingsURLFlag.Name) {
return nil, fmt.Errorf("cannot specify both --%s and --%s flags; choose one method for specifying proposer settings", flags.ProposerSettingsFlag.Name, flags.ProposerSettingsURLFlag.Name)
}
psExists, err := db.ProposerSettingsExists(cliCtx.Context)
if err != nil {
return nil, err
}
psl := &settingsLoader{db: db, existsInDB: psExists, options: &flagOptions{}}
if cliCtx.IsSet(flags.SuggestedFeeRecipientFlag.Name) {
psl.loadMethods = append(psl.loadMethods, defaultFlag)
}
if cliCtx.IsSet(flags.ProposerSettingsFlag.Name) {
psl.loadMethods = append(psl.loadMethods, fileFlag)
}
if cliCtx.IsSet(flags.ProposerSettingsURLFlag.Name) {
psl.loadMethods = append(psl.loadMethods, urlFlag)
}
if len(psl.loadMethods) == 0 {
method := none
if psExists {
// override with db
method = onlyDB
}
psl.loadMethods = append(psl.loadMethods, method)
}
for _, o := range opts {
if err := o(cliCtx, psl); err != nil {
return nil, err
}
}
return psl, nil
}
// Load saves the proposer settings to the database
func (psl *settingsLoader) Load(cliCtx *cli.Context) (*proposer.Settings, error) {
loadConfig := &validatorpb.ProposerSettingsPayload{}
// override settings based on other options
if psl.options.builderConfig != nil && psl.options.gasLimit != nil {
psl.options.builderConfig.GasLimit = *psl.options.gasLimit
}
// check if database has settings already
if psl.existsInDB {
dbps, err := psl.db.ProposerSettings(cliCtx.Context)
if err != nil {
return nil, err
}
loadConfig = dbps.ToConsensus()
}
// start to process based on load method
for _, method := range psl.loadMethods {
switch method {
case defaultFlag:
suggestedFeeRecipient := cliCtx.String(flags.SuggestedFeeRecipientFlag.Name)
if !common.IsHexAddress(suggestedFeeRecipient) {
return nil, errors.Errorf("--%s is not a valid Ethereum address", flags.SuggestedFeeRecipientFlag.Name)
}
if err := config.WarnNonChecksummedAddress(suggestedFeeRecipient); err != nil {
return nil, err
}
defaultConfig := &validatorpb.ProposerOptionPayload{
FeeRecipient: suggestedFeeRecipient,
}
if psl.options.builderConfig != nil {
defaultConfig.Builder = psl.options.builderConfig.ToConsensus()
}
loadConfig.DefaultConfig = defaultConfig
case fileFlag:
var settingFromFile *validatorpb.ProposerSettingsPayload
if err := config.UnmarshalFromFile(cliCtx.String(flags.ProposerSettingsFlag.Name), &settingFromFile); err != nil {
return nil, err
}
if settingFromFile == nil {
return nil, errors.Errorf("proposer settings is empty after unmarshalling from file specified by %s flag", flags.ProposerSettingsFlag.Name)
}
loadConfig = psl.processProposerSettings(settingFromFile, loadConfig)
case urlFlag:
var settingFromURL *validatorpb.ProposerSettingsPayload
if err := config.UnmarshalFromURL(cliCtx.Context, cliCtx.String(flags.ProposerSettingsURLFlag.Name), &settingFromURL); err != nil {
return nil, err
}
if settingFromURL == nil {
return nil, errors.New("proposer settings is empty after unmarshalling from url")
}
loadConfig = psl.processProposerSettings(settingFromURL, loadConfig)
case onlyDB:
loadConfig = psl.processProposerSettings(nil, loadConfig)
case none:
if psl.options.builderConfig != nil {
// if there are no proposer settings provided, create a default where fee recipient is not populated, this will be skipped for validator registration on validators that don't have a fee recipient set.
// skip saving to DB if only builder settings are provided until a trigger like keymanager API updates with fee recipient values
option := &proposer.Option{
BuilderConfig: psl.options.builderConfig.Clone(),
}
loadConfig.DefaultConfig = option.ToConsensus()
}
default:
return nil, errors.New("load method for proposer settings does not exist")
}
}
// exit early if nothing is provided
if loadConfig == nil || (loadConfig.ProposerConfig == nil && loadConfig.DefaultConfig == nil) {
log.Warn("No proposer settings were provided")
return nil, nil
}
ps, err := proposer.SettingFromConsensus(loadConfig)
if err != nil {
return nil, err
}
if err := psl.db.SaveProposerSettings(cliCtx.Context, ps); err != nil {
return nil, err
}
return ps, nil
}
func (psl *settingsLoader) processProposerSettings(loadedSettings, dbSettings *validatorpb.ProposerSettingsPayload) *validatorpb.ProposerSettingsPayload {
if loadedSettings == nil && dbSettings == nil {
return nil
}
// loaded settings have higher priority than db settings
newSettings := &validatorpb.ProposerSettingsPayload{}
var builderConfig *validatorpb.BuilderConfig
var gasLimitOnly *validator.Uint64
if psl.options != nil {
if psl.options.builderConfig != nil {
builderConfig = psl.options.builderConfig.ToConsensus()
}
if psl.options.gasLimit != nil {
gasLimitOnly = psl.options.gasLimit
}
}
if dbSettings != nil && dbSettings.DefaultConfig != nil {
if builderConfig == nil {
dbSettings.DefaultConfig.Builder = nil
}
newSettings.DefaultConfig = dbSettings.DefaultConfig
}
if loadedSettings != nil && loadedSettings.DefaultConfig != nil {
newSettings.DefaultConfig = loadedSettings.DefaultConfig
}
// process any builder overrides on defaults
if newSettings.DefaultConfig != nil {
newSettings.DefaultConfig.Builder = processBuilderConfig(newSettings.DefaultConfig.Builder, builderConfig, gasLimitOnly)
}
if dbSettings != nil && len(dbSettings.ProposerConfig) != 0 {
for _, option := range dbSettings.ProposerConfig {
if builderConfig == nil {
option.Builder = nil
}
}
newSettings.ProposerConfig = dbSettings.ProposerConfig
}
if loadedSettings != nil && len(loadedSettings.ProposerConfig) != 0 {
newSettings.ProposerConfig = loadedSettings.ProposerConfig
}
// process any overrides for proposer config
for _, option := range newSettings.ProposerConfig {
if option != nil {
option.Builder = processBuilderConfig(option.Builder, builderConfig, gasLimitOnly)
}
}
// if default and proposer configs are both missing even after db setting
if newSettings.DefaultConfig == nil && newSettings.ProposerConfig == nil {
return nil
}
return newSettings
}
func processBuilderConfig(current *validatorpb.BuilderConfig, override *validatorpb.BuilderConfig, gasLimitOnly *validator.Uint64) *validatorpb.BuilderConfig {
if current != nil {
current.GasLimit = reviewGasLimit(current.GasLimit)
if override != nil {
current.Enabled = override.Enabled
}
if gasLimitOnly != nil {
current.GasLimit = *gasLimitOnly
}
return current
}
return override
}
func reviewGasLimit(gasLimit validator.Uint64) validator.Uint64 {
// sets gas limit to default if not defined or set to 0
if gasLimit == 0 {
return validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit)
}
// TODO(10810): add in warning for ranges
return gasLimit
}

View File

@ -0,0 +1,921 @@
package loader
import (
"context"
"flag"
"fmt"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/prysmaticlabs/prysm/v5/cmd/validator/flags"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/validator/db/iface"
dbTest "github.com/prysmaticlabs/prysm/v5/validator/db/testing"
logtest "github.com/sirupsen/logrus/hooks/test"
"github.com/urfave/cli/v2"
)
func TestProposerSettingsLoader(t *testing.T) {
hook := logtest.NewGlobal()
type proposerSettingsFlag struct {
dir string
url string
defaultfee string
defaultgas string
}
type args struct {
proposerSettingsFlagValues *proposerSettingsFlag
}
tests := []struct {
name string
args args
want func() *proposer.Settings
urlResponse string
wantInitErr string
wantErr string
wantLog string
withdb func(db iface.ValidatorDB) error
validatorRegistrationEnabled bool
skipDBSavedCheck bool
}{
{
name: "db settings override file settings if file default config is missing",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/proposer-config-only.json",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xae967917c465db8578ca9024c205720b1a3651A9"),
},
},
}
},
withdb: func(db iface.ValidatorDB) error {
settings := &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xae967917c465db8578ca9024c205720b1a3651A9"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
return db.SaveProposerSettings(context.Background(), settings)
},
},
{
name: "db settings override file settings if file proposer config is missing and enable builder is true",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/default-only-proposer-config.json",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xae967917c465db8578ca9024c205720b1a3651A9"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
withdb: func(db iface.ValidatorDB) error {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
},
}
return db.SaveProposerSettings(context.Background(), settings)
},
validatorRegistrationEnabled: true,
},
{
name: "Empty json file loaded throws a warning",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/empty.json",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
return nil
},
wantLog: "No proposer settings were provided",
skipDBSavedCheck: true,
},
{
name: "Happy Path default only proposer settings file with builder settings,",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/default-only-proposer-config.json",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
return &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xae967917c465db8578ca9024c205720b1a3651A9"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
},
{
name: "Happy Path Config file File, bad checksum",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config-badchecksum.json",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xae967917c465db8578ca9024c205720b1a3651A9"),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xae967917c465db8578ca9024c205720b1a3651A9"),
},
},
}
},
wantErr: "",
wantLog: "is not a checksum Ethereum address",
},
{
name: "Happy Path Config file File multiple fee recipients",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config-multiple.json",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
key2, err := hexutil.Decode("0xb057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7b")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
bytesutil.ToBytes48(key2): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x60155530FCE8a85ec7055A5F8b2bE214B3DaeFd4"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(35000000),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
}
},
wantErr: "",
},
{
name: "Happy Path Config URL File",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "./testdata/good-prepare-beacon-proposer-config.json",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
wantErr: "",
},
{
name: "Happy Path Config YAML file with custom Gas Limit",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config.yaml",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 40000000,
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: false,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
wantErr: "",
},
{
name: "Happy Path Suggested Fee ",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
},
},
want: func() *proposer.Settings {
return &proposer.Settings{
ProposeConfig: nil,
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
wantErr: "",
},
{
name: "Happy Path Suggested Fee , validator registration enabled",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
},
},
want: func() *proposer.Settings {
return &proposer.Settings{
ProposeConfig: nil,
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
wantErr: "",
validatorRegistrationEnabled: true,
},
{
name: "Happy Path Suggested Fee , validator registration enabled and default gas",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
defaultgas: "50000000",
},
},
want: func() *proposer.Settings {
return &proposer.Settings{
ProposeConfig: nil,
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 50000000,
},
},
}
},
wantErr: "",
validatorRegistrationEnabled: true,
},
{
name: "File with default gas that overrides",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config.yaml",
url: "",
defaultfee: "",
defaultgas: "50000000",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 50000000,
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: false,
GasLimit: validator.Uint64(50000000),
},
},
}
},
wantErr: "",
},
{
name: "Suggested Fee does not Override Config",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config.json",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89B",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
wantErr: "",
},
{
name: "Suggested Fee with validator registration does not Override Config",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config.json",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89B",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.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() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
validatorRegistrationEnabled: true,
},
{
name: "Enable Builder flag does override completed builder config",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config.yaml",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
validatorRegistrationEnabled: true,
},
{
name: "Only Enable Builder flag",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
return &proposer.Settings{
DefaultConfig: &proposer.Option{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
validatorRegistrationEnabled: true,
skipDBSavedCheck: true,
},
{
name: "No Flags but saved to DB with builder and override removed builder data",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
withdb: func(db iface.ValidatorDB) error {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
return db.SaveProposerSettings(context.Background(), settings)
},
},
{
name: "Enable builder flag but saved to DB without builder data now includes builder data",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
withdb: func(db iface.ValidatorDB) error {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
return db.SaveProposerSettings(context.Background(), settings)
},
validatorRegistrationEnabled: true,
},
{
name: "No flags, but saved to database",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
return &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
withdb: func(db iface.ValidatorDB) error {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
return db.SaveProposerSettings(context.Background(), settings)
},
},
{
name: "No flags set means empty config",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
return nil
},
wantErr: "",
skipDBSavedCheck: true,
},
{
name: "Bad File Path",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/bad-prepare-beacon-proposer-config.json",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
return nil
},
wantErr: "failed to unmarshal yaml file",
},
{
name: "Both URL and Dir flags used resulting in error",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config.json",
url: "./testdata/good-prepare-beacon-proposer-config.json",
defaultfee: "",
},
},
want: func() *proposer.Settings {
return &proposer.Settings{}
},
wantInitErr: "cannot specify both",
},
{
name: "Bad Gas value in JSON",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/bad-gas-value-proposer-settings.json",
url: "",
defaultfee: "",
},
},
want: func() *proposer.Settings {
return nil
},
wantErr: "failed to unmarshal yaml file",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
if tt.args.proposerSettingsFlagValues.dir != "" {
set.String(flags.ProposerSettingsFlag.Name, tt.args.proposerSettingsFlagValues.dir, "")
require.NoError(t, set.Set(flags.ProposerSettingsFlag.Name, tt.args.proposerSettingsFlagValues.dir))
}
if tt.args.proposerSettingsFlagValues.url != "" {
content, err := os.ReadFile(tt.args.proposerSettingsFlagValues.url)
require.NoError(t, err)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/json")
_, err := fmt.Fprintf(w, "%s", content)
require.NoError(t, err)
}))
defer srv.Close()
set.String(flags.ProposerSettingsURLFlag.Name, tt.args.proposerSettingsFlagValues.url, "")
require.NoError(t, set.Set(flags.ProposerSettingsURLFlag.Name, srv.URL))
}
if tt.args.proposerSettingsFlagValues.defaultfee != "" {
set.String(flags.SuggestedFeeRecipientFlag.Name, tt.args.proposerSettingsFlagValues.defaultfee, "")
require.NoError(t, set.Set(flags.SuggestedFeeRecipientFlag.Name, tt.args.proposerSettingsFlagValues.defaultfee))
}
if tt.args.proposerSettingsFlagValues.defaultgas != "" {
set.String(flags.BuilderGasLimitFlag.Name, tt.args.proposerSettingsFlagValues.defaultgas, "")
require.NoError(t, set.Set(flags.BuilderGasLimitFlag.Name, tt.args.proposerSettingsFlagValues.defaultgas))
}
if tt.validatorRegistrationEnabled {
set.Bool(flags.EnableBuilderFlag.Name, true, "")
}
cliCtx := cli.NewContext(&app, set, nil)
validatorDB := dbTest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
if tt.withdb != nil {
err := tt.withdb(validatorDB)
require.NoError(t, err)
}
loader, err := NewProposerSettingsLoader(
cliCtx,
validatorDB,
WithBuilderConfig(),
WithGasLimit(),
)
if tt.wantInitErr != "" {
require.ErrorContains(t, tt.wantInitErr, err)
return
} else {
require.NoError(t, err)
}
got, err := loader.Load(cliCtx)
if tt.wantErr != "" {
require.ErrorContains(t, tt.wantErr, err)
return
}
if tt.wantLog != "" {
assert.LogsContain(t, hook,
tt.wantLog,
)
}
w := tt.want()
require.DeepEqual(t, w, got)
if !tt.skipDBSavedCheck {
dbSettings, err := validatorDB.ProposerSettings(cliCtx.Context)
require.NoError(t, err)
require.DeepEqual(t, w, dbSettings)
}
})
}
}
func Test_ProposerSettingsLoaderWithOnlyBuilder_DoesNotSaveInDB(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.Bool(flags.EnableBuilderFlag.Name, true, "")
cliCtx := cli.NewContext(&app, set, nil)
validatorDB := dbTest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
loader, err := NewProposerSettingsLoader(
cliCtx,
validatorDB,
WithBuilderConfig(),
WithGasLimit(),
)
require.NoError(t, err)
got, err := loader.Load(cliCtx)
require.NoError(t, err)
_, err = validatorDB.ProposerSettings(cliCtx.Context)
require.ErrorContains(t, "no proposer settings found in bucket", err)
want := &proposer.Settings{
DefaultConfig: &proposer.Option{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
Relays: nil,
},
},
}
require.DeepEqual(t, want, got)
}

View File

@ -1,5 +1,4 @@
{
"proposer_config": {},
"default_config": {
"fee_recipient": "0xAe967917c465db8578ca9024c205720b1a3651A9",
"builder": {"enabled": true}

View File

@ -0,0 +1,3 @@
{
}

View File

@ -0,0 +1,7 @@
{
"proposer_config": {
"0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a": {
"fee_recipient": "0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"
}
}
}

View File

@ -1,4 +1,4 @@
package validator_service_config
package proposer
import (
"fmt"
@ -6,51 +6,77 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/config"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client"
)
// ToSettings converts struct to ProposerSettings
func ToSettings(ps *validatorpb.ProposerSettingsPayload) (*ProposerSettings, error) {
settings := &ProposerSettings{}
if ps.ProposerConfig != nil {
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption)
// SettingFromConsensus converts struct to Settings while verifying the fields
func SettingFromConsensus(ps *validatorpb.ProposerSettingsPayload) (*Settings, error) {
settings := &Settings{}
if ps.ProposerConfig != nil && len(ps.ProposerConfig) != 0 {
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*Option)
for key, optionPayload := range ps.ProposerConfig {
if optionPayload.FeeRecipient == "" {
continue
}
b, err := hexutil.Decode(key)
decodedKey, err := hexutil.Decode(key)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("cannot decode public key %s", key))
}
p := &ProposerOption{
if len(decodedKey) != fieldparams.BLSPubkeyLength {
return nil, fmt.Errorf("%v is not a bls public key", key)
}
if err := verifyOption(key, optionPayload); err != nil {
return nil, err
}
p := &Option{
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress(optionPayload.FeeRecipient),
},
}
if optionPayload.Builder != nil {
p.BuilderConfig = ToBuilderConfig(optionPayload.Builder)
p.BuilderConfig = BuilderConfigFromConsensus(optionPayload.Builder)
}
settings.ProposeConfig[bytesutil.ToBytes48(b)] = p
settings.ProposeConfig[bytesutil.ToBytes48(decodedKey)] = p
}
}
if ps.DefaultConfig != nil {
d := &ProposerOption{}
d := &Option{}
if ps.DefaultConfig.FeeRecipient != "" {
if !common.IsHexAddress(ps.DefaultConfig.FeeRecipient) {
return nil, errors.New("default fee recipient is not a valid Ethereum address")
}
if err := config.WarnNonChecksummedAddress(ps.DefaultConfig.FeeRecipient); err != nil {
return nil, err
}
d.FeeRecipientConfig = &FeeRecipientConfig{
FeeRecipient: common.HexToAddress(ps.DefaultConfig.FeeRecipient),
}
}
if ps.DefaultConfig.Builder != nil {
d.BuilderConfig = ToBuilderConfig(ps.DefaultConfig.Builder)
d.BuilderConfig = BuilderConfigFromConsensus(ps.DefaultConfig.Builder)
}
settings.DefaultConfig = d
}
return settings, nil
}
func verifyOption(key string, option *validatorpb.ProposerOptionPayload) error {
if option == nil {
return fmt.Errorf("fee recipient is required for proposer %s", key)
}
if !common.IsHexAddress(option.FeeRecipient) {
return errors.New("fee recipient is not a valid Ethereum address")
}
if err := config.WarnNonChecksummedAddress(option.FeeRecipient); err != nil {
return err
}
return nil
}
// BuilderConfig is the struct representation of the JSON config file set in the validator through the CLI.
// GasLimit is a number set to help the network decide on the maximum gas in each block.
type BuilderConfig struct {
@ -59,29 +85,28 @@ type BuilderConfig struct {
Relays []string `json:"relays,omitempty" yaml:"relays,omitempty"`
}
// ToBuilderConfig converts protobuf to a builder config used in inmemory storage
func ToBuilderConfig(from *validatorpb.BuilderConfig) *BuilderConfig {
// BuilderConfigFromConsensus converts protobuf to a builder config used in in-memory storage
func BuilderConfigFromConsensus(from *validatorpb.BuilderConfig) *BuilderConfig {
if from == nil {
return nil
}
config := &BuilderConfig{
c := &BuilderConfig{
Enabled: from.Enabled,
GasLimit: from.GasLimit,
}
if from.Relays != nil {
relays := make([]string, len(from.Relays))
copy(relays, from.Relays)
config.Relays = relays
c.Relays = relays
}
return config
return c
}
// ProposerSettings is a Prysm internal representation of the fee recipient config on the validator client.
// validatorpb.ProposerSettingsPayload maps to ProposerSettings on import through the CLI.
type ProposerSettings struct {
ProposeConfig map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption
DefaultConfig *ProposerOption
// Settings is a Prysm internal representation of the fee recipient config on the validator client.
// validatorpb.ProposerSettingsPayload maps to Settings on import through the CLI.
type Settings struct {
ProposeConfig map[[fieldparams.BLSPubkeyLength]byte]*Option
DefaultConfig *Option
}
// ShouldBeSaved goes through checks to see if the value should be saveable
@ -89,12 +114,12 @@ type ProposerSettings struct {
// 1. settings are not nil
// 2. proposeconfig is not nil (this defines specific settings for each validator key), default config can be nil in this case and fall back to beacon node settings
// 3. defaultconfig is not nil, meaning it has at least fee recipient settings (this defines general settings for all validator keys but keys will use settings from propose config if available), propose config can be nil in this case
func (settings *ProposerSettings) ShouldBeSaved() bool {
return settings != nil && (settings.ProposeConfig != nil || settings.DefaultConfig != nil && settings.DefaultConfig.FeeRecipientConfig != nil)
func (ps *Settings) ShouldBeSaved() bool {
return ps != nil && (ps.ProposeConfig != nil || ps.DefaultConfig != nil && ps.DefaultConfig.FeeRecipientConfig != nil)
}
// ToPayload converts struct to ProposerSettingsPayload
func (ps *ProposerSettings) ToPayload() *validatorpb.ProposerSettingsPayload {
// ToConsensus converts struct to ProposerSettingsPayload
func (ps *Settings) ToConsensus() *validatorpb.ProposerSettingsPayload {
if ps == nil {
return nil
}
@ -102,25 +127,11 @@ func (ps *ProposerSettings) ToPayload() *validatorpb.ProposerSettingsPayload {
if ps.ProposeConfig != nil {
payload.ProposerConfig = make(map[string]*validatorpb.ProposerOptionPayload)
for key, option := range ps.ProposeConfig {
p := &validatorpb.ProposerOptionPayload{}
if option.FeeRecipientConfig != nil {
p.FeeRecipient = option.FeeRecipientConfig.FeeRecipient.Hex()
}
if option.BuilderConfig != nil {
p.Builder = option.BuilderConfig.ToPayload()
}
payload.ProposerConfig[hexutil.Encode(key[:])] = p
payload.ProposerConfig[hexutil.Encode(key[:])] = option.ToConsensus()
}
}
if ps.DefaultConfig != nil {
p := &validatorpb.ProposerOptionPayload{}
if ps.DefaultConfig.FeeRecipientConfig != nil {
p.FeeRecipient = ps.DefaultConfig.FeeRecipientConfig.FeeRecipient.Hex()
}
if ps.DefaultConfig.BuilderConfig != nil {
p.Builder = ps.DefaultConfig.BuilderConfig.ToPayload()
}
payload.DefaultConfig = p
payload.DefaultConfig = ps.DefaultConfig.ToConsensus()
}
return payload
}
@ -130,23 +141,52 @@ type FeeRecipientConfig struct {
FeeRecipient common.Address
}
// ProposerOption is a Prysm internal representation of the ProposerOptionPayload on the validator client in bytes format instead of hex.
type ProposerOption struct {
// Option is a Prysm internal representation of the ProposerOptionPayload on the validator client in bytes format instead of hex.
type Option struct {
FeeRecipientConfig *FeeRecipientConfig
BuilderConfig *BuilderConfig
}
// Clone creates a deep copy of proposer option
func (po *Option) Clone() *Option {
if po == nil {
return nil
}
p := &Option{}
if po.FeeRecipientConfig != nil {
p.FeeRecipientConfig = po.FeeRecipientConfig.Clone()
}
if po.BuilderConfig != nil {
p.BuilderConfig = po.BuilderConfig.Clone()
}
return p
}
func (po *Option) ToConsensus() *validatorpb.ProposerOptionPayload {
if po == nil {
return nil
}
p := &validatorpb.ProposerOptionPayload{}
if po.FeeRecipientConfig != nil {
p.FeeRecipient = po.FeeRecipientConfig.FeeRecipient.Hex()
}
if po.BuilderConfig != nil {
p.Builder = po.BuilderConfig.ToConsensus()
}
return p
}
// Clone creates a deep copy of the proposer settings
func (ps *ProposerSettings) Clone() *ProposerSettings {
func (ps *Settings) Clone() *Settings {
if ps == nil {
return nil
}
clone := &ProposerSettings{}
clone := &Settings{}
if ps.DefaultConfig != nil {
clone.DefaultConfig = ps.DefaultConfig.Clone()
}
if ps.ProposeConfig != nil {
clone.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption)
clone.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*Option)
for k, v := range ps.ProposeConfig {
keyCopy := k
valCopy := v.Clone()
@ -170,46 +210,31 @@ func (bc *BuilderConfig) Clone() *BuilderConfig {
if bc == nil {
return nil
}
config := &BuilderConfig{}
config.Enabled = bc.Enabled
config.GasLimit = bc.GasLimit
c := &BuilderConfig{}
c.Enabled = bc.Enabled
c.GasLimit = bc.GasLimit
var relays []string
if bc.Relays != nil {
relays = make([]string, len(bc.Relays))
copy(relays, bc.Relays)
config.Relays = relays
c.Relays = relays
}
return config
return c
}
// ToPayload converts Builder Config to the protobuf object
func (bc *BuilderConfig) ToPayload() *validatorpb.BuilderConfig {
// ToConsensus converts Builder Config to the protobuf object
func (bc *BuilderConfig) ToConsensus() *validatorpb.BuilderConfig {
if bc == nil {
return nil
}
config := &validatorpb.BuilderConfig{}
config.Enabled = bc.Enabled
c := &validatorpb.BuilderConfig{}
c.Enabled = bc.Enabled
var relays []string
if bc.Relays != nil {
relays = make([]string, len(bc.Relays))
copy(relays, bc.Relays)
config.Relays = relays
c.Relays = relays
}
config.GasLimit = bc.GasLimit
return config
}
// Clone creates a deep copy of proposer option
func (po *ProposerOption) Clone() *ProposerOption {
if po == nil {
return nil
}
p := &ProposerOption{}
if po.FeeRecipientConfig != nil {
p.FeeRecipientConfig = po.FeeRecipientConfig.Clone()
}
if po.BuilderConfig != nil {
p.BuilderConfig = po.BuilderConfig.Clone()
}
return p
c.GasLimit = bc.GasLimit
return c
}

View File

@ -1,4 +1,4 @@
package validator_service_config
package proposer
import (
"testing"
@ -16,8 +16,8 @@ func Test_Proposer_Setting_Cloning(t *testing.T) {
key1hex := "0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a"
key1, err := hexutil.Decode(key1hex)
require.NoError(t, err)
settings := &ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption{
settings := &Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
@ -29,7 +29,7 @@ func Test_Proposer_Setting_Cloning(t *testing.T) {
},
},
},
DefaultConfig: &ProposerOption{
DefaultConfig: &Option{
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
@ -59,15 +59,15 @@ func Test_Proposer_Setting_Cloning(t *testing.T) {
require.NotEqual(t, settings.DefaultConfig.BuilderConfig.GasLimit, clone.GasLimit)
})
t.Run("Happy Path ToBuilderConfig", func(t *testing.T) {
t.Run("Happy Path BuilderConfigFromConsensus", func(t *testing.T) {
clone := settings.DefaultConfig.BuilderConfig.Clone()
config := ToBuilderConfig(clone.ToPayload())
config := BuilderConfigFromConsensus(clone.ToConsensus())
require.DeepEqual(t, config.Relays, clone.Relays)
require.Equal(t, config.Enabled, clone.Enabled)
require.Equal(t, config.GasLimit, clone.GasLimit)
})
t.Run("To Payload and ToSettings", func(t *testing.T) {
payload := settings.ToPayload()
t.Run("To Payload and SettingFromConsensus", func(t *testing.T) {
payload := settings.ToConsensus()
option, ok := settings.ProposeConfig[bytesutil.ToBytes48(key1)]
require.Equal(t, true, ok)
fee := option.FeeRecipientConfig.FeeRecipient.Hex()
@ -77,7 +77,7 @@ func Test_Proposer_Setting_Cloning(t *testing.T) {
require.Equal(t, settings.DefaultConfig.FeeRecipientConfig.FeeRecipient.Hex(), payload.DefaultConfig.FeeRecipient)
require.Equal(t, settings.DefaultConfig.BuilderConfig.Enabled, payload.DefaultConfig.Builder.Enabled)
potion.FeeRecipient = ""
newSettings, err := ToSettings(payload)
newSettings, err := SettingFromConsensus(payload)
require.NoError(t, err)
// when converting to settings if a fee recipient is empty string then it will be skipped
@ -88,7 +88,7 @@ func Test_Proposer_Setting_Cloning(t *testing.T) {
// if fee recipient is set it will not skip
potion.FeeRecipient = fee
newSettings, err = ToSettings(payload)
newSettings, err = SettingFromConsensus(payload)
require.NoError(t, err)
noption, ok = newSettings.ProposeConfig[bytesutil.ToBytes48(key1)]
require.Equal(t, true, ok)
@ -104,8 +104,8 @@ func TestProposerSettings_ShouldBeSaved(t *testing.T) {
key1, err := hexutil.Decode(key1hex)
require.NoError(t, err)
type fields struct {
ProposeConfig map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption
DefaultConfig *ProposerOption
ProposeConfig map[[fieldparams.BLSPubkeyLength]byte]*Option
DefaultConfig *Option
}
tests := []struct {
name string
@ -115,7 +115,7 @@ func TestProposerSettings_ShouldBeSaved(t *testing.T) {
{
name: "Should be saved, proposeconfig populated and no default config",
fields: fields{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
@ -135,7 +135,7 @@ func TestProposerSettings_ShouldBeSaved(t *testing.T) {
name: "Should be saved, default populated and no proposeconfig ",
fields: fields{
ProposeConfig: nil,
DefaultConfig: &ProposerOption{
DefaultConfig: &Option{
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
@ -151,7 +151,7 @@ func TestProposerSettings_ShouldBeSaved(t *testing.T) {
{
name: "Should be saved, all populated",
fields: fields{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*ProposerOption{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
@ -163,7 +163,7 @@ func TestProposerSettings_ShouldBeSaved(t *testing.T) {
},
},
},
DefaultConfig: &ProposerOption{
DefaultConfig: &Option{
FeeRecipientConfig: &FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
@ -189,7 +189,7 @@ func TestProposerSettings_ShouldBeSaved(t *testing.T) {
name: "Should not be saved, builder data only",
fields: fields{
ProposeConfig: nil,
DefaultConfig: &ProposerOption{
DefaultConfig: &Option{
BuilderConfig: &BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
@ -202,7 +202,7 @@ func TestProposerSettings_ShouldBeSaved(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
settings := &ProposerSettings{
settings := &Settings{
ProposeConfig: tt.fields.ProposeConfig,
DefaultConfig: tt.fields.DefaultConfig,
}

76
config/util.go Normal file
View File

@ -0,0 +1,76 @@
package config
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/util/yaml"
)
func UnmarshalFromURL(ctx context.Context, from string, to interface{}) error {
u, err := url.ParseRequestURI(from)
if err != nil {
return err
}
if u.Scheme == "" || u.Host == "" {
return fmt.Errorf("invalid URL: %s", from)
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, from, nil)
if err != nil {
return errors.Wrap(err, "failed to create http request")
}
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return errors.Wrap(err, "failed to send http request")
}
defer func(Body io.ReadCloser) {
err = Body.Close()
if err != nil {
log.WithError(err).Error("Failed to close response body")
}
}(resp.Body)
if resp.StatusCode != http.StatusOK {
return errors.Errorf("http request to %v failed with status code %d", from, resp.StatusCode)
}
if err := json.NewDecoder(resp.Body).Decode(&to); err != nil {
return errors.Wrap(err, "failed to decode http response")
}
return nil
}
func UnmarshalFromFile(from string, to interface{}) error {
cleanpath := filepath.Clean(from)
b, err := os.ReadFile(cleanpath)
if err != nil {
return errors.Wrap(err, "failed to open file")
}
if err := yaml.Unmarshal(b, to); err != nil {
return errors.Wrap(err, "failed to unmarshal yaml file")
}
return nil
}
func WarnNonChecksummedAddress(feeRecipient string) error {
mixedcaseAddress, err := common.NewMixedcaseAddressFromString(feeRecipient)
if err != nil {
return errors.Wrapf(err, "could not decode fee recipient %s", feeRecipient)
}
if !mixedcaseAddress.ValidChecksum() {
log.Warnf("Fee recipient %s is not a checksum Ethereum address. "+
"The checksummed address is %s and will be used as the fee recipient. "+
"We recommend using a mixed-case address (checksum) "+
"to prevent spelling mistakes in your fee recipient Ethereum address", feeRecipient, mixedcaseAddress.Address().Hex())
}
return nil
}

61
config/util_test.go Normal file
View File

@ -0,0 +1,61 @@
package config
import (
"context"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/sirupsen/logrus/hooks/test"
)
func TestUnmarshalFromURL_Success(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, err := w.Write([]byte(`{"key":"value"}`))
require.NoError(t, err)
}))
defer server.Close()
var result map[string]string
err := UnmarshalFromURL(context.Background(), server.URL, &result)
if err != nil {
t.Errorf("UnmarshalFromURL failed: %v", err)
}
if result["key"] != "value" {
t.Errorf("Expected value to be 'value', got '%s'", result["key"])
}
}
func TestUnmarshalFromFile_Success(t *testing.T) {
// Temporarily create a YAML file
tmpFile, err := os.CreateTemp(t.TempDir(), "example.*.yaml")
require.NoError(t, err)
defer require.NoError(t, os.Remove(tmpFile.Name())) // Clean up
content := []byte("key: value")
require.NoError(t, os.WriteFile(tmpFile.Name(), content, params.BeaconIoConfig().ReadWritePermissions))
require.NoError(t, tmpFile.Close())
var result map[string]string
require.NoError(t, UnmarshalFromFile(tmpFile.Name(), &result))
require.Equal(t, result["key"], "value")
}
func TestWarnNonChecksummedAddress(t *testing.T) {
logHook := test.NewGlobal()
address := "0x967646dCD8d34F4E02204faeDcbAe0cC96fB9245"
err := WarnNonChecksummedAddress(address)
require.NoError(t, err)
assert.LogsDoNotContain(t, logHook, "is not a checksum Ethereum address")
address = strings.ToLower("0x967646dCD8d34F4E02204faeDcbAe0cC96fB9244")
err = WarnNonChecksummedAddress(address)
require.NoError(t, err)
assert.LogsContain(t, logHook, "is not a checksum Ethereum address")
}

View File

@ -10,7 +10,7 @@ go_library(
"//validator:__subpackages__",
],
deps = [
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/primitives:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//validator/accounts/iface:go_default_library",

View File

@ -7,7 +7,7 @@ import (
"sync"
"time"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/validator/accounts/iface"
@ -89,7 +89,7 @@ func (_ *Wallet) InitializeKeymanager(_ context.Context, _ iface.InitKeymanagerC
type Validator struct {
Km keymanager.IKeymanager
proposerSettings *validatorserviceconfig.ProposerSettings
proposerSettings *proposer.Settings
}
func (_ *Validator) LogSubmittedSyncCommitteeMessages() {}
@ -203,12 +203,12 @@ func (_ *Validator) SignValidatorRegistrationRequest(_ context.Context, _ iface2
}
// ProposerSettings for mocking
func (m *Validator) ProposerSettings() *validatorserviceconfig.ProposerSettings {
func (m *Validator) ProposerSettings() *proposer.Settings {
return m.proposerSettings
}
// SetProposerSettings for mocking
func (m *Validator) SetProposerSettings(_ context.Context, settings *validatorserviceconfig.ProposerSettings) error {
func (m *Validator) SetProposerSettings(_ context.Context, settings *proposer.Settings) error {
m.proposerSettings = settings
return nil
}

View File

@ -36,7 +36,7 @@ go_library(
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
@ -126,7 +126,7 @@ go_test(
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/blocks/testing:go_default_library",
"//consensus-types/interfaces:go_default_library",

View File

@ -13,7 +13,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//config/fieldparams:go_default_library",
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//crypto/bls:go_default_library",

View File

@ -6,7 +6,7 @@ import (
"time"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@ -62,8 +62,8 @@ type Validator interface {
CheckDoppelGanger(ctx context.Context) error
PushProposerSettings(ctx context.Context, km keymanager.IKeymanager, slot primitives.Slot, deadline time.Time) error
SignValidatorRegistrationRequest(ctx context.Context, signer SigningFunc, newValidatorRegistration *ethpb.ValidatorRegistrationV1) (*ethpb.SignedValidatorRegistrationV1, error)
ProposerSettings() *validatorserviceconfig.ProposerSettings
SetProposerSettings(context.Context, *validatorserviceconfig.ProposerSettings) error
ProposerSettings() *proposer.Settings
SetProposerSettings(context.Context, *proposer.Settings) error
StartEventStream(ctx context.Context) error
EventStreamIsRunning() bool
NodeIsHealthy(ctx context.Context) bool

View File

@ -11,7 +11,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/async/event"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
@ -225,9 +225,9 @@ func notActive(t *testing.T) [fieldparams.BLSPubkeyLength]byte {
func TestUpdateProposerSettingsAt_EpochStart(t *testing.T) {
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
err := v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
err := v.SetProposerSettings(context.Background(), &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
@ -250,9 +250,9 @@ func TestUpdateProposerSettingsAt_EpochStart(t *testing.T) {
func TestUpdateProposerSettingsAt_EpochEndOk(t *testing.T) {
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}, ProposerSettingWait: time.Duration(params.BeaconConfig().SecondsPerSlot-1) * time.Second}
err := v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
err := v.SetProposerSettings(context.Background(), &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
@ -279,9 +279,9 @@ func TestUpdateProposerSettings_ContinuesAfterValidatorRegistrationFails(t *test
ProposerSettingsErr: errors.Wrap(ErrBuilderValidatorRegistration, errSomeotherError.Error()),
Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}},
}
err := v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
err := v.SetProposerSettings(context.Background(), &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},

View File

@ -17,7 +17,7 @@ import (
lruwrpr "github.com/prysmaticlabs/prysm/v5/cache/lru"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/validator/accounts/wallet"
@ -75,7 +75,7 @@ type ValidatorService struct {
grpcHeaders []string
graffiti []byte
Web3SignerConfig *remoteweb3signer.SetupConfig
proposerSettings *validatorserviceconfig.ProposerSettings
proposerSettings *proposer.Settings
validatorsRegBatchSize int
}
@ -100,7 +100,7 @@ type Config struct {
GraffitiFlag string
Endpoint string
Web3SignerConfig *remoteweb3signer.SetupConfig
ProposerSettings *validatorserviceconfig.ProposerSettings
ProposerSettings *proposer.Settings
BeaconApiEndpoint string
BeaconApiTimeout time.Duration
ValidatorsRegBatchSize int
@ -271,7 +271,7 @@ func (v *ValidatorService) Keymanager() (keymanager.IKeymanager, error) {
}
// ProposerSettings returns a deep copy of the underlying proposer settings in the validator
func (v *ValidatorService) ProposerSettings() *validatorserviceconfig.ProposerSettings {
func (v *ValidatorService) ProposerSettings() *proposer.Settings {
settings := v.validator.ProposerSettings()
if settings != nil {
return settings.Clone()
@ -280,7 +280,7 @@ func (v *ValidatorService) ProposerSettings() *validatorserviceconfig.ProposerSe
}
// SetProposerSettings sets the proposer settings on the validator service as well as the underlying validator
func (v *ValidatorService) SetProposerSettings(ctx context.Context, settings *validatorserviceconfig.ProposerSettings) error {
func (v *ValidatorService) SetProposerSettings(ctx context.Context, settings *proposer.Settings) error {
// validator service proposer settings is only used for pass through from node -> validator service -> validator.
// in memory use of proposer settings happens on validator.
v.proposerSettings = settings

View File

@ -11,7 +11,7 @@ go_library(
visibility = ["//validator:__subpackages__"],
deps = [
"//config/fieldparams:go_default_library",
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",

View File

@ -6,7 +6,7 @@ import (
"time"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
prysmTime "github.com/prysmaticlabs/prysm/v5/time"
@ -52,7 +52,7 @@ type FakeValidator struct {
IndexToPubkeyMap map[uint64][fieldparams.BLSPubkeyLength]byte
PubkeyToIndexMap map[[fieldparams.BLSPubkeyLength]byte]uint64
PubkeysToStatusesMap map[[fieldparams.BLSPubkeyLength]byte]ethpb.ValidatorStatus
proposerSettings *validatorserviceconfig.ProposerSettings
proposerSettings *proposer.Settings
ProposerSettingWait time.Duration
Km keymanager.IKeymanager
}
@ -276,12 +276,12 @@ func (*FakeValidator) SignValidatorRegistrationRequest(_ context.Context, _ ifac
}
// ProposerSettings for mocking
func (fv *FakeValidator) ProposerSettings() *validatorserviceconfig.ProposerSettings {
func (fv *FakeValidator) ProposerSettings() *proposer.Settings {
return fv.proposerSettings
}
// SetProposerSettings for mocking
func (fv *FakeValidator) SetProposerSettings(_ context.Context, settings *validatorserviceconfig.ProposerSettings) error {
func (fv *FakeValidator) SetProposerSettings(_ context.Context, settings *proposer.Settings) error {
fv.proposerSettings = settings
return nil
}

View File

@ -26,7 +26,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/hash"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
@ -106,7 +106,7 @@ type validator struct {
voteStats voteStats
syncCommitteeStats syncCommitteeStats
Web3SignerConfig *remoteweb3signer.SetupConfig
proposerSettings *validatorserviceconfig.ProposerSettings
proposerSettings *proposer.Settings
walletInitializedChannel chan *wallet.Wallet
validatorsRegBatchSize int
}
@ -1028,12 +1028,12 @@ func (v *validator) logDuties(slot primitives.Slot, currentEpochDuties []*ethpb.
}
// ProposerSettings gets the current proposer settings saved in memory validator
func (v *validator) ProposerSettings() *validatorserviceconfig.ProposerSettings {
func (v *validator) ProposerSettings() *proposer.Settings {
return v.proposerSettings
}
// SetProposerSettings sets and saves the passed in proposer settings overriding the in memory one
func (v *validator) SetProposerSettings(ctx context.Context, settings *validatorserviceconfig.ProposerSettings) error {
func (v *validator) SetProposerSettings(ctx context.Context, settings *proposer.Settings) error {
if v.db == nil {
return errors.New("db is not set")
}
@ -1196,6 +1196,10 @@ func (v *validator) buildSignedRegReqs(ctx context.Context, pubkeys [][fieldpara
gasLimit := params.BeaconConfig().DefaultBuilderGasLimit
enabled := false
if v.ProposerSettings().DefaultConfig != nil && v.ProposerSettings().DefaultConfig.FeeRecipientConfig == nil && v.ProposerSettings().DefaultConfig.BuilderConfig != nil {
log.Warn("Builder is `enabled` in default config but will be ignored because no fee recipient was provided!")
}
if v.ProposerSettings().DefaultConfig != nil && v.ProposerSettings().DefaultConfig.FeeRecipientConfig != nil {
defaultConfig := v.ProposerSettings().DefaultConfig
feeRecipient = defaultConfig.FeeRecipientConfig.FeeRecipient // Use cli defaultBuilderConfig for fee recipient.

View File

@ -18,7 +18,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
validatorType "github.com/prysmaticlabs/prysm/v5/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
@ -1415,7 +1415,7 @@ func TestValidator_WaitForKeymanagerInitialization_Interop(t *testing.T) {
require.NotNil(t, km)
}
func TestValidator_PushProposerSettings(t *testing.T) {
func TestValidator_PushSettings(t *testing.T) {
ctrl := gomock.NewController(t)
ctx := context.Background()
db := dbTest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
@ -1459,7 +1459,7 @@ func TestValidator_PushProposerSettings(t *testing.T) {
}
err := v.WaitForKeymanagerInitialization(ctx)
require.NoError(t, err)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option)
km, err := v.Keymanager()
require.NoError(t, err)
keys, err := km.FetchValidatingPublicKeys(ctx)
@ -1479,22 +1479,22 @@ func TestValidator_PushProposerSettings(t *testing.T) {
{FeeRecipient: common.HexToAddress(defaultFeeHex).Bytes(), ValidatorIndex: 2},
},
}).Return(nil, nil)
config[keys[0]] = &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
config[keys[0]] = &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x055Fb65722E7b2455043BFEBf6177F1D2e9738D9"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 40000000,
},
}
err = v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
err = v.SetProposerSettings(context.Background(), &proposer.Settings{
ProposeConfig: config,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(defaultFeeHex),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 35000000,
},
@ -1541,7 +1541,7 @@ func TestValidator_PushProposerSettings(t *testing.T) {
}
err := v.WaitForKeymanagerInitialization(ctx)
require.NoError(t, err)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option)
km, err := v.Keymanager()
require.NoError(t, err)
keys, err := km.FetchValidatingPublicKeys(ctx)
@ -1561,22 +1561,22 @@ func TestValidator_PushProposerSettings(t *testing.T) {
{FeeRecipient: common.HexToAddress(defaultFeeHex).Bytes(), ValidatorIndex: 2},
},
}).Return(nil, nil)
config[keys[0]] = &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
config[keys[0]] = &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x055Fb65722E7b2455043BFEBf6177F1D2e9738D9"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 40000000,
},
}
err = v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
err = v.SetProposerSettings(context.Background(), &proposer.Settings{
ProposeConfig: config,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(defaultFeeHex),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: false,
GasLimit: 35000000,
},
@ -1619,7 +1619,7 @@ func TestValidator_PushProposerSettings(t *testing.T) {
}
err := v.WaitForKeymanagerInitialization(ctx)
require.NoError(t, err)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option)
km, err := v.Keymanager()
require.NoError(t, err)
keys, err := km.FetchValidatingPublicKeys(ctx)
@ -1639,15 +1639,15 @@ func TestValidator_PushProposerSettings(t *testing.T) {
{FeeRecipient: common.HexToAddress(defaultFeeHex).Bytes(), ValidatorIndex: 2},
},
}).Return(nil, nil)
config[keys[0]] = &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
config[keys[0]] = &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x055Fb65722E7b2455043BFEBf6177F1D2e9738D9"),
},
}
err = v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
err = v.SetProposerSettings(context.Background(), &proposer.Settings{
ProposeConfig: config,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(defaultFeeHex),
},
},
@ -1687,13 +1687,13 @@ func TestValidator_PushProposerSettings(t *testing.T) {
require.NoError(t, err)
keys, err := km.FetchValidatingPublicKeys(ctx)
require.NoError(t, err)
err = v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
err = v.SetProposerSettings(context.Background(), &proposer.Settings{
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(defaultFeeHex),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validatorType.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
@ -1748,13 +1748,13 @@ func TestValidator_PushProposerSettings(t *testing.T) {
}
err := v.WaitForKeymanagerInitialization(ctx)
require.NoError(t, err)
err = v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
err = v.SetProposerSettings(context.Background(), &proposer.Settings{
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(defaultFeeHex),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 40000000,
},
@ -1812,7 +1812,7 @@ func TestValidator_PushProposerSettings(t *testing.T) {
}
err := v.WaitForKeymanagerInitialization(ctx)
require.NoError(t, err)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option)
km, err := v.Keymanager()
require.NoError(t, err)
keys, err := km.FetchValidatingPublicKeys(ctx)
@ -1830,15 +1830,15 @@ func TestValidator_PushProposerSettings(t *testing.T) {
{FeeRecipient: common.HexToAddress("0x0").Bytes(), ValidatorIndex: 1},
},
}).Return(nil, nil)
config[keys[0]] = &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
config[keys[0]] = &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.Address{},
},
}
err = v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
err = v.SetProposerSettings(context.Background(), &proposer.Settings{
ProposeConfig: config,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(defaultFeeHex),
},
},
@ -1864,7 +1864,7 @@ func TestValidator_PushProposerSettings(t *testing.T) {
}
err := v.WaitForKeymanagerInitialization(ctx)
require.NoError(t, err)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option)
km, err := v.Keymanager()
require.NoError(t, err)
keys, err := km.FetchValidatingPublicKeys(ctx)
@ -1873,15 +1873,15 @@ func TestValidator_PushProposerSettings(t *testing.T) {
gomock.Any(), // ctx
&ethpb.ValidatorIndexRequest{PublicKey: keys[0][:]},
).Return(nil, errors.New("could not find validator index for public key"))
config[keys[0]] = &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
config[keys[0]] = &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455043BFEBf6177F1D2e9738D9"),
},
}
err = v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
err = v.SetProposerSettings(context.Background(), &proposer.Settings{
ProposeConfig: config,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(defaultFeeHex),
},
},
@ -1907,7 +1907,7 @@ func TestValidator_PushProposerSettings(t *testing.T) {
}
err := v.WaitForKeymanagerInitialization(ctx)
require.NoError(t, err)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption)
config := make(map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option)
km, err := v.Keymanager()
require.NoError(t, err)
keys, err := km.FetchValidatingPublicKeys(ctx)
@ -1921,22 +1921,22 @@ func TestValidator_PushProposerSettings(t *testing.T) {
PublicKeys: [][]byte{keys[0][:]},
}, nil)
config[keys[0]] = &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
config[keys[0]] = &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.Address{},
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 40000000,
},
}
err = v.SetProposerSettings(context.Background(), &validatorserviceconfig.ProposerSettings{
err = v.SetProposerSettings(context.Background(), &proposer.Settings{
ProposeConfig: config,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(defaultFeeHex),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 40000000,
},
@ -2072,26 +2072,26 @@ func TestValidator_buildPrepProposerReqs_WithoutDefaultConfig(t *testing.T) {
}, nil)
v := validator{
validatorClient: client,
proposerSettings: &validatorserviceconfig.ProposerSettings{
proposerSettings: &proposer.Settings{
DefaultConfig: nil,
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
ProposeConfig: map[[48]byte]*proposer.Option{
pubkey1: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient1,
},
},
pubkey2: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient2,
},
},
pubkey3: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient3,
},
},
pubkey4: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient4,
},
},
@ -2215,30 +2215,30 @@ func TestValidator_buildPrepProposerReqs_WithDefaultConfig(t *testing.T) {
v := validator{
validatorClient: client,
proposerSettings: &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
proposerSettings: &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: defaultFeeRecipient,
},
},
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
pubkey1: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient1,
},
},
pubkey2: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient2,
},
},
pubkey3: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient3,
},
},
pubkey8: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient8,
},
},
@ -2322,38 +2322,38 @@ func TestValidator_buildSignedRegReqs_DefaultConfigDisabled(t *testing.T) {
v := validator{
signedValidatorRegistrations: map[[48]byte]*ethpb.SignedValidatorRegistrationV1{},
validatorClient: client,
proposerSettings: &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
proposerSettings: &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: defaultFeeRecipient,
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: false,
GasLimit: 9999,
},
},
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
ProposeConfig: map[[48]byte]*proposer.Option{
pubkey1: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient1,
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 1111,
},
},
pubkey2: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient2,
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: false,
GasLimit: 2222,
},
},
pubkey3: {
FeeRecipientConfig: nil,
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 3333,
},
@ -2407,38 +2407,38 @@ func TestValidator_buildSignedRegReqs_DefaultConfigEnabled(t *testing.T) {
v := validator{
signedValidatorRegistrations: map[[48]byte]*ethpb.SignedValidatorRegistrationV1{},
validatorClient: client,
proposerSettings: &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
proposerSettings: &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: defaultFeeRecipient,
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 9999,
},
},
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
ProposeConfig: map[[48]byte]*proposer.Option{
pubkey1: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient1,
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 1111,
},
},
pubkey2: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient2,
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: false,
GasLimit: 2222,
},
},
pubkey3: {
FeeRecipientConfig: nil,
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 3333,
},
@ -2485,12 +2485,12 @@ func TestValidator_buildSignedRegReqs_SignerOnError(t *testing.T) {
v := validator{
signedValidatorRegistrations: map[[48]byte]*ethpb.SignedValidatorRegistrationV1{},
validatorClient: client,
proposerSettings: &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
proposerSettings: &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: defaultFeeRecipient,
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 9999,
},
@ -2529,22 +2529,22 @@ func TestValidator_buildSignedRegReqs_TimestampBeforeGenesis(t *testing.T) {
signedValidatorRegistrations: map[[48]byte]*ethpb.SignedValidatorRegistrationV1{},
validatorClient: client,
genesisTime: uint64(time.Now().UTC().Unix() + 1000),
proposerSettings: &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
proposerSettings: &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: defaultFeeRecipient,
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 9999,
},
},
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
ProposeConfig: map[[48]byte]*proposer.Option{
pubkey1: {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient1,
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 1111,
},

View File

@ -5,10 +5,13 @@ go_library(
srcs = ["interface.go"],
importpath = "github.com/prysmaticlabs/prysm/v5/validator/db/iface",
# Other packages must use github.com/prysmaticlabs/prysm/v5/validator/db.Database alias.
visibility = ["//validator:__subpackages__"],
visibility = [
"//config:__subpackages__",
"//validator:__subpackages__",
],
deps = [
"//config/fieldparams:go_default_library",
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/primitives:go_default_library",
"//monitoring/backup:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",

View File

@ -6,7 +6,7 @@ import (
"io"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/monitoring/backup"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
@ -65,9 +65,7 @@ type ValidatorDB interface {
GraffitiOrderedIndex(ctx context.Context, fileHash [32]byte) (uint64, error)
// ProposerSettings related methods
ProposerSettings(context.Context) (*validatorServiceConfig.ProposerSettings, error)
ProposerSettings(context.Context) (*proposer.Settings, error)
ProposerSettingsExists(ctx context.Context) (bool, error)
UpdateProposerSettingsDefault(context.Context, *validatorServiceConfig.ProposerOption) error
UpdateProposerSettingsForPubkey(context.Context, [fieldparams.BLSPubkeyLength]byte, *validatorServiceConfig.ProposerOption) error
SaveProposerSettings(ctx context.Context, settings *validatorServiceConfig.ProposerSettings) error
SaveProposerSettings(ctx context.Context, settings *proposer.Settings) error
}

View File

@ -30,7 +30,7 @@ go_library(
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//io/file:go_default_library",
@ -70,7 +70,7 @@ go_test(
deps = [
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//crypto/hash:go_default_library",

View File

@ -2,11 +2,9 @@ package kv
import (
"context"
"fmt"
"github.com/pkg/errors"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client"
bolt "go.etcd.io/bbolt"
"go.opencensus.io/trace"
@ -16,74 +14,9 @@ import (
// ErrNoProposerSettingsFound is an error thrown when no settings are found in bucket
var ErrNoProposerSettingsFound = errors.New("no proposer settings found in bucket")
// UpdateProposerSettingsForPubkey updates the existing settings for an internal representation of the proposers settings file at a particular public key
func (s *Store) UpdateProposerSettingsForPubkey(ctx context.Context, pubkey [fieldparams.BLSPubkeyLength]byte, options *validatorServiceConfig.ProposerOption) error {
_, span := trace.StartSpan(ctx, "validator.db.UpdateProposerSettingsForPubkey")
defer span.End()
err := s.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket(proposerSettingsBucket)
b := bkt.Get(proposerSettingsKey)
if len(b) == 0 {
return fmt.Errorf("no proposer settings found in bucket")
}
to := &validatorpb.ProposerSettingsPayload{}
if err := proto.Unmarshal(b, to); err != nil {
return errors.Wrap(err, "failed to unmarshal proposer settings")
}
settings, err := validatorServiceConfig.ToSettings(to)
if err != nil {
return errors.Wrap(err, "failed to convert payload to proposer settings")
}
if settings.ProposeConfig == nil {
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption)
}
settings.ProposeConfig[pubkey] = options
m, err := proto.Marshal(settings.ToPayload())
if err != nil {
return errors.Wrap(err, "failed to marshal proposer settings")
}
return bkt.Put(proposerSettingsKey, m)
})
return err
}
// UpdateProposerSettingsDefault updates the existing default settings for proposer settings
func (s *Store) UpdateProposerSettingsDefault(ctx context.Context, options *validatorServiceConfig.ProposerOption) error {
_, span := trace.StartSpan(ctx, "validator.db.UpdateProposerSettingsDefault")
defer span.End()
if options == nil {
return errors.New("proposer settings option was empty")
}
if options.FeeRecipientConfig == nil {
return errors.New("fee recipient cannot be empty")
}
err := s.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket(proposerSettingsBucket)
b := bkt.Get(proposerSettingsKey)
if len(b) == 0 {
return ErrNoProposerSettingsFound
}
to := &validatorpb.ProposerSettingsPayload{}
if err := proto.Unmarshal(b, to); err != nil {
return errors.Wrap(err, "failed to unmarshal proposer settings")
}
settings, err := validatorServiceConfig.ToSettings(to)
if err != nil {
return errors.Wrap(err, "failed to convert payload to proposer settings")
}
settings.DefaultConfig = options
m, err := proto.Marshal(settings.ToPayload())
if err != nil {
return errors.Wrap(err, "failed to marshal proposer settings")
}
return bkt.Put(proposerSettingsKey, m)
})
return err
}
// ProposerSettings gets the current proposer settings
func (s *Store) ProposerSettings(ctx context.Context) (*validatorServiceConfig.ProposerSettings, error) {
_, span := trace.StartSpan(ctx, "validator.db.ProposerSettings")
func (s *Store) ProposerSettings(ctx context.Context) (*proposer.Settings, error) {
_, span := trace.StartSpan(ctx, "validator.db.Settings")
defer span.End()
to := &validatorpb.ProposerSettingsPayload{}
if err := s.db.View(func(tx *bolt.Tx) error {
@ -99,7 +32,7 @@ func (s *Store) ProposerSettings(ctx context.Context) (*validatorServiceConfig.P
}); err != nil {
return nil, err
}
return validatorServiceConfig.ToSettings(to)
return proposer.SettingFromConsensus(to)
}
// ProposerSettingsExists returns true or false if the settings exist or not
@ -118,7 +51,7 @@ func (s *Store) ProposerSettingsExists(ctx context.Context) (bool, error) {
}
// SaveProposerSettings saves the entire proposer setting overriding the existing settings
func (s *Store) SaveProposerSettings(ctx context.Context, settings *validatorServiceConfig.ProposerSettings) error {
func (s *Store) SaveProposerSettings(ctx context.Context, settings *proposer.Settings) error {
_, span := trace.StartSpan(ctx, "validator.db.SaveProposerSettings")
defer span.End()
// nothing to save
@ -128,7 +61,7 @@ func (s *Store) SaveProposerSettings(ctx context.Context, settings *validatorSer
}
return s.db.Update(func(tx *bolt.Tx) error {
bkt := tx.Bucket(proposerSettingsBucket)
m, err := proto.Marshal(settings.ToPayload())
m, err := proto.Marshal(settings.ToConsensus())
if err != nil {
return errors.Wrap(err, "failed to marshal proposer settings")
}

View File

@ -8,7 +8,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/testing/require"
@ -20,23 +20,23 @@ func TestStore_ProposerSettings_ReadAndWrite(t *testing.T) {
db := setupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &validatorServiceConfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
settings := &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
},
DefaultConfig: &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: false,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
@ -54,12 +54,12 @@ func TestStore_ProposerSettings_ReadAndWrite(t *testing.T) {
db := setupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &validatorServiceConfig.ProposerSettings{
DefaultConfig: &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
settings := &proposer.Settings{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: false,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
@ -67,38 +67,41 @@ func TestStore_ProposerSettings_ReadAndWrite(t *testing.T) {
}
err = db.SaveProposerSettings(ctx, settings)
require.NoError(t, err)
upatedDefault := &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
updatedDefault := &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x9995733c5af9B61374A128e6F85f553aF09ff89B"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
}
err = db.UpdateProposerSettingsDefault(ctx, upatedDefault)
settings.DefaultConfig = updatedDefault
err = db.SaveProposerSettings(ctx, settings)
require.NoError(t, err)
dbSettings, err := db.ProposerSettings(ctx)
require.NoError(t, err)
require.NotNil(t, dbSettings)
require.DeepEqual(t, dbSettings.DefaultConfig, upatedDefault)
option := &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
require.DeepEqual(t, dbSettings.DefaultConfig, updatedDefault)
option := &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorServiceConfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
}
err = db.UpdateProposerSettingsForPubkey(ctx, bytesutil.ToBytes48(key1), option)
dbSettings.ProposeConfig = map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{bytesutil.ToBytes48(key1): option}
err = db.SaveProposerSettings(ctx, dbSettings)
require.NoError(t, err)
newSettings, err := db.ProposerSettings(ctx)
require.NoError(t, err)
require.NotNil(t, newSettings)
require.DeepEqual(t, newSettings.DefaultConfig, upatedDefault)
require.DeepEqual(t, newSettings.DefaultConfig, updatedDefault)
op, ok := newSettings.ProposeConfig[bytesutil.ToBytes48(key1)]
require.Equal(t, ok, true)
require.DeepEqual(t, op, option)

View File

@ -6,6 +6,7 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/v5/validator/db/testing",
visibility = [
"//cmd:__subpackages__",
"//config:__subpackages__",
"//validator:__subpackages__",
],
deps = [

View File

@ -4,27 +4,19 @@ go_test(
name = "go_default_test",
size = "small",
srcs = ["node_test.go"],
data = glob(["testdata/**"]),
embed = [":go_default_library"],
deps = [
"//cmd:go_default_library",
"//cmd/validator/flags:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
"//io/file:go_default_library",
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//validator/accounts:go_default_library",
"//validator/accounts/wallet:go_default_library",
"//validator/db/iface:go_default_library",
"//validator/db/kv:go_default_library",
"//validator/db/testing:go_default_library",
"//validator/keymanager:go_default_library",
"//validator/keymanager/remote-web3signer:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
@ -50,10 +42,9 @@ go_library(
"//cmd:go_default_library",
"//cmd/validator/flags:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//consensus-types/validator:go_default_library",
"//config/proposer:go_default_library",
"//config/proposer/loader:go_default_library",
"//container/slice:go_default_library",
"//encoding/bytesutil:go_default_library",
"//io/file:go_default_library",
@ -61,7 +52,6 @@ go_library(
"//monitoring/prometheus:go_default_library",
"//monitoring/tracing:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"//runtime:go_default_library",
"//runtime/debug:go_default_library",
"//runtime/prereqs:go_default_library",
@ -75,7 +65,6 @@ go_library(
"//validator/keymanager/remote-web3signer:go_default_library",
"//validator/rpc:go_default_library",
"//validator/web:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_gorilla_mux//:go_default_library",
"@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library",
@ -83,7 +72,6 @@ go_library(
"@com_github_prysmaticlabs_fastssz//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
"@io_k8s_apimachinery//pkg/util/yaml:go_default_library",
"@org_golang_google_protobuf//encoding/protojson:go_default_library",
],
)

View File

@ -5,22 +5,18 @@ package node
import (
"context"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"os/signal"
"path/filepath"
"strconv"
"strings"
"sync"
"syscall"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/gorilla/mux"
gwruntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
@ -33,10 +29,9 @@ import (
"github.com/prysmaticlabs/prysm/v5/cmd"
"github.com/prysmaticlabs/prysm/v5/cmd/validator/flags"
"github.com/prysmaticlabs/prysm/v5/config/features"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/config/proposer/loader"
"github.com/prysmaticlabs/prysm/v5/container/slice"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/io/file"
@ -44,7 +39,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/monitoring/prometheus"
tracing2 "github.com/prysmaticlabs/prysm/v5/monitoring/tracing"
pb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client"
"github.com/prysmaticlabs/prysm/v5/runtime"
"github.com/prysmaticlabs/prysm/v5/runtime/debug"
"github.com/prysmaticlabs/prysm/v5/runtime/prereqs"
@ -61,7 +55,6 @@ import (
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"google.golang.org/protobuf/encoding/protojson"
"k8s.io/apimachinery/pkg/util/yaml"
)
// ValidatorClient defines an instance of an Ethereum validator that manages
@ -469,7 +462,7 @@ func (c *ValidatorClient) registerValidatorService(cliCtx *cli.Context) error {
return err
}
proposerSettings, err := proposerSettings(c.cliCtx, c.db)
ps, err := proposerSettings(c.cliCtx, c.db)
if err != nil {
return err
}
@ -492,7 +485,7 @@ func (c *ValidatorClient) registerValidatorService(cliCtx *cli.Context) error {
WalletInitializedFeed: c.walletInitialized,
GraffitiStruct: graffitiStruct,
Web3SignerConfig: web3signerConfig,
ProposerSettings: proposerSettings,
ProposerSettings: ps,
BeaconApiTimeout: time.Second * 30,
BeaconApiEndpoint: c.cliCtx.String(flags.BeaconRESTApiProviderFlag.Name),
ValidatorsRegBatchSize: c.cliCtx.Int(flags.ValidatorsRegistrationBatchSizeFlag.Name),
@ -553,234 +546,17 @@ func Web3SignerConfig(cliCtx *cli.Context) (*remoteweb3signer.SetupConfig, error
return web3signerConfig, nil
}
func proposerSettings(cliCtx *cli.Context, db iface.ValidatorDB) (*validatorServiceConfig.ProposerSettings, error) {
var fileConfig *validatorpb.ProposerSettingsPayload
if cliCtx.IsSet(flags.ProposerSettingsFlag.Name) && cliCtx.IsSet(flags.ProposerSettingsURLFlag.Name) {
return nil, errors.New("cannot specify both " + flags.ProposerSettingsFlag.Name + " and " + flags.ProposerSettingsURLFlag.Name)
}
builderConfigFromFlag, err := BuilderSettingsFromFlags(cliCtx)
func proposerSettings(cliCtx *cli.Context, db iface.ValidatorDB) (*proposer.Settings, error) {
l, err := loader.NewProposerSettingsLoader(
cliCtx,
db,
loader.WithBuilderConfig(),
loader.WithGasLimit(),
)
if err != nil {
return nil, err
}
// is overridden by file and URL flags
if cliCtx.IsSet(flags.SuggestedFeeRecipientFlag.Name) &&
!cliCtx.IsSet(flags.ProposerSettingsFlag.Name) &&
!cliCtx.IsSet(flags.ProposerSettingsURLFlag.Name) {
suggestedFee := cliCtx.String(flags.SuggestedFeeRecipientFlag.Name)
fileConfig = &validatorpb.ProposerSettingsPayload{
ProposerConfig: nil,
DefaultConfig: &validatorpb.ProposerOptionPayload{
FeeRecipient: suggestedFee,
Builder: builderConfigFromFlag.ToPayload(),
},
}
}
if cliCtx.IsSet(flags.ProposerSettingsFlag.Name) {
if err := unmarshalFromFile(cliCtx.Context, cliCtx.String(flags.ProposerSettingsFlag.Name), &fileConfig); err != nil {
return nil, err
}
}
if cliCtx.IsSet(flags.ProposerSettingsURLFlag.Name) {
if err := unmarshalFromURL(cliCtx.Context, cliCtx.String(flags.ProposerSettingsURLFlag.Name), &fileConfig); err != nil {
return nil, err
}
}
// this condition triggers if SuggestedFeeRecipientFlag,ProposerSettingsFlag or ProposerSettingsURLFlag did not create any settings
if fileConfig == nil {
// Checks the db or enable builder settings before starting the node without proposer settings
// starting the node without proposer settings, will skip API calls for push proposer settings and register validator
return handleNoProposerSettingsFlagsProvided(cliCtx, db, builderConfigFromFlag)
}
// convert file config to proposer config for internal use
vpSettings := &validatorServiceConfig.ProposerSettings{}
// default fileConfig is mandatory
if fileConfig.DefaultConfig == nil {
return nil, errors.New("default fileConfig is required, proposer settings file is either empty or an incorrect format")
}
if !common.IsHexAddress(fileConfig.DefaultConfig.FeeRecipient) {
return nil, errors.New("default fileConfig fee recipient is not a valid eth1 address")
}
psExists, err := db.ProposerSettingsExists(cliCtx.Context)
if err != nil {
return nil, err
}
if err := warnNonChecksummedAddress(fileConfig.DefaultConfig.FeeRecipient); err != nil {
return nil, err
}
vpSettings.DefaultConfig = &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(fileConfig.DefaultConfig.FeeRecipient),
},
BuilderConfig: validatorServiceConfig.ToBuilderConfig(fileConfig.DefaultConfig.Builder),
}
if builderConfigFromFlag != nil {
config := builderConfigFromFlag.Clone()
if config.GasLimit == validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit) && vpSettings.DefaultConfig.BuilderConfig != nil {
config.GasLimit = vpSettings.DefaultConfig.BuilderConfig.GasLimit
}
vpSettings.DefaultConfig.BuilderConfig = config
} else if vpSettings.DefaultConfig.BuilderConfig != nil {
vpSettings.DefaultConfig.BuilderConfig.GasLimit = reviewGasLimit(vpSettings.DefaultConfig.BuilderConfig.GasLimit)
}
if psExists {
// if settings exist update the default
if err := db.UpdateProposerSettingsDefault(cliCtx.Context, vpSettings.DefaultConfig); err != nil {
return nil, err
}
}
if fileConfig.ProposerConfig != nil && len(fileConfig.ProposerConfig) != 0 {
vpSettings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption)
for key, option := range fileConfig.ProposerConfig {
decodedKey, err := hexutil.Decode(key)
if err != nil {
return nil, errors.Wrapf(err, "could not decode public key %s", key)
}
if len(decodedKey) != fieldparams.BLSPubkeyLength {
return nil, fmt.Errorf("%v is not a bls public key", key)
}
if err := verifyOption(key, option); err != nil {
return nil, err
}
currentBuilderConfig := validatorServiceConfig.ToBuilderConfig(option.Builder)
if builderConfigFromFlag != nil {
config := builderConfigFromFlag.Clone()
if config.GasLimit == validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit) && currentBuilderConfig != nil {
config.GasLimit = currentBuilderConfig.GasLimit
}
currentBuilderConfig = config
} else if currentBuilderConfig != nil {
currentBuilderConfig.GasLimit = reviewGasLimit(currentBuilderConfig.GasLimit)
}
o := &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress(option.FeeRecipient),
},
BuilderConfig: currentBuilderConfig,
}
pubkeyB := bytesutil.ToBytes48(decodedKey)
vpSettings.ProposeConfig[pubkeyB] = o
}
if psExists {
// override the existing saved settings if providing values via fileConfig.ProposerConfig
if err := db.SaveProposerSettings(cliCtx.Context, vpSettings); err != nil {
return nil, err
}
}
}
if !psExists {
// if no proposer settings ever existed in the db just save the settings
if err := db.SaveProposerSettings(cliCtx.Context, vpSettings); err != nil {
return nil, err
}
}
return vpSettings, nil
}
func verifyOption(key string, option *validatorpb.ProposerOptionPayload) error {
if option == nil {
return fmt.Errorf("fee recipient is required for proposer %s", key)
}
if !common.IsHexAddress(option.FeeRecipient) {
return errors.New("fee recipient is not a valid eth1 address")
}
if err := warnNonChecksummedAddress(option.FeeRecipient); err != nil {
return err
}
return nil
}
func handleNoProposerSettingsFlagsProvided(cliCtx *cli.Context,
db iface.ValidatorDB,
builderConfigFromFlag *validatorServiceConfig.BuilderConfig) (*validatorServiceConfig.ProposerSettings, error) {
log.Info("no proposer settings files have been provided, attempting to load from db.")
// checks db if proposer settings exist if none is provided.
settings, err := db.ProposerSettings(cliCtx.Context)
if err == nil {
// process any overrides to builder settings
overrideBuilderSettings(settings, builderConfigFromFlag)
// if settings are empty
log.Info("successfully loaded proposer settings from db.")
return settings, nil
} else {
log.WithError(err).Warn("no proposer settings will be loaded from the db")
}
if cliCtx.Bool(flags.EnableBuilderFlag.Name) {
// if there are no proposer settings provided, create a default where fee recipient is not populated, this will be skipped for validator registration on validators that don't have a fee recipient set.
// skip saving to DB if only builder settings are provided until a trigger like keymanager API updates with fee recipient values
return &validatorServiceConfig.ProposerSettings{
DefaultConfig: &validatorServiceConfig.ProposerOption{
BuilderConfig: builderConfigFromFlag,
},
}, nil
}
return nil, nil
}
func overrideBuilderSettings(settings *validatorServiceConfig.ProposerSettings, builderConfigFromFlag *validatorServiceConfig.BuilderConfig) {
// override the db settings with the results based on whether the --enable-builder flag is provided.
if builderConfigFromFlag == nil {
log.Infof("proposer settings loaded from db. validator registration to builder is not enabled, please use the --%s flag if you wish to use a builder.", flags.EnableBuilderFlag.Name)
}
if settings.ProposeConfig != nil {
for key := range settings.ProposeConfig {
settings.ProposeConfig[key].BuilderConfig = builderConfigFromFlag
}
}
if settings.DefaultConfig != nil {
settings.DefaultConfig.BuilderConfig = builderConfigFromFlag
}
}
func BuilderSettingsFromFlags(cliCtx *cli.Context) (*validatorServiceConfig.BuilderConfig, error) {
if cliCtx.Bool(flags.EnableBuilderFlag.Name) {
gasLimit := validator.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(validator.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 {
return errors.Wrapf(err, "could not decode fee recipient %s", feeRecipient)
}
if !mixedcaseAddress.ValidChecksum() {
log.Warnf("Fee recipient %s is not a checksum Ethereum address. "+
"The checksummed address is %s and will be used as the fee recipient. "+
"We recommend using a mixed-case address (checksum) "+
"to prevent spelling mistakes in your fee recipient Ethereum address", feeRecipient, mixedcaseAddress.Address().Hex())
}
return nil
}
func reviewGasLimit(gasLimit validator.Uint64) validator.Uint64 {
// sets gas limit to default if not defined or set to 0
if gasLimit == 0 {
return validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit)
}
// TODO(10810): add in warning for ranges
return gasLimit
return l.Load(cliCtx)
}
func (c *ValidatorClient) registerRPCService(router *mux.Router) error {
@ -960,55 +736,6 @@ func clearDB(ctx context.Context, dataDir string, force bool) error {
return nil
}
func unmarshalFromURL(ctx context.Context, from string, to interface{}) error {
u, err := url.ParseRequestURI(from)
if err != nil {
return err
}
if u.Scheme == "" || u.Host == "" {
return fmt.Errorf("invalid URL: %s", from)
}
req, reqerr := http.NewRequestWithContext(ctx, http.MethodGet, from, nil)
if reqerr != nil {
return errors.Wrap(reqerr, "failed to create http request")
}
req.Header.Set("Content-Type", "application/json")
resp, resperr := http.DefaultClient.Do(req)
if resperr != nil {
return errors.Wrap(resperr, "failed to send http request")
}
defer func(Body io.ReadCloser) {
err = Body.Close()
if err != nil {
log.WithError(err).Error("failed to close response body")
}
}(resp.Body)
if resp.StatusCode != http.StatusOK {
return errors.Errorf("http request to %v failed with status code %d", from, resp.StatusCode)
}
if decodeerr := json.NewDecoder(resp.Body).Decode(&to); decodeerr != nil {
return errors.Wrap(decodeerr, "failed to decode http response")
}
return nil
}
func unmarshalFromFile(ctx context.Context, from string, to interface{}) error {
if ctx == nil {
return errors.New("node: nil context passed to unmarshalFromFile")
}
cleanpath := filepath.Clean(from)
b, err := os.ReadFile(cleanpath)
if err != nil {
return errors.Wrap(err, "failed to open file")
}
if err := yaml.Unmarshal(b, to); err != nil {
return errors.Wrap(err, "failed to unmarshal yaml file")
}
return nil
}
func configureFastSSZHashingAlgorithm() {
fastssz.EnableVectorizedHTR = true
}

View File

@ -3,31 +3,21 @@ package node
import (
"context"
"flag"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path"
"path/filepath"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/prysmaticlabs/prysm/v5/cmd"
"github.com/prysmaticlabs/prysm/v5/cmd/validator/flags"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/io/file"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/validator/accounts"
"github.com/prysmaticlabs/prysm/v5/validator/accounts/wallet"
"github.com/prysmaticlabs/prysm/v5/validator/db/iface"
"github.com/prysmaticlabs/prysm/v5/validator/db/kv"
dbTest "github.com/prysmaticlabs/prysm/v5/validator/db/testing"
"github.com/prysmaticlabs/prysm/v5/validator/keymanager"
remoteweb3signer "github.com/prysmaticlabs/prysm/v5/validator/keymanager/remote-web3signer"
logtest "github.com/sirupsen/logrus/hooks/test"
@ -344,722 +334,3 @@ func TestWeb3SignerConfig(t *testing.T) {
})
}
}
func TestProposerSettings(t *testing.T) {
hook := logtest.NewGlobal()
type proposerSettingsFlag struct {
dir string
url string
defaultfee string
defaultgas string
}
type args struct {
proposerSettingsFlagValues *proposerSettingsFlag
}
tests := []struct {
name string
args args
want func() *validatorserviceconfig.ProposerSettings
urlResponse string
wantErr string
wantLog string
withdb func(db iface.ValidatorDB) error
validatorRegistrationEnabled bool
}{
{
name: "Happy Path default only proposer settings file with builder settings,",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/default-only-proposer-config.json",
url: "",
defaultfee: "",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
return &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xae967917c465db8578ca9024c205720b1a3651A9"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
},
{
name: "Happy Path Config file File, bad checksum",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config-badchecksum.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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xae967917c465db8578ca9024c205720b1a3651A9"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xae967917c465db8578ca9024c205720b1a3651A9"),
},
},
}
},
wantErr: "",
wantLog: "is not a checksum Ethereum address",
},
{
name: "Happy Path Config file File multiple fee recipients",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config-multiple.json",
url: "",
defaultfee: "",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
key2, err := hexutil.Decode("0xb057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7b")
require.NoError(t, err)
return &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
bytesutil.ToBytes48(key2): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x60155530FCE8a85ec7055A5F8b2bE214B3DaeFd4"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(35000000),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
}
},
wantErr: "",
},
{
name: "Happy Path Config URL File",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "./testdata/good-prepare-beacon-proposer-config.json",
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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
wantErr: "",
},
{
name: "Happy Path Config YAML file with custom Gas Limit",
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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: 40000000,
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: false,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
wantErr: "",
},
{
name: "Happy Path Suggested Fee ",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
return &validatorserviceconfig.ProposerSettings{
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
wantErr: "",
},
{
name: "Happy Path Suggested Fee , validator registration enabled",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
return &validatorserviceconfig.ProposerSettings{
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
wantErr: "",
validatorRegistrationEnabled: true,
},
{
name: "Happy Path Suggested Fee , validator registration enabled and default gas",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89A",
defaultgas: "50000000",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
return &validatorserviceconfig.ProposerSettings{
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: 50000000,
},
},
}
},
wantErr: "",
validatorRegistrationEnabled: true,
},
{
name: "Suggested Fee does not Override Config",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config.json",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89B",
},
},
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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
wantErr: "",
},
{
name: "Suggested Fee with validator registration does not Override Config",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config.json",
url: "",
defaultfee: "0x6e35733c5af9B61374A128e6F85f553aF09ff89B",
},
},
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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
validatorRegistrationEnabled: true,
},
{
name: "Enable Builder flag does 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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
validatorRegistrationEnabled: true,
},
{
name: "Only Enable Builder flag",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
return &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
validatorRegistrationEnabled: true,
},
{
name: "No Flags but saved to DB with builder and override removed builder data",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
withdb: func(db iface.ValidatorDB) error {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(40000000),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
return db.SaveProposerSettings(context.Background(), settings)
},
},
{
name: "Enable builder flag but saved to DB without builder data now includes builder data",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
},
},
}
},
withdb: func(db iface.ValidatorDB) error {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
return db.SaveProposerSettings(context.Background(), settings)
},
validatorRegistrationEnabled: true,
},
{
name: "No flags, but saved to database",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
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): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
},
withdb: func(db iface.ValidatorDB) error {
key1, err := hexutil.Decode("0xa057816155ad77931185101128655c0191bd0214c201ca48ed887f6c4c6adf334070efcd75140eada5ac83a92506dd7a")
require.NoError(t, err)
settings := &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorserviceconfig.ProposerOption{
bytesutil.ToBytes48(key1): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x50155530FCE8a85ec7055A5F8b2bE214B3DaeFd3"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x6e35733c5af9B61374A128e6F85f553aF09ff89A"),
},
},
}
return db.SaveProposerSettings(context.Background(), settings)
},
},
{
name: "No flags set means empty config",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "",
url: "",
defaultfee: "",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
return nil
},
wantErr: "",
},
{
name: "Bad File Path",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/bad-prepare-beacon-proposer-config.json",
url: "",
defaultfee: "",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
return nil
},
wantErr: "failed to unmarshal yaml file",
},
{
name: "Both URL and Dir flags used resulting in error",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/good-prepare-beacon-proposer-config.json",
url: "./testdata/good-prepare-beacon-proposer-config.json",
defaultfee: "",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
return &validatorserviceconfig.ProposerSettings{}
},
wantErr: "cannot specify both",
},
{
name: "Bad Gas value in JSON",
args: args{
proposerSettingsFlagValues: &proposerSettingsFlag{
dir: "./testdata/bad-gas-value-proposer-settings.json",
url: "",
defaultfee: "",
},
},
want: func() *validatorserviceconfig.ProposerSettings {
return nil
},
wantErr: "failed to unmarshal yaml file",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
if tt.args.proposerSettingsFlagValues.dir != "" {
set.String(flags.ProposerSettingsFlag.Name, tt.args.proposerSettingsFlagValues.dir, "")
require.NoError(t, set.Set(flags.ProposerSettingsFlag.Name, tt.args.proposerSettingsFlagValues.dir))
}
if tt.args.proposerSettingsFlagValues.url != "" {
content, err := os.ReadFile(tt.args.proposerSettingsFlagValues.url)
require.NoError(t, err)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/json")
_, err := fmt.Fprintf(w, "%s", content)
require.NoError(t, err)
}))
defer srv.Close()
set.String(flags.ProposerSettingsURLFlag.Name, tt.args.proposerSettingsFlagValues.url, "")
require.NoError(t, set.Set(flags.ProposerSettingsURLFlag.Name, srv.URL))
}
if tt.args.proposerSettingsFlagValues.defaultfee != "" {
set.String(flags.SuggestedFeeRecipientFlag.Name, tt.args.proposerSettingsFlagValues.defaultfee, "")
require.NoError(t, set.Set(flags.SuggestedFeeRecipientFlag.Name, tt.args.proposerSettingsFlagValues.defaultfee))
}
if tt.args.proposerSettingsFlagValues.defaultgas != "" {
set.String(flags.BuilderGasLimitFlag.Name, tt.args.proposerSettingsFlagValues.defaultgas, "")
require.NoError(t, set.Set(flags.BuilderGasLimitFlag.Name, tt.args.proposerSettingsFlagValues.defaultgas))
}
if tt.validatorRegistrationEnabled {
set.Bool(flags.EnableBuilderFlag.Name, true, "")
}
cliCtx := cli.NewContext(&app, set, nil)
validatorDB := dbTest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
if tt.withdb != nil {
err := tt.withdb(validatorDB)
require.NoError(t, err)
}
got, err := proposerSettings(cliCtx, validatorDB)
if tt.wantErr != "" {
require.ErrorContains(t, tt.wantErr, err)
return
}
if tt.wantLog != "" {
assert.LogsContain(t, hook,
tt.wantLog,
)
}
w := tt.want()
require.DeepEqual(t, w, got)
})
}
}
func Test_ProposerSettingsWithOnlyBuilder_DoesNotSaveInDB(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.Bool(flags.EnableBuilderFlag.Name, true, "")
cliCtx := cli.NewContext(&app, set, nil)
validatorDB := dbTest.SetupDB(t, [][fieldparams.BLSPubkeyLength]byte{})
got, err := proposerSettings(cliCtx, validatorDB)
require.NoError(t, err)
_, err = validatorDB.ProposerSettings(cliCtx.Context)
require.ErrorContains(t, "no proposer settings found in bucket", err)
want := &validatorserviceconfig.ProposerSettings{
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{
Enabled: true,
GasLimit: validator.Uint64(params.BeaconConfig().DefaultBuilderGasLimit),
Relays: nil,
},
},
}
require.DeepEqual(t, want, got)
}

View File

@ -33,7 +33,7 @@ go_library(
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//crypto/bls:go_default_library",
@ -112,7 +112,7 @@ go_test(
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//config/validator/service:go_default_library",
"//config/proposer:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//crypto/bls:go_default_library",

View File

@ -15,7 +15,7 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/rpc/eth/shared"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
validatorServiceConfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
@ -611,10 +611,10 @@ func (s *Server) SetFeeRecipientByPubkey(w http.ResponseWriter, r *http.Request)
settings := s.validatorService.ProposerSettings()
switch {
case settings == nil:
settings = &validatorServiceConfig.ProposerSettings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
settings = &proposer.Settings{
ProposeConfig: map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(pubkey): {
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient,
},
BuilderConfig: nil,
@ -623,13 +623,13 @@ func (s *Server) SetFeeRecipientByPubkey(w http.ResponseWriter, r *http.Request)
DefaultConfig: nil,
}
case settings.ProposeConfig == nil:
var builderConfig *validatorServiceConfig.BuilderConfig
var builderConfig *proposer.BuilderConfig
if settings.DefaultConfig != nil && settings.DefaultConfig.BuilderConfig != nil {
builderConfig = settings.DefaultConfig.BuilderConfig.Clone()
}
settings.ProposeConfig = map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption{
settings.ProposeConfig = map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option{
bytesutil.ToBytes48(pubkey): {
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient,
},
BuilderConfig: builderConfig,
@ -638,16 +638,16 @@ func (s *Server) SetFeeRecipientByPubkey(w http.ResponseWriter, r *http.Request)
default:
proposerOption, found := settings.ProposeConfig[bytesutil.ToBytes48(pubkey)]
if found && proposerOption != nil {
proposerOption.FeeRecipientConfig = &validatorServiceConfig.FeeRecipientConfig{
proposerOption.FeeRecipientConfig = &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient,
}
} else {
var builderConfig = &validatorServiceConfig.BuilderConfig{}
var builderConfig = &proposer.BuilderConfig{}
if settings.DefaultConfig != nil && settings.DefaultConfig.BuilderConfig != nil {
builderConfig = settings.DefaultConfig.BuilderConfig.Clone()
}
settings.ProposeConfig[bytesutil.ToBytes48(pubkey)] = &validatorServiceConfig.ProposerOption{
FeeRecipientConfig: &validatorServiceConfig.FeeRecipientConfig{
settings.ProposeConfig[bytesutil.ToBytes48(pubkey)] = &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: feeRecipient,
},
BuilderConfig: builderConfig,
@ -769,7 +769,7 @@ func (s *Server) SetGasLimit(w http.ResponseWriter, r *http.Request) {
httputil.HandleError(w, "Gas limit changes only apply when builder is enabled", http.StatusInternalServerError)
return
}
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*validatorServiceConfig.ProposerOption)
settings.ProposeConfig = make(map[[fieldparams.BLSPubkeyLength]byte]*proposer.Option)
option := settings.DefaultConfig.Clone()
option.BuilderConfig.GasLimit = validator.Uint64(gasLimit)
settings.ProposeConfig[bytesutil.ToBytes48(pubkey)] = option

View File

@ -16,7 +16,7 @@ import (
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
validatorserviceconfig "github.com/prysmaticlabs/prysm/v5/config/validator/service"
"github.com/prysmaticlabs/prysm/v5/config/proposer"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/consensus-types/validator"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
@ -849,20 +849,20 @@ func TestServer_GetGasLimit(t *testing.T) {
tests := []struct {
name string
args *validatorserviceconfig.ProposerSettings
args *proposer.Settings
pubkey [48]byte
want uint64
}{
{
name: "ProposerSetting for specific pubkey exists",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
args: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(byteval): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: 123456789},
BuilderConfig: &proposer.BuilderConfig{GasLimit: 123456789},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: 987654321},
DefaultConfig: &proposer.Option{
BuilderConfig: &proposer.BuilderConfig{GasLimit: 987654321},
},
},
pubkey: bytesutil.ToBytes48(byteval),
@ -870,14 +870,14 @@ func TestServer_GetGasLimit(t *testing.T) {
},
{
name: "ProposerSetting for specific pubkey does not exist",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
args: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(byteval): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: 123456789},
BuilderConfig: &proposer.BuilderConfig{GasLimit: 123456789},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: 987654321},
DefaultConfig: &proposer.Option{
BuilderConfig: &proposer.BuilderConfig{GasLimit: 987654321},
},
},
// no settings for the following validator, so the gaslimit returned is the default value.
@ -941,7 +941,7 @@ func TestServer_SetGasLimit(t *testing.T) {
name string
pubkey []byte
newGasLimit uint64
proposerSettings *validatorserviceconfig.ProposerSettings
proposerSettings *proposer.Settings
w []*want
beaconReturn *beaconResp
wantErr string
@ -957,7 +957,7 @@ func TestServer_SetGasLimit(t *testing.T) {
name: "ProposerSettings.ProposeConfig is nil AND ProposerSettings.DefaultConfig is nil",
pubkey: pubkey1,
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
proposerSettings: &proposer.Settings{
ProposeConfig: nil,
DefaultConfig: nil,
},
@ -967,9 +967,9 @@ func TestServer_SetGasLimit(t *testing.T) {
name: "ProposerSettings.ProposeConfig is nil AND ProposerSettings.DefaultConfig.BuilderConfig is nil",
pubkey: pubkey1,
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
proposerSettings: &proposer.Settings{
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{
DefaultConfig: &proposer.Option{
BuilderConfig: nil,
},
},
@ -979,8 +979,8 @@ func TestServer_SetGasLimit(t *testing.T) {
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{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: nil,
},
@ -993,10 +993,10 @@ func TestServer_SetGasLimit(t *testing.T) {
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{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{},
BuilderConfig: &proposer.BuilderConfig{},
},
},
DefaultConfig: nil,
@ -1007,10 +1007,10 @@ func TestServer_SetGasLimit(t *testing.T) {
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{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(pubkey2): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
GasLimit: 12345,
},
@ -1028,14 +1028,14 @@ func TestServer_SetGasLimit(t *testing.T) {
name: "ProposerSettings.ProposeConfig is defined for pubkey, BuilderConfig is nil AND ProposerSettings.DefaultConfig.BuilderConfig is defined",
pubkey: pubkey1,
newGasLimit: 9999,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(pubkey2): {
BuilderConfig: nil,
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{
DefaultConfig: &proposer.Option{
BuilderConfig: &proposer.BuilderConfig{
Enabled: true,
},
},
@ -1149,24 +1149,24 @@ func TestServer_DeleteGasLimit(t *testing.T) {
tests := []struct {
name string
pubkey []byte
proposerSettings *validatorserviceconfig.ProposerSettings
proposerSettings *proposer.Settings
wantError error
w []want
}{
{
name: "delete existing gas limit with default config",
pubkey: pubkey1,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(987654321)},
BuilderConfig: &proposer.BuilderConfig{GasLimit: validator.Uint64(987654321)},
},
bytesutil.ToBytes48(pubkey2): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(123456789)},
BuilderConfig: &proposer.BuilderConfig{GasLimit: validator.Uint64(123456789)},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(5555)},
DefaultConfig: &proposer.Option{
BuilderConfig: &proposer.BuilderConfig{GasLimit: validator.Uint64(5555)},
},
},
wantError: nil,
@ -1185,13 +1185,13 @@ func TestServer_DeleteGasLimit(t *testing.T) {
{
name: "delete existing gas limit with no default config",
pubkey: pubkey1,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(987654321)},
BuilderConfig: &proposer.BuilderConfig{GasLimit: validator.Uint64(987654321)},
},
bytesutil.ToBytes48(pubkey2): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(123456789)},
BuilderConfig: &proposer.BuilderConfig{GasLimit: validator.Uint64(123456789)},
},
},
},
@ -1211,10 +1211,10 @@ func TestServer_DeleteGasLimit(t *testing.T) {
{
name: "delete nonexist gas limit",
pubkey: pubkey2,
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(pubkey1): {
BuilderConfig: &validatorserviceconfig.BuilderConfig{GasLimit: validator.Uint64(987654321)},
BuilderConfig: &proposer.BuilderConfig{GasLimit: validator.Uint64(987654321)},
},
},
},
@ -1444,22 +1444,22 @@ func TestServer_ListFeeRecipientByPubkey(t *testing.T) {
tests := []struct {
name string
args *validatorserviceconfig.ProposerSettings
args *proposer.Settings
want *want
cached *eth.FeeRecipientByPubKeyResponse
}{
{
name: "ProposerSettings.ProposeConfig.FeeRecipientConfig defined for pubkey (and ProposerSettings.DefaultConfig.FeeRecipientConfig defined)",
args: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
args: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(byteval): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
},
},
@ -1470,10 +1470,10 @@ func TestServer_ListFeeRecipientByPubkey(t *testing.T) {
},
{
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{
args: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{},
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},
@ -1576,7 +1576,7 @@ func TestServer_FeeRecipientByPubkey(t *testing.T) {
tests := []struct {
name string
args string
proposerSettings *validatorserviceconfig.ProposerSettings
proposerSettings *proposer.Settings
want *want
wantErr bool
beaconReturn *beaconResp
@ -1597,7 +1597,7 @@ func TestServer_FeeRecipientByPubkey(t *testing.T) {
{
name: "ProposerSetting.ProposeConfig is nil",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
proposerSettings: &proposer.Settings{
ProposeConfig: nil,
},
want: &want{
@ -1612,9 +1612,9 @@ func TestServer_FeeRecipientByPubkey(t *testing.T) {
{
name: "ProposerSetting.ProposeConfig is nil AND ProposerSetting.Defaultconfig is defined",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
proposerSettings: &proposer.Settings{
ProposeConfig: nil,
DefaultConfig: &validatorserviceconfig.ProposerOption{},
DefaultConfig: &proposer.Option{},
},
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
@ -1628,8 +1628,8 @@ func TestServer_FeeRecipientByPubkey(t *testing.T) {
{
name: "ProposerSetting.ProposeConfig is defined for pubkey",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(byteval): {},
},
},
@ -1645,8 +1645,8 @@ func TestServer_FeeRecipientByPubkey(t *testing.T) {
{
name: "ProposerSetting.ProposeConfig not defined for pubkey",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{},
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{},
},
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
@ -1660,8 +1660,8 @@ func TestServer_FeeRecipientByPubkey(t *testing.T) {
{
name: "ProposerSetting.ProposeConfig is nil for pubkey",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(byteval): nil,
},
},
@ -1677,11 +1677,11 @@ func TestServer_FeeRecipientByPubkey(t *testing.T) {
{
name: "ProposerSetting.ProposeConfig is nil for pubkey AND DefaultConfig is not nil",
args: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(byteval): nil,
},
DefaultConfig: &validatorserviceconfig.ProposerOption{},
DefaultConfig: &proposer.Option{},
},
want: &want{
valEthAddress: "0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9",
@ -1777,22 +1777,22 @@ func TestServer_DeleteFeeRecipientByPubkey(t *testing.T) {
}
tests := []struct {
name string
proposerSettings *validatorserviceconfig.ProposerSettings
proposerSettings *proposer.Settings
want *want
wantErr bool
}{
{
name: "Happy Path Test",
proposerSettings: &validatorserviceconfig.ProposerSettings{
ProposeConfig: map[[48]byte]*validatorserviceconfig.ProposerOption{
proposerSettings: &proposer.Settings{
ProposeConfig: map[[48]byte]*proposer.Option{
bytesutil.ToBytes48(byteval): {
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x055Fb65722E7b2455012BFEBf6177F1D2e9738D5"),
},
},
},
DefaultConfig: &validatorserviceconfig.ProposerOption{
FeeRecipientConfig: &validatorserviceconfig.FeeRecipientConfig{
DefaultConfig: &proposer.Option{
FeeRecipientConfig: &proposer.FeeRecipientConfig{
FeeRecipient: common.HexToAddress("0x046Fb65722E7b2455012BFEBf6177F1D2e9738D9"),
},
},