Skip to content

Commit

Permalink
Add network switch command (#26)
Browse files Browse the repository at this point in the history
* Add network switch command

* Stop all services + daemon if running

* remove peer dbs if they exist
  • Loading branch information
cmmarslender authored Sep 24, 2024
1 parent c2392c4 commit e7d7145
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 12 deletions.
11 changes: 2 additions & 9 deletions cmd/config/edit.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package config

import (
"os"
"path"

"github.com/chia-network/go-chia-libs/pkg/config"
"github.com/chia-network/go-modules/pkg/slogs"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
)

// editCmd generates a new chia config
Expand Down Expand Up @@ -61,14 +59,9 @@ chia-tools config edit --set full_node.port=58444 --set full_node.target_peer_co
}
}

out, err := yaml.Marshal(cfg)
err = cfg.Save()
if err != nil {
slogs.Logr.Fatal("error marshalling config", "error", err)
}

err = os.WriteFile(cfgPath, out, 0655)
if err != nil {
slogs.Logr.Fatal("error writing output file", "error", err)
slogs.Logr.Fatal("error saving config", "error", err)
}
},
}
Expand Down
17 changes: 17 additions & 0 deletions cmd/network/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package network

import (
"github.com/spf13/cobra"

"github.com/chia-network/chia-tools/cmd"
)

// networkCmd represents the config command
var networkCmd = &cobra.Command{
Use: "network",
Short: "Utilities for working with chia networks",
}

func init() {
cmd.RootCmd.AddCommand(networkCmd)
}
240 changes: 240 additions & 0 deletions cmd/network/switch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
package network

import (
"errors"
"fmt"
"net"
"os"
"path"
"syscall"

"github.com/chia-network/go-chia-libs/pkg/config"
"github.com/chia-network/go-chia-libs/pkg/rpc"
"github.com/chia-network/go-modules/pkg/slogs"
"github.com/spf13/cobra"
)

var switchCmd = &cobra.Command{
Use: "switch",
Short: "Switches the active network on this machine",
Example: "chia-tools network switch testneta",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
networkName := args[0]
slogs.Logr.Info("Swapping to network", "network", networkName)

chiaRoot, err := config.GetChiaRootPath()
if err != nil {
slogs.Logr.Fatal("error determining chia root", "error", err)
}
slogs.Logr.Debug("Chia root discovered", "CHIA_ROOT", chiaRoot)

cfg, err := config.GetChiaConfig()
if err != nil {
slogs.Logr.Fatal("error loading config", "error", err)
}
slogs.Logr.Debug("Successfully loaded config")

currentNetwork := *cfg.SelectedNetwork
slogs.Logr.Info("discovered current network", "current-network", currentNetwork)

if currentNetwork == networkName {
slogs.Logr.Fatal("current network name and new network name are the same", "current", currentNetwork, "new", networkName)
}

// Ensure a folder to store the current network's sub-epoch-summaries and height-to-hash files exists
cacheFileDirOldNetwork := path.Join(chiaRoot, "db", currentNetwork)
cacheFileDirNewNetwork := path.Join(chiaRoot, "db", networkName)

slogs.Logr.Debug("ensuring directory exists for current network cache files", "directory", cacheFileDirOldNetwork)
err = os.MkdirAll(cacheFileDirOldNetwork, 0755)
if err != nil {
slogs.Logr.Fatal("error creating cache file directory for current network", "error", err, "directory", cacheFileDirOldNetwork)
}

slogs.Logr.Debug("ensuring directory exists for new network cache files", "directory", cacheFileDirNewNetwork)
err = os.MkdirAll(cacheFileDirNewNetwork, 0755)
if err != nil {
slogs.Logr.Fatal("error creating cache file directory for new network", "error", err, "directory", cacheFileDirNewNetwork)
}

// Check if Full Node is running
slogs.Logr.Debug("initializing websocket client to ensure chia is stopped")
rpcClient, err := rpc.NewClient(rpc.ConnectionModeWebsocket, rpc.WithAutoConfig(), rpc.WithSyncWebsocket())
if err != nil {
slogs.Logr.Fatal("error initializing RPC client", "error", err)
}

slogs.Logr.Debug("Attempting to stop chia services if running")
_, _, err = rpcClient.DaemonService.Exit()
if err != nil {
if !isConnectionRefused(err) {
slogs.Logr.Fatal("error stopping chia services", "error", err)
}
}

// Safe to move files now
activeSubEpochSummariesPath := path.Join(chiaRoot, "db", "sub-epoch-summaries")
activeHeightToHashPath := path.Join(chiaRoot, "db", "height-to-hash")

// Move current cache files to the network subdir
err = moveAndOverwriteFile(activeSubEpochSummariesPath, path.Join(cacheFileDirOldNetwork, "sub-epoch-summaries"))
if err != nil {
slogs.Logr.Fatal("error moving sub-epoch-summaries file", "error", err)
}
err = moveAndOverwriteFile(activeHeightToHashPath, path.Join(cacheFileDirOldNetwork, "height-to-hash"))
if err != nil {
slogs.Logr.Fatal("error moving height-to-hash file", "error", err)
}

// Move old cached files to active dir
err = moveAndOverwriteFile(path.Join(cacheFileDirNewNetwork, "sub-epoch-summaries"), activeSubEpochSummariesPath)
if err != nil {
slogs.Logr.Fatal("error moving sub-epoch-summaries file", "error", err)
}
err = moveAndOverwriteFile(path.Join(cacheFileDirNewNetwork, "height-to-hash"), activeHeightToHashPath)
if err != nil {
slogs.Logr.Fatal("error moving height-to-hash file", "error", err)
}

introducerHost := "introducer.chia.net"
dnsIntroducerHost := "dns-introducer.chia.net"
fullNodePort := uint16(8444)
peersFilePath := "peers.dat"
walletPeersFilePath := "wallet/db/wallet_peers.dat"
bootstrapPeers := []string{"node.chia.net"}
if networkName != "mainnet" {
introducerHost = fmt.Sprintf("introducer-%s.chia.net", networkName)
dnsIntroducerHost = fmt.Sprintf("dns-introducer-%s.chia.net", networkName)
fullNodePort = uint16(58444)
peersFilePath = fmt.Sprintf("peers-%s.dat", networkName)
walletPeersFilePath = fmt.Sprintf("wallet/db/wallet_peers-%s.dat", networkName)
bootstrapPeers = []string{fmt.Sprintf("node-%s.chia.net", networkName)}
}
pathUpdates := map[string]any{
"selected_network": networkName,
"farmer.full_node_peers": []config.Peer{
{
Host: "localhost",
Port: fullNodePort,
},
},
"full_node.database_path": fmt.Sprintf("db/blockchain_v2_%s.sqlite", networkName),
"full_node.dns_servers": []string{dnsIntroducerHost},
"full_node.peers_file_path": peersFilePath,
"full_node.port": fullNodePort,
"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,
"timelord.full_node_peers": []config.Peer{
{
Host: "localhost",
Port: fullNodePort,
},
},
"wallet.dns_servers": []string{dnsIntroducerHost},
"wallet.full_node_peers": []config.Peer{
{
Host: "localhost",
Port: fullNodePort,
},
},
"wallet.introducer_peer.host": introducerHost,
"wallet.introducer_peer.port": fullNodePort,
"wallet.wallet_peers_file_path": walletPeersFilePath,
}
for path, value := range pathUpdates {
pathMap := config.ParsePathsFromStrings([]string{path}, false)
var key string
var pathSlice []string
for key, pathSlice = range pathMap {
break
}
slogs.Logr.Debug("setting config path", "path", path, "value", value)
err = cfg.SetFieldByPath(pathSlice, value)
if err != nil {
slogs.Logr.Fatal("error setting path in config", "key", key, "value", value, "error", err)
}
}

slogs.Logr.Debug("saving config")
err = cfg.Save()
if err != nil {
slogs.Logr.Fatal("error saving chia config", "error", err)
}

err = removeFileIfExists(path.Join(chiaRoot, "db", peersFilePath))
if err != nil {
slogs.Logr.Error("error removing old peers.dat file", "path", peersFilePath, "error", err)
}

slogs.Logr.Info("Complete")
},
}

func init() {
networkCmd.AddCommand(switchCmd)
}

func isConnectionRefused(err error) bool {
var netErr *net.OpError
if errors.As(err, &netErr) {
if netErr.Op == "dial" {
var syscallError *os.SyscallError
if errors.As(netErr.Err, &syscallError) {
return syscallError.Syscall == "connect" && errors.Is(syscallError.Err, syscall.ECONNREFUSED)
}
}
}
return false
}

func moveAndOverwriteFile(sourcePath, destPath string) error {
if _, err := os.Stat(sourcePath); err != nil {
if os.IsNotExist(err) {
slogs.Logr.Debug("source path doesn't exist, skipping move", "source", sourcePath, "dest", destPath)
return nil
}
return fmt.Errorf("error checking source file: %w", err)
}

// Remove the destination file if it exists
slogs.Logr.Debug("checking if destination file exists before moving", "dest", destPath)
if _, err := os.Stat(destPath); err == nil {
slogs.Logr.Debug("Destination file already exists. Deleting", "dest", destPath)
err = os.Remove(destPath)
if err != nil {
return fmt.Errorf("error removing destination file: %w", err)
}
}

slogs.Logr.Debug("moving file to destination", "source", sourcePath, "dest", destPath)
err := os.Rename(sourcePath, destPath)
if err != nil {
return fmt.Errorf("error moving file: %w", err)
}

slogs.Logr.Debug("moved successfully", "source", sourcePath, "dest", destPath)
return nil
}

func removeFileIfExists(path string) error {
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
slogs.Logr.Debug("source path doesn't exist, skipping delete", "path", path)
return nil
}
return fmt.Errorf("error checking source file: %w", err)
}

slogs.Logr.Debug("removing file at path", "path", path)
err := os.Remove(path)
if err != nil {
return fmt.Errorf("error removing file: %w", err)
}

return nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/chia-network/chia-tools
go 1.22.4

require (
github.com/chia-network/go-chia-libs v0.14.2
github.com/chia-network/go-chia-libs v0.15.2
github.com/chia-network/go-modules v0.0.5
github.com/spf13/cast v1.7.0
github.com/spf13/cobra v1.8.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/chia-network/go-chia-libs v0.14.2 h1:CMXPaxnyxT295T4kDohUzbEltgp6TMsIhFKgZ3qDJwk=
github.com/chia-network/go-chia-libs v0.14.2/go.mod h1:npTqaFSjTdMxE7hc0LOmWJmWGqcs+IERarK5fDxXk/I=
github.com/chia-network/go-chia-libs v0.15.2 h1:zhevELM1r/WFo9zUP2vcptfiP+bfMZqqDQ0G82iWqNs=
github.com/chia-network/go-chia-libs v0.15.2/go.mod h1:npTqaFSjTdMxE7hc0LOmWJmWGqcs+IERarK5fDxXk/I=
github.com/chia-network/go-modules v0.0.5 h1:5luTVlP6RgBXodnFcWFBk2sLdJn+6vQ4wObim683C7c=
github.com/chia-network/go-modules v0.0.5/go.mod h1:5AiYBxQSvf2aFSOizTqFXXSeb9AucZWrWmRCVwUMO3A=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
_ "github.com/chia-network/chia-tools/cmd/certs"
_ "github.com/chia-network/chia-tools/cmd/config"
_ "github.com/chia-network/chia-tools/cmd/datalayer"
_ "github.com/chia-network/chia-tools/cmd/network"
_ "github.com/chia-network/chia-tools/cmd/testnet"
)

Expand Down

0 comments on commit e7d7145

Please sign in to comment.