From 77c298d8d39fd2692ac9fdea051aba984a17ebf2 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 14 Nov 2023 11:34:05 +0100 Subject: [PATCH] updates --- client/v2/go.mod | 3 - client/v2/internal/prompt/validation.go | 68 ++++++++++++++++++++ client/v2/internal/prompt/validation_test.go | 39 +++++++++++ x/auth/autocli.go | 8 ++- x/bank/autocli.go | 17 ++++- x/consensus/autocli.go | 11 +++- x/crisis/autocli.go | 11 +++- x/distribution/autocli.go | 10 ++- x/gov/autocli.go | 8 ++- x/gov/client/cli/prompt.go | 2 + x/mint/autocli.go | 11 +++- x/slashing/autocli.go | 8 ++- x/staking/autocli.go | 8 ++- 13 files changed, 181 insertions(+), 23 deletions(-) create mode 100644 client/v2/internal/prompt/validation.go create mode 100644 client/v2/internal/prompt/validation_test.go diff --git a/client/v2/go.mod b/client/v2/go.mod index 478e33d84211..319326a342ab 100644 --- a/client/v2/go.mod +++ b/client/v2/go.mod @@ -18,9 +18,6 @@ require ( google.golang.org/protobuf v1.31.0 gotest.tools/v3 v3.5.1 sigs.k8s.io/yaml v1.4.0 -) - -require ( github.com/chzyer/readline v1.5.1 // indirect github.com/manifoldco/promptui v0.9.0 // indirect ) diff --git a/client/v2/internal/prompt/validation.go b/client/v2/internal/prompt/validation.go new file mode 100644 index 000000000000..0d79347173db --- /dev/null +++ b/client/v2/internal/prompt/validation.go @@ -0,0 +1,68 @@ +package prompt + +import ( + "fmt" + "net/url" + "unicode" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ValidatePromptNotEmpty validates that the input is not empty. +func ValidatePromptNotEmpty(input string) error { + if input == "" { + return fmt.Errorf("input cannot be empty") + } + + return nil +} + +// ValidatePromptURL validates that the input is a valid URL. +func ValidatePromptURL(input string) error { + _, err := url.ParseRequestURI(input) + if err != nil { + return fmt.Errorf("invalid URL: %w", err) + } + + return nil +} + +// ValidatePromptAddress validates that the input is a valid Bech32 address. +func ValidatePromptAddress(input string) error { // TODO(@julienrbrt) remove and add prompts in AutoCLI + _, err := sdk.AccAddressFromBech32(input) + if err == nil { + return nil + } + + _, err = sdk.ValAddressFromBech32(input) + if err == nil { + return nil + } + + _, err = sdk.ConsAddressFromBech32(input) + if err == nil { + return nil + } + + return fmt.Errorf("invalid address: %w", err) +} + +// ValidatePromptYesNo validates that the input is valid sdk.COins +func ValidatePromptCoins(input string) error { + if _, err := sdk.ParseCoinsNormalized(input); err != nil { + return fmt.Errorf("invalid coins: %w", err) + } + + return nil +} + +// CamelCaseToString converts a camel case string to a string with spaces. +func CamelCaseToString(str string) string { + w := []rune(str) + for i := len(w) - 1; i > 1; i-- { + if unicode.IsUpper(w[i]) { + w = append(w[:i], append([]rune{' '}, w[i:]...)...) + } + } + return string(w) +} diff --git a/client/v2/internal/prompt/validation_test.go b/client/v2/internal/prompt/validation_test.go new file mode 100644 index 000000000000..dad507c05429 --- /dev/null +++ b/client/v2/internal/prompt/validation_test.go @@ -0,0 +1,39 @@ +package prompt_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "cosmossdk.io/client/v2/internal/prompt" +) + +func TestValidatePromptNotEmpty(t *testing.T) { + require := require.New(t) + + require.NoError(prompt.ValidatePromptNotEmpty("foo")) + require.ErrorContains(prompt.ValidatePromptNotEmpty(""), "input cannot be empty") +} + +func TestValidatePromptURL(t *testing.T) { + require := require.New(t) + + require.NoError(prompt.ValidatePromptURL("https://example.com")) + require.ErrorContains(prompt.ValidatePromptURL("foo"), "invalid URL") +} + +func TestValidatePromptAddress(t *testing.T) { + require := require.New(t) + + require.NoError(prompt.ValidatePromptAddress("cosmos1huydeevpz37sd9snkgul6070mstupukw00xkw9")) + require.NoError(prompt.ValidatePromptAddress("cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9u2lcnj0")) + require.NoError(prompt.ValidatePromptAddress("cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h")) + require.ErrorContains(prompt.ValidatePromptAddress("foo"), "invalid address") +} + +func TestValidatePromptCoins(t *testing.T) { + require := require.New(t) + + require.NoError(prompt.ValidatePromptCoins("100stake")) + require.ErrorContains(prompt.ValidatePromptCoins("foo"), "invalid coins") +} diff --git a/x/auth/autocli.go b/x/auth/autocli.go index 30f06fb5936f..298e9c45c274 100644 --- a/x/auth/autocli.go +++ b/x/auth/autocli.go @@ -80,8 +80,12 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { Service: authv1beta1.Msg_ServiceDesc.ServiceName, RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { - RpcMethod: "UpdateParams", - Skip: true, // skipped because authority gated + RpcMethod: "UpdateParams", + Use: "update-params-proposal [params]", + Short: "Submit a proposal to update auth module params", + Example: fmt.Sprintf(`%s tx auth update-params-proposal '{ params }'`, version.AppName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, + GovProposal: true, }, }, }, diff --git a/x/bank/autocli.go b/x/bank/autocli.go index 377ba96db207..03b87ec8bb3a 100644 --- a/x/bank/autocli.go +++ b/x/bank/autocli.go @@ -1,10 +1,13 @@ package bank import ( + "fmt" "strings" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" + + "github.com/cosmos/cosmos-sdk/version" ) // AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. @@ -109,13 +112,21 @@ Note: multiple coins can be send by space separated.`, { RpcMethod: "UpdateParams", Use: "update-params-proposal [params]", - Short: "Submit a parameter change proposal for the bank module", + Short: "Submit a proposal to update bank module params", + Example: fmt.Sprintf(`%s tx bank update-params-proposal '{ params }'`, version.AppName), PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, GovProposal: true, }, { - RpcMethod: "SetSendEnabled", - Skip: true, // skipped because authority gated + RpcMethod: "SetSendEnabled", + Use: "set-send-enabled-proposal [send_enabled]", + Short: "Submit a proposal to set/update/delete send enabled entries", + Example: fmt.Sprintf(`%s tx bank set-send-enabled-proposal '{"denom":"stake","enabled":true}'`, version.AppName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "send_enabled", Varargs: true}}, + FlagOptions: map[string]*autocliv1.FlagOptions{ + "use_default_for": {Name: "use-default-for", Usage: "Use default for the given denom (delete a send enabled entry)"}, + }, + GovProposal: true, }, }, }, diff --git a/x/consensus/autocli.go b/x/consensus/autocli.go index 5a2e00900cc4..65d48c912f95 100644 --- a/x/consensus/autocli.go +++ b/x/consensus/autocli.go @@ -1,10 +1,13 @@ package consensus import ( + "fmt" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" consensusv1 "cosmossdk.io/api/cosmos/consensus/v1" "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" + "github.com/cosmos/cosmos-sdk/version" ) // AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. @@ -27,8 +30,12 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { Service: consensusv1.Msg_ServiceDesc.ServiceName, RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { - RpcMethod: "UpdateParams", - Skip: true, // skipped because authority gated + RpcMethod: "UpdateParams", + Use: "update-params-proposal [params]", + Short: "Submit a proposal to update consensus module params", + Example: fmt.Sprintf(`%s tx consensus update-params-proposal '{ params }'`, version.AppName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, + GovProposal: true, }, }, }, diff --git a/x/crisis/autocli.go b/x/crisis/autocli.go index 92edd95d0cd8..cf241c730d07 100644 --- a/x/crisis/autocli.go +++ b/x/crisis/autocli.go @@ -1,8 +1,11 @@ package crisis import ( + "fmt" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" crisisv1beta1 "cosmossdk.io/api/cosmos/crisis/v1beta1" + "github.com/cosmos/cosmos-sdk/version" ) // AutoCLIOptions implements the autocli.HasAutoCLIConfig interface. @@ -21,8 +24,12 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, }, { - RpcMethod: "UpdateParams", - Skip: true, // Skipped because UpdateParams is authority gated + RpcMethod: "UpdateParams", + Use: "update-params-proposal [params]", + Short: "Submit a proposal to update crisis module params", + Example: fmt.Sprintf(`%s tx crisis update-params-proposal '{ params }'`, version.AppName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, + GovProposal: true, }, }, }, diff --git a/x/distribution/autocli.go b/x/distribution/autocli.go index b323975c389f..caa2948c4053 100644 --- a/x/distribution/autocli.go +++ b/x/distribution/autocli.go @@ -127,12 +127,16 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, }, { - RpcMethod: "UpdateParams", - Skip: true, // skipped because authority gated + RpcMethod: "UpdateParams", + Use: "update-params-proposal [params]", + Short: "Submit a proposal to update distribution module params", + Example: fmt.Sprintf(`%s tx distribution update-params-proposal '{ params }'`, version.AppName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, + GovProposal: true, }, { RpcMethod: "CommunityPoolSpend", - Skip: true, // skipped because authority gated + Skip: true, // skipped because deprecated in favor of protocolpool }, }, EnhanceCustomCommand: true, diff --git a/x/gov/autocli.go b/x/gov/autocli.go index 8bd6aa49a337..d843452abb09 100644 --- a/x/gov/autocli.go +++ b/x/gov/autocli.go @@ -131,8 +131,12 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { }, }, { - RpcMethod: "UpdateParams", - Skip: true, // skipped because authority gated + RpcMethod: "UpdateParams", + Use: "update-params-proposal [params]", + Short: "Submit a proposal to update gov module params", + Example: fmt.Sprintf(`%s tx gov update-params-proposal '{ params }'`, version.AppName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, + GovProposal: true, }, }, EnhanceCustomCommand: true, // We still have manual commands in gov that we want to keep diff --git a/x/gov/client/cli/prompt.go b/x/gov/client/cli/prompt.go index 81960fcf904e..b2fcca629ee2 100644 --- a/x/gov/client/cli/prompt.go +++ b/x/gov/client/cli/prompt.go @@ -58,6 +58,8 @@ var suggestedProposalTypes = []proposalType{ // Prompt prompts the user for all values of the given type. // data is the struct to be filled // namePrefix is the name to be displayed as "Enter " +// TODO: when bringing this in autocli, use proto message instead +// this will simplify the get address logic func Prompt[T any](data T, namePrefix string) (T, error) { v := reflect.ValueOf(&data).Elem() if v.Kind() == reflect.Interface { diff --git a/x/mint/autocli.go b/x/mint/autocli.go index 8ac35d04b6c8..627562ee2bed 100644 --- a/x/mint/autocli.go +++ b/x/mint/autocli.go @@ -1,8 +1,11 @@ package mint import ( + "fmt" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" mintv1beta1 "cosmossdk.io/api/cosmos/mint/v1beta1" + "github.com/cosmos/cosmos-sdk/version" ) func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { @@ -31,8 +34,12 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { Service: mintv1beta1.Msg_ServiceDesc.ServiceName, RpcCommandOptions: []*autocliv1.RpcCommandOptions{ { - RpcMethod: "UpdateParams", - Skip: true, // skipped because authority gated + RpcMethod: "UpdateParams", + Use: "update-params-proposal [params]", + Short: "Submit a proposal to update mint module params", + Example: fmt.Sprintf(`%s tx mint update-params-proposal '{ params }'`, version.AppName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, + GovProposal: true, }, }, }, diff --git a/x/slashing/autocli.go b/x/slashing/autocli.go index fede1143e72d..62e3d53bae2d 100644 --- a/x/slashing/autocli.go +++ b/x/slashing/autocli.go @@ -46,8 +46,12 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { Example: fmt.Sprintf("%s tx slashing unjail --from [validator]", version.AppName), }, { - RpcMethod: "UpdateParams", - Skip: true, // skipped because authority gated + RpcMethod: "UpdateParams", + Use: "update-params-proposal [params]", + Short: "Submit a proposal to update slashing module params", + Example: fmt.Sprintf(`%s tx slashing update-params-proposal '{ params }'`, version.AppName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, + GovProposal: true, }, }, }, diff --git a/x/staking/autocli.go b/x/staking/autocli.go index f708109fd5d4..9d6f60f1e281 100644 --- a/x/staking/autocli.go +++ b/x/staking/autocli.go @@ -174,8 +174,12 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions { PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "validator_address"}, {ProtoField: "amount"}, {ProtoField: "creation_height"}}, }, { - RpcMethod: "UpdateParams", - Skip: true, // skipped because authority gated + RpcMethod: "UpdateParams", + Use: "update-params-proposal [params]", + Short: "Submit a proposal to update staking module params", + Example: fmt.Sprintf(`%s tx staking update-params-proposal '{ params }'`, version.AppName), + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "params"}}, + GovProposal: true, }, }, EnhanceCustomCommand: true,