feat(x/distribution): add autocli config query (backport #16218) (#16594)

Co-authored-by: Jeancarlo Barrios <JeancarloBarrios@users.noreply.github.com>
This commit is contained in:
mergify[bot] 2023-06-16 16:21:15 +02:00 committed by GitHub
parent ae3e30a715
commit feab9b6380
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 179 additions and 1262 deletions

View File

@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements
* (all) [#16497](https://github.com/cosmos/cosmos-sdk/pull/16497) Removed all exported vestiges of `sdk.MustSortJSON` and `sdk.SortJSON`.
* (x/distribution) [#16218](https://github.com/cosmos/cosmos-sdk/pull/16218) Add Autocli config to distribution module.
### Bug Fixes

View File

@ -3,10 +3,11 @@ package distribution
import (
"fmt"
"cosmossdk.io/simapp"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/suite"
"cosmossdk.io/simapp"
sdktestutil "github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"

View File

@ -4,14 +4,14 @@ import (
"context"
"encoding/hex"
"fmt"
"strings"
"time"
"cosmossdk.io/math"
"cosmossdk.io/simapp"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/suite"
"cosmossdk.io/simapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec/address"
@ -72,430 +72,6 @@ func (s *E2ETestSuite) TearDownSuite() {
s.network.Cleanup()
}
func (s *E2ETestSuite) TestGetCmdQueryParams() {
val := s.network.Validators[0]
testCases := []struct {
name string
args []string
expectedOutput string
}{
{
"json output",
[]string{fmt.Sprintf("--%s=json", flags.FlagOutput)},
`{"community_tax":"0.020000000000000000","base_proposer_reward":"0.000000000000000000","bonus_proposer_reward":"0.000000000000000000","withdraw_addr_enabled":true}`,
},
{
"text output",
[]string{fmt.Sprintf("--%s=text", flags.FlagOutput)},
`base_proposer_reward: "0.000000000000000000"
bonus_proposer_reward: "0.000000000000000000"
community_tax: "0.020000000000000000"
withdraw_addr_enabled: true`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryParams()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
})
}
}
func (s *E2ETestSuite) TestGetCmdQueryValidatorDistributionInfo() {
val := s.network.Validators[0]
testCases := []struct {
name string
args []string
expErr bool
}{
{
"invalid val address",
[]string{"invalid address", fmt.Sprintf("--%s=json", flags.FlagOutput)},
true,
},
{
"json output",
[]string{val.ValAddress.String(), fmt.Sprintf("--%s=json", flags.FlagOutput)},
false,
},
{
"text output",
[]string{val.ValAddress.String(), fmt.Sprintf("--%s=text", flags.FlagOutput)},
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryValidatorDistributionInfo()
clientCtx := val.ClientCtx
_, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
}
})
}
}
func (s *E2ETestSuite) TestGetCmdQueryValidatorOutstandingRewards() {
val := s.network.Validators[0]
_, err := s.network.WaitForHeight(4)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"invalid validator address",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
"foo",
},
true,
"",
},
{
"json output",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val.Address).String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
`{"rewards":[{"denom":"stake","amount":"232.260000000000000000"}]}`,
},
{
"text output",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val.Address).String(),
},
false,
`rewards:
- amount: "232.260000000000000000"
denom: stake`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryValidatorOutstandingRewards()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
}
})
}
}
func (s *E2ETestSuite) TestGetCmdQueryValidatorCommission() {
val := s.network.Validators[0]
_, err := s.network.WaitForHeight(4)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"invalid validator address",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
"foo",
},
true,
"",
},
{
"json output",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val.Address).String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
`{"commission":[{"denom":"stake","amount":"116.130000000000000000"}]}`,
},
{
"text output",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val.Address).String(),
},
false,
`commission:
- amount: "116.130000000000000000"
denom: stake`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryValidatorCommission()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
}
})
}
}
func (s *E2ETestSuite) TestGetCmdQueryValidatorSlashes() {
val := s.network.Validators[0]
_, err := s.network.WaitForHeight(4)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"invalid validator address",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
"foo", "1", "3",
},
true,
"",
},
{
"invalid start height",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val.Address).String(), "-1", "3",
},
true,
"",
},
{
"invalid end height",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val.Address).String(), "1", "-3",
},
true,
"",
},
{
"json output",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val.Address).String(), "1", "3",
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
"{\"slashes\":[],\"pagination\":{\"next_key\":null,\"total\":\"0\"}}",
},
{
"text output",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val.Address).String(), "1", "3",
},
false,
"pagination:\n next_key: null\n total: \"0\"\nslashes: []",
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryValidatorSlashes()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
}
})
}
}
func (s *E2ETestSuite) TestGetCmdQueryDelegatorRewards() {
val := s.network.Validators[0]
addr := val.Address
valAddr := sdk.ValAddress(addr)
_, err := s.network.WaitForHeightWithTimeout(11, time.Minute)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"invalid delegator address",
[]string{
fmt.Sprintf("--%s=5", flags.FlagHeight),
"foo", valAddr.String(),
},
true,
"",
},
{
"invalid validator address",
[]string{
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(), "foo",
},
true,
"",
},
{
"json output",
[]string{
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
fmt.Sprintf(`{"rewards":[{"validator_address":"%s","reward":[{"denom":"stake","amount":"193.550000000000000000"}]}],"total":[{"denom":"stake","amount":"193.550000000000000000"}]}`, valAddr.String()),
},
{
"json output (specific validator)",
[]string{
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(), valAddr.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
`{"rewards":[{"denom":"stake","amount":"193.550000000000000000"}]}`,
},
{
"text output",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(),
},
false,
fmt.Sprintf(`rewards:
- reward:
- amount: "193.550000000000000000"
denom: stake
validator_address: %s
total:
- amount: "193.550000000000000000"
denom: stake`, valAddr.String()),
},
{
"text output (specific validator)",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(), valAddr.String(),
},
false,
`rewards:
- amount: "193.550000000000000000"
denom: stake`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryDelegatorRewards(address.NewBech32Codec("cosmos"))
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
}
})
}
}
func (s *E2ETestSuite) TestGetCmdQueryCommunityPool() {
val := s.network.Validators[0]
_, err := s.network.WaitForHeight(4)
s.Require().NoError(err)
testCases := []struct {
name string
args []string
expectedOutput string
}{
{
"json output",
[]string{fmt.Sprintf("--%s=3", flags.FlagHeight), fmt.Sprintf("--%s=json", flags.FlagOutput)},
`{"pool":[{"denom":"stake","amount":"4.740000000000000000"}]}`,
},
{
"text output",
[]string{fmt.Sprintf("--%s=text", flags.FlagOutput), fmt.Sprintf("--%s=3", flags.FlagHeight)},
`pool:
- amount: "4.740000000000000000"
denom: stake`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryCommunityPool()
clientCtx := val.ClientCtx
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
})
}
}
func (s *E2ETestSuite) TestNewWithdrawRewardsCmd() {
val := s.network.Validators[0]

105
x/distribution/autocli.go Normal file
View File

@ -0,0 +1,105 @@
package distribution
import (
"fmt"
"strings"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
distirbuitonv1beta1 "cosmossdk.io/api/cosmos/distribution/v1beta1"
"github.com/cosmos/cosmos-sdk/version"
)
var (
FlagCommission = "commission"
FlagMaxMessagesPerTx = "max-msgs"
)
// AutoCLIOptions implements the autocli.HasAutoCLIConfig interface.
func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
exAccAddress, err := am.ac.BytesToString([]byte("A58856F0FD53BF058B4909A21AEC019107BA6A58856F0FD53BF058B4909A21AEC019107BA6"))
if err != nil {
panic(err)
}
return &autocliv1.ModuleOptions{
Query: &autocliv1.ServiceCommandDescriptor{
Service: distirbuitonv1beta1.Query_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Params",
Use: "params",
Short: "Query the current distribution parameters.",
},
{
RpcMethod: "ValidatorDistributionInfo",
Use: "validator-distribution-info [validator]",
Short: "Query validator distribution info",
Example: fmt.Sprintf(`Example: $ %s query distribution validator-distribution-info %s`,
version.AppName, exAccAddress,
),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "validator_address"},
},
},
{
RpcMethod: "ValidatorOutstandingRewards",
Use: "validator-outstanding-rewards [validator]",
Short: "Query distribution outstanding (un-withdrawn) rewards for a validator and all their delegations",
Example: fmt.Sprintf(`$ %s query distribution validator-outstanding-rewards [validator-address]`, version.AppName),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "validator_address"},
},
},
{
RpcMethod: "ValidatorCommission",
Use: "commission [validator]",
Short: "Query distribution validator commission",
Example: fmt.Sprintf(`$ %s query distribution commission [validator-address]`, version.AppName),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "validator_address"},
},
},
{
RpcMethod: "ValidatorSlashes",
Use: "slashes [validator] [start-height] [end-height]",
Short: "Query distribution validator slashes",
Example: fmt.Sprintf(`$ %s query distribution slashes [validator-address] 0 100`, version.AppName),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "validator_address"},
{ProtoField: "starting_height"},
{ProtoField: "ending_height"},
},
},
{
RpcMethod: "DelegationRewards",
Use: "rewards [delegator-addr] [validator-addr]",
Short: "Query all distribution delegator rewards or rewards from a particular validator",
Long: "Query all rewards earned by a delegator, optionally restrict to rewards from a single validator.",
Example: strings.TrimSpace(
fmt.Sprintf(`
$ %s query distribution rewards %s
$ %s query distribution rewards %s [validator-address]
`,
version.AppName, exAccAddress, version.AppName, exAccAddress,
),
),
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "delegator_address"},
{ProtoField: "validator_address"},
},
},
{
RpcMethod: "CommunityPool",
Use: "community-pool",
Short: "Query the amount of coins in the community pool",
Example: fmt.Sprintf(`$ %s query distribution community-pool`, version.AppName),
},
},
},
Tx: &autocliv1.ServiceCommandDescriptor{
Service: distirbuitonv1beta1.Msg_ServiceDesc.ServiceName,
},
}
}

View File

@ -1,367 +0,0 @@
package cli
import (
"fmt"
"strconv"
"strings"
"cosmossdk.io/core/address"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
)
// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd(ac address.Codec) *cobra.Command {
distQueryCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Querying commands for the distribution module",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
distQueryCmd.AddCommand(
GetCmdQueryParams(),
GetCmdQueryValidatorDistributionInfo(),
GetCmdQueryValidatorOutstandingRewards(),
GetCmdQueryValidatorCommission(),
GetCmdQueryValidatorSlashes(),
GetCmdQueryDelegatorRewards(ac),
GetCmdQueryCommunityPool(),
)
return distQueryCmd
}
// GetCmdQueryParams implements the query params command.
func GetCmdQueryParams() *cobra.Command {
cmd := &cobra.Command{
Use: "params",
Args: cobra.NoArgs,
Short: "Query distribution params",
RunE: func(cmd *cobra.Command, _ []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(&res.Params)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryValidatorDistributionInfo implements the query validator distribution info command.
func GetCmdQueryValidatorDistributionInfo() *cobra.Command {
bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()
cmd := &cobra.Command{
Use: "validator-distribution-info [validator]",
Args: cobra.ExactArgs(1),
Short: "Query validator distribution info",
Long: strings.TrimSpace(
fmt.Sprintf(`Query validator distribution info.
Example:
$ %s query distribution validator-distribution-info %s1lwjmdnks33xwnmfayc64ycprww49n33mtm92ne
`,
version.AppName, bech32PrefixValAddr,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
validatorAddr, err := sdk.ValAddressFromBech32(args[0])
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.ValidatorDistributionInfo(cmd.Context(), &types.QueryValidatorDistributionInfoRequest{
ValidatorAddress: validatorAddr.String(),
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryValidatorOutstandingRewards implements the query validator
// outstanding rewards command.
func GetCmdQueryValidatorOutstandingRewards() *cobra.Command {
bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()
cmd := &cobra.Command{
Use: "validator-outstanding-rewards [validator]",
Args: cobra.ExactArgs(1),
Short: "Query distribution outstanding (un-withdrawn) rewards for a validator and all their delegations",
Long: strings.TrimSpace(
fmt.Sprintf(`Query distribution outstanding (un-withdrawn) rewards for a validator and all their delegations.
Example:
$ %s query distribution validator-outstanding-rewards %s1lwjmdnks33xwnmfayc64ycprww49n33mtm92ne
`,
version.AppName, bech32PrefixValAddr,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
validatorAddr, err := sdk.ValAddressFromBech32(args[0])
if err != nil {
return err
}
res, err := queryClient.ValidatorOutstandingRewards(
cmd.Context(),
&types.QueryValidatorOutstandingRewardsRequest{ValidatorAddress: validatorAddr.String()},
)
if err != nil {
return err
}
return clientCtx.PrintProto(&res.Rewards)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryValidatorCommission implements the query validator commission command.
func GetCmdQueryValidatorCommission() *cobra.Command {
bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()
cmd := &cobra.Command{
Use: "commission [validator]",
Args: cobra.ExactArgs(1),
Short: "Query distribution validator commission",
Long: strings.TrimSpace(
fmt.Sprintf(`Query validator commission rewards from delegators to that validator.
Example:
$ %s query distribution commission %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj
`,
version.AppName, bech32PrefixValAddr,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
validatorAddr, err := sdk.ValAddressFromBech32(args[0])
if err != nil {
return err
}
res, err := queryClient.ValidatorCommission(
cmd.Context(),
&types.QueryValidatorCommissionRequest{ValidatorAddress: validatorAddr.String()},
)
if err != nil {
return err
}
return clientCtx.PrintProto(&res.Commission)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryValidatorSlashes implements the query validator slashes command.
func GetCmdQueryValidatorSlashes() *cobra.Command {
bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()
cmd := &cobra.Command{
Use: "slashes [validator] [start-height] [end-height]",
Args: cobra.ExactArgs(3),
Short: "Query distribution validator slashes",
Long: strings.TrimSpace(
fmt.Sprintf(`Query all slashes of a validator for a given block range.
Example:
$ %s query distribution slashes %svaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 0 100
`,
version.AppName, bech32PrefixValAddr,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
validatorAddr, err := sdk.ValAddressFromBech32(args[0])
if err != nil {
return err
}
startHeight, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return fmt.Errorf("start-height %s not a valid uint, please input a valid start-height", args[1])
}
endHeight, err := strconv.ParseUint(args[2], 10, 64)
if err != nil {
return fmt.Errorf("end-height %s not a valid uint, please input a valid end-height", args[2])
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
res, err := queryClient.ValidatorSlashes(
cmd.Context(),
&types.QueryValidatorSlashesRequest{
ValidatorAddress: validatorAddr.String(),
StartingHeight: startHeight,
EndingHeight: endHeight,
Pagination: pageReq,
},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "validator slashes")
return cmd
}
// GetCmdQueryDelegatorRewards implements the query delegator rewards command.
func GetCmdQueryDelegatorRewards(ac address.Codec) *cobra.Command {
bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix()
bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()
cmd := &cobra.Command{
Use: "rewards [delegator-addr] [validator-addr]",
Args: cobra.RangeArgs(1, 2),
Short: "Query all distribution delegator rewards or rewards from a particular validator",
Long: strings.TrimSpace(
fmt.Sprintf(`Query all rewards earned by a delegator, optionally restrict to rewards from a single validator.
Example:
$ %s query distribution rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p
$ %s query distribution rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj
`,
version.AppName, bech32PrefixAccAddr, version.AppName, bech32PrefixAccAddr, bech32PrefixValAddr,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
_, err = ac.StringToBytes(args[0])
if err != nil {
return err
}
// query for rewards from a particular delegation
ctx := cmd.Context()
if len(args) == 2 {
validatorAddr, err := sdk.ValAddressFromBech32(args[1])
if err != nil {
return err
}
res, err := queryClient.DelegationRewards(
ctx,
&types.QueryDelegationRewardsRequest{DelegatorAddress: args[0], ValidatorAddress: validatorAddr.String()},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
}
res, err := queryClient.DelegationTotalRewards(
ctx,
&types.QueryDelegationTotalRewardsRequest{DelegatorAddress: args[0]},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryCommunityPool returns the command for fetching community pool info.
func GetCmdQueryCommunityPool() *cobra.Command {
cmd := &cobra.Command{
Use: "community-pool",
Args: cobra.NoArgs,
Short: "Query the amount of coins in the community pool",
Long: strings.TrimSpace(
fmt.Sprintf(`Query all coins in the community pool which is under Governance control.
Example:
$ %s query distribution community-pool
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.CommunityPool(cmd.Context(), &types.QueryCommunityPoolRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

View File

@ -1,464 +0,0 @@
package cli_test
import (
"fmt"
"io"
"strings"
"testing"
abci "github.com/cometbft/cometbft/abci/types"
rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/distribution/client/cli"
distrtestutil "github.com/cosmos/cosmos-sdk/x/distribution/testutil"
"github.com/cosmos/cosmos-sdk/x/gov"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
)
type CLITestSuite struct {
suite.Suite
kr keyring.Keyring
encCfg testutilmod.TestEncodingConfig
baseCtx client.Context
clientCtx client.Context
}
func TestCLITestSuite(t *testing.T) {
suite.Run(t, new(CLITestSuite))
}
func (s *CLITestSuite) SetupSuite() {
s.encCfg = testutilmod.MakeTestEncodingConfig(gov.AppModuleBasic{}, 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(clitestutil.MockCometRPC{Client: rpcclientmock.Client{}}).
WithAccountRetriever(client.MockAccountRetriever{}).
WithOutput(io.Discard).
WithChainID("test-chain")
ctxGen := func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
}
s.clientCtx = ctxGen()
cfg, err := network.DefaultConfigWithAppConfig(distrtestutil.AppConfig)
s.Require().NoError(err)
genesisState := cfg.GenesisState
var mintData minttypes.GenesisState
s.Require().NoError(cfg.Codec.UnmarshalJSON(genesisState[minttypes.ModuleName], &mintData))
inflation := sdk.MustNewDecFromStr("1.0")
mintData.Minter.Inflation = inflation
mintData.Params.InflationMin = inflation
mintData.Params.InflationMax = inflation
mintDataBz, err := cfg.Codec.MarshalJSON(&mintData)
s.Require().NoError(err)
genesisState[minttypes.ModuleName] = mintDataBz
cfg.GenesisState = genesisState
}
func (s *CLITestSuite) TestGetCmdQueryParams() {
testCases := []struct {
name string
args []string
expectedOutput string
}{
{
"json output",
[]string{fmt.Sprintf("--%s=json", flags.FlagOutput)},
`{"community_tax":"0","base_proposer_reward":"0","bonus_proposer_reward":"0","withdraw_addr_enabled":false}`,
},
{
"text output",
[]string{fmt.Sprintf("--%s=text", flags.FlagOutput)},
`base_proposer_reward: "0"
bonus_proposer_reward: "0"
community_tax: "0"
withdraw_addr_enabled: false`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryParams()
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
})
}
}
func (s *CLITestSuite) TestGetCmdQueryValidatorDistributionInfo() {
addr := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
val := sdk.ValAddress(addr[0].Address.String())
testCases := []struct {
name string
args []string
expErr bool
}{
{
"invalid val address",
[]string{"invalid address", fmt.Sprintf("--%s=json", flags.FlagOutput)},
true,
},
{
"json output",
[]string{val.String(), fmt.Sprintf("--%s=json", flags.FlagOutput)},
false,
},
{
"text output",
[]string{val.String(), fmt.Sprintf("--%s=text", flags.FlagOutput)},
false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryValidatorDistributionInfo()
_, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
}
})
}
}
func (s *CLITestSuite) TestGetCmdQueryValidatorOutstandingRewards() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"invalid validator address",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
"foo",
},
true,
"",
},
{
"json output",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val[0].Address).String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
`{"rewards":[]}`,
},
{
"text output",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val[0].Address).String(),
},
false,
`rewards: []`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryValidatorOutstandingRewards()
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
}
})
}
}
func (s *CLITestSuite) TestGetCmdQueryValidatorCommission() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"invalid validator address",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
"foo",
},
true,
"",
},
{
"json output",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val[0].Address).String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
`{"commission":[]}`,
},
{
"text output",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val[0].Address).String(),
},
false,
`commission: []`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryValidatorCommission()
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
}
})
}
}
func (s *CLITestSuite) TestGetCmdQueryValidatorSlashes() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"invalid validator address",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
"foo", "1", "3",
},
true,
"",
},
{
"invalid start height",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val[0].Address).String(), "-1", "3",
},
true,
"",
},
{
"invalid end height",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val[0].Address).String(), "1", "-3",
},
true,
"",
},
{
"json output",
[]string{
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val[0].Address).String(), "1", "3",
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
"{\"slashes\":[],\"pagination\":null}",
},
{
"text output",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=3", flags.FlagHeight),
sdk.ValAddress(val[0].Address).String(), "1", "3",
},
false,
"pagination: null\nslashes: []",
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryValidatorSlashes()
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
}
})
}
}
func (s *CLITestSuite) TestGetCmdQueryDelegatorRewards() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
addr := val[0].Address
valAddr := sdk.ValAddress(addr)
testCases := []struct {
name string
args []string
expectErr bool
expectedOutput string
}{
{
"invalid delegator address",
[]string{
fmt.Sprintf("--%s=5", flags.FlagHeight),
"foo", valAddr.String(),
},
true,
"",
},
{
"invalid validator address",
[]string{
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(), "foo",
},
true,
"",
},
{
"json output",
[]string{
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
`{"rewards":[],"total":[]}`,
},
{
"json output (specific validator)",
[]string{
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(), valAddr.String(),
fmt.Sprintf("--%s=json", flags.FlagOutput),
},
false,
`{"rewards":[]}`,
},
{
"text output",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(),
},
false,
`rewards: []
total: []`,
},
{
"text output (specific validator)",
[]string{
fmt.Sprintf("--%s=text", flags.FlagOutput),
fmt.Sprintf("--%s=5", flags.FlagHeight),
addr.String(), valAddr.String(),
},
false,
`rewards: []`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryDelegatorRewards(address.NewBech32Codec("cosmos"))
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
}
})
}
}
func (s *CLITestSuite) TestGetCmdQueryCommunityPool() {
testCases := []struct {
name string
args []string
expectedOutput string
}{
{
"json output",
[]string{fmt.Sprintf("--%s=3", flags.FlagHeight), fmt.Sprintf("--%s=json", flags.FlagOutput)},
`{"pool":[]}`,
},
{
"text output",
[]string{fmt.Sprintf("--%s=text", flags.FlagOutput), fmt.Sprintf("--%s=3", flags.FlagHeight)},
`pool: []`,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := cli.GetCmdQueryCommunityPool()
out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
})
}
}

View File

@ -3,20 +3,84 @@ package cli_test
import (
"context"
"fmt"
"io"
"testing"
sdkmath "cosmossdk.io/math"
abci "github.com/cometbft/cometbft/abci/types"
rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/distribution/client/cli"
distrtestutil "github.com/cosmos/cosmos-sdk/x/distribution/testutil"
"github.com/cosmos/cosmos-sdk/x/gov"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
)
type CLITestSuite struct {
suite.Suite
kr keyring.Keyring
encCfg testutilmod.TestEncodingConfig
baseCtx client.Context
clientCtx client.Context
}
func TestCLITestSuite(t *testing.T) {
suite.Run(t, new(CLITestSuite))
}
func (s *CLITestSuite) SetupSuite() {
s.encCfg = testutilmod.MakeTestEncodingConfig(gov.AppModuleBasic{}, 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(clitestutil.MockCometRPC{Client: rpcclientmock.Client{}}).
WithAccountRetriever(client.MockAccountRetriever{}).
WithOutput(io.Discard).
WithChainID("test-chain")
ctxGen := func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
}
s.clientCtx = ctxGen()
cfg, err := network.DefaultConfigWithAppConfig(distrtestutil.AppConfig)
s.Require().NoError(err)
genesisState := cfg.GenesisState
var mintData minttypes.GenesisState
s.Require().NoError(cfg.Codec.UnmarshalJSON(genesisState[minttypes.ModuleName], &mintData))
inflation := sdk.MustNewDecFromStr("1.0")
mintData.Minter.Inflation = inflation
mintData.Params.InflationMin = inflation
mintData.Params.InflationMax = inflation
mintDataBz, err := cfg.Codec.MarshalJSON(&mintData)
s.Require().NoError(err)
genesisState[minttypes.ModuleName] = mintDataBz
cfg.GenesisState = genesisState
}
func (s *CLITestSuite) TestTxWithdrawRewardsCmd() {
val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)

View File

@ -10,9 +10,10 @@ import (
"github.com/spf13/cobra"
modulev1 "cosmossdk.io/api/cosmos/distribution/module/v1"
"cosmossdk.io/depinject"
"cosmossdk.io/core/address"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/depinject"
"cosmossdk.io/core/store"
@ -63,7 +64,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
}
// ValidateGenesis performs genesis state validation for the distribution module.
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config sdkclient.TxEncodingConfig, bz json.RawMessage) error {
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ sdkclient.TxEncodingConfig, bz json.RawMessage) error {
var data types.GenesisState
if err := cdc.UnmarshalJSON(bz, &data); err != nil {
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
@ -86,7 +87,7 @@ func (ab AppModuleBasic) GetTxCmd() *cobra.Command {
// GetQueryCmd returns the root query command for the distribution module.
func (ab AppModuleBasic) GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd(ab.ac)
return nil
}
// RegisterInterfaces implements InterfaceModule
@ -191,7 +192,7 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
}
// ProposalMsgs returns msgs used for governance proposals for simulations.
func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg {
func (AppModule) ProposalMsgs(_ module.SimulationState) []simtypes.WeightedProposalMsg {
return simulation.ProposalMsgs()
}