diff --git a/cmd/network/switch.go b/cmd/network/switch.go index 2350592..8f3d35c 100644 --- a/cmd/network/switch.go +++ b/cmd/network/switch.go @@ -1,6 +1,7 @@ package network import ( + "encoding/json" "errors" "fmt" "net" @@ -40,6 +41,14 @@ func init() { networkCmd.AddCommand(switchCmd) } +// retainedSettings are the settings we want to keep track of when switching networks so we can swap back to them in the future +type retainedSettings struct { + DNSServers []string `json:"dns_servers"` + BootstrapPeers []string `json:"bootstrap_peers"` + StaticPeers []string `json:"static_peers"` + FullNodePeers []config.Peer `json:"full_node_peers"` +} + // SwitchNetwork implements the logic to swap networks func SwitchNetwork(networkName string, checkForRunningNode bool) { slogs.Logr.Info("Swapping to network", "network", networkName) @@ -91,6 +100,35 @@ func SwitchNetwork(networkName string, checkForRunningNode bool) { slogs.Logr.Fatal("error creating cache file directory for new network", "error", err, "directory", cacheFileDirNewNetwork) } + previousSettings := retainedSettings{ + DNSServers: cfg.FullNode.DNSServers, + BootstrapPeers: cfg.Seeder.BootstrapPeers, + StaticPeers: cfg.Seeder.StaticPeers, + FullNodePeers: cfg.FullNode.FullNodePeers, + } + marshalled, err := json.Marshal(previousSettings) + if err != nil { + slogs.Logr.Fatal("error marshalling retained settings to json", "error", err) + } + err = os.WriteFile(path.Join(cacheFileDirOldNetwork, "settings.json"), marshalled, 0644) + if err != nil { + slogs.Logr.Fatal("error writing settings for old network", "error", err) + } + + var settingsToRestore *retainedSettings + newSettingsPath := path.Join(cacheFileDirNewNetwork, "settings.json") + if _, err := os.Stat(newSettingsPath); err == nil { + settings, err := os.ReadFile(newSettingsPath) + if err != nil { + slogs.Logr.Fatal("error reading stored settings for the new network", "error", err) + } + settingsToRestore = &retainedSettings{} + err = json.Unmarshal(settings, settingsToRestore) + if err != nil { + slogs.Logr.Fatal("error unmarshalling stored settings for the new network", "error", err) + } + } + // Check if Full Node is running if checkForRunningNode { slogs.Logr.Debug("initializing websocket client to ensure chia is stopped") @@ -133,24 +171,44 @@ func SwitchNetwork(networkName string, checkForRunningNode bool) { } introducerHost := "introducer.chia.net" - dnsIntroducerHost := "dns-introducer.chia.net" + dnsIntroducerHosts := []string{"dns-introducer.chia.net"} fullNodePort := uint16(8444) - peersFilePath := "peers.dat" + var fullnodePeers []config.Peer + peersFilePath := "db/peers.dat" walletPeersFilePath := "wallet/db/wallet_peers.dat" bootstrapPeers := []string{"node.chia.net"} + var staticPeers []string if networkName != "mainnet" { introducerHost = fmt.Sprintf("introducer-%s.chia.net", networkName) - dnsIntroducerHost = fmt.Sprintf("dns-introducer-%s.chia.net", networkName) + dnsIntroducerHosts = []string{fmt.Sprintf("dns-introducer-%s.chia.net", networkName)} fullNodePort = uint16(58444) - peersFilePath = fmt.Sprintf("peers-%s.dat", networkName) + peersFilePath = fmt.Sprintf("db/peers-%s.dat", networkName) walletPeersFilePath = fmt.Sprintf("wallet/db/wallet_peers-%s.dat", networkName) bootstrapPeers = []string{fmt.Sprintf("node-%s.chia.net", networkName)} } + + // Any stored settings for the new network should be applied here, before any flags override them + if settingsToRestore != nil { + slogs.Logr.Info("restoring stored settings for this network") + if len(settingsToRestore.DNSServers) > 0 { + dnsIntroducerHosts = settingsToRestore.DNSServers + } + if len(settingsToRestore.BootstrapPeers) > 0 { + bootstrapPeers = settingsToRestore.BootstrapPeers + } + if len(settingsToRestore.StaticPeers) > 0 { + staticPeers = settingsToRestore.StaticPeers + } + if len(settingsToRestore.FullNodePeers) > 0 { + fullnodePeers = settingsToRestore.FullNodePeers + } + } + if introFlag := viper.GetString("switch-introducer"); introFlag != "" { introducerHost = introFlag } if dnsIntroFlag := viper.GetString("switch-dns-introducer"); dnsIntroFlag != "" { - dnsIntroducerHost = dnsIntroFlag + dnsIntroducerHosts = []string{dnsIntroFlag} } if bootPeer := viper.GetString("switch-bootstrap-peer"); bootPeer != "" { bootstrapPeers = []string{bootPeer} @@ -172,22 +230,24 @@ func SwitchNetwork(networkName string, checkForRunningNode bool) { }, }, "full_node.database_path": fmt.Sprintf("db/blockchain_v2_%s.sqlite", networkName), - "full_node.dns_servers": []string{dnsIntroducerHost}, + "full_node.dns_servers": dnsIntroducerHosts, "full_node.peers_file_path": peersFilePath, "full_node.port": fullNodePort, + "full_node.full_node_peers": fullnodePeers, "full_node.introducer_peer.host": introducerHost, "full_node.introducer_peer.port": fullNodePort, "introducer.port": fullNodePort, "seeder.port": fullNodePort, "seeder.other_peers_port": fullNodePort, "seeder.bootstrap_peers": bootstrapPeers, + "seeder.static_peers": staticPeers, "timelord.full_node_peers": []config.Peer{ { Host: "localhost", Port: fullNodePort, }, }, - "wallet.dns_servers": []string{dnsIntroducerHost}, + "wallet.dns_servers": dnsIntroducerHosts, "wallet.full_node_peers": []config.Peer{ { Host: "localhost", @@ -198,14 +258,14 @@ func SwitchNetwork(networkName string, checkForRunningNode bool) { "wallet.introducer_peer.port": fullNodePort, "wallet.wallet_peers_file_path": walletPeersFilePath, } - for path, value := range pathUpdates { - pathMap := config.ParsePathsFromStrings([]string{path}, false) + for configPath, value := range pathUpdates { + pathMap := config.ParsePathsFromStrings([]string{configPath}, false) var key string var pathSlice []string for key, pathSlice = range pathMap { break } - slogs.Logr.Debug("setting config path", "path", path, "value", value) + slogs.Logr.Debug("setting config path", "path", configPath, "value", value) err = cfg.SetFieldByPath(pathSlice, value) if err != nil { slogs.Logr.Fatal("error setting path in config", "key", key, "value", value, "error", err) diff --git a/cmd/network/switch_test.go b/cmd/network/switch_test.go index 9429d92..cb807ca 100644 --- a/cmd/network/switch_test.go +++ b/cmd/network/switch_test.go @@ -76,7 +76,7 @@ func TestNetworkSwitch(t *testing.T) { assert.Equal(t, []config.Peer{localpeer}, cfg.Farmer.FullNodePeers) assert.Equal(t, "db/blockchain_v2_unittestnet.sqlite", cfg.FullNode.DatabasePath) assert.Equal(t, []string{"dns-introducer-unittestnet.chia.net"}, cfg.FullNode.DNSServers) - assert.Equal(t, "peers-unittestnet.dat", cfg.FullNode.PeersFilePath) + assert.Equal(t, "db/peers-unittestnet.dat", cfg.FullNode.PeersFilePath) assert.Equal(t, port, cfg.FullNode.Port) assert.Equal(t, config.Peer{Host: "introducer-unittestnet.chia.net", Port: port}, cfg.FullNode.IntroducerPeer) assert.Equal(t, port, cfg.Introducer.Port) @@ -88,3 +88,43 @@ func TestNetworkSwitch(t *testing.T) { assert.Equal(t, config.Peer{Host: "introducer-unittestnet.chia.net", Port: port}, cfg.Wallet.IntroducerPeer) assert.Equal(t, "wallet/db/wallet_peers-unittestnet.dat", cfg.Wallet.WalletPeersFilePath) } + +func TestNetworkSwitch_SettingRetention(t *testing.T) { + cmd.InitLogs() + setupDefaultConfig(t) + cfg, err := config.GetChiaConfig() + assert.NoError(t, err) + assert.Equal(t, "mainnet", *cfg.SelectedNetwork) + + // Set some custom dns introducers, and ensure they are back when swapping away and back to mainnet + cfg.FullNode.DNSServers = []string{"dns-mainnet-1.example.com", "dns-mainnet-2.example.com"} + cfg.Seeder.BootstrapPeers = []string{"bootstrap-mainnet-1.example.com"} + cfg.Seeder.StaticPeers = []string{"static-peer-1.example.com"} + cfg.FullNode.FullNodePeers = []config.Peer{{Host: "fn-peer-1.example.com", Port: 1234}} + err = cfg.Save() + assert.NoError(t, err) + + // reload config from disk to ensure the dns servers were persisted + cfg, err = config.GetChiaConfig() + assert.NoError(t, err) + assert.Equal(t, []string{"dns-mainnet-1.example.com", "dns-mainnet-2.example.com"}, cfg.FullNode.DNSServers) + + network.SwitchNetwork("unittestnet", false) + // reload config from disk to ensure defaults are in the config now + cfg, err = config.GetChiaConfig() + assert.NoError(t, err) + assert.Equal(t, []string{"dns-introducer-unittestnet.chia.net"}, cfg.FullNode.DNSServers) + assert.Equal(t, []string{"node-unittestnet.chia.net"}, cfg.Seeder.BootstrapPeers) + assert.Equal(t, []string{}, cfg.Seeder.StaticPeers) + assert.Equal(t, []config.Peer{}, cfg.FullNode.FullNodePeers) + + network.SwitchNetwork("mainnet", false) + + // reload config from disk + cfg, err = config.GetChiaConfig() + assert.NoError(t, err) + assert.Equal(t, []string{"dns-mainnet-1.example.com", "dns-mainnet-2.example.com"}, cfg.FullNode.DNSServers) + assert.Equal(t, []string{"bootstrap-mainnet-1.example.com"}, cfg.Seeder.BootstrapPeers) + assert.Equal(t, []string{"static-peer-1.example.com"}, cfg.Seeder.StaticPeers) + assert.Equal(t, []config.Peer{{Host: "fn-peer-1.example.com", Port: 1234}}, cfg.FullNode.FullNodePeers) +}