Skip to content

Commit 13d78de

Browse files
authored
fix: Add validation on create gentx (backport #11693) (#11698)
1 parent ffef0ba commit 13d78de

File tree

5 files changed

+104
-88
lines changed

5 files changed

+104
-88
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
3939

4040
### Improvements
4141

42+
* [\#11693](https://github.com/cosmos/cosmos-sdk/pull/11693) Add validation for gentx cmd.
4243
* [\#11686](https://github.com/cosmos/cosmos-sdk/pull/11686) Update the min required Golang version to `1.17`.
4344
* (x/auth/vesting) [\#11652](https://github.com/cosmos/cosmos-sdk/pull/11652) Add util functions for `Period(s)`
4445

types/coin.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -814,13 +814,13 @@ func ParseCoinNormalized(coinStr string) (coin Coin, err error) {
814814
return coin, nil
815815
}
816816

817-
// ParseCoinsNormalized will parse out a list of coins separated by commas, and normalize them by converting to smallest
818-
// unit. If the parsing is successuful, the provided coins will be sanitized by removing zero coins and sorting the coin
817+
// ParseCoinsNormalized will parse out a list of coins separated by commas, and normalize them by converting to the smallest
818+
// unit. If the parsing is successful, the provided coins will be sanitized by removing zero coins and sorting the coin
819819
// set. Lastly a validation of the coin set is executed. If the check passes, ParseCoinsNormalized will return the
820820
// sanitized coins.
821-
// Otherwise it will return an error.
821+
// Otherwise, it will return an error.
822822
// If an empty string is provided to ParseCoinsNormalized, it returns nil Coins.
823-
// ParseCoinsNormalized supports decimal coins as inputs, and truncate them to int after converted to smallest unit.
823+
// ParseCoinsNormalized supports decimal coins as inputs, and truncate them to int after converted to the smallest unit.
824824
// Expected format: "{amount0}{denomination},...,{amountN}{denominationN}"
825825
func ParseCoinsNormalized(coinStr string) (Coins, error) {
826826
coins, err := ParseDecCoins(coinStr)

x/genutil/client/cli/gentx.go

+4
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o
162162
w := bytes.NewBuffer([]byte{})
163163
clientCtx = clientCtx.WithOutput(w)
164164

165+
if err = msg.ValidateBasic(); err != nil {
166+
return err
167+
}
168+
165169
if err = authclient.PrintUnsignedStdTx(txBldr, clientCtx, []sdk.Msg{msg}); err != nil {
166170
return errors.Wrap(err, "failed to print unsigned std tx")
167171
}

x/genutil/client/testutil/suite.go

+93-82
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
package testutil
22

33
import (
4-
"context"
54
"fmt"
6-
"io/ioutil"
5+
"io"
76
"os"
87
"path/filepath"
98

109
"github.com/stretchr/testify/suite"
1110

12-
"github.com/cosmos/cosmos-sdk/client"
1311
"github.com/cosmos/cosmos-sdk/client/flags"
1412
"github.com/cosmos/cosmos-sdk/simapp"
15-
"github.com/cosmos/cosmos-sdk/testutil"
13+
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
1614
"github.com/cosmos/cosmos-sdk/testutil/network"
1715
sdk "github.com/cosmos/cosmos-sdk/types"
1816
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
@@ -48,84 +46,97 @@ func (s *IntegrationTestSuite) TearDownSuite() {
4846

4947
func (s *IntegrationTestSuite) TestGenTxCmd() {
5048
val := s.network.Validators[0]
51-
dir := s.T().TempDir()
52-
53-
cmd := cli.GenTxCmd(
54-
simapp.ModuleBasics,
55-
val.ClientCtx.TxConfig, banktypes.GenesisBalancesIterator{}, val.ClientCtx.HomeDir)
56-
57-
_, out := testutil.ApplyMockIO(cmd)
58-
clientCtx := val.ClientCtx.WithOutput(out)
59-
60-
ctx := context.Background()
61-
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
62-
49+
clientCtx := val.ClientCtx
6350
amount := sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(12))
64-
genTxFile := filepath.Join(dir, "myTx")
65-
cmd.SetArgs([]string{
66-
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
67-
fmt.Sprintf("--%s=%s", flags.FlagOutputDocument, genTxFile),
68-
val.Moniker,
69-
amount.String(),
70-
})
71-
72-
err := cmd.ExecuteContext(ctx)
73-
s.Require().NoError(err)
74-
75-
// validate generated transaction.
76-
open, err := os.Open(genTxFile)
77-
s.Require().NoError(err)
78-
79-
all, err := ioutil.ReadAll(open)
80-
s.Require().NoError(err)
81-
82-
tx, err := val.ClientCtx.TxConfig.TxJSONDecoder()(all)
83-
s.Require().NoError(err)
84-
85-
msgs := tx.GetMsgs()
86-
s.Require().Len(msgs, 1)
87-
88-
s.Require().Equal(sdk.MsgTypeURL(&types.MsgCreateValidator{}), sdk.MsgTypeURL(msgs[0]))
89-
s.Require().Equal([]sdk.AccAddress{val.Address}, msgs[0].GetSigners())
90-
s.Require().Equal(amount, msgs[0].(*types.MsgCreateValidator).Value)
91-
s.Require().NoError(tx.ValidateBasic())
92-
}
93-
94-
func (s *IntegrationTestSuite) TestGenTxCmdPubkey() {
95-
val := s.network.Validators[0]
96-
dir := s.T().TempDir()
97-
98-
cmd := cli.GenTxCmd(
99-
simapp.ModuleBasics,
100-
val.ClientCtx.TxConfig,
101-
banktypes.GenesisBalancesIterator{},
102-
val.ClientCtx.HomeDir,
103-
)
104-
105-
_, out := testutil.ApplyMockIO(cmd)
106-
clientCtx := val.ClientCtx.WithOutput(out)
10751

108-
ctx := context.Background()
109-
ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx)
110-
111-
amount := sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(12))
112-
genTxFile := filepath.Join(dir, "myTx")
113-
114-
cmd.SetArgs([]string{
115-
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
116-
fmt.Sprintf("--%s=%s", flags.FlagOutputDocument, genTxFile),
117-
fmt.Sprintf("--%s={\"key\":\"BOIkjkFruMpfOFC9oNPhiJGfmY2pHF/gwHdLDLnrnS0=\"}", stakingcli.FlagPubKey),
118-
val.Moniker,
119-
amount.String(),
120-
})
121-
s.Require().Error(cmd.ExecuteContext(ctx))
122-
123-
cmd.SetArgs([]string{
124-
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
125-
fmt.Sprintf("--%s=%s", flags.FlagOutputDocument, genTxFile),
126-
fmt.Sprintf("--%s={\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"BOIkjkFruMpfOFC9oNPhiJGfmY2pHF/gwHdLDLnrnS0=\"}", stakingcli.FlagPubKey),
127-
val.Moniker,
128-
amount.String(),
129-
})
130-
s.Require().NoError(cmd.ExecuteContext(ctx))
52+
tests := []struct {
53+
name string
54+
args []string
55+
expError bool
56+
}{
57+
{
58+
name: "invalid commission rate returns error",
59+
args: []string{
60+
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
61+
fmt.Sprintf("--%s=1", stakingcli.FlagCommissionRate),
62+
val.Moniker,
63+
amount.String(),
64+
},
65+
expError: true,
66+
},
67+
{
68+
name: "valid gentx",
69+
args: []string{
70+
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
71+
val.Moniker,
72+
amount.String(),
73+
},
74+
expError: false,
75+
},
76+
{
77+
name: "invalid pubkey",
78+
args: []string{
79+
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
80+
fmt.Sprintf("--%s={\"key\":\"BOIkjkFruMpfOFC9oNPhiJGfmY2pHF/gwHdLDLnrnS0=\"}", stakingcli.FlagPubKey),
81+
val.Moniker,
82+
amount.String(),
83+
},
84+
expError: true,
85+
},
86+
{
87+
name: "valid pubkey flag",
88+
args: []string{
89+
fmt.Sprintf("--%s=%s", flags.FlagChainID, s.network.Config.ChainID),
90+
fmt.Sprintf("--%s={\"@type\":\"/cosmos.crypto.ed25519.PubKey\",\"key\":\"BOIkjkFruMpfOFC9oNPhiJGfmY2pHF/gwHdLDLnrnS0=\"}", stakingcli.FlagPubKey),
91+
val.Moniker,
92+
amount.String(),
93+
},
94+
expError: false,
95+
},
96+
}
97+
98+
for _, tc := range tests {
99+
tc := tc
100+
101+
dir := s.T().TempDir()
102+
genTxFile := filepath.Join(dir, "myTx")
103+
tc.args = append(tc.args, fmt.Sprintf("--%s=%s", flags.FlagOutputDocument, genTxFile))
104+
105+
s.Run(tc.name, func() {
106+
cmd := cli.GenTxCmd(
107+
simapp.ModuleBasics,
108+
val.ClientCtx.TxConfig,
109+
banktypes.GenesisBalancesIterator{},
110+
val.ClientCtx.HomeDir)
111+
112+
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
113+
114+
if tc.expError {
115+
s.Require().Error(err)
116+
117+
_, err = os.Open(genTxFile)
118+
s.Require().Error(err)
119+
} else {
120+
s.Require().NoError(err, "test: %s\noutput: %s", tc.name, out.String())
121+
122+
// validate generated transaction.
123+
open, err := os.Open(genTxFile)
124+
s.Require().NoError(err)
125+
126+
all, err := io.ReadAll(open)
127+
s.Require().NoError(err)
128+
129+
tx, err := val.ClientCtx.TxConfig.TxJSONDecoder()(all)
130+
s.Require().NoError(err)
131+
132+
msgs := tx.GetMsgs()
133+
s.Require().Len(msgs, 1)
134+
135+
s.Require().Equal(sdk.MsgTypeURL(&types.MsgCreateValidator{}), sdk.MsgTypeURL(msgs[0]))
136+
s.Require().True(val.Address.Equals(msgs[0].GetSigners()[0]))
137+
s.Require().Equal(amount, msgs[0].(*types.MsgCreateValidator).Value)
138+
s.Require().NoError(tx.ValidateBasic())
139+
}
140+
})
141+
}
131142
}

x/genutil/gentx_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func (suite *GenTxTestSuite) setAccountBalance(addr sdk.AccAddress, amount int64
6464
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
6565
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
6666

67-
err := simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)})
67+
err := simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, amount)})
6868
suite.Require().NoError(err)
6969

7070
bankGenesisState := suite.app.BankKeeper.ExportGenesis(suite.ctx)
@@ -230,7 +230,7 @@ func (suite *GenTxTestSuite) TestDeliverGenTxs() {
230230
"success",
231231
func() {
232232
_ = suite.setAccountBalance(addr1, 50)
233-
_ = suite.setAccountBalance(addr2, 0)
233+
_ = suite.setAccountBalance(addr2, 1)
234234

235235
msg := banktypes.NewMsgSend(addr1, addr2, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)})
236236
tx, err := helpers.GenTx(

0 commit comments

Comments
 (0)