diff --git a/cmd/common/flags.go b/cmd/common/flags.go index d7367cfa..c0f4ab1e 100644 --- a/cmd/common/flags.go +++ b/cmd/common/flags.go @@ -25,6 +25,9 @@ var ( // VerboseFlag specifies the command's verbosity. VerboseFlag *flag.FlagSet + + // DenominationFlags holds flags for --description, --symbol, and --num-decimals. + DenominationFlags *flag.FlagSet ) // FormatType specifies the type of format for output of commands. @@ -65,6 +68,10 @@ var ( answerYes bool outputFormat = FormatText verbose bool + + denominationDescription string + denominationSymbol string + denominationNumDecimals uint ) // GetHeight returns the user-selected block height. @@ -125,4 +132,9 @@ func init() { VerboseFlag = flag.NewFlagSet("", flag.ContinueOnError) VerboseFlag.BoolVarP(&verbose, "verbose", "v", false, "verbose") + + DenominationFlags = flag.NewFlagSet("", flag.ContinueOnError) + DenominationFlags.StringVar(&denominationDescription, "description", "", "description") + DenominationFlags.StringVar(&denominationSymbol, "symbol", "", "symbol") + DenominationFlags.UintVar(&denominationNumDecimals, "num-decimals", 0, "number of decimals") } diff --git a/cmd/common/prompts.go b/cmd/common/prompts.go index 544bc13f..377baac6 100644 --- a/cmd/common/prompts.go +++ b/cmd/common/prompts.go @@ -53,6 +53,61 @@ func Confirm(msg, abortMsg string) { } } +// DenominationDetails holds the editable description/symbol/decimal-places fields used by the +// network add, add-local, and paratime add commands. +type DenominationDetails struct { + Description string + Symbol string + Decimals uint8 +} + +// AskDenominationDetails prompts for description, symbol and num-decimals unless -y given. +func AskDenominationDetails(d *DenominationDetails) { + if denominationDescription != "" { + d.Description = denominationDescription + } + if denominationSymbol != "" { + d.Symbol = denominationSymbol + } + if denominationNumDecimals != 0 { + d.Decimals = uint8(denominationNumDecimals) //nolint: gosec + } + + if GetAnswerYes() { + return + } + + questions := []*survey.Question{ + { + Name: "description", + Prompt: &survey.Input{Message: "Description:", Default: d.Description}, + }, + { + Name: "symbol", + Prompt: &survey.Input{Message: "Denomination symbol:", Default: d.Symbol}, + }, + { + Name: "decimals", + Prompt: &survey.Input{ + Message: "Denomination decimal places:", + Default: fmt.Sprintf("%d", d.Decimals), + }, + Validate: survey.Required, + }, + } + answers := struct { + Description string + Symbol string + Decimals uint8 + }{} + err := AskMulti(questions, &answers) + cobra.CheckErr(err) + + d.Description = answers.Description + d.Symbol = answers.Symbol + d.Decimals = answers.Decimals +} + // AskNewPassphrase asks the user to create a new passphrase. func AskNewPassphrase() string { var answers struct { diff --git a/cmd/network/add.go b/cmd/network/add.go index 2aa16931..0fe52d22 100644 --- a/cmd/network/add.go +++ b/cmd/network/add.go @@ -10,6 +10,7 @@ import ( "github.com/oasisprotocol/oasis-sdk/client-sdk/go/config" "github.com/oasisprotocol/oasis-sdk/client-sdk/go/connection" + "github.com/oasisprotocol/cli/cmd/common" cliConfig "github.com/oasisprotocol/cli/config" ) @@ -61,7 +62,7 @@ var addCmd = &cobra.Command{ cobra.CheckErr(net.Validate()) - // Ask user for some additional parameters. + // Let the user change detected parameters, if needed. networkDetailsFromSurvey(&net) err := cfg.Networks.Add(name, &net) @@ -71,3 +72,8 @@ var addCmd = &cobra.Command{ cobra.CheckErr(err) }, } + +func init() { + addCmd.Flags().AddFlagSet(common.AnswerYesFlag) + addCmd.Flags().AddFlagSet(common.DenominationFlags) +} diff --git a/cmd/network/add_local.go b/cmd/network/add_local.go index ff5ae930..97dfd8d8 100644 --- a/cmd/network/add_local.go +++ b/cmd/network/add_local.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/spf13/cobra" - flag "github.com/spf13/pflag" cmnGrpc "github.com/oasisprotocol/oasis-core/go/common/grpc" "github.com/oasisprotocol/oasis-sdk/client-sdk/go/config" @@ -18,34 +17,28 @@ import ( cliConfig "github.com/oasisprotocol/cli/config" ) -var ( - symbol string - numDecimals uint - description string - - addLocalCmd = &cobra.Command{ - Use: "add-local ", - Short: "Add a new local network", - Args: cobra.ExactArgs(2), - Run: func(_ *cobra.Command, args []string) { - name, rpc := args[0], args[1] - - // Validate initial network configuration early. - cobra.CheckErr(config.ValidateIdentifier(name)) - - // Check if a local file name was given without protocol. - if !strings.HasPrefix(rpc, "unix:") { - if info, err := os.Stat(rpc); err == nil { - if !info.IsDir() { - rpc = "unix:" + rpc - } +var addLocalCmd = &cobra.Command{ + Use: "add-local ", + Short: "Add a new local network", + Args: cobra.ExactArgs(2), + Run: func(_ *cobra.Command, args []string) { + name, rpc := args[0], args[1] + + // Validate initial network configuration early. + cobra.CheckErr(config.ValidateIdentifier(name)) + + // Check if a local file name was given without protocol. + if !strings.HasPrefix(rpc, "unix:") { + if info, err := os.Stat(rpc); err == nil { + if !info.IsDir() { + rpc = "unix:" + rpc } } + } - AddLocalNetwork(name, rpc) - }, - } -) + AddLocalNetwork(name, rpc) + }, +} func AddLocalNetwork(name string, rpc string) { cfg := cliConfig.Global() @@ -75,40 +68,19 @@ func AddLocalNetwork(name string, rpc string) { net.ChainContext = chainContext cobra.CheckErr(net.Validate()) - // With a very high probability, the user is going to be - // adding a local endpoint for an existing network, so try - // to clone config details from any of the hardcoded - // defaults. - var clonedDefault bool + // Try to clone config details from any of the hardcoded defaults. for _, defaultNet := range config.DefaultNetworks.All { if defaultNet.ChainContext != chainContext { continue } - // Yep. net.Denomination = defaultNet.Denomination net.ParaTimes = defaultNet.ParaTimes - clonedDefault = true break } - if symbol != "" { - net.Denomination.Symbol = symbol - } - - if numDecimals != 0 { - net.Denomination.Decimals = uint8(numDecimals) //nolint: gosec - } - - if description != "" { - net.Description = description - } - - // If we failed to crib details from a hardcoded config, - // and user did not set -y flag ask the user. - if !clonedDefault && !common.GetAnswerYes() { - networkDetailsFromSurvey(&net) - } + // Let the user change detected parameters, if needed. + networkDetailsFromSurvey(&net) err = cfg.Networks.Add(name, &net) cobra.CheckErr(err) @@ -149,16 +121,5 @@ func extractAbsPath(rpc string) (string, error) { func init() { addLocalCmd.Flags().AddFlagSet(common.AnswerYesFlag) - - symbolFlag := flag.NewFlagSet("", flag.ContinueOnError) - symbolFlag.StringVar(&symbol, "symbol", "", "network's symbol") - addLocalCmd.Flags().AddFlagSet(symbolFlag) - - numDecimalsFlag := flag.NewFlagSet("", flag.ContinueOnError) - numDecimalsFlag.UintVar(&numDecimals, "num-decimals", 0, "network's number of decimals") - addLocalCmd.Flags().AddFlagSet(numDecimalsFlag) - - descriptionFlag := flag.NewFlagSet("", flag.ContinueOnError) - descriptionFlag.StringVar(&description, "description", "", "network's description") - addLocalCmd.Flags().AddFlagSet(descriptionFlag) + addLocalCmd.Flags().AddFlagSet(common.DenominationFlags) } diff --git a/cmd/network/network.go b/cmd/network/network.go index bd14f612..9f8099fe 100644 --- a/cmd/network/network.go +++ b/cmd/network/network.go @@ -1,7 +1,6 @@ package network import ( - "github.com/AlecAivazis/survey/v2" "github.com/spf13/cobra" "github.com/oasisprotocol/oasis-sdk/client-sdk/go/config" @@ -18,36 +17,22 @@ var Cmd = &cobra.Command{ } func networkDetailsFromSurvey(net *config.Network) { - // Ask user for some additional parameters. - questions := []*survey.Question{ - { - Name: "description", - Prompt: &survey.Input{Message: "Description:"}, - }, - { - Name: "symbol", - Prompt: &survey.Input{Message: "Denomination symbol:"}, - }, - { - Name: "decimals", - Prompt: &survey.Input{ - Message: "Denomination decimal places:", - Default: "9", - }, - Validate: survey.Required, - }, + // 9 is the default used for new networks when nothing better (an existing value cloned from a + // hardcoded default network, or a --num-decimals flag) is available. + decimals := net.Denomination.Decimals + if decimals == 0 { + decimals = 9 } - answers := struct { - Description string - Symbol string - Decimals uint8 - }{} - err := common.AskMulti(questions, &answers) - cobra.CheckErr(err) + details := common.DenominationDetails{ + Description: net.Description, + Symbol: net.Denomination.Symbol, + Decimals: decimals, + } + common.AskDenominationDetails(&details) - net.Description = answers.Description - net.Denomination.Symbol = answers.Symbol - net.Denomination.Decimals = answers.Decimals + net.Description = details.Description + net.Denomination.Symbol = details.Symbol + net.Denomination.Decimals = details.Decimals } func init() { diff --git a/cmd/paratime/add.go b/cmd/paratime/add.go index a86a48aa..474c371d 100644 --- a/cmd/paratime/add.go +++ b/cmd/paratime/add.go @@ -3,9 +3,7 @@ package paratime import ( "fmt" - "github.com/AlecAivazis/survey/v2" "github.com/spf13/cobra" - flag "github.com/spf13/pflag" "github.com/oasisprotocol/oasis-sdk/client-sdk/go/config" @@ -13,114 +11,52 @@ import ( cliConfig "github.com/oasisprotocol/cli/config" ) -var ( - symbol string - numDecimals uint - description string - - addCmd = &cobra.Command{ - Use: "add ", - Short: "Add a new ParaTime", - Args: cobra.ExactArgs(3), - ValidArgsFunction: common.NetworksAt(0), // at position 1. - Run: func(_ *cobra.Command, args []string) { - cfg := cliConfig.Global() - network, name, id := args[0], args[1], args[2] - - net, exists := cfg.Networks.All[network] - if !exists { - cobra.CheckErr(fmt.Errorf("network '%s' does not exist", network)) - } - - pt := config.ParaTime{ - ID: id, - } - // Validate initial paratime configuration early. - cobra.CheckErr(config.ValidateIdentifier(name)) - cobra.CheckErr(pt.Validate()) - - paratimeInfo := struct { - Description string - Symbol string - Decimals uint8 - }{ - Symbol: net.Denomination.Symbol, - Decimals: net.Denomination.Decimals, - } - - if symbol != "" { - paratimeInfo.Symbol = symbol - } - - if numDecimals != 0 { - paratimeInfo.Decimals = uint8(numDecimals) - } - - if description != "" { - paratimeInfo.Description = description - } - - if !common.GetAnswerYes() { - // Ask user for some additional parameters. - questions := []*survey.Question{ - { - Name: "description", - Prompt: &survey.Input{ - Message: "Description:", - Default: paratimeInfo.Description, - }, - }, - { - Name: "symbol", - Prompt: &survey.Input{ - Message: "Denomination symbol:", - Default: paratimeInfo.Symbol, - }, - }, - { - Name: "decimals", - Prompt: &survey.Input{ - Message: "Denomination decimal places:", - Default: fmt.Sprintf("%d", paratimeInfo.Decimals), - }, - Validate: survey.Required, - }, - } - - err := common.AskMulti(questions, ¶timeInfo) - cobra.CheckErr(err) - } - - pt.Description = paratimeInfo.Description - pt.Denominations = map[string]*config.DenominationInfo{ - config.NativeDenominationKey: { - Symbol: paratimeInfo.Symbol, - Decimals: paratimeInfo.Decimals, - }, - } - pt.ConsensusDenomination = config.NativeDenominationKey // TODO: Make this configurable. - - err := net.ParaTimes.Add(name, &pt) - cobra.CheckErr(err) - - err = cfg.Save() - cobra.CheckErr(err) - }, - } -) +var addCmd = &cobra.Command{ + Use: "add ", + Short: "Add a new ParaTime", + Args: cobra.ExactArgs(3), + ValidArgsFunction: common.NetworksAt(0), // at position 1. + Run: func(_ *cobra.Command, args []string) { + cfg := cliConfig.Global() + network, name, id := args[0], args[1], args[2] + + net, exists := cfg.Networks.All[network] + if !exists { + cobra.CheckErr(fmt.Errorf("network '%s' does not exist", network)) + } + + pt := config.ParaTime{ + ID: id, + } + // Validate initial paratime configuration early. + cobra.CheckErr(config.ValidateIdentifier(name)) + cobra.CheckErr(pt.Validate()) + + // Inherit the network's denomination as the default, then ask for the rest. + details := common.DenominationDetails{ + Symbol: net.Denomination.Symbol, + Decimals: net.Denomination.Decimals, + } + common.AskDenominationDetails(&details) + + pt.Description = details.Description + pt.Denominations = map[string]*config.DenominationInfo{ + config.NativeDenominationKey: { + Symbol: details.Symbol, + Decimals: details.Decimals, + }, + } + pt.ConsensusDenomination = config.NativeDenominationKey // TODO: Make this configurable. + + err := net.ParaTimes.Add(name, &pt) + cobra.CheckErr(err) + + err = cfg.Save() + cobra.CheckErr(err) + }, +} func init() { addCmd.Flags().AddFlagSet(common.AnswerYesFlag) - - symbolFlag := flag.NewFlagSet("", flag.ContinueOnError) - symbolFlag.StringVar(&symbol, "symbol", "", "paratime's symbol") - addCmd.Flags().AddFlagSet(symbolFlag) - - numDecimalsFlag := flag.NewFlagSet("", flag.ContinueOnError) - numDecimalsFlag.UintVar(&numDecimals, "num-decimals", 0, "paratime's number of decimals") - addCmd.Flags().AddFlagSet(numDecimalsFlag) - - descriptionFlag := flag.NewFlagSet("", flag.ContinueOnError) - descriptionFlag.StringVar(&description, "description", "", "paratime's description") - addCmd.Flags().AddFlagSet(descriptionFlag) + addCmd.Flags().AddFlagSet(common.DenominationFlags) } diff --git a/examples/paratime/00-list.out b/examples/paratime/00-list.out index c277146d..093d7db9 100644 --- a/examples/paratime/00-list.out +++ b/examples/paratime/00-list.out @@ -1,11 +1,13 @@ -NETWORK PARATIME ID DENOMINATIONS -mainnet cipher 000000000000000000000000000000000000000000000000e199119c992377cb ROSE[9] (*) -mainnet emerald 000000000000000000000000000000000000000000000000e2eaa99fc008f87f ROSE[18] (*) -mainnet sapphire (*) 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) -testnet cipher 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) -testnet emerald 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) -testnet pontusx_dev 0000000000000000000000000000000000000000000000004febe52eb412b421 EURAU[18] (*) - TEST[18] -testnet pontusx_test 00000000000000000000000000000000000000000000000004a6f9071c007069 EURAU[18] (*) - TEST[18] -testnet sapphire (*) 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) +NETWORK PARATIME ID DENOMINATIONS +localnet emerald 8000000000000000000000000000000000000000000000000000000000000000 TEST[18] (*) +localnet sapphire (*) 8000000000000000000000000000000000000000000000000000000000000000 TEST[18] (*) +mainnet cipher 000000000000000000000000000000000000000000000000e199119c992377cb ROSE[9] (*) +mainnet emerald 000000000000000000000000000000000000000000000000e2eaa99fc008f87f ROSE[18] (*) +mainnet sapphire (*) 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) +testnet cipher 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) +testnet emerald 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) +testnet pontusx_dev 0000000000000000000000000000000000000000000000004febe52eb412b421 EURAU[18] (*) + TEST[18] +testnet pontusx_test 00000000000000000000000000000000000000000000000004a6f9071c007069 EURAU[18] (*) + TEST[18] +testnet sapphire (*) 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) diff --git a/examples/paratime/02-list.out b/examples/paratime/02-list.out index 90aeb5a8..3b9213a9 100644 --- a/examples/paratime/02-list.out +++ b/examples/paratime/02-list.out @@ -1,11 +1,13 @@ -NETWORK PARATIME ID DENOMINATIONS -mainnet cipher 000000000000000000000000000000000000000000000000e199119c992377cb ROSE[9] (*) -mainnet emerald 000000000000000000000000000000000000000000000000e2eaa99fc008f87f ROSE[18] (*) -mainnet sapphire (*) 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) -testnet cipher (*) 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) -testnet emerald 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) -testnet pontusx_dev 0000000000000000000000000000000000000000000000004febe52eb412b421 EURAU[18] (*) - TEST[18] -testnet pontusx_test 00000000000000000000000000000000000000000000000004a6f9071c007069 EURAU[18] (*) - TEST[18] -testnet sapphire 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) +NETWORK PARATIME ID DENOMINATIONS +localnet emerald 8000000000000000000000000000000000000000000000000000000000000000 TEST[18] (*) +localnet sapphire (*) 8000000000000000000000000000000000000000000000000000000000000000 TEST[18] (*) +mainnet cipher 000000000000000000000000000000000000000000000000e199119c992377cb ROSE[9] (*) +mainnet emerald 000000000000000000000000000000000000000000000000e2eaa99fc008f87f ROSE[18] (*) +mainnet sapphire (*) 000000000000000000000000000000000000000000000000f80306c9858e7279 ROSE[18] (*) +testnet cipher (*) 0000000000000000000000000000000000000000000000000000000000000000 TEST[9] (*) +testnet emerald 00000000000000000000000000000000000000000000000072c8215e60d5bca7 TEST[18] (*) +testnet pontusx_dev 0000000000000000000000000000000000000000000000004febe52eb412b421 EURAU[18] (*) + TEST[18] +testnet pontusx_test 00000000000000000000000000000000000000000000000004a6f9071c007069 EURAU[18] (*) + TEST[18] +testnet sapphire 000000000000000000000000000000000000000000000000a6d1e3ebf60dff6c TEST[18] (*) diff --git a/go.mod b/go.mod index 68fd9b9c..5c82300e 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 github.com/oasisprotocol/metadata-registry-tools v0.0.0-20220406100644-7e9a2b991920 github.com/oasisprotocol/oasis-core/go v0.2602.0 - github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.16.1 + github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.17.0 github.com/olekukonko/tablewriter v1.1.2 github.com/opencontainers/image-spec v1.1.1 github.com/spf13/cobra v1.10.2 diff --git a/go.sum b/go.sum index 645d3f21..ee97f43b 100644 --- a/go.sum +++ b/go.sum @@ -438,8 +438,8 @@ github.com/oasisprotocol/metadata-registry-tools v0.0.0-20220406100644-7e9a2b991 github.com/oasisprotocol/metadata-registry-tools v0.0.0-20220406100644-7e9a2b991920/go.mod h1:MKr/giwakLyCCjSWh0W9Pbaf7rDD1K96Wr57OhNoUK0= github.com/oasisprotocol/oasis-core/go v0.2602.0 h1:j4gdbwHGsDvQDwEw9H/1dXlsDAcHv/th5fFxAW/b/qI= github.com/oasisprotocol/oasis-core/go v0.2602.0/go.mod h1:SqafK3p7fiLsOB5KaBDXGuCEH5W1GQgYZJXzbSkQapo= -github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.16.1 h1:nYd83QOnWavxAOiltVAsaOhVze+NLrYLlY2Ioll89io= -github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.16.1/go.mod h1:XWVBXiDxjr39P5Q1DdliPD80G6eduTaf83IZWefBau0= +github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.17.0 h1:AuLVIubVxmlAIjH5tBTvvdGLfdppmSwVa55MW/IKIds= +github.com/oasisprotocol/oasis-sdk/client-sdk/go v0.17.0/go.mod h1:KObCZNXFbt9A8rjgHKcd4Bs7S7hNUvwFKaxka9sOWC8= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc=