From 5e5b21c7cd168d46ecbb01f0e5fe64350fe2d86b Mon Sep 17 00:00:00 2001 From: Itay Date: Tue, 29 Aug 2023 15:11:03 +0300 Subject: [PATCH] chore: Add prompt and output when changing DA layer (#462) --- cmd/config/init/dir_not_empty.go | 23 -------------- cmd/config/init/init.go | 3 +- cmd/config/init/output.go | 16 ++-------- cmd/config/set/da.go | 41 +++++++++++++++++++++---- cmd/keys/list/list.go | 2 +- cmd/migrate/v_0_1_12.go | 13 +++++++- cmd/utils/keys.go | 5 +++- cmd/utils/output.go | 18 ++++++++++- data_layer/avail/avail.go | 10 +++---- data_layer/avail/utils.go | 10 +++++++ utils/filesystem.go | 51 ++++++++++++++++++++++++++++++++ 11 files changed, 138 insertions(+), 54 deletions(-) delete mode 100644 cmd/config/init/dir_not_empty.go create mode 100644 utils/filesystem.go diff --git a/cmd/config/init/dir_not_empty.go b/cmd/config/init/dir_not_empty.go deleted file mode 100644 index b3d53694..00000000 --- a/cmd/config/init/dir_not_empty.go +++ /dev/null @@ -1,23 +0,0 @@ -package initconfig - -import ( - "fmt" - "os" -) - -func dirNotEmpty(path string) (bool, error) { - info, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - return false, nil - } - return false, err - } - - if !info.IsDir() { - return false, fmt.Errorf("%s is not a directory", path) - } - - files, err := os.ReadDir(path) - return len(files) > 0, err -} diff --git a/cmd/config/init/init.go b/cmd/config/init/init.go index ee93a7d6..865d8a44 100644 --- a/cmd/config/init/init.go +++ b/cmd/config/init/init.go @@ -2,6 +2,7 @@ package initconfig import ( "fmt" + global_utils "github.com/dymensionxyz/roller/utils" "os" "github.com/dymensionxyz/roller/cmd/consts" @@ -75,7 +76,7 @@ func runInit(cmd *cobra.Command, args []string) error { if err != nil { return err } - isRootExist, err := dirNotEmpty(initConfig.Home) + isRootExist, err := global_utils.DirNotEmpty(initConfig.Home) if err != nil { return err } diff --git a/cmd/config/init/output.go b/cmd/config/init/output.go index 318555bf..e337c514 100644 --- a/cmd/config/init/output.go +++ b/cmd/config/init/output.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/dymensionxyz/roller/cmd/utils" "github.com/dymensionxyz/roller/config" - "github.com/manifoldco/promptui" ) type OutputHandler struct { @@ -24,7 +23,7 @@ func (o *OutputHandler) printInitOutput(rollappConfig config.RollappConfig, addr fmt.Printf("šŸ’ˆ RollApp '%s' configuration files have been successfully generated on your local machine. Congratulations!\n\n", rollappId) fmt.Println(FormatTokenSupplyLine(rollappConfig)) fmt.Println() - utils.PrintAddresses(formatAddresses(rollappConfig, addresses)) + utils.PrintAddressesWithTitle(formatAddresses(rollappConfig, addresses)) fmt.Printf("\nšŸ”” Please fund these addresses to register and run the rollapp.\n") } @@ -32,16 +31,5 @@ func (o *OutputHandler) PromptOverwriteConfig(home string) (bool, error) { if o.NoOutput { return true, nil } - prompt := promptui.Prompt{ - Label: fmt.Sprintf("Directory %s is not empty. Do you want to overwrite", home), - IsConfirm: true, - } - _, err := prompt.Run() - if err != nil { - if err == promptui.ErrAbort { - return false, nil - } - return false, err - } - return true, nil + return utils.PromptBool(fmt.Sprintf("Directory %s is not empty. Do you want to overwrite", home)) } diff --git a/cmd/config/set/da.go b/cmd/config/set/da.go index 06e7bb87..0a38a2a4 100644 --- a/cmd/config/set/da.go +++ b/cmd/config/set/da.go @@ -3,9 +3,11 @@ package set import ( "fmt" "github.com/dymensionxyz/roller/cmd/consts" + "github.com/dymensionxyz/roller/cmd/utils" "github.com/dymensionxyz/roller/config" datalayer "github.com/dymensionxyz/roller/data_layer" "github.com/dymensionxyz/roller/sequencer" + global_utils "github.com/dymensionxyz/roller/utils" "os" "path/filepath" ) @@ -23,7 +25,19 @@ func setDA(rlpCfg config.RollappConfig, value string) error { } func updateDaConfig(rlpCfg config.RollappConfig, newDa config.DAType) error { - if err := cleanDADir(rlpCfg); err != nil { + daCfgDirPath := filepath.Join(rlpCfg.Home, consts.ConfigDirName.DALightNode) + dirExist, err := global_utils.DirNotEmpty(daCfgDirPath) + if err != nil { + return err + } + if dirExist { + if yes, err := utils.PromptBool("Changing DA will remove the old DA keys permanently. Are you sure you want to proceed"); err != nil { + return err + } else if !yes { + return nil + } + } + if err := os.RemoveAll(daCfgDirPath); err != nil { return err } daManager := datalayer.NewDAManager(newDa, rlpCfg.Home) @@ -34,9 +48,24 @@ func updateDaConfig(rlpCfg config.RollappConfig, newDa config.DAType) error { if err := sequencer.UpdateDymintDAConfig(rlpCfg); err != nil { return err } - return config.WriteConfigToTOML(rlpCfg) -} - -func cleanDADir(cfg config.RollappConfig) error { - return os.RemoveAll(filepath.Join(cfg.Home, consts.ConfigDirName.DALightNode)) + if err := config.WriteConfigToTOML(rlpCfg); err != nil { + return err + } + fmt.Printf("šŸ’ˆ RollApp DA has been successfully set to '%s'\n\n", newDa) + if newDa != config.Local { + addresses := make([]utils.AddressData, 0) + damanager := datalayer.NewDAManager(newDa, rlpCfg.Home) + daAddress, err := damanager.GetDAAccountAddress() + if err != nil { + return err + } + addresses = append(addresses, utils.AddressData{ + Name: damanager.GetKeyName(), + Addr: daAddress, + }) + fmt.Printf("šŸ”‘ Address:\n\n") + utils.PrintAddresses(addresses) + fmt.Printf("\nšŸ”” Please fund this address to run the DA light client.\n") + } + return nil } diff --git a/cmd/keys/list/list.go b/cmd/keys/list/list.go index 6e282713..a06ba2ba 100644 --- a/cmd/keys/list/list.go +++ b/cmd/keys/list/list.go @@ -71,7 +71,7 @@ func Cmd() *cobra.Command { if outputType == "json" { utils.PrettifyErrorIfExists(printAsJSON(addresses)) } else if outputType == "text" { - utils.PrintAddresses(addresses) + utils.PrintAddressesWithTitle(addresses) } }, } diff --git a/cmd/migrate/v_0_1_12.go b/cmd/migrate/v_0_1_12.go index ee82176c..2db773c2 100644 --- a/cmd/migrate/v_0_1_12.go +++ b/cmd/migrate/v_0_1_12.go @@ -3,8 +3,10 @@ package migrate import ( "github.com/dymensionxyz/roller/config" datalayer "github.com/dymensionxyz/roller/data_layer" + "github.com/dymensionxyz/roller/data_layer/avail" "github.com/dymensionxyz/roller/sequencer" "github.com/dymensionxyz/roller/utils" + "path/filepath" ) type VersionMigratorV0112 struct{} @@ -20,5 +22,14 @@ func (v *VersionMigratorV0112) PerformMigration(rlpCfg config.RollappConfig) err if sequencerDaConfig == "" { return nil } - return utils.UpdateFieldInToml(dymintTomlPath, "da_config", sequencerDaConfig) + if err := utils.UpdateFieldInToml(dymintTomlPath, "da_config", sequencerDaConfig); err != nil { + return err + } + if rlpCfg.DA == config.Avail { + availNewCfgPath := avail.GetCfgFilePath(rlpCfg.Home) + if err := utils.MoveFile(filepath.Join(rlpCfg.Home, avail.ConfigFileName), availNewCfgPath); err != nil { + return err + } + } + return nil } diff --git a/cmd/utils/keys.go b/cmd/utils/keys.go index c7df3f59..fe50aa9d 100644 --- a/cmd/utils/keys.go +++ b/cmd/utils/keys.go @@ -60,8 +60,11 @@ type AddressData struct { Addr string } -func PrintAddresses(addresses []AddressData) { +func PrintAddressesWithTitle(addresses []AddressData) { fmt.Printf("šŸ”‘ Addresses:\n\n") + PrintAddresses(addresses) +} +func PrintAddresses(addresses []AddressData) { data := make([][]string, 0, len(addresses)) for _, address := range addresses { data = append(data, []string{address.Name, address.Addr}) diff --git a/cmd/utils/output.go b/cmd/utils/output.go index f72f2b32..0b4df188 100644 --- a/cmd/utils/output.go +++ b/cmd/utils/output.go @@ -3,6 +3,7 @@ package utils import ( "errors" "fmt" + "github.com/manifoldco/promptui" "math/big" "os" "time" @@ -39,7 +40,7 @@ func PrintInsufficientBalancesIfAny(addressesData []NotFundedAddressData, config fmt.Println() fmt.Println("šŸ’ˆ Please fund these addresses and try again.") } - PrettifyErrorIfExists(errors.New("The following addresses have insufficient balance to perform this operation"), + PrettifyErrorIfExists(errors.New("the following addresses have insufficient balance to perform this operation"), printAddresses) } @@ -61,6 +62,21 @@ type OutputHandler struct { spinner *spinner.Spinner } +func PromptBool(msg string) (bool, error) { + prompt := promptui.Prompt{ + Label: msg, + IsConfirm: true, + } + _, err := prompt.Run() + if err != nil { + if err == promptui.ErrAbort { + return false, nil + } + return false, err + } + return true, nil +} + func NewOutputHandler(noOutput bool) *OutputHandler { if noOutput { return &OutputHandler{ diff --git a/data_layer/avail/avail.go b/data_layer/avail/avail.go index 9fb4fe77..8e0adcad 100644 --- a/data_layer/avail/avail.go +++ b/data_layer/avail/avail.go @@ -2,13 +2,11 @@ package avail import ( "fmt" - "math/big" - "os/exec" - "path/filepath" - "github.com/dymensionxyz/roller/cmd/consts" "github.com/dymensionxyz/roller/cmd/utils" "github.com/dymensionxyz/roller/config" + "math/big" + "os/exec" gsrpc "github.com/centrifuge/go-substrate-rpc-client/v4" "github.com/centrifuge/go-substrate-rpc-client/v4/signature" @@ -18,7 +16,7 @@ import ( ) const ( - availConfigFileName = "avail.toml" + ConfigFileName = "avail.toml" mnemonicEntropySize = 256 keyringNetworkID uint8 = 42 DeafultRPCEndpoint = "wss://dymension-devnet.avail.tools/ws" @@ -42,7 +40,7 @@ func (a *Avail) SetMetricsEndpoint(endpoint string) { } func NewAvail(root string) *Avail { - cfgPath := filepath.Join(root, availConfigFileName) + cfgPath := GetCfgFilePath(root) availConfig, err := loadConfigFromTOML(cfgPath) if err != nil { entropySeed, err := bip39.NewEntropy(mnemonicEntropySize) diff --git a/data_layer/avail/utils.go b/data_layer/avail/utils.go index 9f9d24d2..6c569583 100644 --- a/data_layer/avail/utils.go +++ b/data_layer/avail/utils.go @@ -1,7 +1,9 @@ package avail import ( + "github.com/dymensionxyz/roller/cmd/consts" "os" + "path/filepath" "github.com/pelletier/go-toml" ) @@ -11,6 +13,10 @@ func writeConfigToTOML(path string, c Avail) error { if err != nil { return err } + dir := filepath.Dir(path) + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } err = os.WriteFile(path, tomlBytes, 0644) if err != nil { return err @@ -32,3 +38,7 @@ func loadConfigFromTOML(path string) (Avail, error) { return config, nil } + +func GetCfgFilePath(rollerHome string) string { + return filepath.Join(rollerHome, consts.ConfigDirName.DALightNode, ConfigFileName) +} diff --git a/utils/filesystem.go b/utils/filesystem.go new file mode 100644 index 00000000..c9e8a804 --- /dev/null +++ b/utils/filesystem.go @@ -0,0 +1,51 @@ +package utils + +import ( + "fmt" + "io" + "os" + "path/filepath" +) + +func DirNotEmpty(path string) (bool, error) { + info, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + return false, err + } + + if !info.IsDir() { + return false, fmt.Errorf("%s is not a directory", path) + } + + files, err := os.ReadDir(path) + return len(files) > 0, err +} + +func MoveFile(src, dst string) error { + srcFile, err := os.Open(src) + if err != nil { + return fmt.Errorf("failed to open source file: %w", err) + } + defer func() { _ = srcFile.Close() }() + err = os.MkdirAll(filepath.Dir(dst), 0755) + if err != nil { + return fmt.Errorf("failed to create parent directories: %w", err) + } + dstFile, err := os.Create(dst) + if err != nil { + return fmt.Errorf("failed to create destination file: %w", err) + } + defer func() { _ = dstFile.Close() }() + _, err = io.Copy(dstFile, srcFile) + if err != nil { + return fmt.Errorf("failed to copy file: %w", err) + } + err = os.Remove(src) + if err != nil { + return fmt.Errorf("failed to delete source file: %w", err) + } + return nil +}