Skip to content

Commit

Permalink
feat: create-validator now takes a json file as arg (#14864)
Browse files Browse the repository at this point in the history
  • Loading branch information
likhita-809 committed Feb 22, 2023
1 parent 77660ec commit 57653f8
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 180 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

* (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.
* (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>`.
* (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.
* (x/evidence) [#14757](https://github.com/cosmos/cosmos-sdk/pull/14757) Evidence messages do not need to implement a `.Type()` anymore.
Expand Down Expand Up @@ -263,6 +264,7 @@ extension interfaces. `module.Manager.Modules` is now of type `map[string]interf

### CLI Breaking Changes

* (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.
* (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>`.
* (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.
* (grpc-web) [#14652](https://github.com/cosmos/cosmos-sdk/pull/14652) Remove `grpc-web.address` flag.
Expand Down
113 changes: 69 additions & 44 deletions tests/e2e/staking/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
Expand Down Expand Up @@ -97,11 +96,6 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
require := s.Require()
val := s.network.Validators[0]

consPrivKey := ed25519.GenPrivKey()
consPubKeyBz, err := s.cfg.Codec.MarshalInterfaceJSON(consPrivKey.PubKey())
require.NoError(err)
require.NotNil(consPubKeyBz)

k, _, err := val.ClientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(err)

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

validJSON := fmt.Sprintf(`
{
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
"amount": "%dstake",
"moniker": "NewValidator",
"commission-rate": "0.5",
"commission-max-rate": "1.0",
"commission-max-change-rate": "0.1",
"min-self-delegation": "1"
}`, 100)
validJSONFile := testutil.WriteToNewTempFile(s.T(), validJSON)
defer func() {
if err := validJSONFile.Close(); err != nil {
val.Ctx.Logger.Info("Error closing file: %s\n", err)
}
}()

noAmountJSON := `
{
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
"moniker": "NewValidator",
"commission-rate": "0.5",
"commission-max-rate": "1.0",
"commission-max-change-rate": "0.1",
"min-self-delegation": "1"
}`
noAmountJSONFile := testutil.WriteToNewTempFile(s.T(), noAmountJSON)
defer func() {
if err := noAmountJSONFile.Close(); err != nil {
val.Ctx.Logger.Info("Error closing file: %s\n", err)
}
}()

noPubKeyJSON := fmt.Sprintf(`
{
"amount": "%dstake",
"moniker": "NewValidator",
"commission-rate": "0.5",
"commission-max-rate": "1.0",
"commission-max-change-rate": "0.1",
"min-self-delegation": "1"
}`, 100)
noPubKeyJSONFile := testutil.WriteToNewTempFile(s.T(), noPubKeyJSON)
defer func() {
if err := noPubKeyJSONFile.Close(); err != nil {
val.Ctx.Logger.Info("Error closing file: %s\n", err)
}
}()

noMonikerJSON := fmt.Sprintf(`
{
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
"amount": "%dstake",
"commission-rate": "0.5",
"commission-max-rate": "1.0",
"commission-max-change-rate": "0.1",
"min-self-delegation": "1"
}`, 100)
noMonikerJSONFile := testutil.WriteToNewTempFile(s.T(), noMonikerJSON)
defer func() {
if err := noMonikerJSONFile.Close(); err != nil {
val.Ctx.Logger.Info("Error closing file: %s\n", err)
}
}()

testCases := []struct {
name string
args []string
Expand All @@ -130,14 +189,7 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
{
"invalid transaction (missing amount)",
[]string{
fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity),
fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite),
fmt.Sprintf("--%s=contact@newvalidator.io", cli.FlagSecurityContact),
fmt.Sprintf("--%s='Hey, I am a new validator. Please delegate!'", cli.FlagDetails),
fmt.Sprintf("--%s=0.5", cli.FlagCommissionRate),
fmt.Sprintf("--%s=1.0", cli.FlagCommissionMaxRate),
fmt.Sprintf("--%s=0.1", cli.FlagCommissionMaxChangeRate),
fmt.Sprintf("--%s=1", cli.FlagMinSelfDelegation),
noAmountJSONFile.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
Expand All @@ -148,15 +200,7 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
{
"invalid transaction (missing pubkey)",
[]string{
fmt.Sprintf("--%s=%dstake", cli.FlagAmount, 100),
fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity),
fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite),
fmt.Sprintf("--%s=contact@newvalidator.io", cli.FlagSecurityContact),
fmt.Sprintf("--%s='Hey, I am a new validator. Please delegate!'", cli.FlagDetails),
fmt.Sprintf("--%s=0.5", cli.FlagCommissionRate),
fmt.Sprintf("--%s=1.0", cli.FlagCommissionMaxRate),
fmt.Sprintf("--%s=0.1", cli.FlagCommissionMaxChangeRate),
fmt.Sprintf("--%s=1", cli.FlagMinSelfDelegation),
noPubKeyJSONFile.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
Expand All @@ -167,16 +211,7 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
{
"invalid transaction (missing moniker)",
[]string{
fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKeyBz),
fmt.Sprintf("--%s=%dstake", cli.FlagAmount, 100),
fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity),
fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite),
fmt.Sprintf("--%s=contact@newvalidator.io", cli.FlagSecurityContact),
fmt.Sprintf("--%s='Hey, I am a new validator. Please delegate!'", cli.FlagDetails),
fmt.Sprintf("--%s=0.5", cli.FlagCommissionRate),
fmt.Sprintf("--%s=1.0", cli.FlagCommissionMaxRate),
fmt.Sprintf("--%s=0.1", cli.FlagCommissionMaxChangeRate),
fmt.Sprintf("--%s=1", cli.FlagMinSelfDelegation),
noMonikerJSONFile.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
Expand All @@ -187,17 +222,7 @@ func (s *E2ETestSuite) TestNewCreateValidatorCmd() {
{
"valid transaction",
[]string{
fmt.Sprintf("--%s=%s", cli.FlagPubKey, consPubKeyBz),
fmt.Sprintf("--%s=%dstake", cli.FlagAmount, 100),
fmt.Sprintf("--%s=NewValidator", cli.FlagMoniker),
fmt.Sprintf("--%s=AFAF00C4", cli.FlagIdentity),
fmt.Sprintf("--%s=https://newvalidator.io", cli.FlagWebsite),
fmt.Sprintf("--%s=contact@newvalidator.io", cli.FlagSecurityContact),
fmt.Sprintf("--%s='Hey, I am a new validator. Please delegate!'", cli.FlagDetails),
fmt.Sprintf("--%s=0.5", cli.FlagCommissionRate),
fmt.Sprintf("--%s=1.0", cli.FlagCommissionMaxRate),
fmt.Sprintf("--%s=0.1", cli.FlagCommissionMaxChangeRate),
fmt.Sprintf("--%s=1", cli.FlagMinSelfDelegation),
validJSONFile.Name(),
fmt.Sprintf("--%s=%s", flags.FlagFrom, newAddr),
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
Expand Down
32 changes: 21 additions & 11 deletions x/staking/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1565,29 +1565,39 @@ The command `create-validator` allows users to create new validator initialized
Usage:

```bash
simd tx staking create-validator [flags]
simd tx staking create-validator [path/to/validator.json] [flags]
```

Example:

```bash
simd tx staking create-validator \
--amount=1000000stake \
--pubkey=$(simd tendermint show-validator) \
--moniker="my-moniker" \
--website="https://myweb.site" \
--details="description of your validator" \
simd tx staking create-validator /path/to/validator.json \
--chain-id="name_of_chain_id" \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1" \
--gas="auto" \
--gas-adjustment="1.2" \
--gas-prices="0.025stake" \
--from=mykey
```

where `validator.json` contains:

```json
{
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"BnbwFpeONLqvWqJb3qaUbL5aoIcW3fSuAp9nT3z5f20="},
"amount": "1000000stake",
"moniker": "my-moniker",
"website": "https://myweb.site",
"security": "security-contact@gmail.com",
"details": "description of your validator",
"commission-rate": "0.10",
"commission-max-rate": "0.20",
"commission-max-change-rate": "0.01",
"min-self-delegation": "1"
}
```

and pubkey can be obtained by using `simd tendermint show-validator` command.

##### delegate

The command `delegate` allows users to delegate liquid tokens to a validator.
Expand Down
12 changes: 0 additions & 12 deletions x/staking/client/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,3 @@ func flagSetCommissionUpdate() *flag.FlagSet {

return fs
}

func flagSetDescriptionCreate() *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)

fs.String(FlagMoniker, "", "The validator's name")
fs.String(FlagIdentity, "", "The optional identity signature (ex. UPort or Keybase)")
fs.String(FlagWebsite, "", "The validator's (optional) website")
fs.String(FlagSecurityContact, "", "The validator's (optional) security contact email")
fs.String(FlagDetails, "", "The validator's (optional) details")

return fs
}
94 changes: 38 additions & 56 deletions x/staking/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,46 @@ func NewTxCmd() *cobra.Command {
// NewCreateValidatorCmd returns a CLI command handler for creating a MsgCreateValidator transaction.
func NewCreateValidatorCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-validator",
Use: "create-validator [path/to/validator.json]",
Short: "create new validator initialized with a self-delegation to it",
Args: cobra.ExactArgs(1),
Long: `Create a new validator initialized with a self-delegation by submitting a JSON file with the new validator details.`,
Example: strings.TrimSpace(
fmt.Sprintf(`
$ %s tx staking create-validator path/to/validator.json --from keyname
Where validator.json contains:
{
"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
"amount": "1000000stake",
"moniker": "myvalidator",
"identity": "optional identity signature (ex. UPort or Keybase)",
"website": "validator's (optional) website",
"security": "validator's (optional) security contact email",
"details": "validator's (optional) details",
"commission-rate": "0.1",
"commission-max-rate": "0.2",
"commission-max-change-rate": "0.01",
"min-self-delegation": "1"
}
where we can get the pubkey using "%s tendermint show-validator"
`, version.AppName, version.AppName)),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

validator, err := parseAndValidateValidatorJSON(clientCtx.Codec, args[0])
if err != nil {
return err
}

txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).
WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)
txf, msg, err := newBuildCreateValidatorMsg(clientCtx, txf, cmd.Flags())
txf, msg, err := newBuildCreateValidatorMsg(clientCtx, txf, cmd.Flags(), validator)
if err != nil {
return err
}
Expand All @@ -77,20 +106,11 @@ func NewCreateValidatorCmd() *cobra.Command {
},
}

cmd.Flags().AddFlagSet(FlagSetPublicKey())
cmd.Flags().AddFlagSet(FlagSetAmount())
cmd.Flags().AddFlagSet(flagSetDescriptionCreate())
cmd.Flags().AddFlagSet(FlagSetCommissionCreate())
cmd.Flags().AddFlagSet(FlagSetMinSelfDelegation())

cmd.Flags().String(FlagIP, "", fmt.Sprintf("The node's public IP. It takes effect only when used in combination with --%s", flags.FlagGenerateOnly))
cmd.Flags().String(FlagNodeID, "", "The node's ID")
flags.AddTxFlagsToCmd(cmd)

_ = cmd.MarkFlagRequired(flags.FlagFrom)
_ = cmd.MarkFlagRequired(FlagAmount)
_ = cmd.MarkFlagRequired(FlagPubKey)
_ = cmd.MarkFlagRequired(FlagMoniker)

return cmd
}
Expand Down Expand Up @@ -339,57 +359,19 @@ $ %s tx staking cancel-unbond %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake
return cmd
}

func newBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet) (tx.Factory, *types.MsgCreateValidator, error) {
fAmount, _ := fs.GetString(FlagAmount)
amount, err := sdk.ParseCoinNormalized(fAmount)
if err != nil {
return txf, nil, err
}

func newBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet, val validator) (tx.Factory, *types.MsgCreateValidator, error) {
valAddr := clientCtx.GetFromAddress()
pkStr, err := fs.GetString(FlagPubKey)
if err != nil {
return txf, nil, err
}

var pk cryptotypes.PubKey
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(pkStr), &pk); err != nil {
return txf, nil, err
}

moniker, _ := fs.GetString(FlagMoniker)
identity, _ := fs.GetString(FlagIdentity)
website, _ := fs.GetString(FlagWebsite)
security, _ := fs.GetString(FlagSecurityContact)
details, _ := fs.GetString(FlagDetails)
description := types.NewDescription(
moniker,
identity,
website,
security,
details,
val.Moniker,
val.Identity,
val.Website,
val.Security,
val.Details,
)

// get the initial validator commission parameters
rateStr, _ := fs.GetString(FlagCommissionRate)
maxRateStr, _ := fs.GetString(FlagCommissionMaxRate)
maxChangeRateStr, _ := fs.GetString(FlagCommissionMaxChangeRate)

commissionRates, err := buildCommissionRates(rateStr, maxRateStr, maxChangeRateStr)
if err != nil {
return txf, nil, err
}

// get the initial validator min self delegation
msbStr, _ := fs.GetString(FlagMinSelfDelegation)

minSelfDelegation, ok := sdk.NewIntFromString(msbStr)
if !ok {
return txf, nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "minimum self delegation must be a positive integer")
}

msg, err := types.NewMsgCreateValidator(
sdk.ValAddress(valAddr), pk, amount, description, commissionRates, minSelfDelegation,
sdk.ValAddress(valAddr), val.PubKey, val.Amount, description, val.CommissionRates, val.MinSelfDelegation,
)
if err != nil {
return txf, nil, err
Expand Down
Loading

0 comments on commit 57653f8

Please sign in to comment.