Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions cli/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package cli

import (
"os"
"strings"

"github.com/flashbots/mev-boost/server/types"
"gopkg.in/yaml.v3"
)

type RelayConfigYAML struct {
URL string `yaml:"url"`
EnableTimingGames bool `yaml:"enable_timing_games"`
TargetFirstRequestMs uint64 `yaml:"target_first_request_ms"`
FrequencyGetHeaderMs uint64 `yaml:"frequency_getheader_ms"`
}

// Config holds all configuration settings from the config file
type Config struct {
TimeoutGetHeaderMs uint64 `yaml:"timeout_get_header_ms"`
LateInSlotTimeMs uint64 `yaml:"late_in_slot_time_ms"`
Relays []RelayConfigYAML `yaml:"relays"`
}

type ConfigResult struct {
RelayConfigs map[string]types.RelayConfig
TimeoutGetHeaderMs uint64
LateInSlotTimeMs uint64
}

// LoadConfigFile loads configurations from a YAML file
func LoadConfigFile(configPath string) (*ConfigResult, error) {
data, err := os.ReadFile(configPath)
if err != nil {
return nil, err
}

var config Config
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, err
}

timeoutGetHeaderMs := config.TimeoutGetHeaderMs
if timeoutGetHeaderMs == 0 {
timeoutGetHeaderMs = 900
}

lateInSlotTimeMs := config.LateInSlotTimeMs
if lateInSlotTimeMs == 0 {
lateInSlotTimeMs = 1000
}

configMap := make(map[string]types.RelayConfig)
for _, relay := range config.Relays {
relayEntry, err := types.NewRelayEntry(strings.TrimSpace(relay.URL))
if err != nil {
return nil, err
}
relayConfig := types.RelayConfig{
RelayEntry: relayEntry,
EnableTimingGames: relay.EnableTimingGames,
TargetFirstRequestMs: relay.TargetFirstRequestMs,
FrequencyGetHeaderMs: relay.FrequencyGetHeaderMs,
}
configMap[relayEntry.String()] = relayConfig
}

return &ConfigResult{
RelayConfigs: configMap,
TimeoutGetHeaderMs: timeoutGetHeaderMs,
LateInSlotTimeMs: lateInSlotTimeMs,
}, nil
}

// MergeRelayConfigs merges relays passed via --relays to config file settings.
// this allows the users to still use --relays if they dont want to provide a config file
func MergeRelayConfigs(relays []types.RelayEntry, configMap map[string]types.RelayConfig) []types.RelayConfig {
configs := make([]types.RelayConfig, 0, len(relays))

for _, entry := range relays {
if config, exists := configMap[entry.String()]; exists {
config.RelayEntry = entry
configs = append(configs, config)
} else {
configs = append(configs, types.NewRelayConfig(entry))
}
}

return configs
}
7 changes: 7 additions & 0 deletions cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var flags = []cli.Flag{
hoodiFlag,
// relay
relaysFlag,
relayConfigFlag,
deprecatedRelayMonitorFlag,
minBidFlag,
relayCheckFlag,
Expand Down Expand Up @@ -135,6 +136,12 @@ var (
Usage: "relay urls - single entry or comma-separated list (scheme://pubkey@host)",
Category: RelayCategory,
}
relayConfigFlag = &cli.StringFlag{
Name: "config",
Sources: cli.EnvVars("CONFIG_FILE"),
Usage: "path to YAML configuration file",
Category: RelayCategory,
}
deprecatedRelayMonitorFlag = &cli.StringSliceFlag{
Name: "relay-monitors",
Aliases: []string{"relay-monitor"},
Expand Down
60 changes: 50 additions & 10 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/flashbots/mev-boost/common"
"github.com/flashbots/mev-boost/config"
"github.com/flashbots/mev-boost/server"
serverTypes "github.com/flashbots/mev-boost/server/types"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v3"
)
Expand All @@ -29,6 +30,14 @@ const (
genesisTimeHoodi = 1742213400
)

type RelaySetupResult struct {
RelayConfigs []serverTypes.RelayConfig
MinBid types.U256Str
RelayCheck bool
TimeoutGetHeaderMs uint64
LateInSlotTimeMs uint64
}

var (
// errors
errInvalidLoglevel = errors.New("invalid loglevel")
Expand Down Expand Up @@ -66,7 +75,7 @@ func start(_ context.Context, cmd *cli.Command) error {

var (
genesisForkVersion, genesisTime = setupGenesis(cmd)
relays, minBid, relayCheck = setupRelays(cmd)
relaySetup = setupRelays(cmd)
listenAddr = cmd.String(addrFlag.Name)
metricsEnabled = cmd.Bool(metricsFlag.Name)
metricsAddr = cmd.String(metricsAddrFlag.Name)
Expand All @@ -75,23 +84,25 @@ func start(_ context.Context, cmd *cli.Command) error {
opts := server.BoostServiceOpts{
Log: log,
ListenAddr: listenAddr,
Relays: relays,
RelayConfigs: relaySetup.RelayConfigs,
GenesisForkVersionHex: genesisForkVersion,
GenesisTime: genesisTime,
RelayCheck: relayCheck,
RelayMinBid: minBid,
RelayCheck: relaySetup.RelayCheck,
RelayMinBid: relaySetup.MinBid,
RequestTimeoutGetHeader: time.Duration(cmd.Int(timeoutGetHeaderFlag.Name)) * time.Millisecond,
RequestTimeoutGetPayload: time.Duration(cmd.Int(timeoutGetPayloadFlag.Name)) * time.Millisecond,
RequestTimeoutRegVal: time.Duration(cmd.Int(timeoutRegValFlag.Name)) * time.Millisecond,
RequestMaxRetries: cmd.Int(maxRetriesFlag.Name),
MetricsAddr: metricsAddr,
TimeoutGetHeaderMs: relaySetup.TimeoutGetHeaderMs,
LateInSlotTimeMs: relaySetup.LateInSlotTimeMs,
}
service, err := server.NewBoostService(opts)
if err != nil {
log.WithError(err).Fatal("failed creating the server")
}

if relayCheck && service.CheckRelays() == 0 {
if relaySetup.RelayCheck && service.CheckRelays() == 0 {
log.Error("no relay passed the health-check!")
}

Expand All @@ -108,7 +119,7 @@ func start(_ context.Context, cmd *cli.Command) error {
return service.StartHTTPServer()
}

func setupRelays(cmd *cli.Command) (relayList, types.U256Str, bool) {
func setupRelays(cmd *cli.Command) RelaySetupResult {
// For backwards compatibility with the -relays flag.
var relays relayList
if cmd.IsSet(relaysFlag.Name) {
Expand All @@ -125,9 +136,32 @@ func setupRelays(cmd *cli.Command) (relayList, types.U256Str, bool) {
if len(relays) == 0 {
log.Fatal("no relays specified")
}
log.Infof("using %d relays", len(relays))
for index, relay := range relays {
log.Infof("relay #%d: %s", index+1, relay.String())

// load configuration via config file
var configMap map[string]serverTypes.RelayConfig
var timeoutGetHeaderMs uint64 = 900
var lateInSlotTimeMs uint64 = 1000
if cmd.IsSet(relayConfigFlag.Name) {
configPath := cmd.String(relayConfigFlag.Name)
log.Infof("loading config from: %s", configPath)
configResult, err := LoadConfigFile(configPath)
if err != nil {
log.WithError(err).Fatal("failed to load config file")
} else {
configMap = configResult.RelayConfigs
timeoutGetHeaderMs = configResult.TimeoutGetHeaderMs
lateInSlotTimeMs = configResult.LateInSlotTimeMs
}
}
relayConfigs := MergeRelayConfigs(relays, configMap)

log.Infof("using %d relays", len(relayConfigs))
for index, config := range relayConfigs {
if config.EnableTimingGames {
log.Infof("relay #%d: %s timing games: enabled", index+1, config.RelayEntry.String())
} else {
log.Infof("relay #%d: %s", index+1, config.RelayEntry.String())
}
}

relayMinBidWei, err := sanitizeMinBid(cmd.Float(minBidFlag.Name))
Expand All @@ -137,7 +171,13 @@ func setupRelays(cmd *cli.Command) (relayList, types.U256Str, bool) {
if relayMinBidWei.BigInt().Sign() > 0 {
log.Infof("min bid set to %v eth (%v wei)", cmd.Float(minBidFlag.Name), relayMinBidWei)
}
return relays, *relayMinBidWei, cmd.Bool(relayCheckFlag.Name)
return RelaySetupResult{
RelayConfigs: relayConfigs,
MinBid: *relayMinBidWei,
RelayCheck: cmd.Bool(relayCheckFlag.Name),
TimeoutGetHeaderMs: timeoutGetHeaderMs,
LateInSlotTimeMs: lateInSlotTimeMs,
}
}

func setupGenesis(cmd *cli.Command) (string, uint64) {
Expand Down
21 changes: 21 additions & 0 deletions examples/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Example configuration for mev-boost

# timeout settings for get_header requests
timeout_get_header_ms: 900 # timeout for get_header request in milliseconds
late_in_slot_time_ms: 1000 # threshold that defines when in a slot is considered "too late"

# Relay configurations
relays:
# relay with timing games enabled
- url: https://0x9000009807ed12c1f08bf4e81c6da3ba8e3fc3d953898ce0102433094e5f22f21102ec057841fcb81978ed1ea0fa8246@relay.relayer1.net
enable_timing_games: true
# time in ms from slot start for the first getHeader request
target_first_request_ms: 200
# time in ms between subsequent getHeader requests
frequency_getheader_ms: 100

# relay with timing games disabled (standard behavior)
- url: https://0x9000009807ed12c1f08bf4e81c6da3ba8e3fc3d953898ce0102433094e5f22f21102ec057841fcb81978ed1ea0fa8246@relay.relayer2.com
enable_timing_games: false
target_first_request_ms: 0
frequency_getheader_ms: 0
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,5 @@ require (
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/sys v0.32.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gopkg.in/yaml.v3 v3.0.1
)
Loading
Loading