Skip to content

Commit 57653f8

Browse files
authored
feat: create-validator now takes a json file as arg (#14864)
1 parent 77660ec commit 57653f8

File tree

7 files changed

+322
-180
lines changed

7 files changed

+322
-180
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
7979

8080
### Improvements
8181

82+
* (x/staking) [#14864](https://github.com/cosmos/cosmos-sdk/pull/14864) `create-validator` CLI command now takes a json file as an arg instead of having a bunch of required flags to it.
8283
* (cli) [#14659](https://github.com/cosmos/cosmos-sdk/pull/14659) Added ability to query blocks by either height/hash `simd q block --type=height|hash <height|hash>`.
8384
* (store) [#14410](https://github.com/cosmos/cosmos-sdk/pull/14410) `rootmulti.Store.loadVersion` has validation to check if all the module stores' height is correct, it will error if any module store has incorrect height.
8485
* (x/evidence) [#14757](https://github.com/cosmos/cosmos-sdk/pull/14757) Evidence messages do not need to implement a `.Type()` anymore.
@@ -263,6 +264,7 @@ extension interfaces. `module.Manager.Modules` is now of type `map[string]interf
263264

264265
### CLI Breaking Changes
265266

267+
* (x/staking) [#14864](https://github.com/cosmos/cosmos-sdk/pull/14864) `create-validator` CLI command now takes a json file as an arg instead of having a bunch of required flags to it.
266268
* (cli) [#14659](https://github.com/cosmos/cosmos-sdk/pull/14659) `simd q block <height>` is removed as it just output json. The new command allows either height/hash and is `simd q block --type=height|hash <height|hash>`.
267269
* (x/gov) [#14880](https://github.com/cosmos/cosmos-sdk/pull/14880) Remove `simd tx gov submit-legacy-proposal cancel-software-upgrade` and `software-upgrade` commands. These commands are now in the `x/upgrade` module and using gov v1. Use `tx upgrade software-upgrade` instead.
268270
* (grpc-web) [#14652](https://github.com/cosmos/cosmos-sdk/pull/14652) Remove `grpc-web.address` flag.

tests/e2e/staking/suite.go

+69-44
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"github.com/cosmos/cosmos-sdk/client/flags"
1717
"github.com/cosmos/cosmos-sdk/crypto/hd"
1818
"github.com/cosmos/cosmos-sdk/crypto/keyring"
19-
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
2019
"github.com/cosmos/cosmos-sdk/testutil"
2120
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
2221
"github.com/cosmos/cosmos-sdk/testutil/network"
@@ -97,11 +96,6 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
9796
require := s.Require()
9897
val := s.network.Validators[0]
9998

100-
consPrivKey := ed25519.GenPrivKey()
101-
consPubKeyBz, err := s.cfg.Codec.MarshalInterfaceJSON(consPrivKey.PubKey())
102-
require.NoError(err)
103-
require.NotNil(consPubKeyBz)
104-
10599
k, _, err := val.ClientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
106100
require.NoError(err)
107101

@@ -120,6 +114,71 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
120114
require.NoError(err)
121115
s.Require().NoError(s.network.WaitForNextBlock())
122116

117+
validJSON := fmt.Sprintf(`
118+
{
119+
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
120+
"amount": "%dstake",
121+
"moniker": "NewValidator",
122+
"commission-rate": "0.5",
123+
"commission-max-rate": "1.0",
124+
"commission-max-change-rate": "0.1",
125+
"min-self-delegation": "1"
126+
}`, 100)
127+
validJSONFile := testutil.WriteToNewTempFile(s.T(), validJSON)
128+
defer func() {
129+
if err := validJSONFile.Close(); err != nil {
130+
val.Ctx.Logger.Info("Error closing file: %s\n", err)
131+
}
132+
}()
133+
134+
noAmountJSON := `
135+
{
136+
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
137+
"moniker": "NewValidator",
138+
"commission-rate": "0.5",
139+
"commission-max-rate": "1.0",
140+
"commission-max-change-rate": "0.1",
141+
"min-self-delegation": "1"
142+
}`
143+
noAmountJSONFile := testutil.WriteToNewTempFile(s.T(), noAmountJSON)
144+
defer func() {
145+
if err := noAmountJSONFile.Close(); err != nil {
146+
val.Ctx.Logger.Info("Error closing file: %s\n", err)
147+
}
148+
}()
149+
150+
noPubKeyJSON := fmt.Sprintf(`
151+
{
152+
"amount": "%dstake",
153+
"moniker": "NewValidator",
154+
"commission-rate": "0.5",
155+
"commission-max-rate": "1.0",
156+
"commission-max-change-rate": "0.1",
157+
"min-self-delegation": "1"
158+
}`, 100)
159+
noPubKeyJSONFile := testutil.WriteToNewTempFile(s.T(), noPubKeyJSON)
160+
defer func() {
161+
if err := noPubKeyJSONFile.Close(); err != nil {
162+
val.Ctx.Logger.Info("Error closing file: %s\n", err)
163+
}
164+
}()
165+
166+
noMonikerJSON := fmt.Sprintf(`
167+
{
168+
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
169+
"amount": "%dstake",
170+
"commission-rate": "0.5",
171+
"commission-max-rate": "1.0",
172+
"commission-max-change-rate": "0.1",
173+
"min-self-delegation": "1"
174+
}`, 100)
175+
noMonikerJSONFile := testutil.WriteToNewTempFile(s.T(), noMonikerJSON)
176+
defer func() {
177+
if err := noMonikerJSONFile.Close(); err != nil {
178+
val.Ctx.Logger.Info("Error closing file: %s\n", err)
179+
}
180+
}()
181+
123182
testCases := []struct {
124183
name string
125184
args []string
@@ -130,14 +189,7 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
130189
{
131190
"invalid transaction (missing amount)",
132191
[]string{
133-
fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity),
134-
fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite),
135-
fmt.Sprintf("--%[email protected]", cli.FlagSecurityContact),
136-
fmt.Sprintf("--%s='Hey, I am a new validator. Please delegate!'", cli.FlagDetails),
137-
fmt.Sprintf("--%s=0.5", cli.FlagCommissionRate),
138-
fmt.Sprintf("--%s=1.0", cli.FlagCommissionMaxRate),
139-
fmt.Sprintf("--%s=0.1", cli.FlagCommissionMaxChangeRate),
140-
fmt.Sprintf("--%s=1", cli.FlagMinSelfDelegation),
192+
noAmountJSONFile.Name(),
141193
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr),
142194
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
143195
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
@@ -148,15 +200,7 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
148200
{
149201
"invalid transaction (missing pubkey)",
150202
[]string{
151-
fmt.Sprintf("--%s=%dstake", cli.FlagAmount, 100),
152-
fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity),
153-
fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite),
154-
fmt.Sprintf("--%[email protected]", cli.FlagSecurityContact),
155-
fmt.Sprintf("--%s='Hey, I am a new validator. Please delegate!'", cli.FlagDetails),
156-
fmt.Sprintf("--%s=0.5", cli.FlagCommissionRate),
157-
fmt.Sprintf("--%s=1.0", cli.FlagCommissionMaxRate),
158-
fmt.Sprintf("--%s=0.1", cli.FlagCommissionMaxChangeRate),
159-
fmt.Sprintf("--%s=1", cli.FlagMinSelfDelegation),
203+
noPubKeyJSONFile.Name(),
160204
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr),
161205
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
162206
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
@@ -167,16 +211,7 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
167211
{
168212
"invalid transaction (missing moniker)",
169213
[]string{
170-
fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKeyBz),
171-
fmt.Sprintf("--%s=%dstake", cli.FlagAmount, 100),
172-
fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity),
173-
fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite),
174-
fmt.Sprintf("--%[email protected]", cli.FlagSecurityContact),
175-
fmt.Sprintf("--%s='Hey, I am a new validator. Please delegate!'", cli.FlagDetails),
176-
fmt.Sprintf("--%s=0.5", cli.FlagCommissionRate),
177-
fmt.Sprintf("--%s=1.0", cli.FlagCommissionMaxRate),
178-
fmt.Sprintf("--%s=0.1", cli.FlagCommissionMaxChangeRate),
179-
fmt.Sprintf("--%s=1", cli.FlagMinSelfDelegation),
214+
noMonikerJSONFile.Name(),
180215
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr),
181216
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
182217
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
@@ -187,17 +222,7 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
187222
{
188223
"valid transaction",
189224
[]string{
190-
fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKeyBz),
191-
fmt.Sprintf("--%s=%dstake", cli.FlagAmount, 100),
192-
fmt.Sprintf("--%s=NewValidator", cli.FlagMoniker),
193-
fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity),
194-
fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite),
195-
fmt.Sprintf("--%[email protected]", cli.FlagSecurityContact),
196-
fmt.Sprintf("--%s='Hey, I am a new validator. Please delegate!'", cli.FlagDetails),
197-
fmt.Sprintf("--%s=0.5", cli.FlagCommissionRate),
198-
fmt.Sprintf("--%s=1.0", cli.FlagCommissionMaxRate),
199-
fmt.Sprintf("--%s=0.1", cli.FlagCommissionMaxChangeRate),
200-
fmt.Sprintf("--%s=1", cli.FlagMinSelfDelegation),
225+
validJSONFile.Name(),
201226
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr),
202227
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
203228
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),

x/staking/README.md

+21-11
Original file line numberDiff line numberDiff line change
@@ -1565,29 +1565,39 @@ The command `create-validator` allows users to create new validator initialized
15651565
Usage:
15661566

15671567
```bash
1568-
simd tx staking create-validator [flags]
1568+
simd tx staking create-validator [path/to/validator.json] [flags]
15691569
```
15701570

15711571
Example:
15721572

15731573
```bash
1574-
simd tx staking create-validator \
1575-
--amount=1000000stake \
1576-
--pubkey=$(simd tendermint show-validator) \
1577-
--moniker="my-moniker" \
1578-
--website="https://myweb.site" \
1579-
--details="description of your validator" \
1574+
simd tx staking create-validator /path/to/validator.json \
15801575
--chain-id="name_of_chain_id" \
1581-
--commission-rate="0.10" \
1582-
--commission-max-rate="0.20" \
1583-
--commission-max-change-rate="0.01" \
1584-
--min-self-delegation="1" \
15851576
--gas="auto" \
15861577
--gas-adjustment="1.2" \
15871578
--gas-prices="0.025stake" \
15881579
--from=mykey
15891580
```
15901581

1582+
where `validator.json` contains:
1583+
1584+
```json
1585+
{
1586+
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"BnbwFpeONLqvWqJb3qaUbL5aoIcW3fSuAp9nT3z5f20="},
1587+
"amount": "1000000stake",
1588+
"moniker": "my-moniker",
1589+
"website": "https://myweb.site",
1590+
"security": "[email protected]",
1591+
"details": "description of your validator",
1592+
"commission-rate": "0.10",
1593+
"commission-max-rate": "0.20",
1594+
"commission-max-change-rate": "0.01",
1595+
"min-self-delegation": "1"
1596+
}
1597+
```
1598+
1599+
and pubkey can be obtained by using `simd tendermint show-validator` command.
1600+
15911601
##### delegate
15921602

15931603
The command `delegate` allows users to delegate liquid tokens to a validator.

x/staking/client/cli/flags.go

-12
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,3 @@ func flagSetCommissionUpdate() *flag.FlagSet {
100100

101101
return fs
102102
}
103-
104-
func flagSetDescriptionCreate() *flag.FlagSet {
105-
fs := flag.NewFlagSet("", flag.ContinueOnError)
106-
107-
fs.String(FlagMoniker, "", "The validator's name")
108-
fs.String(FlagIdentity, "", "The optional identity signature (ex. UPort or Keybase)")
109-
fs.String(FlagWebsite, "", "The validator's (optional) website")
110-
fs.String(FlagSecurityContact, "", "The validator's (optional) security contact email")
111-
fs.String(FlagDetails, "", "The validator's (optional) details")
112-
113-
return fs
114-
}

x/staking/client/cli/tx.go

+38-56
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,46 @@ func NewTxCmd() *cobra.Command {
5858
// NewCreateValidatorCmd returns a CLI command handler for creating a MsgCreateValidator transaction.
5959
func NewCreateValidatorCmd() *cobra.Command {
6060
cmd := &cobra.Command{
61-
Use: "create-validator",
61+
Use: "create-validator [path/to/validator.json]",
6262
Short: "create new validator initialized with a self-delegation to it",
63+
Args: cobra.ExactArgs(1),
64+
Long: `Create a new validator initialized with a self-delegation by submitting a JSON file with the new validator details.`,
65+
Example: strings.TrimSpace(
66+
fmt.Sprintf(`
67+
$ %s tx staking create-validator path/to/validator.json --from keyname
68+
69+
Where validator.json contains:
70+
71+
{
72+
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
73+
"amount": "1000000stake",
74+
"moniker": "myvalidator",
75+
"identity": "optional identity signature (ex. UPort or Keybase)",
76+
"website": "validator's (optional) website",
77+
"security": "validator's (optional) security contact email",
78+
"details": "validator's (optional) details",
79+
"commission-rate": "0.1",
80+
"commission-max-rate": "0.2",
81+
"commission-max-change-rate": "0.01",
82+
"min-self-delegation": "1"
83+
}
84+
85+
where we can get the pubkey using "%s tendermint show-validator"
86+
`, version.AppName, version.AppName)),
6387
RunE: func(cmd *cobra.Command, args []string) error {
6488
clientCtx, err := client.GetClientTxContext(cmd)
6589
if err != nil {
6690
return err
6791
}
6892

93+
validator, err := parseAndValidateValidatorJSON(clientCtx.Codec, args[0])
94+
if err != nil {
95+
return err
96+
}
97+
6998
txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).
7099
WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)
71-
txf, msg, err := newBuildCreateValidatorMsg(clientCtx, txf, cmd.Flags())
100+
txf, msg, err := newBuildCreateValidatorMsg(clientCtx, txf, cmd.Flags(), validator)
72101
if err != nil {
73102
return err
74103
}
@@ -77,20 +106,11 @@ func NewCreateValidatorCmd() *cobra.Command {
77106
},
78107
}
79108

80-
cmd.Flags().AddFlagSet(FlagSetPublicKey())
81-
cmd.Flags().AddFlagSet(FlagSetAmount())
82-
cmd.Flags().AddFlagSet(flagSetDescriptionCreate())
83-
cmd.Flags().AddFlagSet(FlagSetCommissionCreate())
84-
cmd.Flags().AddFlagSet(FlagSetMinSelfDelegation())
85-
86109
cmd.Flags().String(FlagIP, "", fmt.Sprintf("The node's public IP. It takes effect only when used in combination with --%s", flags.FlagGenerateOnly))
87110
cmd.Flags().String(FlagNodeID, "", "The node's ID")
88111
flags.AddTxFlagsToCmd(cmd)
89112

90113
_ = cmd.MarkFlagRequired(flags.FlagFrom)
91-
_ = cmd.MarkFlagRequired(FlagAmount)
92-
_ = cmd.MarkFlagRequired(FlagPubKey)
93-
_ = cmd.MarkFlagRequired(FlagMoniker)
94114

95115
return cmd
96116
}
@@ -339,57 +359,19 @@ $ %s tx staking cancel-unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake
339359
return cmd
340360
}
341361

342-
func newBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet) (tx.Factory, *types.MsgCreateValidator, error) {
343-
fAmount, _ := fs.GetString(FlagAmount)
344-
amount, err := sdk.ParseCoinNormalized(fAmount)
345-
if err != nil {
346-
return txf, nil, err
347-
}
348-
362+
func newBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet, val validator) (tx.Factory, *types.MsgCreateValidator, error) {
349363
valAddr := clientCtx.GetFromAddress()
350-
pkStr, err := fs.GetString(FlagPubKey)
351-
if err != nil {
352-
return txf, nil, err
353-
}
354364

355-
var pk cryptotypes.PubKey
356-
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(pkStr), &pk); err != nil {
357-
return txf, nil, err
358-
}
359-
360-
moniker, _ := fs.GetString(FlagMoniker)
361-
identity, _ := fs.GetString(FlagIdentity)
362-
website, _ := fs.GetString(FlagWebsite)
363-
security, _ := fs.GetString(FlagSecurityContact)
364-
details, _ := fs.GetString(FlagDetails)
365365
description := types.NewDescription(
366-
moniker,
367-
identity,
368-
website,
369-
security,
370-
details,
366+
val.Moniker,
367+
val.Identity,
368+
val.Website,
369+
val.Security,
370+
val.Details,
371371
)
372372

373-
// get the initial validator commission parameters
374-
rateStr, _ := fs.GetString(FlagCommissionRate)
375-
maxRateStr, _ := fs.GetString(FlagCommissionMaxRate)
376-
maxChangeRateStr, _ := fs.GetString(FlagCommissionMaxChangeRate)
377-
378-
commissionRates, err := buildCommissionRates(rateStr, maxRateStr, maxChangeRateStr)
379-
if err != nil {
380-
return txf, nil, err
381-
}
382-
383-
// get the initial validator min self delegation
384-
msbStr, _ := fs.GetString(FlagMinSelfDelegation)
385-
386-
minSelfDelegation, ok := sdk.NewIntFromString(msbStr)
387-
if !ok {
388-
return txf, nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "minimum self delegation must be a positive integer")
389-
}
390-
391373
msg, err := types.NewMsgCreateValidator(
392-
sdk.ValAddress(valAddr), pk, amount, description, commissionRates, minSelfDelegation,
374+
sdk.ValAddress(valAddr), val.PubKey, val.Amount, description, val.CommissionRates, val.MinSelfDelegation,
393375
)
394376
if err != nil {
395377
return txf, nil, err

0 commit comments

Comments
 (0)