The core protocol of WoopChain
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.
 
 
 
woop/cmd/harmony/config_migrations.go

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)
}