You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
434 lines
13 KiB
434 lines
13 KiB
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
|
|
goversion "github.com/hashicorp/go-version"
|
|
"github.com/pelletier/go-toml" // TODO support go-toml/v2
|
|
|
|
"github.com/harmony-one/harmony/api/service/legacysync"
|
|
harmonyconfig "github.com/harmony-one/harmony/internal/configs/harmony"
|
|
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
|
|
)
|
|
|
|
const legacyConfigVersion = "1.0.4"
|
|
|
|
func doMigrations(confVersion string, confTree *toml.Tree) error {
|
|
Ver, err := goversion.NewVersion(confVersion)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid or missing config file version - '%s'", confVersion)
|
|
}
|
|
legacyVer, _ := goversion.NewVersion(legacyConfigVersion)
|
|
migrationKey := confVersion
|
|
if Ver.LessThan(legacyVer) {
|
|
migrationKey = legacyConfigVersion
|
|
}
|
|
|
|
migration, found := migrations[migrationKey]
|
|
|
|
// Version does not match any of the migration criteria
|
|
if !found {
|
|
return fmt.Errorf("unrecognized config version - %s", confVersion)
|
|
}
|
|
|
|
for confVersion != tomlConfigVersion {
|
|
confTree = migration(confTree)
|
|
confVersion = confTree.Get("Version").(string)
|
|
migration = migrations[confVersion]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func migrateConf(confBytes []byte) (harmonyconfig.HarmonyConfig, string, error) {
|
|
var (
|
|
migratedFrom string
|
|
)
|
|
confTree, err := toml.LoadBytes(confBytes)
|
|
if err != nil {
|
|
return harmonyconfig.HarmonyConfig{}, "", fmt.Errorf("config file parse error - %s", err.Error())
|
|
}
|
|
confVersion, found := confTree.Get("Version").(string)
|
|
if !found {
|
|
return harmonyconfig.HarmonyConfig{}, "", errors.New("config file invalid - no version entry found")
|
|
}
|
|
migratedFrom = confVersion
|
|
if confVersion != tomlConfigVersion {
|
|
err = doMigrations(confVersion, confTree)
|
|
if err != nil {
|
|
return harmonyconfig.HarmonyConfig{}, "", err
|
|
}
|
|
}
|
|
|
|
// At this point we must be at current config version so
|
|
// we can safely unmarshal it
|
|
var config harmonyconfig.HarmonyConfig
|
|
if err := confTree.Unmarshal(&config); err != nil {
|
|
return harmonyconfig.HarmonyConfig{}, "", err
|
|
}
|
|
return config, migratedFrom, nil
|
|
}
|
|
|
|
var (
|
|
migrations = make(map[string]configMigrationFunc)
|
|
)
|
|
|
|
type configMigrationFunc func(*toml.Tree) *toml.Tree
|
|
|
|
func init() {
|
|
migrations["1.0.4"] = func(confTree *toml.Tree) *toml.Tree {
|
|
ntStr := confTree.Get("Network.NetworkType").(string)
|
|
nt := parseNetworkType(ntStr)
|
|
|
|
defDNSSyncConf := getDefaultDNSSyncConfig(nt)
|
|
defSyncConfig := getDefaultSyncConfig(nt)
|
|
|
|
// Legacy conf missing fields
|
|
if confTree.Get("Sync") == nil {
|
|
confTree.Set("Sync", defSyncConfig)
|
|
}
|
|
|
|
if confTree.Get("HTTP.RosettaPort") == nil {
|
|
confTree.Set("HTTP.RosettaPort", defaultConfig.HTTP.RosettaPort)
|
|
}
|
|
|
|
if confTree.Get("RPCOpt.RateLimterEnabled") == nil {
|
|
confTree.Set("RPCOpt.RateLimterEnabled", defaultConfig.RPCOpt.RateLimterEnabled)
|
|
}
|
|
|
|
if confTree.Get("RPCOpt.RequestsPerSecond") == nil {
|
|
confTree.Set("RPCOpt.RequestsPerSecond", defaultConfig.RPCOpt.RequestsPerSecond)
|
|
}
|
|
|
|
if confTree.Get("P2P.IP") == nil {
|
|
confTree.Set("P2P.IP", defaultConfig.P2P.IP)
|
|
}
|
|
|
|
if confTree.Get("Prometheus") == nil {
|
|
if defaultConfig.Prometheus != nil {
|
|
confTree.Set("Prometheus", *defaultConfig.Prometheus)
|
|
}
|
|
}
|
|
|
|
zoneField := confTree.Get("Network.DNSZone")
|
|
if zone, ok := zoneField.(string); ok {
|
|
confTree.Set("DNSSync.Zone", zone)
|
|
}
|
|
|
|
portField := confTree.Get("Network.DNSPort")
|
|
if p, ok := portField.(int64); ok {
|
|
p = p - legacysync.SyncingPortDifference
|
|
confTree.Set("DNSSync.Port", p)
|
|
} else {
|
|
confTree.Set("DNSSync.Port", nodeconfig.DefaultDNSPort)
|
|
}
|
|
|
|
syncingField := confTree.Get("Network.LegacySyncing")
|
|
if syncing, ok := syncingField.(bool); ok {
|
|
confTree.Set("DNSSync.LegacySyncing", syncing)
|
|
}
|
|
|
|
clientField := confTree.Get("Sync.LegacyClient")
|
|
if client, ok := clientField.(bool); ok {
|
|
confTree.Set("DNSSync.Client", client)
|
|
} else {
|
|
confTree.Set("DNSSync.Client", defDNSSyncConf.Client)
|
|
}
|
|
|
|
serverField := confTree.Get("Sync.LegacyServer")
|
|
if server, ok := serverField.(bool); ok {
|
|
confTree.Set("DNSSync.Server", server)
|
|
} else {
|
|
confTree.Set("DNSSync.Server", defDNSSyncConf.Client)
|
|
}
|
|
|
|
serverPort := defDNSSyncConf.ServerPort
|
|
serverPortField := confTree.Get("Sync.LegacyServerPort")
|
|
if port, ok := serverPortField.(int64); ok {
|
|
serverPort = int(port)
|
|
}
|
|
confTree.Set("DNSSync.ServerPort", serverPort)
|
|
|
|
downloaderEnabledField := confTree.Get("Sync.Downloader")
|
|
if downloaderEnabled, ok := downloaderEnabledField.(bool); ok && downloaderEnabled {
|
|
// If we enabled downloader previously, run stream sync protocol.
|
|
confTree.Set("Sync.Enabled", true)
|
|
}
|
|
|
|
confTree.Set("Version", "2.0.0")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.0.0"] = func(confTree *toml.Tree) *toml.Tree {
|
|
// Legacy conf missing fields
|
|
if confTree.Get("Log.VerbosePrints") == nil {
|
|
confTree.Set("Log.VerbosePrints", defaultConfig.Log.VerbosePrints)
|
|
}
|
|
|
|
confTree.Set("Version", "2.1.0")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.1.0"] = func(confTree *toml.Tree) *toml.Tree {
|
|
// Legacy conf missing fields
|
|
if confTree.Get("Pprof.Enabled") == nil {
|
|
confTree.Set("Pprof.Enabled", true)
|
|
}
|
|
if confTree.Get("Pprof.Folder") == nil {
|
|
confTree.Set("Pprof.Folder", defaultConfig.Pprof.Folder)
|
|
}
|
|
if confTree.Get("Pprof.ProfileNames") == nil {
|
|
confTree.Set("Pprof.ProfileNames", defaultConfig.Pprof.ProfileNames)
|
|
}
|
|
if confTree.Get("Pprof.ProfileIntervals") == nil {
|
|
confTree.Set("Pprof.ProfileIntervals", defaultConfig.Pprof.ProfileIntervals)
|
|
}
|
|
if confTree.Get("Pprof.ProfileDebugValues") == nil {
|
|
confTree.Set("Pprof.ProfileDebugValues", defaultConfig.Pprof.ProfileDebugValues)
|
|
}
|
|
if confTree.Get("P2P.DiscConcurrency") == nil {
|
|
confTree.Set("P2P.DiscConcurrency", defaultConfig.P2P.DiscConcurrency)
|
|
}
|
|
|
|
confTree.Set("Version", "2.2.0")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.2.0"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("HTTP.AuthPort") == nil {
|
|
confTree.Set("HTTP.AuthPort", defaultConfig.HTTP.AuthPort)
|
|
}
|
|
|
|
confTree.Set("Version", "2.3.0")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.3.0"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("P2P.MaxConnsPerIP") == nil {
|
|
confTree.Set("P2P.MaxConnsPerIP", defaultConfig.P2P.MaxConnsPerIP)
|
|
}
|
|
|
|
confTree.Set("Version", "2.4.0")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.4.0"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("WS.AuthPort") == nil {
|
|
confTree.Set("WS.AuthPort", defaultConfig.WS.AuthPort)
|
|
}
|
|
|
|
confTree.Set("Version", "2.5.0")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.0"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("TxPool.AccountSlots") == nil {
|
|
confTree.Set("TxPool.AccountSlots", defaultConfig.TxPool.AccountSlots)
|
|
}
|
|
|
|
confTree.Set("Version", "2.5.1")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.1"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("P2P.DisablePrivateIPScan") == nil {
|
|
confTree.Set("P2P.DisablePrivateIPScan", defaultConfig.P2P.DisablePrivateIPScan)
|
|
}
|
|
|
|
confTree.Set("Version", "2.5.2")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.2"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("RPCOpt.EthRPCsEnabled") == nil {
|
|
confTree.Set("RPCOpt.EthRPCsEnabled", defaultConfig.RPCOpt.EthRPCsEnabled)
|
|
}
|
|
|
|
if confTree.Get("RPCOpt.StakingRPCsEnabled") == nil {
|
|
confTree.Set("RPCOpt.StakingRPCsEnabled", defaultConfig.RPCOpt.StakingRPCsEnabled)
|
|
}
|
|
|
|
if confTree.Get("RPCOpt.LegacyRPCsEnabled") == nil {
|
|
confTree.Set("RPCOpt.LegacyRPCsEnabled", defaultConfig.RPCOpt.LegacyRPCsEnabled)
|
|
}
|
|
|
|
if confTree.Get("RPCOpt.RpcFilterFile") == nil {
|
|
confTree.Set("RPCOpt.RpcFilterFile", defaultConfig.RPCOpt.RpcFilterFile)
|
|
}
|
|
|
|
confTree.Set("Version", "2.5.3")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.3"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("TxPool.AllowedTxsFile") == nil {
|
|
confTree.Set("TxPool.AllowedTxsFile", defaultConfig.TxPool.AllowedTxsFile)
|
|
}
|
|
confTree.Set("Version", "2.5.4")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.4"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("TxPool.GlobalSlots") == nil {
|
|
confTree.Set("TxPool.GlobalSlots", defaultConfig.TxPool.GlobalSlots)
|
|
}
|
|
confTree.Set("Version", "2.5.5")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.5"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("Log.Console") == nil {
|
|
confTree.Set("Log.Console", defaultConfig.Log.Console)
|
|
}
|
|
confTree.Set("Version", "2.5.6")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.6"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("P2P.MaxPeers") == nil {
|
|
confTree.Set("P2P.MaxPeers", defaultConfig.P2P.MaxPeers)
|
|
}
|
|
confTree.Set("Version", "2.5.7")
|
|
return confTree
|
|
}
|
|
migrations["2.5.7"] = func(confTree *toml.Tree) *toml.Tree {
|
|
confTree.Delete("DNSSync.LegacySyncing")
|
|
|
|
confTree.Set("Version", "2.5.8")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.8"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("Sync.StagedSync") == nil {
|
|
confTree.Set("Sync.StagedSync", defaultConfig.Sync.StagedSync)
|
|
confTree.Set("Sync.StagedSyncCfg", defaultConfig.Sync.StagedSyncCfg)
|
|
}
|
|
confTree.Set("Version", "2.5.9")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.9"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("P2P.WaitForEachPeerToConnect") == nil {
|
|
confTree.Set("P2P.WaitForEachPeerToConnect", defaultConfig.P2P.WaitForEachPeerToConnect)
|
|
}
|
|
confTree.Set("Version", "2.5.10")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.10"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("P2P.ConnManagerLowWatermark") == nil {
|
|
confTree.Set("P2P.ConnManagerLowWatermark", defaultConfig.P2P.ConnManagerLowWatermark)
|
|
}
|
|
if confTree.Get("P2P.ConnManagerHighWatermark") == nil {
|
|
confTree.Set("P2P.ConnManagerHighWatermark", defaultConfig.P2P.ConnManagerHighWatermark)
|
|
}
|
|
if confTree.Get("Sync.MaxAdvertiseWaitTime") == nil {
|
|
confTree.Set("Sync.MaxAdvertiseWaitTime", defaultConfig.Sync.MaxAdvertiseWaitTime)
|
|
}
|
|
confTree.Set("Version", "2.5.11")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.11"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("General.TriesInMemory") == nil {
|
|
confTree.Set("General.TriesInMemory", defaultConfig.General.TriesInMemory)
|
|
}
|
|
confTree.Set("Version", "2.5.12")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.12"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("HTTP.ReadTimeout") == nil {
|
|
confTree.Set("HTTP.ReadTimeout", defaultConfig.HTTP.ReadTimeout)
|
|
}
|
|
if confTree.Get("HTTP.WriteTimeout") == nil {
|
|
confTree.Set("HTTP.WriteTimeout", defaultConfig.HTTP.WriteTimeout)
|
|
}
|
|
if confTree.Get("HTTP.IdleTimeout") == nil {
|
|
confTree.Set("HTTP.IdleTimeout", defaultConfig.HTTP.IdleTimeout)
|
|
}
|
|
if confTree.Get("RPCOpt.EvmCallTimeout") == nil {
|
|
confTree.Set("RPCOpt.EvmCallTimeout", defaultConfig.RPCOpt.EvmCallTimeout)
|
|
}
|
|
confTree.Set("Version", "2.5.13")
|
|
return confTree
|
|
}
|
|
|
|
migrations["2.5.13"] = func(confTree *toml.Tree) *toml.Tree {
|
|
if confTree.Get("TxPool.AccountQueue") == nil {
|
|
confTree.Set("TxPool.AccountQueue", defaultConfig.TxPool.AccountQueue)
|
|
}
|
|
if confTree.Get("TxPool.GlobalQueue") == nil {
|
|
confTree.Set("TxPool.GlobalQueue", defaultConfig.TxPool.GlobalQueue)
|
|
}
|
|
if confTree.Get("TxPool.Lifetime") == nil {
|
|
confTree.Set("TxPool.Lifetime", defaultConfig.TxPool.Lifetime.String())
|
|
}
|
|
if confTree.Get("TxPool.PriceLimit") == nil {
|
|
confTree.Set("TxPool.PriceLimit", defaultConfig.TxPool.PriceLimit)
|
|
}
|
|
if confTree.Get("TxPool.PriceBump") == nil {
|
|
confTree.Set("TxPool.PriceBump", defaultConfig.TxPool.PriceBump)
|
|
}
|
|
|
|
confTree.Set("Version", "2.5.14")
|
|
return confTree
|
|
}
|
|
|
|
// check that the latest version here is the same as in default.go
|
|
largestKey := getNextVersion(migrations)
|
|
if largestKey != tomlConfigVersion {
|
|
panic(fmt.Sprintf("next migration value: %s, toml version: %s", largestKey, tomlConfigVersion))
|
|
}
|
|
}
|
|
|
|
func getNextVersion(x map[string]configMigrationFunc) string {
|
|
versionMap := make(map[string]interface{}, 1)
|
|
versionMap["Version"] = "FakeVersion"
|
|
tree, _ := toml.TreeFromMap(versionMap)
|
|
|
|
// needs to be sorted in case the order is incorrect
|
|
keys := make([]string, len(x))
|
|
i := 0
|
|
for k := range x {
|
|
keys[i] = k
|
|
i++
|
|
}
|
|
// sorting keys (versions)
|
|
// each key is in format "x.x.x". Normal sort won't work if the versions
|
|
// don't have same number of digits, for example 1.02.10 and 1.2.9
|
|
// so, we need a custom sort
|
|
sort.Slice(keys, func(i, j int) bool {
|
|
v1 := keys[i]
|
|
v2 := keys[j]
|
|
v1Parts := strings.Split(v1, ".")
|
|
v2Parts := strings.Split(v2, ".")
|
|
if len(v1Parts) > len(v2Parts) {
|
|
return true
|
|
} else if len(v1Parts) < len(v2Parts) {
|
|
return false
|
|
}
|
|
for i := 0; i < len(v1Parts); i++ {
|
|
n1, err1 := strconv.ParseInt(v1Parts[i], 10, 32)
|
|
if err1 != nil {
|
|
panic("wrong version format")
|
|
}
|
|
n2, err2 := strconv.ParseInt(v2Parts[i], 10, 32)
|
|
if err2 != nil {
|
|
panic("wrong version format")
|
|
}
|
|
if n1 > n2 {
|
|
return true
|
|
} else if n1 < n2 {
|
|
return false
|
|
}
|
|
}
|
|
return false
|
|
})
|
|
requiredFunc := x[keys[0]]
|
|
tree = requiredFunc(tree)
|
|
return tree.Get("Version").(string)
|
|
}
|
|
|