forked from flashbots/mev-boost
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.go
More file actions
170 lines (146 loc) · 4.4 KB
/
config.go
File metadata and controls
170 lines (146 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package cli
import (
"os"
"path/filepath"
"strings"
"github.com/flashbots/mev-boost/server/types"
"github.com/fsnotify/fsnotify"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
)
type RelayConfigYAML struct {
URL string `yaml:"url"`
ID string `yaml:"id"`
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
}
// ConfigWatcher provides hot reloading of config files
type ConfigWatcher struct {
v *viper.Viper
configPath string
cliRelays []types.RelayEntry
onConfigChange func(*ConfigResult)
log *logrus.Entry
}
// 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
}
return parseConfig(config)
}
// NewConfigWatcher creates a new config file watcher
func NewConfigWatcher(configPath string, cliRelays []types.RelayEntry, log *logrus.Entry) (*ConfigWatcher, error) {
v := viper.New()
absPath, err := filepath.Abs(configPath)
if err != nil {
return nil, err
}
v.SetConfigFile(absPath)
v.SetConfigType("yaml")
if err := v.ReadInConfig(); err != nil {
return nil, err
}
return &ConfigWatcher{
v: v,
configPath: absPath,
cliRelays: cliRelays,
log: log,
}, nil
}
// Watch starts watching the config file for changes
func (cw *ConfigWatcher) Watch(onConfigChange func(*ConfigResult)) {
cw.onConfigChange = onConfigChange
cw.v.OnConfigChange(func(_ fsnotify.Event) {
cw.log.Info("config file changed, reloading...")
var config Config
if err := cw.v.Unmarshal(&config); err != nil {
cw.log.WithError(err).Error("failed to unmarshal new config, keeping old config")
return
}
newConfig, err := parseConfig(config)
if err != nil {
cw.log.WithError(err).Error("failed to parse new config, keeping old config")
return
}
cw.log.Infof("successfully loaded new config")
if cw.onConfigChange != nil {
cw.onConfigChange(newConfig)
}
})
cw.v.WatchConfig()
}
// MergeRelayConfigs merges relays passed via --relays with 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)
processedURLs := make(map[string]bool)
for _, entry := range relays {
urlStr := entry.String()
if config, exists := configMap[urlStr]; exists {
config.RelayEntry = entry
configs = append(configs, config)
} else {
configs = append(configs, types.NewRelayConfig(entry))
}
processedURLs[urlStr] = true
}
for urlStr, config := range configMap {
if !processedURLs[urlStr] {
configs = append(configs, config)
}
}
return configs
}
func parseConfig(config Config) (*ConfigResult, error) {
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
}
if relay.ID != "" {
relayEntry.ID = relay.ID
} else {
relayEntry.ID = relayEntry.URL.String()
}
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
}