From ccc8003a8096a1eaa5f3597f011b038efd05e375 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 3 Aug 2022 12:08:41 -0400 Subject: [PATCH 01/10] chore!: Refactor x/bank CLI Tests (#12706) --- CHANGELOG.md | 2 + client/account_retriever.go | 23 ++ client/context.go | 12 +- client/flags/flags.go | 6 +- client/grpc_query.go | 3 +- client/query.go | 7 +- client/tendermint.go | 28 ++ client/tx/factory.go | 1 - server/cmd/execute.go | 17 +- simapp/simd/cmd/root.go | 2 - x/auth/client/cli/tips.go | 2 +- x/auth/client/cli/tx_multisign.go | 1 - x/auth/client/cli/tx_sign.go | 2 - x/auth/client/cli/validate_sigs.go | 1 - x/bank/client/cli/query.go | 9 + x/bank/client/cli/query_test.go | 362 ++++++++++++++++++++++++++ x/bank/client/cli/suite_test.go | 96 +++++++ x/bank/client/cli/tx.go | 1 - x/bank/client/cli/tx_test.go | 211 +++++++++++++++ x/bank/client/testutil/cli_helpers.go | 1 - x/genutil/client/cli/gentx.go | 1 - 21 files changed, 757 insertions(+), 31 deletions(-) create mode 100644 client/tendermint.go create mode 100644 x/bank/client/cli/query_test.go create mode 100644 x/bank/client/cli/suite_test.go create mode 100644 x/bank/client/cli/tx_test.go delete mode 100644 x/bank/client/testutil/cli_helpers.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 273478719204..cad0d2cfd9e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* (x/bank) [#12706](https://github.com/cosmos/cosmos-sdk/pull/12706) Added the `chain-id` flag to the `AddTxFlagsToCmd` API. There is no longer a need to explicitly register this flag on commands whens `AddTxFlagsToCmd` is already called. * [#12791](https://github.com/cosmos/cosmos-sdk/pull/12791) Bump the math library used in the sdk and replace old usages of sdk.* * (x/params) [#12615](https://github.com/cosmos/cosmos-sdk/pull/12615) Add `GetParamSetIfExists` function to params `Subspace` to prevent panics on breaking changes. * [#12717](https://github.com/cosmos/cosmos-sdk/pull/12717) Use injected encoding params in simapp. @@ -70,6 +71,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (x/bank) [#12706](https://github.com/cosmos/cosmos-sdk/pull/12706) Removed the `testutil` package from the `x/bank/client` package. * (simapp) [#12747](https://github.com/cosmos/cosmos-sdk/pull/12747) Remove `simapp.MakeTestEncodingConfig`. Please use `moduletestutil.MakeTestEncodingConfig` (`types/module/testutil`) in tests instead. * (x/bank) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) `NewSendAuthorization` takes a new argument of an optional list of addresses allowed to receive bank assests via authz MsgSend grant. You can pass `nil` for the same behavior as before, i.e. any recipient is allowed. * (x/bank) [\#12593](https://github.com/cosmos/cosmos-sdk/pull/12593) Add `SpendableCoin` method to `BaseViewKeeper` diff --git a/client/account_retriever.go b/client/account_retriever.go index 8e2fd14c1fcd..24de5423e2ea 100644 --- a/client/account_retriever.go +++ b/client/account_retriever.go @@ -22,3 +22,26 @@ type AccountRetriever interface { EnsureExists(clientCtx Context, addr sdk.AccAddress) error GetAccountNumberSequence(clientCtx Context, addr sdk.AccAddress) (accNum uint64, accSeq uint64, err error) } + +var _ AccountRetriever = (*MockAccountRetriever)(nil) + +// MockAccountRetriever defines a no-op basic AccountRetriever that can be used +// in mocked contexts. Tests or context that need more sophisticated testing +// state should implement their own mock AccountRetriever. +type MockAccountRetriever struct{} + +func (mar MockAccountRetriever) GetAccount(_ Context, _ sdk.AccAddress) (Account, error) { + return nil, nil +} + +func (mar MockAccountRetriever) GetAccountWithHeight(_ Context, _ sdk.AccAddress) (Account, int64, error) { + return nil, 0, nil +} + +func (mar MockAccountRetriever) EnsureExists(_ Context, _ sdk.AccAddress) error { + return nil +} + +func (mar MockAccountRetriever) GetAccountNumberSequence(_ Context, _ sdk.AccAddress) (uint64, uint64, error) { + return 0, 0, nil +} diff --git a/client/context.go b/client/context.go index be5c84af6070..b635ff953d2e 100644 --- a/client/context.go +++ b/client/context.go @@ -7,14 +7,10 @@ import ( "io" "os" + "github.com/gogo/protobuf/proto" "github.com/spf13/viper" - - "sigs.k8s.io/yaml" - "google.golang.org/grpc" - - "github.com/gogo/protobuf/proto" - rpcclient "github.com/tendermint/tendermint/rpc/client" + "sigs.k8s.io/yaml" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -26,7 +22,7 @@ import ( // handling and queries. type Context struct { FromAddress sdk.AccAddress - Client rpcclient.Client + Client TendermintRPC GRPCClient *grpc.ClientConn ChainID string Codec codec.Codec @@ -128,7 +124,7 @@ func (ctx Context) WithHeight(height int64) Context { // WithClient returns a copy of the context with an updated RPC client // instance. -func (ctx Context) WithClient(client rpcclient.Client) Context { +func (ctx Context) WithClient(client TendermintRPC) Context { ctx.Client = client return ctx } diff --git a/client/flags/flags.go b/client/flags/flags.go index 12bd7fd24cf4..9164ab599d6a 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -79,6 +79,7 @@ const ( FlagReverse = "reverse" FlagTip = "tip" FlagAux = "aux" + FlagOutput = tmcli.OutputFlag // Tendermint logging flags FlagLogLevel = "log_level" @@ -93,7 +94,7 @@ var LineBreak = &cobra.Command{Run: func(*cobra.Command, []string) {}} func AddQueryFlagsToCmd(cmd *cobra.Command) { cmd.Flags().String(FlagNode, "tcp://localhost:26657", ": to Tendermint RPC interface for this chain") cmd.Flags().Int64(FlagHeight, 0, "Use a specific height to query state at (this can error if the node is pruning state)") - cmd.Flags().StringP(tmcli.OutputFlag, "o", "text", "Output format (text|json)") + cmd.Flags().StringP(FlagOutput, "o", "text", "Output format (text|json)") // some base commands does not require chainID e.g `simd testnet` while subcommands do // hence the flag should not be required for those commands @@ -102,7 +103,7 @@ func AddQueryFlagsToCmd(cmd *cobra.Command) { // AddTxFlagsToCmd adds common flags to a module tx command. func AddTxFlagsToCmd(cmd *cobra.Command) { - cmd.Flags().StringP(tmcli.OutputFlag, "o", "json", "Output format (text|json)") + cmd.Flags().StringP(FlagOutput, "o", "json", "Output format (text|json)") cmd.Flags().String(FlagKeyringDir, "", "The client Keyring directory; if omitted, the default 'home' directory will be used") cmd.Flags().String(FlagFrom, "", "Name or address of private key with which to sign") cmd.Flags().Uint64P(FlagAccountNumber, "a", 0, "The account number of the signing account (offline mode only)") @@ -125,6 +126,7 @@ func AddTxFlagsToCmd(cmd *cobra.Command) { cmd.Flags().String(FlagFeeGranter, "", "Fee granter grants fees for the transaction") cmd.Flags().String(FlagTip, "", "Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator") cmd.Flags().Bool(FlagAux, false, "Generate aux signer data instead of sending a tx") + cmd.Flags().String(FlagChainID, "", "The network chain ID") // --gas can accept integers and "auto" cmd.Flags().String(FlagGas, "", fmt.Sprintf("gas limit to set per-transaction; set to %q to calculate sufficient gas automatically (default %d)", GasFlagAuto, DefaultGasLimit)) diff --git a/client/grpc_query.go b/client/grpc_query.go index a5b348ca1058..da8b2e8fa268 100644 --- a/client/grpc_query.go +++ b/client/grpc_query.go @@ -7,10 +7,11 @@ import ( "reflect" "strconv" - "github.com/cosmos/cosmos-sdk/codec" proto "github.com/gogo/protobuf/proto" "google.golang.org/grpc/encoding" + "github.com/cosmos/cosmos-sdk/codec" + gogogrpc "github.com/gogo/protobuf/grpc" abci "github.com/tendermint/tendermint/abci/types" "google.golang.org/grpc" diff --git a/client/query.go b/client/query.go index f81787147e91..88f0595c5ad3 100644 --- a/client/query.go +++ b/client/query.go @@ -6,12 +6,11 @@ import ( "strings" "github.com/pkg/errors" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - abci "github.com/tendermint/tendermint/abci/types" tmbytes "github.com/tendermint/tendermint/libs/bytes" rpcclient "github.com/tendermint/tendermint/rpc/client" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "github.com/cosmos/cosmos-sdk/store/rootmulti" sdk "github.com/cosmos/cosmos-sdk/types" @@ -20,7 +19,7 @@ import ( // GetNode returns an RPC client. If the context's client is not defined, an // error is returned. -func (ctx Context) GetNode() (rpcclient.Client, error) { +func (ctx Context) GetNode() (TendermintRPC, error) { if ctx.Client == nil { return nil, errors.New("no RPC client is defined in offline mode") } diff --git a/client/tendermint.go b/client/tendermint.go new file mode 100644 index 000000000000..4eb56f5f2670 --- /dev/null +++ b/client/tendermint.go @@ -0,0 +1,28 @@ +package client + +import ( + "context" + + "github.com/tendermint/tendermint/libs/bytes" + rpcclient "github.com/tendermint/tendermint/rpc/client" + "github.com/tendermint/tendermint/rpc/coretypes" +) + +// TendermintRPC defines the interface of a Tendermint RPC client needed for +// queries and transaction handling. +type TendermintRPC interface { + rpcclient.ABCIClient + + Validators(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error) + Status(context.Context) (*coretypes.ResultStatus, error) + Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error) + BlockchainInfo(ctx context.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error) + Tx(ctx context.Context, hash bytes.HexBytes, prove bool) (*coretypes.ResultTx, error) + TxSearch( + ctx context.Context, + query string, + prove bool, + page, perPage *int, + orderBy string, + ) (*coretypes.ResultTxSearch, error) +} diff --git a/client/tx/factory.go b/client/tx/factory.go index 15304e8e5e70..ff8eaec07bdd 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -392,7 +392,6 @@ func (f Factory) getSimPK() (cryptotypes.PubKey, error) { // the updated fields will be returned. func (f Factory) Prepare(clientCtx client.Context) (Factory, error) { fc := f - from := clientCtx.GetFromAddress() if err := fc.accountRetriever.EnsureExists(clientCtx, from); err != nil { diff --git a/server/cmd/execute.go b/server/cmd/execute.go index 4f715d3cc3de..70068ff6b4e4 100644 --- a/server/cmd/execute.go +++ b/server/cmd/execute.go @@ -20,14 +20,11 @@ import ( func Execute(rootCmd *cobra.Command, envPrefix string, defaultHome string) error { // Create and set a client.Context on the command's Context. During the pre-run // of the root command, a default initialized client.Context is provided to - // seed child command execution with values such as AccountRetriver, Keyring, + // seed child command execution with values such as AccountRetriever, Keyring, // and a Tendermint RPC. This requires the use of a pointer reference when // getting and setting the client.Context. Ideally, we utilize // https://github.com/spf13/cobra/pull/1118. - srvCtx := server.NewDefaultContext() - ctx := context.Background() - ctx = context.WithValue(ctx, client.ClientContextKey, &client.Context{}) - ctx = context.WithValue(ctx, server.ServerContextKey, srvCtx) + ctx := CreateExecuteContext(context.Background()) rootCmd.PersistentFlags().String(flags.FlagLogLevel, zerolog.InfoLevel.String(), "The logging level (trace|debug|info|warn|error|fatal|panic)") rootCmd.PersistentFlags().String(flags.FlagLogFormat, tmlog.LogFormatPlain, "The logging format (json|plain)") @@ -35,3 +32,13 @@ func Execute(rootCmd *cobra.Command, envPrefix string, defaultHome string) error executor := tmcli.PrepareBaseCmd(rootCmd, envPrefix, defaultHome) return executor.ExecuteContext(ctx) } + +// CreateExecuteContext returns a base Context with server and client context +// values initialized. +func CreateExecuteContext(ctx context.Context) context.Context { + srvCtx := server.NewDefaultContext() + ctx = context.WithValue(ctx, client.ClientContextKey, &client.Context{}) + ctx = context.WithValue(ctx, server.ServerContextKey, srvCtx) + + return ctx +} diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 7eb91d5d1c59..88a3b6690ed0 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -216,7 +216,6 @@ func queryCommand() *cobra.Command { ) simapp.ModuleBasics.AddQueryCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") return cmd } @@ -243,7 +242,6 @@ func txCommand() *cobra.Command { ) simapp.ModuleBasics.AddTxCommands(cmd) - cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID") return cmd } diff --git a/x/auth/client/cli/tips.go b/x/auth/client/cli/tips.go index 773ad6d619f7..8f86e70b35f9 100644 --- a/x/auth/client/cli/tips.go +++ b/x/auth/client/cli/tips.go @@ -76,7 +76,7 @@ func GetAuxToFeeCommand() *cobra.Command { } flags.AddTxFlagsToCmd(cmd) - cmd.Flags().String(flags.FlagChainID, "", "network chain ID") + return cmd } diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index 48c819cb8eab..0a2824ffe6d0 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -65,7 +65,6 @@ The SIGN_MODE_DIRECT sign mode is not supported.' cmd.Flags().String(flags.FlagOutputDocument, "", "The document is written to the given file instead of STDOUT") cmd.Flags().Bool(flagAmino, false, "Generate Amino-encoded JSON suitable for submitting to the txs REST endpoint") flags.AddTxFlagsToCmd(cmd) - cmd.Flags().String(flags.FlagChainID, "", "network chain ID") return cmd } diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index 53fa016e6ac2..45fd71fa083c 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -54,7 +54,6 @@ account key. It implies --signature-only. cmd.Flags().String(flagMultisig, "", "Address or key name of the multisig account on behalf of which the transaction shall be signed") cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT") cmd.Flags().Bool(flagSigOnly, true, "Print only the generated signature, then exit") - cmd.Flags().String(flags.FlagChainID, "", "network chain ID") flags.AddTxFlagsToCmd(cmd) cmd.MarkFlagRequired(flags.FlagFrom) @@ -192,7 +191,6 @@ be generated via the 'multisign' command. cmd.Flags().Bool(flagOverwrite, false, "Overwrite existing signatures with a new one. If disabled, new signature will be appended") cmd.Flags().Bool(flagSigOnly, false, "Print only the signatures") cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT") - cmd.Flags().String(flags.FlagChainID, "", "The network chain ID") cmd.Flags().Bool(flagAmino, false, "Generate Amino encoded JSON suitable for submiting to the txs REST endpoint") flags.AddTxFlagsToCmd(cmd) diff --git a/x/auth/client/cli/validate_sigs.go b/x/auth/client/cli/validate_sigs.go index 7d4da92bac39..0ad65c71e35a 100644 --- a/x/auth/client/cli/validate_sigs.go +++ b/x/auth/client/cli/validate_sigs.go @@ -30,7 +30,6 @@ transaction will be not be performed as that will require RPC communication with Args: cobra.ExactArgs(1), } - cmd.Flags().String(flags.FlagChainID, "", "The network chain ID") flags.AddTxFlagsToCmd(cmd) return cmd diff --git a/x/bank/client/cli/query.go b/x/bank/client/cli/query.go index 10e5885f9653..df544fd315d6 100644 --- a/x/bank/client/cli/query.go +++ b/x/bank/client/cli/query.go @@ -59,6 +59,7 @@ Example: if err != nil { return err } + denom, err := cmd.Flags().GetString(FlagDenom) if err != nil { return err @@ -75,17 +76,22 @@ Example: if err != nil { return err } + ctx := cmd.Context() + if denom == "" { params := types.NewQueryAllBalancesRequest(addr, pageReq) + res, err := queryClient.AllBalances(ctx, params) if err != nil { return err } + return clientCtx.PrintProto(res) } params := types.NewQueryBalanceRequest(addr, denom) + res, err := queryClient.Balance(ctx, params) if err != nil { return err @@ -125,6 +131,7 @@ To query for the client metadata of a specific coin denomination use: if err != nil { return err } + denom, err := cmd.Flags().GetString(FlagDenom) if err != nil { return err @@ -178,6 +185,7 @@ To query for the total supply of a specific coin denomination use: if err != nil { return err } + denom, err := cmd.Flags().GetString(FlagDenom) if err != nil { return err @@ -190,6 +198,7 @@ To query for the total supply of a specific coin denomination use: if err != nil { return err } + if denom == "" { res, err := queryClient.TotalSupply(ctx, &types.QueryTotalSupplyRequest{Pagination: pageReq}) if err != nil { diff --git a/x/bank/client/cli/query_test.go b/x/bank/client/cli/query_test.go new file mode 100644 index 000000000000..b782f0799ce8 --- /dev/null +++ b/x/bank/client/cli/query_test.go @@ -0,0 +1,362 @@ +package cli_test + +import ( + "bytes" + "context" + "fmt" + "io" + + "github.com/gogo/protobuf/proto" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/client/cli" + "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func (s *CLITestSuite) TestGetBalancesCmd() { + accounts := s.createKeyringAccounts(1) + + cmd := cli.GetBalancesCmd() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expectResult proto.Message + expectErr bool + }{ + { + "valid query", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&types.QueryAllBalancesResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + accounts[0].address.String(), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + &types.QueryAllBalancesResponse{}, + false, + }, + { + "valid query with denom", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&types.QueryBalanceResponse{ + Balance: &sdk.Coin{}, + }) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + accounts[0].address.String(), + fmt.Sprintf("--%s=photon", cli.FlagDenom), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + &sdk.Coin{}, + false, + }, + { + "invalid address", + func() client.Context { + return s.baseCtx + }, + []string{ + "foo", + }, + nil, + true, + }, + { + "invalid denom", + func() client.Context { + c := newMockTendermintRPC(abci.ResponseQuery{ + Code: 1, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + accounts[0].address.String(), + fmt.Sprintf("--%s=foo", cli.FlagDenom), + }, + nil, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(outBuf.Bytes(), tc.expectResult)) + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestGetCmdDenomsMetadata() { + cmd := cli.GetCmdDenomsMetadata() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expectResult proto.Message + expectErr bool + }{ + { + "valid query", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&types.QueryDenomsMetadataResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + &types.QueryDenomsMetadataResponse{}, + false, + }, + { + "valid query with denom", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&types.QueryDenomMetadataResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + fmt.Sprintf("--%s=photon", cli.FlagDenom), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + &types.QueryDenomMetadataResponse{}, + false, + }, + { + "invalid query with denom", + func() client.Context { + c := newMockTendermintRPC(abci.ResponseQuery{ + Code: 1, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + fmt.Sprintf("--%s=foo", cli.FlagDenom), + }, + nil, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(outBuf.Bytes(), tc.expectResult)) + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestGetCmdQueryTotalSupply() { + cmd := cli.GetCmdQueryTotalSupply() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expectResult proto.Message + expectErr bool + }{ + { + "valid query", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&types.QueryTotalSupplyResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + &types.QueryTotalSupplyResponse{}, + false, + }, + { + "valid query with denom", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&types.QuerySupplyOfResponse{ + Amount: sdk.Coin{}, + }) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + fmt.Sprintf("--%s=photon", cli.FlagDenom), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + &sdk.Coin{}, + false, + }, + { + "invalid query with denom", + func() client.Context { + c := newMockTendermintRPC(abci.ResponseQuery{ + Code: 1, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + fmt.Sprintf("--%s=foo", cli.FlagDenom), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + nil, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(outBuf.Bytes(), tc.expectResult)) + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestGetCmdQuerySendEnabled() { + cmd := cli.GetCmdQuerySendEnabled() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expectResult proto.Message + expectErr bool + }{ + { + "valid query", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&types.QuerySendEnabledResponse{ + SendEnabled: []*types.SendEnabled{}, + }) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + &types.QuerySendEnabledResponse{}, + false, + }, + { + "valid query with denoms", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&types.QuerySendEnabledResponse{ + SendEnabled: []*types.SendEnabled{}, + }) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + []string{ + "photon", + "stake", + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + &types.QuerySendEnabledResponse{}, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(s.encCfg.Codec.UnmarshalJSON(outBuf.Bytes(), tc.expectResult)) + s.Require().NoError(err) + } + }) + } +} diff --git a/x/bank/client/cli/suite_test.go b/x/bank/client/cli/suite_test.go new file mode 100644 index 000000000000..82fcd699befc --- /dev/null +++ b/x/bank/client/cli/suite_test.go @@ -0,0 +1,96 @@ +package cli_test + +import ( + "context" + "fmt" + "io" + "testing" + + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/bytes" + rpcclient "github.com/tendermint/tendermint/rpc/client" + rpcclientmock "github.com/tendermint/tendermint/rpc/client/mock" + "github.com/tendermint/tendermint/rpc/coretypes" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/bank" +) + +var _ client.TendermintRPC = (*mockTendermintRPC)(nil) + +type mockTendermintRPC struct { + rpcclientmock.Client + + responseQuery abci.ResponseQuery +} + +func newMockTendermintRPC(respQuery abci.ResponseQuery) mockTendermintRPC { + return mockTendermintRPC{responseQuery: respQuery} +} + +func (_ mockTendermintRPC) BroadcastTxSync(context.Context, tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { + return &coretypes.ResultBroadcastTx{Code: 0}, nil +} + +func (m mockTendermintRPC) ABCIQueryWithOptions( + _ context.Context, + _ string, _ bytes.HexBytes, + _ rpcclient.ABCIQueryOptions, +) (*coretypes.ResultABCIQuery, error) { + return &coretypes.ResultABCIQuery{Response: m.responseQuery}, nil +} + +type account struct { + name string + address sdk.AccAddress +} + +type CLITestSuite struct { + suite.Suite + + kr keyring.Keyring + encCfg testutilmod.TestEncodingConfig + baseCtx client.Context +} + +func TestMigrateTestSuite(t *testing.T) { + suite.Run(t, new(CLITestSuite)) +} + +func (s *CLITestSuite) SetupSuite() { + s.encCfg = testutilmod.MakeTestEncodingConfig(bank.AppModuleBasic{}) + s.kr = keyring.NewInMemory(s.encCfg.Codec) + s.baseCtx = client.Context{}. + WithKeyring(s.kr). + WithTxConfig(s.encCfg.TxConfig). + WithCodec(s.encCfg.Codec). + WithClient(mockTendermintRPC{Client: rpcclientmock.New()}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard) +} + +func (s *CLITestSuite) createKeyringAccounts(num int) []account { + accounts := make([]account, num) + for i := range accounts { + record, _, err := s.kr.NewMnemonic( + fmt.Sprintf("key-%d", i), + keyring.English, + sdk.FullFundraiserPath, + keyring.DefaultBIP39Passphrase, + hd.Secp256k1) + s.Require().NoError(err) + + addr, err := record.GetAddress() + s.Require().NoError(err) + + accounts[i] = account{name: record.Name, address: addr} + } + + return accounts +} diff --git a/x/bank/client/cli/tx.go b/x/bank/client/cli/tx.go index 5deb617b8952..b0bac9b8282d 100644 --- a/x/bank/client/cli/tx.go +++ b/x/bank/client/cli/tx.go @@ -138,7 +138,6 @@ When using '--dry-run' a key name cannot be used, only a bech32 address. } cmd.Flags().Bool(FlagSplit, false, "Send the equally split token amount to each address") - flags.AddTxFlagsToCmd(cmd) return cmd diff --git a/x/bank/client/cli/tx_test.go b/x/bank/client/cli/tx_test.go new file mode 100644 index 000000000000..ba0904f14f8e --- /dev/null +++ b/x/bank/client/cli/tx_test.go @@ -0,0 +1,211 @@ +package cli_test + +import ( + "context" + "fmt" + "io" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/client/cli" +) + +func (s *CLITestSuite) TestSendTxCmd() { + accounts := s.createKeyringAccounts(1) + cmd := cli.NewSendTxCmd() + cmd.SetOutput(io.Discard) + + extraArgs := []string{ + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("photon", sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=test-chain", flags.FlagChainID), + } + + testCases := []struct { + name string + ctxGen func() client.Context + from, to sdk.AccAddress + amount sdk.Coins + extraArgs []string + expectErr bool + }{ + { + "valid transaction", + func() client.Context { + return s.baseCtx + }, + accounts[0].address, + accounts[0].address, + sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(10)), + sdk.NewCoin("photon", sdk.NewInt(40)), + ), + extraArgs, + false, + }, + { + "invalid to address", + func() client.Context { + return s.baseCtx + }, + accounts[0].address, + sdk.AccAddress{}, + sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(10)), + sdk.NewCoin("photon", sdk.NewInt(40)), + ), + extraArgs, + true, + }, + { + "invalid coins", + func() client.Context { + return s.baseCtx + }, + accounts[0].address, + accounts[0].address, + nil, + extraArgs, + true, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(append([]string{tc.from.String(), tc.to.String(), tc.amount.String()}, tc.extraArgs...)) + + s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + +func (s *CLITestSuite) TestMultiSendTxCmd() { + accounts := s.createKeyringAccounts(3) + + cmd := cli.NewMultiSendTxCmd() + cmd.SetOutput(io.Discard) + + extraArgs := []string{ + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("photon", sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=test-chain", flags.FlagChainID), + } + + testCases := []struct { + name string + ctxGen func() client.Context + from string + to []string + amount sdk.Coins + extraArgs []string + expectErr bool + }{ + { + "valid transaction", + func() client.Context { + return s.baseCtx + }, + accounts[0].address.String(), + []string{ + accounts[1].address.String(), + accounts[2].address.String(), + }, + sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(10)), + sdk.NewCoin("photon", sdk.NewInt(40)), + ), + extraArgs, + false, + }, + { + "invalid from address", + func() client.Context { + return s.baseCtx + }, + "foo", + []string{ + accounts[1].address.String(), + accounts[2].address.String(), + }, + sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(10)), + sdk.NewCoin("photon", sdk.NewInt(40)), + ), + extraArgs, + true, + }, + { + "invalid recipients", + func() client.Context { + return s.baseCtx + }, + accounts[0].address.String(), + []string{ + accounts[1].address.String(), + "bar", + }, + sdk.NewCoins( + sdk.NewCoin("stake", sdk.NewInt(10)), + sdk.NewCoin("photon", sdk.NewInt(40)), + ), + extraArgs, + true, + }, + { + "invalid amount", + func() client.Context { + return s.baseCtx + }, + accounts[0].address.String(), + []string{ + accounts[1].address.String(), + accounts[2].address.String(), + }, + nil, + extraArgs, + true, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + var args []string + args = append(args, tc.from) + args = append(args, tc.to...) + args = append(args, tc.amount.String()) + args = append(args, tc.extraArgs...) + + cmd.SetContext(ctx) + cmd.SetArgs(args) + + s.Require().NoError(client.SetCmdClientContextHandler(tc.ctxGen(), cmd)) + + err := cmd.Execute() + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} diff --git a/x/bank/client/testutil/cli_helpers.go b/x/bank/client/testutil/cli_helpers.go deleted file mode 100644 index 110b2e6a7979..000000000000 --- a/x/bank/client/testutil/cli_helpers.go +++ /dev/null @@ -1 +0,0 @@ -package testutil diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 4880fa375503..433fa987ea16 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -209,7 +209,6 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") cmd.Flags().String(flags.FlagOutputDocument, "", "Write the genesis transaction JSON document to the given file instead of the default location") - cmd.Flags().String(flags.FlagChainID, "", "The network chain ID") cmd.Flags().AddFlagSet(fsCreateValidator) flags.AddTxFlagsToCmd(cmd) From 08e68ba96c96a52114fb61166b132d2b2f2f0963 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Aug 2022 09:44:03 +0200 Subject: [PATCH 02/10] build(deps): Bump github.com/cosmos/iavl from 0.19.0 to 0.19.1 (#12801) Bumps [github.com/cosmos/iavl](https://github.com/cosmos/iavl) from 0.19.0 to 0.19.1. - [Release notes](https://github.com/cosmos/iavl/releases) - [Changelog](https://github.com/cosmos/iavl/blob/master/CHANGELOG.md) - [Commits](https://github.com/cosmos/iavl/compare/v0.19.0...v0.19.1) --- updated-dependencies: - dependency-name: github.com/cosmos/iavl dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marko --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 109c910a3621..65082cf81cd7 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/cosmos/cosmos-sdk/db v1.0.0-beta.1.0.20220726092710-f848e4300a8a github.com/cosmos/cosmos-sdk/store/tools/ics23 v0.0.0-20220726092710-f848e4300a8a github.com/cosmos/go-bip39 v1.0.0 - github.com/cosmos/iavl v0.19.0 + github.com/cosmos/iavl v0.19.1 github.com/cosmos/ledger-cosmos-go v0.11.1 github.com/gogo/gateway v1.1.0 github.com/gogo/protobuf v1.3.2 diff --git a/go.sum b/go.sum index eeeb42c3c5ee..f1a8b79ab2bd 100644 --- a/go.sum +++ b/go.sum @@ -299,8 +299,8 @@ github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= -github.com/cosmos/iavl v0.19.0 h1:sgyrjqOkycXiN7Tuupuo4QAldKFg7Sipyfeg/IL7cps= -github.com/cosmos/iavl v0.19.0/go.mod h1:l5h9pAB3m5fihB3pXVgwYqdY8aBsMagqz7T0MUjxZeA= +github.com/cosmos/iavl v0.19.1 h1:3gaq9b6SjiB0KBTygRnAvEGml2pQlu1TH8uma5g63Ys= +github.com/cosmos/iavl v0.19.1/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= From 970582d183e11ad4cbe23b68cb69ff645117a580 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Aug 2022 09:56:46 +0200 Subject: [PATCH 03/10] build(deps): Bump github.com/cosmos/iavl in /store/tools/ics23 (#12804) Bumps [github.com/cosmos/iavl](https://github.com/cosmos/iavl) from 0.19.0 to 0.19.1. - [Release notes](https://github.com/cosmos/iavl/releases) - [Changelog](https://github.com/cosmos/iavl/blob/master/CHANGELOG.md) - [Commits](https://github.com/cosmos/iavl/compare/v0.19.0...v0.19.1) --- updated-dependencies: - dependency-name: github.com/cosmos/iavl dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Marko --- store/tools/ics23/go.mod | 2 +- store/tools/ics23/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/store/tools/ics23/go.mod b/store/tools/ics23/go.mod index 703189bc13d8..2a39abb436fe 100644 --- a/store/tools/ics23/go.mod +++ b/store/tools/ics23/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/confio/ics23/go v0.7.0 github.com/cosmos/cosmos-sdk v0.46.0 - github.com/cosmos/iavl v0.19.0 + github.com/cosmos/iavl v0.19.1 github.com/lazyledger/smt v0.2.1-0.20210709230900-03ea40719554 github.com/tendermint/tendermint v0.35.9 github.com/tendermint/tm-db v0.6.7 diff --git a/store/tools/ics23/go.sum b/store/tools/ics23/go.sum index b9bd5affa953..5d72333ef953 100644 --- a/store/tools/ics23/go.sum +++ b/store/tools/ics23/go.sum @@ -203,8 +203,8 @@ github.com/cosmos/cosmos-sdk v0.46.0 h1:TwifvVmAmqUNB70tN1clrqExryWyBU3RxbI2QZEJ github.com/cosmos/cosmos-sdk v0.46.0/go.mod h1:u6Ci6+V+srijJhzctEEPYBygUz3O2YXP5ZijPnV6mt0= github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= -github.com/cosmos/iavl v0.19.0 h1:sgyrjqOkycXiN7Tuupuo4QAldKFg7Sipyfeg/IL7cps= -github.com/cosmos/iavl v0.19.0/go.mod h1:l5h9pAB3m5fihB3pXVgwYqdY8aBsMagqz7T0MUjxZeA= +github.com/cosmos/iavl v0.19.1 h1:3gaq9b6SjiB0KBTygRnAvEGml2pQlu1TH8uma5g63Ys= +github.com/cosmos/iavl v0.19.1/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= From 8c23f6f957d1c0bedd314806d1ac65bea59b084c Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Thu, 4 Aug 2022 01:27:54 -0700 Subject: [PATCH 04/10] perf: fix: tx/textual/valuerender: use io.WriteString to skip str->byteslice + fix negative sign dropping (#12815) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed in an audit that the differeent value renderers perform an expensive and unnecessary string->byteslice in cases where the output write implements io.StringWriter. This change instead invokes io.WriteString(w, formatted) instead of: w.Write([]byte(formatted)) and added benchmarks that show an improvement from just the 1 line change: ```shell $ benchstat before.txt after.txt name old time/op new time/op delta IntValueRendererFormat-8 4.13µs ± 3% 3.95µs ± 6% -4.55% (p=0.000 n=15+14) BytesValueRendererFormat-8 5.22ms ± 3% 4.77ms ± 5% -8.60% (p=0.000 n=15+14) name old alloc/op new alloc/op delta IntValueRendererFormat-8 3.64kB ± 0% 3.31kB ± 0% -9.01% (p=0.000 n=15+15) BytesValueRendererFormat-8 12.6MB ± 0% 8.4MB ± 0% -33.22% (p=0.000 n=15+15) name old allocs/op new allocs/op delta IntValueRendererFormat-8 76.0 ± 0% 67.0 ± 0% -11.84% (p=0.000 n=15+15) BytesValueRendererFormat-8 27.0 ± 0% 18.0 ± 0% -33.33% (p=0.000 n=15+15) ``` While here, implemented negative sign preservation because previously the code wasn't tested for negative values so passing in negative values such as: "-10000000.11" would produce: "10'000'000.11" instead of the proper value with the negative sign preserved: "-10'000'000.11" Fixes #12810 Fixes #12812 --- tx/textual/internal/testdata/decimals.json | 6 +- tx/textual/valuerenderer/bench_test.go | 67 +++++++++++++++++++ tx/textual/valuerenderer/bytes.go | 4 +- tx/textual/valuerenderer/dec.go | 2 +- tx/textual/valuerenderer/int.go | 6 +- .../valuerenderer/valuerenderer_test.go | 21 +++--- 6 files changed, 91 insertions(+), 15 deletions(-) create mode 100644 tx/textual/valuerenderer/bench_test.go diff --git a/tx/textual/internal/testdata/decimals.json b/tx/textual/internal/testdata/decimals.json index 8893fef9e24b..3564b597d92b 100644 --- a/tx/textual/internal/testdata/decimals.json +++ b/tx/textual/internal/testdata/decimals.json @@ -39,5 +39,9 @@ ["0.000000000000001000", "0.000000000000001"], ["0.000000000000000100", "0.0000000000000001"], ["0.000000000000000010", "0.00000000000000001"], - ["0.000000000000000001", "0.000000000000000001"] + ["0.000000000000000001", "0.000000000000000001"], + ["-10.0", "-10"], + ["-10000", "-10'000"], + ["-9999", "-9'999"], + ["-999999999999", "-999'999'999'999"] ] diff --git a/tx/textual/valuerenderer/bench_test.go b/tx/textual/valuerenderer/bench_test.go new file mode 100644 index 000000000000..fd485fbd7643 --- /dev/null +++ b/tx/textual/valuerenderer/bench_test.go @@ -0,0 +1,67 @@ +package valuerenderer + +import ( + "bytes" + "context" + "testing" + + "google.golang.org/protobuf/reflect/protoreflect" +) + +var intValues = []protoreflect.Value{ + protoreflect.ValueOfString("10.00"), + protoreflect.ValueOfString("999.00"), + protoreflect.ValueOfString("999.9999"), + protoreflect.ValueOfString("99999999.9999"), + protoreflect.ValueOfString("9999999999999999999"), + protoreflect.ValueOfString("1000000000000000000000000000000000000000000000000000000.00"), + protoreflect.ValueOfString("77777777777.777777777777777777777700"), + protoreflect.ValueOfString("-77777777777.777777777777777777777700"), + protoreflect.ValueOfString("777777777777777777777777.77777777700"), +} + +func BenchmarkIntValueRendererFormat(b *testing.B) { + ctx := context.Background() + ivr := new(intValueRenderer) + buf := new(bytes.Buffer) + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + for _, value := range intValues { + if err := ivr.Format(ctx, value, buf); err != nil { + b.Fatal(err) + } + } + buf.Reset() + } +} + +var byteValues = []protoreflect.Value{ + protoreflect.ValueOfBytes(bytes.Repeat([]byte("abc"), 1<<20)), + protoreflect.ValueOfBytes([]byte("999.00")), + protoreflect.ValueOfBytes([]byte("999.9999")), + protoreflect.ValueOfBytes([]byte("99999999.9999")), + protoreflect.ValueOfBytes([]byte("9999999999999999999")), + protoreflect.ValueOfBytes([]byte("1000000000000000000000000000000000000000000000000000000.00")), + protoreflect.ValueOfBytes([]byte("77777777777.777777777777777777777700")), + protoreflect.ValueOfBytes([]byte("-77777777777.777777777777777777777700")), + protoreflect.ValueOfBytes([]byte("777777777777777777777777.77777777700")), +} + +func BenchmarkBytesValueRendererFormat(b *testing.B) { + ctx := context.Background() + bvr := new(bytesValueRenderer) + buf := new(bytes.Buffer) + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + for _, value := range byteValues { + if err := bvr.Format(ctx, value, buf); err != nil { + b.Fatal(err) + } + } + buf.Reset() + } +} diff --git a/tx/textual/valuerenderer/bytes.go b/tx/textual/valuerenderer/bytes.go index 23ece74c94df..2600c87be20a 100644 --- a/tx/textual/valuerenderer/bytes.go +++ b/tx/textual/valuerenderer/bytes.go @@ -8,14 +8,14 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" ) -//bytesValueRenderer implements ValueRenderer for bytes +// bytesValueRenderer implements ValueRenderer for bytes type bytesValueRenderer struct { } var _ ValueRenderer = bytesValueRenderer{} func (vr bytesValueRenderer) Format(ctx context.Context, v protoreflect.Value, w io.Writer) error { - _, err := w.Write([]byte(base64.StdEncoding.EncodeToString(v.Bytes()))) + _, err := io.WriteString(w, base64.StdEncoding.EncodeToString(v.Bytes())) return err } diff --git a/tx/textual/valuerenderer/dec.go b/tx/textual/valuerenderer/dec.go index 688ef73c2340..5ea72e110d38 100644 --- a/tx/textual/valuerenderer/dec.go +++ b/tx/textual/valuerenderer/dec.go @@ -21,7 +21,7 @@ func (vr decValueRenderer) Format(_ context.Context, v protoreflect.Value, w io. return err } - _, err = w.Write([]byte(formatted)) + _, err = io.WriteString(w, formatted) return err } diff --git a/tx/textual/valuerenderer/int.go b/tx/textual/valuerenderer/int.go index 2770cce13fbc..476dbe2b4b0c 100644 --- a/tx/textual/valuerenderer/int.go +++ b/tx/textual/valuerenderer/int.go @@ -18,7 +18,7 @@ func (vr intValueRenderer) Format(_ context.Context, v protoreflect.Value, w io. return err } - _, err = w.Write([]byte(formatted)) + _, err = io.WriteString(w, formatted) return err } @@ -30,7 +30,9 @@ func (vr intValueRenderer) Parse(_ context.Context, r io.Reader) (protoreflect.V // operates with string manipulation (instead of manipulating the int or sdk.Int // object). func formatInteger(v string) (string, error) { + sign := "" if v[0] == '-' { + sign = "-" v = v[1:] } if len(v) > 1 { @@ -44,5 +46,5 @@ func formatInteger(v string) (string, error) { v = v[:outputIndex] + thousandSeparator + v[outputIndex:] } - return v, nil + return sign + v, nil } diff --git a/tx/textual/valuerenderer/valuerenderer_test.go b/tx/textual/valuerenderer/valuerenderer_test.go index 36b399f2b026..9d5361674554 100644 --- a/tx/textual/valuerenderer/valuerenderer_test.go +++ b/tx/textual/valuerenderer/valuerenderer_test.go @@ -73,15 +73,18 @@ func TestFormatDecimal(t *testing.T) { require.NoError(t, err) for _, tc := range testcases { - d, err := math.LegacyNewDecFromStr(tc[0]) - require.NoError(t, err) - r, err := valueRendererOf(d) - require.NoError(t, err) - b := new(strings.Builder) - err = r.Format(context.Background(), protoreflect.ValueOf(tc[0]), b) - require.NoError(t, err) - - require.Equal(t, tc[1], b.String()) + tc := tc + t.Run(tc[0], func(t *testing.T) { + d, err := math.LegacyNewDecFromStr(tc[0]) + require.NoError(t, err) + r, err := valueRendererOf(d) + require.NoError(t, err) + b := new(strings.Builder) + err = r.Format(context.Background(), protoreflect.ValueOf(tc[0]), b) + require.NoError(t, err) + + require.Equal(t, tc[1], b.String()) + }) } } From 3672c981b5d03e9ace80458023b31a97476d38a4 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Thu, 4 Aug 2022 13:31:46 -0400 Subject: [PATCH 05/10] docs(adr-59): test scope documentation (#12789) * docs: test scope documentation * migrating doc to an ADR * ADR first draft * Remove old doc * Proofreading * Add entry in README * update note about bdd * Add test matrix table and app_config examples in golang --- docs/architecture/README.md | 1 + docs/architecture/adr-059-test-scopes.md | 249 +++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 docs/architecture/adr-059-test-scopes.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 6cc9f3dea34d..a3446ce1a2fd 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -80,6 +80,7 @@ When writing ADRs, follow the same best practices for writing RFCs. When writing * [ADR 040: Storage and SMT State Commitments](./adr-040-storage-and-smt-state-commitments.md) * [ADR 046: Module Params](./adr-046-module-params.md) * [ADR 057: App Wiring Part I](./adr-057-app-wiring-1.md) +* [ADR 059: Test Scopes](./adr-059-test-scopes.md) ### Draft diff --git a/docs/architecture/adr-059-test-scopes.md b/docs/architecture/adr-059-test-scopes.md new file mode 100644 index 000000000000..b11981ac86a8 --- /dev/null +++ b/docs/architecture/adr-059-test-scopes.md @@ -0,0 +1,249 @@ +# ADR 059: Test Scopes + +## Changelog + +* 2022-08-02: Initial Draft + +## Status + +PROPOSED Partially Implemented + +## Abstract + +Recent work in the SDK aimed at breaking apart the monolithic root go module has highlighted +shortcomings and inconsistencies in our testing paradigm. This ADR clarifies a common +language for talking about test scopes and proposes an ideal state of tests at each scope. + +## Context + +[ADR-053: Go Module Refactoring](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-053-go-module-refactoring.md) expresses our desire for an SDK composed of many +independently versioned Go modules, and [ADR-057: App Wiring Part I](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-057-app-wiring-1.md) offers a methodology +for breaking apart inter-module dependencies through the use of dependency injection. As +described in [EPIC: Separate all SDK modules into standalone go modules](https://github.com/cosmos/cosmos-sdk/issues/11899), module +dependencies are particularly complected in the test phase, where simapp is used as +the key test fixture in setting up and running tests. It is clear that the successful +completion of Phases 3 and 4 in that EPIC require the resolution of this dependency problem. + +In [EPIC: Unit Testing of Modules via Mocks](https://github.com/cosmos/cosmos-sdk/issues/12398) it was thought this Gordian knot could be +unwound by mocking all dependencies in the test phase for each module, but seeing how these +refactors were complete rewrites of test suites discussions began around the fate of the +existing integration tests. One perspective is that they ought to be thrown out, another is +that integration tests have some utility of their own and a place in the SDK's testing story. + +Another point of confusion has been the current state of CLI test suites, [x/auth](https://github.com/cosmos/cosmos-sdk/blob/0f7e56c6f9102cda0ca9aba5b6f091dbca976b5a/x/auth/client/testutil/suite.go#L44-L49) for +example. In code these are called integration tests, but in reality function as end to end +tests by starting up a tendermint node and full application. [EPIC: Rewrite and simplify +CLI tests](https://github.com/cosmos/cosmos-sdk/issues/12696) identifies the ideal state of CLI tests using mocks, but does not address the +place end to end tests may have in the SDK. + +From here we identify three scopes of testing, **unit**, **integration**, **e2e** (end to +end), seek to define the boundaries of each, their shortcomings (real and imposed), and their +ideal state in the SDK. + +### Unit tests + +Unit tests exercise the code contained in a single module (e.g. `/x/bank`) or package +(e.g. `/client`) in isolation from the rest of the code base. Within this we identify two +levels of unit tests, *illustrative* and *journey*. The definitions below lean heavily on +[The BDD Books - Formulation](https://leanpub.com/bddbooks-formulation) section 1.3. + +*Illustrative* tests exercise an atomic part of a module in isolation - in this case we +might do fixture setup/mocking of other parts of the module. + +Tests which exercise a whole module's function with dependencies mocked, are *journeys*. +These are almost like integration tests in that they exercise many things together but still +use mocks. + +Example 1 journey vs illustrative tests - [depinject's BDD style tests](https://github.com/cosmos/cosmos-sdk/blob/main/depinject/features/bindings.feature), show how we can +rapidly build up many illustrative cases demonstrating behavioral rules without [very much +code](https://github.com/cosmos/cosmos-sdk/blob/main/depinject/binding_test.go) while maintaining high level readability. + +Example 2 [depinject table driven tests](https://github.com/cosmos/cosmos-sdk/blob/main/depinject/provider_desc_test.go) + +Example 3 [Bank keeper tests](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/x/bank/keeper/keeper_test.go#L94-L105) - A mock implementation of `AccountKeeper` is +supplied to the keeper constructor. + +#### Limitations + +Certain modules are tightly coupled beyond the test phase. A recent dependency report for +`bank -> auth` found 274 total usages of `auth` in `bank`, 50 of which are in +production code and 224 in test. This tight coupling may suggest that either the modules +should be merged, or refactoring is required to abstract references to the core types tying +the modules together. It could also indicate that these modules should be tested together +in integration tests beyond mocked unit tests. + +In some cases setting up a test case for a module with many mocked dependencies can be quite +cumbersome and the resulting test may only show that the mocking framework works as expected +rather than working as a functional test of interdependent module behavior. + +### Integration tests + +Integration tests define and exercise relationships between an arbitrary number of modules +and/or application subsystems. + +Wiring for integration tests is provided by `depinject` and some [helper code](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/testutil/sims/app_helpers.go#L95) starts up +a running application. A section of the running application may then be tested. Certain +inputs during different phases of the application life cycle are expected to produce +invariant outputs without too much concern for component internals. This type of black box +testing has a larger scope than unit testing. + +Example 1 [client/grpc_query_test/TestGRPCQuery](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/client/grpc_query_test.go#L111-L129) - This test is misplaced in `/client`, +but tests the life cycle of (at least) `runtime` and `bank` as they progress through +startup, genesis and query time. It also exercises the fitness of the client and query +server without putting bytes on the wire through the use of [QueryServiceTestHelper](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/baseapp/grpcrouter_helpers.go#L31). + +Example 2 `x/evidence` Keeper integration tests - Starts up an application composed of [8 +modules](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/x/evidence/testutil/app.yaml#L1) with [5 keepers](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/x/evidence/keeper/keeper_test.go#L101-L106) used in the integration test suite. One test in the suite +exercises [HandleEquivocationEvidence](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/x/evidence/keeper/infraction_test.go#L42) which contains many interactions with the staking +keeper. + +Example 3 - Integration suite app configurations may also be specified via golang (not +YAML as above) [statically](https://github.com/cosmos/cosmos-sdk/blob/main/x/nft/testutil/app_config.go) or [dynamically](https://github.com/cosmos/cosmos-sdk/blob/8c23f6f957d1c0bedd314806d1ac65bea59b084c/tests/integration/bank/keeper/keeper_test.go#L129-L134). + +#### Limitations + +Setting up a particular input state may be more challenging since the application is +starting from a zero state. Some of this may be addressed by good test fixture +abstractions with testing of their own. Tests may also be more brittle, and larger +refactors could impact application initialization in unexpected ways with harder to +understand errors. This could also be seen as a benefit, and indeed the SDK's current +integration tests were helpful in tracking down logic errors during earlier stages +of app-wiring refactors. + +### Simulations + +Simulations (also called generative testing) are a special case of integration tests where +deterministically random module operations are executed against a running simapp, building +blocks on the chain until a specified height is reached. No *specific* assertions are +made for the state transitions resulting from module operations but any error will halt and +fail the simulation. Since `crisis` is included in simapp and the simulation runs +EndBlockers at the end of each block any module invariant violations will also fail +the simulation. + +Modules must implement [AppModuleSimulation.WeightedOperations](https://github.com/cosmos/cosmos-sdk/blob/2bec9d2021918650d3938c3ab242f84289daef80/types/module/simulation.go#L31) to define their +simulation operations. Note that not all modules implement this which may indicate a +gap in current simulation test coverage. + +Modules not returning simulation operations: + +- `auth` +- `capability` +- `evidence` +- `mint` +- `params` + +A separate binary, [runsim](https://github.com/cosmos/tools/tree/master/cmd/runsim), is responsible for kicking off some of these tests and +managing their life cycle. + +#### Limitations + +- [A success](https://github.com/cosmos/cosmos-sdk/runs/7606931983?check_suite_focus=true) may take a long time to run, 7-10 minutes per simulation in CI. +- [Timeouts](https://github.com/cosmos/cosmos-sdk/runs/7606932295?check_suite_focus=true) sometimes occur on apparent successes without any indication why. +- Useful error messages not provided on [failure](https://github.com/cosmos/cosmos-sdk/runs/7606932548?check_suite_focus=true) from CI, requiring a developer to run + the simulation locally to reproduce. + +### E2E tests + +End to end tests exercise the entire system as we understand it in as close an approximation +to a production environment as is practical. Presently these tests are located at +[tests/e2e](https://github.com/cosmos/cosmos-sdk/tree/main/tests/e2e) and rely on [testutil/network](https://github.com/cosmos/cosmos-sdk/tree/main/testutil/network) to start up an in-process Tendermint node. + +#### Limitations + +In general the limitations of end to end tests are orchestration and compute cost. +Scaffolding is required to start up and run a prod-like environment and the this +process takes much longer to start and run than unit or integration tests. + +Global locks present in Tendermint code cause stateful starting/stopping to sometimes hang +or fail intermittently when run in a CI environment. + +The scope of e2e tests has been complected with command line interface testing. + +## Decision + +We accept these test scopes and identify the following decisions points for each. + +| Scope | App Fixture | Mocks? | +|-------------|-------------|--------| +| Unit | None | Yes | +| Integration | depinject | Some | +| Simulation | simapp | No | +| E2E | simapp | No | + +#### Unit Tests + +All modules must have mocked unit test coverage. + +Illustrative tests should outnumber journeys in unit tests. + +~BDD feature tests are recommended when building up illustrative and journey scenarios.~ + +Unit tests should outnumber integration tests. + +Unit tests must not introduce additional dependencies beyond those already present in +production code. + +When module unit test introduction as per [EPIC: Unit testing of modules via mocks](https://github.com/cosmos/cosmos-sdk/issues/12398) +results in a near complete rewrite of an integration test suite the test suite should be +retained and moved to `/tests/integration`. We accept the resulting test logic +duplication but recommend improving the unit test suite through the addition of +illustrative tests. + +#### Integration Tests + +All integration tests shall be located in `/tests/integration`, even those which do not +introduce extra module dependencies. + +To help limit scope and complexity, it is recommended to use the smallest possible number of +modules in application startup, i.e. don't depend on simapp. + +Integration tests should outnumber e2e tests. + +#### Simulations + +Simulations shall startup and test simapp directly. + +#### E2E Tests + +Existing e2e tests shall be migrated to integration tests by removing the dependency on the +test network and in-process Tendermint node to ensure we do not lose test coverage. + +The e2e rest runner shall transition from in process Tendermint to a runner powered by +Docker via [dockertest](https://github.com/ory/dockertest). + +E2E tests exercising a full network upgrade shall be written. + +The CLI testing aspect of existing e2e tests shall be rewritten using the network mocking +demonstrated in [PR#12706](https://github.com/cosmos/cosmos-sdk/pull/12706). + +## Consequences + +### Positive + +- test coverage is increased +- test organization is improved +- reduced dependency graph size in modules +- simapp removed as a dependency from modules +- inter-module dependencies introduced in test code are removed +- reduced CI run time after transitioning away from in process Tendermint + +### Negative + +- some test logic duplication between unit and integration tests during transition +- test written using dockertest DX may be a bit worse + +### Neutral + +- learning curve for BDD style tests +- some discovery required for e2e transition to dockertest + +## Further Discussions + +It may be useful if test suites could be run in integration mode (with mocked tendermint) or +with e2e fixtures (with real tendermint and many nodes). Integration fixtures could be used +for quicker runs, e2e fixures could be used for more battle hardening. + +A PoC is in progress for `x/gov` unit tests demonstrating BDD, helping to determine if +BDD feature tests are recommended when building up illustrative and journey scenarios. + +Levels are network mocking in integration and e2e tests are still being worked on and formalized. From 33517402b231193999427d7cf11a97739622036d Mon Sep 17 00:00:00 2001 From: Esse0404 <97712232+Esse0404@users.noreply.github.com> Date: Thu, 4 Aug 2022 22:27:50 +0200 Subject: [PATCH 06/10] docs: ">" command isn't working properly (#12826) ">" generate a blank file without the output better use --output-document ## Description Closes: #XXXX --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- docs/run-node/txs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/run-node/txs.md b/docs/run-node/txs.md index 59995a267b06..102250d1796b 100644 --- a/docs/run-node/txs.md +++ b/docs/run-node/txs.md @@ -42,7 +42,7 @@ Signing a transaction using the CLI requires the unsigned transaction to be save simd tx sign unsigned_tx.json --chain-id my-test-chain --keyring-backend test --from $MY_VALIDATOR_ADDRESS ``` -This command will decode the unsigned transaction and sign it with `SIGN_MODE_DIRECT` with `$MY_VALIDATOR_ADDRESS`'s key, which we already set up in the keyring. The signed transaction will be output as JSON to the console, and, as above, we can save it to a file by appending `> signed_tx.json`. +This command will decode the unsigned transaction and sign it with `SIGN_MODE_DIRECT` with `$MY_VALIDATOR_ADDRESS`'s key, which we already set up in the keyring. The signed transaction will be output as JSON to the console, and, as above, we can save it to a file by appending `--output-document signed_tx.json`. Some useful flags to consider in the `tx sign` command: From e39d84e06fafc33dcec85db12242e5f481ed0385 Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Fri, 5 Aug 2022 01:03:08 -0700 Subject: [PATCH 07/10] fix: tx/textual/valuerenderer: reject non-digits in dec + int (#12817) --- tx/textual/valuerenderer/bench_test.go | 35 +++++++++++++++++++++++--- tx/textual/valuerenderer/dec.go | 14 ++++++++--- tx/textual/valuerenderer/dec_test.go | 35 ++++++++++++++++++++++++++ tx/textual/valuerenderer/int.go | 17 +++++++++++++ tx/textual/valuerenderer/int_test.go | 35 ++++++++++++++++++++++++++ 5 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 tx/textual/valuerenderer/dec_test.go create mode 100644 tx/textual/valuerenderer/int_test.go diff --git a/tx/textual/valuerenderer/bench_test.go b/tx/textual/valuerenderer/bench_test.go index fd485fbd7643..5ce072ef2ea0 100644 --- a/tx/textual/valuerenderer/bench_test.go +++ b/tx/textual/valuerenderer/bench_test.go @@ -9,6 +9,35 @@ import ( ) var intValues = []protoreflect.Value{ + protoreflect.ValueOfString("1000"), + protoreflect.ValueOfString("99900"), + protoreflect.ValueOfString("9999999"), + protoreflect.ValueOfString("999999999999"), + protoreflect.ValueOfString("9999999999999999999"), + protoreflect.ValueOfString("100000000000000000000000000000000000000000000000000000000"), + protoreflect.ValueOfString("77777777777777777777777777777777700"), + protoreflect.ValueOfString("-77777777777777777777777777777777700"), + protoreflect.ValueOfString("77777777777777777777777777777777700"), +} + +func BenchmarkIntValueRendererFormat(b *testing.B) { + ctx := context.Background() + ivr := new(intValueRenderer) + buf := new(bytes.Buffer) + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + for _, value := range intValues { + if err := ivr.Format(ctx, value, buf); err != nil { + b.Fatal(err) + } + } + buf.Reset() + } +} + +var decimalValues = []protoreflect.Value{ protoreflect.ValueOfString("10.00"), protoreflect.ValueOfString("999.00"), protoreflect.ValueOfString("999.9999"), @@ -20,16 +49,16 @@ var intValues = []protoreflect.Value{ protoreflect.ValueOfString("777777777777777777777777.77777777700"), } -func BenchmarkIntValueRendererFormat(b *testing.B) { +func BenchmarkDecimalValueRendererFormat(b *testing.B) { ctx := context.Background() - ivr := new(intValueRenderer) + dvr := new(decValueRenderer) buf := new(bytes.Buffer) b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { for _, value := range intValues { - if err := ivr.Format(ctx, value, buf); err != nil { + if err := dvr.Format(ctx, value, buf); err != nil { b.Fatal(err) } } diff --git a/tx/textual/valuerenderer/dec.go b/tx/textual/valuerenderer/dec.go index 5ea72e110d38..6c26876613b0 100644 --- a/tx/textual/valuerenderer/dec.go +++ b/tx/textual/valuerenderer/dec.go @@ -34,15 +34,15 @@ func (vr decValueRenderer) Parse(_ context.Context, r io.Reader) (protoreflect.V // object). func formatDecimal(v string) (string, error) { parts := strings.Split(v, ".") + if len(parts) > 2 { + return "", fmt.Errorf("invalid decimal: too many points in %s", v) + } + intPart, err := formatInteger(parts[0]) if err != nil { return "", err } - if len(parts) > 2 { - return "", fmt.Errorf("invalid decimal %s", v) - } - if len(parts) == 1 { return intPart, nil } @@ -52,5 +52,11 @@ func formatDecimal(v string) (string, error) { return intPart, nil } + // Ensure that the decimal part has only digits. + // https://github.com/cosmos/cosmos-sdk/issues/12811 + if !hasOnlyDigits(decPart) { + return "", fmt.Errorf("non-digits detected after decimal point in: %q", decPart) + } + return intPart + "." + decPart, nil } diff --git a/tx/textual/valuerenderer/dec_test.go b/tx/textual/valuerenderer/dec_test.go new file mode 100644 index 000000000000..187c6fd55139 --- /dev/null +++ b/tx/textual/valuerenderer/dec_test.go @@ -0,0 +1,35 @@ +package valuerenderer + +import ( + "strings" + "testing" +) + +func TestFormatDecimalNonDigits(t *testing.T) { + badCases := []string{ + "10.a", + "1a.10", + "p1a10.", + "0.10p", + "--10", + "12.😎😎", + "11111111111133333333333333333333333333333a", + "11111111111133333333333333333333333333333 192892", + } + + for _, value := range badCases { + value := value + t.Run(value, func(t *testing.T) { + s, err := formatDecimal(value) + if err == nil { + t.Fatal("Expected an error") + } + if g, w := err.Error(), "non-digits"; !strings.Contains(g, w) { + t.Errorf("Error mismatch\nGot: %q\nWant substring: %q", g, w) + } + if s != "" { + t.Fatalf("Got a non-empty string: %q", s) + } + }) + } +} diff --git a/tx/textual/valuerenderer/int.go b/tx/textual/valuerenderer/int.go index 476dbe2b4b0c..572f3b9b170a 100644 --- a/tx/textual/valuerenderer/int.go +++ b/tx/textual/valuerenderer/int.go @@ -2,6 +2,7 @@ package valuerenderer import ( "context" + "fmt" "io" "strings" @@ -26,6 +27,18 @@ func (vr intValueRenderer) Parse(_ context.Context, r io.Reader) (protoreflect.V panic("implement me") } +func hasOnlyDigits(s string) bool { + if s == "" { + return false + } + for _, r := range s { + if r < '0' || r > '9' { + return false + } + } + return true +} + // formatInteger formats an integer into a value-rendered string. This function // operates with string manipulation (instead of manipulating the int or sdk.Int // object). @@ -37,7 +50,11 @@ func formatInteger(v string) (string, error) { } if len(v) > 1 { v = strings.TrimLeft(v, "0") + } + // Ensure that the string contains only digits at this point. + if !hasOnlyDigits(v) { + return "", fmt.Errorf("expecting only digits 0-9, but got non-digits in %q", v) } startOffset := 3 diff --git a/tx/textual/valuerenderer/int_test.go b/tx/textual/valuerenderer/int_test.go new file mode 100644 index 000000000000..4e30599faf17 --- /dev/null +++ b/tx/textual/valuerenderer/int_test.go @@ -0,0 +1,35 @@ +package valuerenderer + +import ( + "strings" + "testing" +) + +func TestFormatIntegerNonDigits(t *testing.T) { + badCases := []string{ + "a10", + "1a10", + "p1a10", + "10p", + "--10", + "😎😎", + "11111111111133333333333333333333333333333a", + "11111111111133333333333333333333333333333 192892", + } + + for _, value := range badCases { + value := value + t.Run(value, func(t *testing.T) { + s, err := formatInteger(value) + if err == nil { + t.Fatal("Expected an error") + } + if g, w := err.Error(), "but got non-digits in"; !strings.Contains(g, w) { + t.Errorf("Error mismatch\nGot: %q\nWant substring: %q", g, w) + } + if s != "" { + t.Fatalf("Got a non-empty string: %q", s) + } + }) + } +} From 5f9e7e6ea6b49208c5aed1f38dd8715b060f1a9c Mon Sep 17 00:00:00 2001 From: JooHyung Kim <14wnrkim@gmail.com> Date: Sat, 6 Aug 2022 00:17:24 +0900 Subject: [PATCH 08/10] refactor: x/distr module create querier (#12829) Co-authored-by: Aleksandr Bezobchuk --- x/distribution/keeper/grpc_query.go | 28 +++++++++++++++--------- x/distribution/keeper/grpc_query_test.go | 4 ++-- x/distribution/module.go | 2 +- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/x/distribution/keeper/grpc_query.go b/x/distribution/keeper/grpc_query.go index 2daceeafbc08..c511b5240251 100644 --- a/x/distribution/keeper/grpc_query.go +++ b/x/distribution/keeper/grpc_query.go @@ -14,10 +14,18 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) -var _ types.QueryServer = Keeper{} +var _ types.QueryServer = Querier{} + +type Querier struct { + Keeper +} + +func NewQuerier(keeper Keeper) Querier { + return Querier{Keeper: keeper} +} // Params queries params of distribution module -func (k Keeper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { +func (k Querier) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { ctx := sdk.UnwrapSDKContext(c) params := k.GetParams(ctx) @@ -25,7 +33,7 @@ func (k Keeper) Params(c context.Context, req *types.QueryParamsRequest) (*types } // ValidatorOutstandingRewards queries rewards of a validator address -func (k Keeper) ValidatorOutstandingRewards(c context.Context, req *types.QueryValidatorOutstandingRewardsRequest) (*types.QueryValidatorOutstandingRewardsResponse, error) { +func (k Querier) ValidatorOutstandingRewards(c context.Context, req *types.QueryValidatorOutstandingRewardsRequest) (*types.QueryValidatorOutstandingRewardsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -46,7 +54,7 @@ func (k Keeper) ValidatorOutstandingRewards(c context.Context, req *types.QueryV } // ValidatorCommission queries accumulated commission for a validator -func (k Keeper) ValidatorCommission(c context.Context, req *types.QueryValidatorCommissionRequest) (*types.QueryValidatorCommissionResponse, error) { +func (k Querier) ValidatorCommission(c context.Context, req *types.QueryValidatorCommissionRequest) (*types.QueryValidatorCommissionResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -67,7 +75,7 @@ func (k Keeper) ValidatorCommission(c context.Context, req *types.QueryValidator } // ValidatorSlashes queries slash events of a validator -func (k Keeper) ValidatorSlashes(c context.Context, req *types.QueryValidatorSlashesRequest) (*types.QueryValidatorSlashesResponse, error) { +func (k Querier) ValidatorSlashes(c context.Context, req *types.QueryValidatorSlashesRequest) (*types.QueryValidatorSlashesResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -110,7 +118,7 @@ func (k Keeper) ValidatorSlashes(c context.Context, req *types.QueryValidatorSla } // DelegationRewards the total rewards accrued by a delegation -func (k Keeper) DelegationRewards(c context.Context, req *types.QueryDelegationRewardsRequest) (*types.QueryDelegationRewardsResponse, error) { +func (k Querier) DelegationRewards(c context.Context, req *types.QueryDelegationRewardsRequest) (*types.QueryDelegationRewardsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -151,7 +159,7 @@ func (k Keeper) DelegationRewards(c context.Context, req *types.QueryDelegationR } // DelegationTotalRewards the total rewards accrued by a each validator -func (k Keeper) DelegationTotalRewards(c context.Context, req *types.QueryDelegationTotalRewardsRequest) (*types.QueryDelegationTotalRewardsResponse, error) { +func (k Querier) DelegationTotalRewards(c context.Context, req *types.QueryDelegationTotalRewardsRequest) (*types.QueryDelegationTotalRewardsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -188,7 +196,7 @@ func (k Keeper) DelegationTotalRewards(c context.Context, req *types.QueryDelega } // DelegatorValidators queries the validators list of a delegator -func (k Keeper) DelegatorValidators(c context.Context, req *types.QueryDelegatorValidatorsRequest) (*types.QueryDelegatorValidatorsResponse, error) { +func (k Querier) DelegatorValidators(c context.Context, req *types.QueryDelegatorValidatorsRequest) (*types.QueryDelegatorValidatorsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -216,7 +224,7 @@ func (k Keeper) DelegatorValidators(c context.Context, req *types.QueryDelegator } // DelegatorWithdrawAddress queries Query/delegatorWithdrawAddress -func (k Keeper) DelegatorWithdrawAddress(c context.Context, req *types.QueryDelegatorWithdrawAddressRequest) (*types.QueryDelegatorWithdrawAddressResponse, error) { +func (k Querier) DelegatorWithdrawAddress(c context.Context, req *types.QueryDelegatorWithdrawAddressRequest) (*types.QueryDelegatorWithdrawAddressResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -236,7 +244,7 @@ func (k Keeper) DelegatorWithdrawAddress(c context.Context, req *types.QueryDele } // CommunityPool queries the community pool coins -func (k Keeper) CommunityPool(c context.Context, req *types.QueryCommunityPoolRequest) (*types.QueryCommunityPoolResponse, error) { +func (k Querier) CommunityPool(c context.Context, req *types.QueryCommunityPoolRequest) (*types.QueryCommunityPoolResponse, error) { ctx := sdk.UnwrapSDKContext(c) pool := k.GetFeePoolCommunityCoins(ctx) diff --git a/x/distribution/keeper/grpc_query_test.go b/x/distribution/keeper/grpc_query_test.go index ec63e72c3b52..60dd9648d8d6 100644 --- a/x/distribution/keeper/grpc_query_test.go +++ b/x/distribution/keeper/grpc_query_test.go @@ -52,7 +52,7 @@ func (suite *KeeperTestSuite) SetupTest() { ctx := app.BaseApp.NewContext(false, tmproto.Header{}) queryHelper := baseapp.NewQueryServerTestHelper(ctx, suite.interfaceRegistry) - types.RegisterQueryServer(queryHelper, suite.distrKeeper) + types.RegisterQueryServer(queryHelper, keeper.NewQuerier(suite.distrKeeper)) queryClient := types.NewQueryClient(queryHelper) suite.ctx = ctx @@ -370,7 +370,7 @@ func (suite *KeeperTestSuite) TestGRPCDelegationRewards() { ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) queryHelper := baseapp.NewQueryServerTestHelper(ctx, suite.interfaceRegistry) - types.RegisterQueryServer(queryHelper, suite.distrKeeper) + types.RegisterQueryServer(queryHelper, keeper.NewQuerier(suite.distrKeeper)) queryClient := types.NewQueryClient(queryHelper) val := suite.stakingKeeper.Validator(ctx, valAddrs[0]) diff --git a/x/distribution/module.go b/x/distribution/module.go index 26372bd876c2..068f50fcee9f 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -135,7 +135,7 @@ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { // RegisterServices registers module services. func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) - types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) m := keeper.NewMigrator(am.keeper, am.legacySubspace) if err := cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2); err != nil { From 78e71f1d939256875ccf0171a5aa329114bb3356 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Aug 2022 22:17:20 +0000 Subject: [PATCH 09/10] build(deps): Bump github.com/golangci/golangci-lint from 1.47.3 to 1.48.0 (#12832) Bumps [github.com/golangci/golangci-lint](https://github.com/golangci/golangci-lint) from 1.47.3 to 1.48.0.
Release notes

Sourced from github.com/golangci/golangci-lint's releases.

v1.48.0

Changelog

  • 368c41cd build(deps): bump github.com/daixiang0/gci from 0.5.0 to 0.6.0 (#3035)
  • 2d8fea81 build(deps): bump github.com/daixiang0/gci from 0.6.0 to 0.6.2 (#3058)
  • aeb5860c build(deps): bump github.com/kisielk/errcheck from 1.6.1 to 1.6.2 (#3059)
  • 0559b922 build(deps): bump revgrep to HEAD (#3054)
  • 6313fa9a contextcheck: disable linter (#3050)
  • 0ba1388a feat: add usestdlibvars (#3016)
  • 1557692e feat: go1.19 support (#3037)
  • 15cba447 gci: add missing custom-order setting (#3052)
  • 9a1b9492 ifshort: deprecate linter (#3034)
  • f8f8f9a6 nolint: drop allow-leading-space option and add "nolint:all" (#3002)
Changelog

Sourced from github.com/golangci/golangci-lint's changelog.

v1.48.0

  1. new linters
  2. updated linters
    • contextcheck: disable linter
    • errcheck: from 1.6.1 to 1.6.2
    • gci: add missing custom-order setting
    • gci: from 0.5.0 to 0.6.0
    • ifshort: deprecate linter
    • nolint: drop allow-leading-space option and add "nolint:all"
    • revgrep: bump to HEAD
  3. documentation
    • remove outdated info on source install
  4. misc
    • go1.19 support
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/golangci/golangci-lint&package-manager=go_modules&previous-version=1.47.3&new-version=1.48.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- go.mod | 9 +++++---- go.sum | 16 ++++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 65082cf81cd7..5ee7fd883d3a 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 - github.com/golangci/golangci-lint v1.47.3 + github.com/golangci/golangci-lint v1.48.0 github.com/google/uuid v1.3.0 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 @@ -103,7 +103,7 @@ require ( github.com/cosmos/gorocksdb v1.2.0 // indirect github.com/cosmos/ledger-go v0.9.2 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect - github.com/daixiang0/gci v0.5.0 // indirect + github.com/daixiang0/gci v0.6.2 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/denis-tingaikin/go-header v0.4.3 // indirect @@ -147,7 +147,7 @@ require ( github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect github.com/golangci/misspell v0.3.5 // indirect - github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 // indirect + github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/go-cmp v0.5.8 // indirect @@ -177,7 +177,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/julz/importas v0.1.0 // indirect - github.com/kisielk/errcheck v1.6.1 // indirect + github.com/kisielk/errcheck v1.6.2 // indirect github.com/kisielk/gotool v1.0.0 // indirect github.com/klauspost/compress v1.15.1 // indirect github.com/kulti/thelper v0.6.3 // indirect @@ -227,6 +227,7 @@ require ( github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect + github.com/sashamelentyev/usestdlibvars v1.8.0 // indirect github.com/securego/gosec/v2 v2.12.0 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/sirupsen/logrus v1.9.0 // indirect diff --git a/go.sum b/go.sum index f1a8b79ab2bd..3392333b9288 100644 --- a/go.sum +++ b/go.sum @@ -322,8 +322,8 @@ github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbd github.com/cucumber/common/messages/go/v17 v17.1.1 h1:RNqopvIFyLWnKv0LfATh34SWBhXeoFTJnSrgm9cT/Ts= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/daixiang0/gci v0.4.2/go.mod h1:d0f+IJhr9loBtIq+ebwhRoTt1LGbPH96ih8bKlsRT9E= -github.com/daixiang0/gci v0.5.0 h1:3+Z8nb/4dhJQYjpEbG4wt5na+KFJJTZ++PVEq/MVKX4= -github.com/daixiang0/gci v0.5.0/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= +github.com/daixiang0/gci v0.6.2 h1:TXCP5RqjE/UupXO+p33MEhqdv7QxjKGw5MVkt9ATiMs= +github.com/daixiang0/gci v0.6.2/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -555,16 +555,17 @@ github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPSh github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks= github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= github.com/golangci/golangci-lint v1.47.0/go.mod h1:3TZhfF5KolbIkXYjUFvER6G9CoxzLEaafr/u/QI1S5A= -github.com/golangci/golangci-lint v1.47.3 h1:ri7A2DgtFpxgqcMSsU3qIT0IBm/SCdYgXlvmJx4szUU= -github.com/golangci/golangci-lint v1.47.3/go.mod h1:IvT5xyPX1W8JUJJrV60gcMzgQe1ttW/38yAzn6LuHOk= +github.com/golangci/golangci-lint v1.48.0 h1:hRiBNk9iRqdAKMa06ntfEiLyza1/3IE9rHLNJaek4a8= +github.com/golangci/golangci-lint v1.48.0/go.mod h1:5N+oxduCho+7yuccW69upg/O7cxjfR/d+IQeiNxGmKM= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo= github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= -github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 h1:SgM7GDZTxtTTQPU84heOxy34iG5Du7F2jcoZnvp+fXI= github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= +github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ= +github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -817,8 +818,9 @@ github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSX github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/errcheck v1.6.1 h1:cErYo+J4SmEjdXZrVXGwLJCE2sB06s23LpkcyWNrT+s= github.com/kisielk/errcheck v1.6.1/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= +github.com/kisielk/errcheck v1.6.2 h1:uGQ9xI8/pgc9iOoCe7kWQgRE6SBTrCGmTSf0LrEtY7c= +github.com/kisielk/errcheck v1.6.2/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= @@ -1200,6 +1202,8 @@ github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3 github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sashamelentyev/usestdlibvars v1.8.0 h1:QnWP9IOEuRyYKH+IG0LlQIjuJlc0rfdo4K3/Zh3WRMw= +github.com/sashamelentyev/usestdlibvars v1.8.0/go.mod h1:BFt7b5mSVHaaa26ZupiNRV2ODViQBxZZVhtAxAJRrjs= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= From fe892125098a1aaa6b91a206940eeaf3098f7d88 Mon Sep 17 00:00:00 2001 From: Ari Rubinstein Date: Sun, 7 Aug 2022 01:20:56 -0700 Subject: [PATCH 10/10] fix(docs): typo in staking/state (#12834) --- x/staking/spec/01_state.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/staking/spec/01_state.md b/x/staking/spec/01_state.md index 3c01cce247d5..57dfc7f4ef56 100644 --- a/x/staking/spec/01_state.md +++ b/x/staking/spec/01_state.md @@ -30,7 +30,7 @@ Validators can have one of three statuses * `Unbonded`: The validator is not in the active set. They cannot sign blocks and do not earn rewards. They can receive delegations. -* `Bonded`": Once the validator receives sufficient bonded tokens they automtically join the +* `Bonded`: Once the validator receives sufficient bonded tokens they automtically join the active set during [`EndBlock`](./05_end_block.md#validator-set-changes) and their status is updated to `Bonded`. They are signing blocks and receiving rewards. They can receive further delegations. They can be slashed for misbehavior. Delegators to this validator who unbond their delegation