diff --git a/PENDING.md b/PENDING.md index bf69135face3..a084f76d1539 100644 --- a/PENDING.md +++ b/PENDING.md @@ -8,8 +8,8 @@ BREAKING CHANGES * [\#2222] all endpoints renamed from `/stake` -> `/staking` * [\#1268] `LooseTokens` -> `NotBondedTokens` * [\#3289] misc renames: - * `Validator.UnbondingMinTime` -> `Validator.UnbondingCompletionTime` - * `Delegation` -> `Value` in `MsgCreateValidator` and `MsgDelegate` + * `Validator.UnbondingMinTime` -> `Validator.UnbondingCompletionTime` + * `Delegation` -> `Value` in `MsgCreateValidator` and `MsgDelegate` * `MsgBeginUnbonding` -> `MsgUndelegate` * Gaia CLI (`gaiacli`) @@ -19,6 +19,7 @@ BREAKING CHANGES * [\#3069](https://github.com/cosmos/cosmos-sdk/pull/3069) `--fee` flag renamed to `--fees` to support multiple coins * [\#3156](https://github.com/cosmos/cosmos-sdk/pull/3156) Remove unimplemented `gaiacli init` command * [\#2222] `gaiacli tx stake` -> `gaiacli tx staking`, `gaiacli query stake` -> `gaiacli query staking` + * [\#3320](https://github.com/cosmos/cosmos-sdk/pull/3320) Ensure all `gaiacli query` commands respect the `--output` and `--indent` flags * Gaia * https://github.com/cosmos/cosmos-sdk/issues/2838 - Move store keys to constants @@ -32,14 +33,21 @@ BREAKING CHANGES * [\#3064](https://github.com/cosmos/cosmos-sdk/issues/3064) Sanitize `sdk.Coin` denom. Coins denoms are now case insensitive, i.e. 100fooToken equals to 100FOOTOKEN. * [\#3195](https://github.com/cosmos/cosmos-sdk/issues/3195) Allows custom configuration for syncable strategy * [\#3242](https://github.com/cosmos/cosmos-sdk/issues/3242) Fix infinite gas +<<<<<<< HEAD meter utilization during aborted ante handler executions. * [x/distribution] \#3292 Enable or disable withdraw addresses with a parameter in the param store * [staking] \#2222 `/stake` -> `/staking` module rename * [staking] \#1268 `LooseTokens` -> `NotBondedTokens` - * [staking] \#1402 Redelegation and unbonding-delegation structs changed to include multiple an array of entries + * [staking] \#1402 Redelegation and unbonding-delegation structs changed to include multiple an array of entries +======= + meter utilization during aborted ante handler executions. + * [\#2222] [x/staking] `/stake` -> `/staking` module rename + * \#3292 [x/distribution] Enable or disable withdraw addresses with a parameter in the param store + * [staking] \#1402 Redelegation and unbonding-delegation structs changed to include multiple an array of entries +>>>>>>> Pending.md * [staking] \#3289 misc renames: - * `Validator.UnbondingMinTime` -> `Validator.UnbondingCompletionTime` - * `Delegation` -> `Value` in `MsgCreateValidator` and `MsgDelegate` + * `Validator.UnbondingMinTime` -> `Validator.UnbondingCompletionTime` + * `Delegation` -> `Value` in `MsgCreateValidator` and `MsgDelegate` * `MsgBeginUnbonding` -> `MsgUndelegate` * [\#3315] Increase decimal precision to 18 * [\#3328](https://github.com/cosmos/cosmos-sdk/issues/3328) [x/gov] Remove redundant action tag @@ -114,8 +122,12 @@ IMPROVEMENTS slashing, and staking modules. * [\#3093](https://github.com/cosmos/cosmos-sdk/issues/3093) Ante handler does no longer read all accounts in one go when processing signatures as signature verification may fail before last signature is checked. - * [staking] \#1402 Add for multiple simultaneous redelegations or unbonding-delegations within an unbonding period +<<<<<<< HEAD + * [staking] \#1402 Add for multiple simultaneous redelegations or unbonding-delegations within an unbonding period * [staking] \#1268 staking spec rewrite +======= + * [x/stake] \#1402 Add for multiple simultaneous redelegations or unbonding-delegations within an unbonding period +>>>>>>> Pending.md * Tendermint diff --git a/client/context/context.go b/client/context/context.go index 86404d45c729..307ce4fe033c 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -35,6 +35,7 @@ type CLIContext struct { AccDecoder auth.AccountDecoder Client rpcclient.Client Output io.Writer + OutputFormat string Height int64 NodeURI string From string @@ -76,6 +77,7 @@ func NewCLIContext() CLIContext { NodeURI: nodeURI, AccountStore: auth.StoreKey, From: viper.GetString(client.FlagFrom), + OutputFormat: viper.GetString(cli.OutputFlag), Height: viper.GetInt64(client.FlagHeight), TrustNode: viper.GetBool(client.FlagTrustNode), UseLedger: viper.GetBool(client.FlagUseLedger), @@ -254,3 +256,28 @@ func (ctx CLIContext) WithSimulation(simulate bool) CLIContext { ctx.Simulate = simulate return ctx } + +// PrintOutput prints output while respecting output and indent flags +// NOTE: pass in marshalled structs that have been unmarshaled +// because this function will panic on marshaling errors +func (ctx CLIContext) PrintOutput(toPrint fmt.Stringer) (err error) { + var out []byte + + switch ctx.OutputFormat { + case "text": + out = []byte(toPrint.String()) + case "json": + if ctx.Indent { + out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ") + } else { + out, err = ctx.Codec.MarshalJSON(toPrint) + } + } + + if err != nil { + return + } + + fmt.Println(string(out)) + return +} diff --git a/client/tx/search.go b/client/tx/search.go index e8c4eb1e1806..29537e00bd11 100644 --- a/client/tx/search.go +++ b/client/tx/search.go @@ -98,6 +98,7 @@ $ gaiacli query txs --tags ':&:' --page 1 --limit 30 cmd.Flags().String(flagTags, "", "tag:value list of tags that must match") cmd.Flags().Int32(flagPage, defaultPage, "Query a specific page of paginated results") cmd.Flags().Int32(flagLimit, defaultLimit, "Query number of transactions results per page returned") + cmd.MarkFlagRequired(flagTags) return cmd } diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 2fb00d4b6532..3fdaefcd21c6 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -383,7 +383,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom).Int64()) proposalsQuery := f.QueryGovProposals() - require.Equal(t, "No matching proposals found", proposalsQuery) + require.Empty(t, proposalsQuery) // Test submit generate only for submit proposal success, stdout, stderr := f.TxGovSubmitProposal( @@ -418,7 +418,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { // Ensure query proposals returns properly proposalsQuery = f.QueryGovProposals() - require.Equal(t, " 1 - Test", proposalsQuery) + require.Equal(t, uint64(1), proposalsQuery[0].GetProposalID()) // Query the deposits on the proposal deposit := f.QueryGovDeposit(1, fooAddr) @@ -489,11 +489,11 @@ func TestGaiaCLISubmitProposal(t *testing.T) { // Ensure no proposals in deposit period proposalsQuery = f.QueryGovProposals("--status=DepositPeriod") - require.Equal(t, "No matching proposals found", proposalsQuery) + require.Empty(t, proposalsQuery) // Ensure the proposal returns as in the voting period proposalsQuery = f.QueryGovProposals("--status=VotingPeriod") - require.Equal(t, " 1 - Test", proposalsQuery) + require.Equal(t, uint64(1), proposalsQuery[0].GetProposalID()) // submit a second test proposal f.TxGovSubmitProposal(keyFoo, "Text", "Apples", "test", sdk.NewInt64Coin(denom, 5)) @@ -501,7 +501,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { // Test limit on proposals query proposalsQuery = f.QueryGovProposals("--limit=1") - require.Equal(t, " 2 - Apples", proposalsQuery) + require.Equal(t, uint64(2), proposalsQuery[0].GetProposalID()) f.Cleanup() } diff --git a/cmd/gaia/cli_test/test_helpers.go b/cmd/gaia/cli_test/test_helpers.go index 7e1b1b9797db..eeda98615518 100644 --- a/cmd/gaia/cli_test/test_helpers.go +++ b/cmd/gaia/cli_test/test_helpers.go @@ -380,7 +380,7 @@ func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool { // QueryStakingParameters is gaiacli query staking parameters func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params { - cmd := fmt.Sprintf("gaiacli query staking parameters %v", f.Flags()) + cmd := fmt.Sprintf("gaiacli query staking params %v", f.Flags()) out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "") var params staking.Params cdc := app.MakeCodec() @@ -426,11 +426,18 @@ func (f *Fixtures) QueryGovParamTallying() gov.TallyParams { } // QueryGovProposals is gaiacli query gov proposals -func (f *Fixtures) QueryGovProposals(flags ...string) string { +func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals { cmd := fmt.Sprintf("gaiacli query gov proposals %v", f.Flags()) stdout, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), "") + if strings.Contains(stderr, "No matching proposals found") { + return gov.Proposals{} + } require.Empty(f.T, stderr) - return stdout + var out gov.Proposals + cdc := app.MakeCodec() + err := cdc.UnmarshalJSON([]byte(stdout), &out) + require.NoError(f.T, err) + return out } // QueryGovProposal is gaiacli query gov proposal diff --git a/docs/gaia/gaiacli.md b/docs/gaia/gaiacli.md index 37d239d85391..5982c30d4eda 100644 --- a/docs/gaia/gaiacli.md +++ b/docs/gaia/gaiacli.md @@ -380,15 +380,13 @@ Don't use more `steak` thank you have! You can always get more by using the [Fau Once submitted a delegation to a validator, you can see it's information by using the following command: ```bash -gaiacli query staking delegation \ - --address-delegator= \ - --validator= +gaiacli query staking delegation ``` Or if you want to check all your current delegations with disctinct validators: ```bash -gaiacli query staking delegations +gaiacli query staking delegations ``` You can also get previous delegation(s) status by adding the `--height` flag. @@ -412,9 +410,7 @@ The unbonding will be automatically completed when the unbonding period has pass Once you begin an unbonding-delegation, you can see it's information by using the following command: ```bash -gaiacli query staking unbonding-delegation \ - --address-delegator= \ - --validator= \ +gaiacli query staking unbonding-delegation ``` Or if you want to check all your current unbonding-delegations with disctinct validators: @@ -426,7 +422,7 @@ gaiacli query staking unbonding-delegations Additionally, as you can get all the unbonding-delegations from a particular validator: ```bash - gaiacli query staking unbonding-delegations-from +gaiacli query staking unbonding-delegations-from ``` To get previous unbonding-delegation(s) status on past blocks, try adding the `--height` flag. @@ -453,10 +449,7 @@ The redelegation will be automatically completed when the unbonding period has p Once you begin an redelegation, you can see it's information by using the following command: ```bash -gaiacli query staking redelegation \ - --address-delegator= \ - --addr-validator-source= \ - --addr-validator-dest= \ +gaiacli query staking redelegation ``` Or if you want to check all your current unbonding-delegations with disctinct validators: @@ -478,7 +471,7 @@ To get previous redelegation(s) status on past blocks, try adding the `--height` Parameters define high level settings for staking. You can get the current values by using: ```bash -gaiacli query staking parameters +gaiacli query staking params ``` With the above command you will get the values for: @@ -629,6 +622,12 @@ gaiacli query gov tally To check the current governance parameters run: +```bash +gaiacli query gov params +``` + +To query subsets of the governance parameters run: + ```bash gaiacli query gov param voting gaiacli query gov param tallying diff --git a/x/auth/account.go b/x/auth/account.go index f04cb179a32c..8759de80d9b2 100644 --- a/x/auth/account.go +++ b/x/auth/account.go @@ -2,6 +2,7 @@ package auth import ( "errors" + "fmt" "time" "github.com/tendermint/tendermint/crypto" @@ -35,6 +36,9 @@ type Account interface { // Calculates the amount of coins that can be sent to other accounts given // the current time. SpendableCoins(blockTime time.Time) sdk.Coins + + // Ensure that account implements stringer + String() string } // VestingAccount defines an account type that vests coins via a vesting schedule. @@ -74,6 +78,16 @@ type BaseAccount struct { Sequence uint64 `json:"sequence"` } +// String implements fmt.Stringer +func (acc BaseAccount) String() string { + return fmt.Sprintf(`Account %s: + Coins: %s + PubKey: %s + AccountNumber: %d + Sequence: %d`, acc.Address, acc.Coins, + acc.PubKey.Address(), acc.AccountNumber, acc.Sequence) +} + // Prototype function for BaseAccount func ProtoBaseAccount() Account { return &BaseAccount{} @@ -164,6 +178,22 @@ type BaseVestingAccount struct { EndTime int64 // when the coins become unlocked } +// String implements fmt.Stringer +func (bva BaseVestingAccount) String() string { + return fmt.Sprintf(`Vesting Account %s: + Coins: %s + PubKey: %s + AccountNumber: %d + Sequence: %d + OriginalVesting: %s + DelegatedFree: %s + DelegatedVesting: %s + EndTime: %d `, bva.Address, bva.Coins, + bva.PubKey.Address(), bva.AccountNumber, bva.Sequence, + bva.OriginalVesting, bva.DelegatedFree, + bva.DelegatedVesting, bva.EndTime) +} + // spendableCoins returns all the spendable coins for a vesting account given a // set of vesting coins. // @@ -342,6 +372,22 @@ func NewContinuousVestingAccount( } } +func (cva ContinuousVestingAccount) String() string { + return fmt.Sprintf(`Vesting Account %s: + Coins: %s + PubKey: %s + AccountNumber: %d + Sequence: %d + OriginalVesting: %s + DelegatedFree: %s + DelegatedVesting: %s + StartTime: %d + EndTime: %d `, cva.Address, cva.Coins, + cva.PubKey.Address(), cva.AccountNumber, cva.Sequence, + cva.OriginalVesting, cva.DelegatedFree, + cva.DelegatedVesting, cva.StartTime, cva.EndTime) +} + // GetVestedCoins returns the total number of vested coins. If no coins are vested, // nil is returned. func (cva ContinuousVestingAccount) GetVestedCoins(blockTime time.Time) sdk.Coins { diff --git a/x/auth/client/cli/account.go b/x/auth/client/cli/account.go index 922b3e2db202..f68873187746 100644 --- a/x/auth/client/cli/account.go +++ b/x/auth/client/cli/account.go @@ -1,8 +1,6 @@ package cli import ( - "fmt" - "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" @@ -20,18 +18,14 @@ func GetAccountCmd(storeName string, cdc *codec.Codec) *cobra.Command { Short: "Query account balance", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - // find the key to look up the account - addr := args[0] + cliCtx := context.NewCLIContext(). + WithCodec(cdc).WithAccountDecoder(cdc) - key, err := sdk.AccAddressFromBech32(addr) + key, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } - cliCtx := context.NewCLIContext(). - WithCodec(cdc). - WithAccountDecoder(cdc) - if err = cliCtx.EnsureAccountExistsFromAddr(key); err != nil { return err } @@ -41,18 +35,7 @@ func GetAccountCmd(storeName string, cdc *codec.Codec) *cobra.Command { return err } - var output []byte - if cliCtx.Indent { - output, err = cdc.MarshalJSONIndent(acc, "", " ") - } else { - output, err = cdc.MarshalJSON(acc) - } - if err != nil { - return err - } - - fmt.Println(string(output)) - return nil + return cliCtx.PrintOutput(acc) }, } diff --git a/x/distribution/client/cli/query.go b/x/distribution/client/cli/query.go index 3427a4509948..09d4b458ac2d 100644 --- a/x/distribution/client/cli/query.go +++ b/x/distribution/client/cli/query.go @@ -10,82 +10,75 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" distr "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/distribution/types" ) // GetCmdQueryParams implements the query params command. func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "params", - Args: cobra.ExactArgs(0), + Args: cobra.NoArgs, Short: "Query distribution params", RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := queryParams(cliCtx, cdc, queryRoute) + route := fmt.Sprintf("custom/%s/params/community_tax", queryRoute) + retCommunityTax, err := cliCtx.QueryWithData(route, []byte{}) if err != nil { return err } - fmt.Println(string(res)) - return nil - - }, - } - return cmd -} + route = fmt.Sprintf("custom/%s/params/base_proposer_reward", queryRoute) + retBaseProposerReward, err := cliCtx.QueryWithData(route, []byte{}) + if err != nil { + return err + } -func queryParams(cliCtx context.CLIContext, cdc *codec.Codec, queryRoute string) ([]byte, error) { - retCommunityTax, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/community_tax", queryRoute), []byte{}) - if err != nil { - return nil, err - } + route = fmt.Sprintf("custom/%s/params/bonus_proposer_reward", queryRoute) + retBonusProposerReward, err := cliCtx.QueryWithData(route, []byte{}) + if err != nil { + return err + } - retBaseProposerReward, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/base_proposer_reward", queryRoute), []byte{}) - if err != nil { - return nil, err - } + route = fmt.Sprintf("custom/%s/params/withdraw_addr_enabled", queryRoute) + retWithdrawAddrEnabled, err := cliCtx.QueryWithData(route, []byte{}) + if err != nil { + return err + } - retBonusProposerReward, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/bonus_proposer_reward", queryRoute), []byte{}) - if err != nil { - return nil, err - } + params := NewPrettyParams(retCommunityTax, retBaseProposerReward, + retBonusProposerReward, retWithdrawAddrEnabled) - retWithdrawAddrEnabled, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/withdraw_addr_enabled", queryRoute), []byte{}) - if err != nil { - return nil, err + return cliCtx.PrintOutput(params) + }, } - - return codec.MarshalJSONIndent(cdc, NewPrettyParams(retCommunityTax, retBaseProposerReward, retBonusProposerReward, retWithdrawAddrEnabled)) } // GetCmdQueryOutstandingRewards implements the query outstanding rewards command. func GetCmdQueryOutstandingRewards(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "outstanding-rewards", - Args: cobra.ExactArgs(0), + Args: cobra.NoArgs, Short: "Query distribution outstanding (un-withdrawn) rewards", RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := queryOutstandingRewards(cliCtx, cdc, queryRoute) + route := fmt.Sprintf("custom/%s/outstanding_rewards", queryRoute) + res, err := cliCtx.QueryWithData(route, []byte{}) if err != nil { return err } - fmt.Println(string(res)) - return nil + var outstandingRewards types.OutstandingRewards + cdc.MustUnmarshalJSON(res, &outstandingRewards) + return cliCtx.PrintOutput(outstandingRewards) }, } - return cmd -} - -func queryOutstandingRewards(cliCtx context.CLIContext, cdc *codec.Codec, queryRoute string) ([]byte, error) { - return cliCtx.QueryWithData(fmt.Sprintf("custom/%s/outstanding_rewards", queryRoute), []byte{}) } // GetCmdQueryValidatorCommission implements the query validator commission command. func GetCmdQueryValidatorCommission(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "commission [validator]", Args: cobra.ExactArgs(1), Short: "Query distribution validator commission", @@ -97,29 +90,27 @@ func GetCmdQueryValidatorCommission(queryRoute string, cdc *codec.Codec) *cobra. return err } - res, err := queryValidatorCommission(cliCtx, cdc, queryRoute, distr.NewQueryValidatorCommissionParams(validatorAddr)) + bz, err := cdc.MarshalJSON(distr.NewQueryValidatorCommissionParams(validatorAddr)) if err != nil { return err } - fmt.Println(string(res)) - return nil - }, - } - return cmd -} + route := fmt.Sprintf("custom/%s/validator_commission", queryRoute) + res, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } -func queryValidatorCommission(cliCtx context.CLIContext, cdc *codec.Codec, queryRoute string, params distr.QueryValidatorCommissionParams) ([]byte, error) { - bz, err := cdc.MarshalJSON(params) - if err != nil { - return nil, err + var valCom types.ValidatorAccumulatedCommission + cdc.MustUnmarshalJSON(res, &valCom) + return cliCtx.PrintOutput(valCom) + }, } - return cliCtx.QueryWithData(fmt.Sprintf("custom/%s/validator_commission", queryRoute), bz) } // GetCmdQueryValidatorSlashes implements the query validator slashes command. func GetCmdQueryValidatorSlashes(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "slashes [validator] [start-height] [end-height]", Args: cobra.ExactArgs(3), Short: "Query distribution validator slashes", @@ -141,29 +132,27 @@ func GetCmdQueryValidatorSlashes(queryRoute string, cdc *codec.Codec) *cobra.Com return fmt.Errorf("end-height %s not a valid uint, please input a valid end-height", args[2]) } - res, err := queryValidatorSlashes(cliCtx, cdc, queryRoute, distr.NewQueryValidatorSlashesParams(validatorAddr, startHeight, endHeight)) + params := distr.NewQueryValidatorSlashesParams(validatorAddr, startHeight, endHeight) + bz, err := cdc.MarshalJSON(params) if err != nil { return err } - fmt.Println(string(res)) - return nil - }, - } - return cmd -} + res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/validator_slashes", queryRoute), bz) + if err != nil { + return err + } -func queryValidatorSlashes(cliCtx context.CLIContext, cdc *codec.Codec, queryRoute string, params distr.QueryValidatorSlashesParams) ([]byte, error) { - bz, err := cdc.MarshalJSON(params) - if err != nil { - return nil, err + var slashes types.ValidatorSlashEvent + cdc.MustUnmarshalJSON(res, &slashes) + return cliCtx.PrintOutput(slashes) + }, } - return cliCtx.QueryWithData(fmt.Sprintf("custom/%s/validator_slashes", queryRoute), bz) } // GetCmdQueryDelegatorRewards implements the query delegator rewards command. func GetCmdQueryDelegatorRewards(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "rewards [delegator] [validator]", Args: cobra.ExactArgs(2), Short: "Query distribution delegator rewards", @@ -180,22 +169,21 @@ func GetCmdQueryDelegatorRewards(queryRoute string, cdc *codec.Codec) *cobra.Com return err } - res, err := queryDelegationRewards(cliCtx, cdc, queryRoute, distr.NewQueryDelegationRewardsParams(delegatorAddr, validatorAddr)) + params := distr.NewQueryDelegationRewardsParams(delegatorAddr, validatorAddr) + bz, err := cdc.MarshalJSON(params) if err != nil { return err } - fmt.Println(string(res)) - return nil - }, - } - return cmd -} + route := fmt.Sprintf("custom/%s/delegation_rewards", queryRoute) + res, err := cliCtx.QueryWithData(route, bz) + if err != nil { + return err + } -func queryDelegationRewards(cliCtx context.CLIContext, cdc *codec.Codec, queryRoute string, params distr.QueryDelegationRewardsParams) ([]byte, error) { - bz, err := cdc.MarshalJSON(params) - if err != nil { - return nil, err + var coins sdk.DecCoins + cdc.MustUnmarshalJSON(res, &coins) + return cliCtx.PrintOutput(coins) + }, } - return cliCtx.QueryWithData(fmt.Sprintf("custom/%s/delegation_rewards", queryRoute), bz) } diff --git a/x/distribution/client/cli/util.go b/x/distribution/client/cli/util.go index 11eabd8f0475..06e24a6b7e60 100644 --- a/x/distribution/client/cli/util.go +++ b/x/distribution/client/cli/util.go @@ -2,6 +2,7 @@ package cli import ( "encoding/json" + "fmt" ) // Convenience struct for CLI output @@ -21,3 +22,13 @@ func NewPrettyParams(communityTax json.RawMessage, baseProposerReward json.RawMe WithdrawAddrEnabled: withdrawAddrEnabled, } } + +func (pp PrettyParams) String() string { + return fmt.Sprintf(`Distribution Params: + Community Tax: %s + Base Proposer Reward: %s + Bonus Proposer Reward: %s + Withdraw Addr Enabled: %s`, pp.CommunityTax, + pp.BaseProposerReward, pp.BonusProposerReward, pp.WithdrawAddrEnabled) + +} diff --git a/x/distribution/types/validator.go b/x/distribution/types/validator.go index 8d9c10f0cf73..807a3ff44444 100644 --- a/x/distribution/types/validator.go +++ b/x/distribution/types/validator.go @@ -1,6 +1,9 @@ package types import ( + "fmt" + "strings" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -50,3 +53,22 @@ func NewValidatorSlashEvent(validatorPeriod uint64, fraction sdk.Dec) ValidatorS Fraction: fraction, } } + +func (vs ValidatorSlashEvent) String() string { + return fmt.Sprintf(`Period: %d +Fraction: %s`, vs.ValidatorPeriod, vs.Fraction) +} + +// ValidatorSlashEvents is a collection of ValidatorSlashEvent +type ValidatorSlashEvents []ValidatorSlashEvent + +func (vs ValidatorSlashEvents) String() string { + out := "Validator Slash Events:\n" + for i, sl := range vs { + out += fmt.Sprintf(` Slash %d: + Period: %d + Fraction: %s +`, i, sl.ValidatorPeriod, sl.Fraction) + } + return strings.TrimSpace(out) +} diff --git a/x/gov/client/cli/query.go b/x/gov/client/cli/query.go index e72d66a9ce29..fd8c9a9651e3 100644 --- a/x/gov/client/cli/query.go +++ b/x/gov/client/cli/query.go @@ -17,7 +17,7 @@ import ( // GetCmdQueryProposal implements the query proposal command. func GetCmdQueryProposal(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "proposal [proposal-id]", Args: cobra.ExactArgs(1), Short: "Query details of a single proposal", @@ -36,33 +36,16 @@ $ gaiacli query gov proposal 1 } // Query the proposal - res, err := queryProposal(proposalID, cliCtx, cdc, queryRoute) + res, err := gcutils.QueryProposalByID(proposalID, cliCtx, cdc, queryRoute) if err != nil { return err } - fmt.Println(string(res)) - return nil + var proposal gov.Proposal + cdc.MustUnmarshalJSON(res, &proposal) + return cliCtx.PrintOutput(proposal) }, } - - return cmd -} - -func queryProposal(proposalID uint64, cliCtx context.CLIContext, cdc *codec.Codec, queryRoute string) ([]byte, error) { - // Construct query - params := gov.NewQueryProposalParams(proposalID) - bz, err := cdc.MarshalJSON(params) - if err != nil { - return nil, err - } - - // Query store - res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/proposal", queryRoute), bz) - if err != nil { - return nil, err - } - return res, err } // GetCmdQueryProposals implements a query proposals command. @@ -125,22 +108,17 @@ $ gaiacli query gov proposals --status (DepositPeriod|VotingPeriod|Passed|Reject return err } - var matchingProposals []gov.Proposal + var matchingProposals gov.Proposals err = cdc.UnmarshalJSON(res, &matchingProposals) if err != nil { return err } if len(matchingProposals) == 0 { - fmt.Println("No matching proposals found") - return nil - } - - for _, proposal := range matchingProposals { - fmt.Printf(" %d - %s\n", proposal.GetProposalID(), proposal.GetTitle()) + return fmt.Errorf("No matching proposals found") } - return nil + return cliCtx.PrintOutput(matchingProposals) }, } @@ -155,7 +133,7 @@ $ gaiacli query gov proposals --status (DepositPeriod|VotingPeriod|Passed|Reject // Command to Get a Proposal Information // GetCmdQueryVote implements the query proposal vote command. func GetCmdQueryVote(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "vote [proposal-id] [voter-address]", Args: cobra.ExactArgs(2), Short: "Query details of a single vote", @@ -175,7 +153,7 @@ $ gaiacli query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk } // check to see if the proposal is in the store - _, err = queryProposal(proposalID, cliCtx, cdc, queryRoute) + _, err = gcutils.QueryProposalByID(proposalID, cliCtx, cdc, queryRoute) if err != nil { return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } @@ -204,19 +182,17 @@ $ gaiacli query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk if err != nil { return err } + cdc.UnmarshalJSON(res, &vote) } - fmt.Println(string(res)) - return nil + return cliCtx.PrintOutput(vote) }, } - - return cmd } // GetCmdQueryVotes implements the command to query for proposal votes. func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "votes [proposal-id]", Args: cobra.ExactArgs(1), Short: "Query votes on a proposal", @@ -242,15 +218,13 @@ $ gaiacli query gov votes 1 } // check to see if the proposal is in the store - res, err := queryProposal(proposalID, cliCtx, cdc, queryRoute) + res, err := gcutils.QueryProposalByID(proposalID, cliCtx, cdc, queryRoute) if err != nil { return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } var proposal gov.Proposal - if err := cdc.UnmarshalJSON(res, &proposal); err != nil { - return err - } + cdc.MustUnmarshalJSON(res, &proposal) propStatus := proposal.GetStatus() if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { @@ -263,18 +237,17 @@ $ gaiacli query gov votes 1 return err } - fmt.Println(string(res)) - return nil + var votes gov.Votes + cdc.MustUnmarshalJSON(res, &votes) + return cliCtx.PrintOutput(votes) }, } - - return cmd } // Command to Get a specific Deposit Information // GetCmdQueryDeposit implements the query proposal deposit command. func GetCmdQueryDeposit(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "deposit [proposal-id] [depositer-address]", Args: cobra.ExactArgs(2), Short: "Query details of a deposit", @@ -294,7 +267,7 @@ $ gaiacli query gov deposit 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk } // check to see if the proposal is in the store - _, err = queryProposal(proposalID, cliCtx, cdc, queryRoute) + _, err = gcutils.QueryProposalByID(proposalID, cliCtx, cdc, queryRoute) if err != nil { return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } @@ -316,26 +289,24 @@ $ gaiacli query gov deposit 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk } var deposit gov.Deposit - cdc.UnmarshalJSON(res, &deposit) + cdc.MustUnmarshalJSON(res, &deposit) if deposit.Empty() { res, err = gcutils.QueryDepositByTxQuery(cdc, cliCtx, params) if err != nil { return err } + cdc.MustUnmarshalJSON(res, &deposit) } - fmt.Println(string(res)) - return nil + return cliCtx.PrintOutput(deposit) }, } - - return cmd } // GetCmdQueryDeposits implements the command to query for proposal deposits. func GetCmdQueryDeposits(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "deposits [proposal-id]", Args: cobra.ExactArgs(1), Short: "Query deposits on a proposal", @@ -360,15 +331,13 @@ $ gaiacli query gov deposits 1 } // check to see if the proposal is in the store - res, err := queryProposal(proposalID, cliCtx, cdc, queryRoute) + res, err := gcutils.QueryProposalByID(proposalID, cliCtx, cdc, queryRoute) if err != nil { - return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) + return fmt.Errorf("Failed to fetch proposal with id %d: %s", proposalID, err) } var proposal gov.Proposal - if err := cdc.UnmarshalJSON(res, &proposal); err != nil { - return err - } + cdc.MustUnmarshalJSON(res, &proposal) propStatus := proposal.GetStatus() if !(propStatus == gov.StatusVotingPeriod || propStatus == gov.StatusDepositPeriod) { @@ -381,17 +350,16 @@ $ gaiacli query gov deposits 1 return err } - fmt.Println(string(res)) - return nil + var dep gov.Deposits + cdc.MustUnmarshalJSON(res, &dep) + return cliCtx.PrintOutput(dep) }, } - - return cmd } // GetCmdQueryTally implements the command to query for proposal tally result. func GetCmdQueryTally(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "tally [proposal-id]", Args: cobra.ExactArgs(1), Short: "Get the tally of a proposal vote", @@ -410,7 +378,7 @@ $ gaiacli query gov tally 1 } // check to see if the proposal is in the store - _, err = queryProposal(proposalID, cliCtx, cdc, queryRoute) + _, err = gcutils.QueryProposalByID(proposalID, cliCtx, cdc, queryRoute) if err != nil { return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } @@ -428,17 +396,48 @@ $ gaiacli query gov tally 1 return err } - fmt.Println(string(res)) - return nil + var tally gov.TallyResult + cdc.MustUnmarshalJSON(res, &tally) + return cliCtx.PrintOutput(tally) }, } - - return cmd } // GetCmdQueryProposal implements the query proposal command. func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ + Use: "params", + Short: "Query the parameters (voting|tallying|deposit) of the governance process", + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + tp, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/tallying", queryRoute), nil) + if err != nil { + return err + } + dp, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/deposit", queryRoute), nil) + if err != nil { + return err + } + vp, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/params/voting", queryRoute), nil) + if err != nil { + return err + } + + var tallyParams gov.TallyParams + cdc.MustUnmarshalJSON(tp, &tallyParams) + var depositParams gov.DepositParams + cdc.MustUnmarshalJSON(dp, &depositParams) + var votingParams gov.VotingParams + cdc.MustUnmarshalJSON(vp, &votingParams) + + return cliCtx.PrintOutput(gov.NewParams(votingParams, tallyParams, depositParams)) + }, + } +} + +// GetCmdQueryProposal implements the query proposal command. +func GetCmdQueryParam(queryRoute string, cdc *codec.Codec) *cobra.Command { + return &cobra.Command{ Use: "param [param-type]", Args: cobra.ExactArgs(1), Short: "Query the parameters (voting|tallying|deposit) of the governance process", @@ -450,18 +449,32 @@ func GetCmdQueryParams(queryRoute string, cdc *codec.Codec) *cobra.Command { if err != nil { return err } - - fmt.Println(string(res)) - return nil + var out fmt.Stringer + switch args[0] { + case "voting": + var param gov.VotingParams + cdc.MustUnmarshalJSON(res, ¶m) + out = param + case "tallying": + var param gov.TallyParams + cdc.MustUnmarshalJSON(res, ¶m) + out = param + case "deposit": + var param gov.DepositParams + cdc.MustUnmarshalJSON(res, ¶m) + out = param + default: + return fmt.Errorf("Argument must be one of (voting|tallying|deposit), was %s", args[0]) + } + + return cliCtx.PrintOutput(out) }, } - - return cmd } // GetCmdQueryProposer implements the query proposer command. func GetCmdQueryProposer(queryRoute string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "proposer [proposal-id]", Args: cobra.ExactArgs(1), Short: "Query the proposer of a governance proposal", @@ -474,15 +487,12 @@ func GetCmdQueryProposer(queryRoute string, cdc *codec.Codec) *cobra.Command { return fmt.Errorf("proposal-id %s is not a valid uint", args[0]) } - res, err := gcutils.QueryProposerByTxQuery(cdc, cliCtx, proposalID) + prop, err := gcutils.QueryProposerByTxQuery(cdc, cliCtx, proposalID) if err != nil { return err } - fmt.Println(string(res)) - return nil + return cliCtx.PrintOutput(prop) }, } - - return cmd } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 557b819087b7..89deae745672 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -194,7 +194,7 @@ $ gaiacli tx gov deposit 1 10stake --from mykey } // check to see if the proposal is in the store - _, err = queryProposal(proposalID, cliCtx, cdc, queryRoute) + _, err = govClientUtils.QueryProposalByID(proposalID, cliCtx, cdc, queryRoute) if err != nil { return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } @@ -270,7 +270,7 @@ $ gaiacli tx gov vote 1 yes --from mykey } // check to see if the proposal is in the store - _, err = queryProposal(proposalID, cliCtx, cdc, queryRoute) + _, err = govClientUtils.QueryProposalByID(proposalID, cliCtx, cdc, queryRoute) if err != nil { return fmt.Errorf("Failed to fetch proposal-id %d: %s", proposalID, err) } diff --git a/x/gov/client/module_client.go b/x/gov/client/module_client.go index 4ad8f01fd06b..f66546ba92c2 100644 --- a/x/gov/client/module_client.go +++ b/x/gov/client/module_client.go @@ -31,6 +31,7 @@ func (mc ModuleClient) GetQueryCmd() *cobra.Command { govCli.GetCmdQueryProposals(mc.storeKey, mc.cdc), govCli.GetCmdQueryVote(mc.storeKey, mc.cdc), govCli.GetCmdQueryVotes(mc.storeKey, mc.cdc), + govCli.GetCmdQueryParam(mc.storeKey, mc.cdc), govCli.GetCmdQueryParams(mc.storeKey, mc.cdc), govCli.GetCmdQueryProposer(mc.storeKey, mc.cdc), govCli.GetCmdQueryDeposit(mc.storeKey, mc.cdc), diff --git a/x/gov/client/utils/query.go b/x/gov/client/utils/query.go index a4b728092a30..dadd7dd534ee 100644 --- a/x/gov/client/utils/query.go +++ b/x/gov/client/utils/query.go @@ -22,6 +22,15 @@ type Proposer struct { Proposer string `json:"proposer"` } +// NewProposer returns a new Proposer given id and proposer +func NewProposer(proposalID uint64, proposer string) Proposer { + return Proposer{proposalID, proposer} +} + +func (p Proposer) String() string { + return fmt.Sprintf("Proposal with ID %d was proposed by %s", p.ProposalID, p.Proposer) +} + // QueryDepositsByTxQuery will query for deposits via a direct txs tags query. It // will fetch and build deposits directly from the returned txs and return a // JSON marshalled result or any error that occurred. @@ -201,7 +210,7 @@ func QueryDepositByTxQuery( // ID. func QueryProposerByTxQuery( cdc *codec.Codec, cliCtx context.CLIContext, proposalID uint64, -) ([]byte, error) { +) (Proposer, error) { tags := []string{ fmt.Sprintf("%s='%s'", tags.Action, gov.MsgSubmitProposal{}.Type()), @@ -212,7 +221,7 @@ func QueryProposerByTxQuery( // support configurable pagination. infos, err := tx.SearchTxs(cliCtx, cdc, tags, defaultPage, defaultLimit) if err != nil { - return nil, err + return Proposer{}, err } for _, info := range infos { @@ -220,20 +229,24 @@ func QueryProposerByTxQuery( // there should only be a single proposal under the given conditions if msg.Type() == gov.TypeMsgSubmitProposal { subMsg := msg.(gov.MsgSubmitProposal) - - proposer := Proposer{ - ProposalID: proposalID, - Proposer: subMsg.Proposer.String(), - } - - if cliCtx.Indent { - return cdc.MarshalJSONIndent(proposer, "", " ") - } - - return cdc.MarshalJSON(proposer) + return NewProposer(proposalID, subMsg.Proposer.String()), nil } } } + return Proposer{}, fmt.Errorf("failed to find the proposer for proposalID %d", proposalID) +} + +// QueryProposalByID takes a proposalID and returns a proposal +func QueryProposalByID(proposalID uint64, cliCtx context.CLIContext, cdc *codec.Codec, queryRoute string) ([]byte, error) { + params := gov.NewQueryProposalParams(proposalID) + bz, err := cdc.MarshalJSON(params) + if err != nil { + return nil, err + } - return nil, fmt.Errorf("failed to find the proposer for proposalID %d", proposalID) + res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/proposal", queryRoute), bz) + if err != nil { + return nil, err + } + return res, err } diff --git a/x/gov/depositsvotes.go b/x/gov/depositsvotes.go index 3e2ac56737e8..869ad77dbeee 100644 --- a/x/gov/depositsvotes.go +++ b/x/gov/depositsvotes.go @@ -16,15 +16,29 @@ type Vote struct { Option VoteOption `json:"option"` // option from OptionSet chosen by the voter } +func (v Vote) String() string { + return fmt.Sprintf("Voter %s voted with option %s on proposal %d", v.Voter, v.Option, v.ProposalID) +} + +// Votes is a collection of Vote +type Votes []Vote + +func (v Votes) String() string { + out := fmt.Sprintf("Votes for Proposal %d:", v[0].ProposalID) + for _, vot := range v { + out += fmt.Sprintf("\n %s: %s", vot.Voter, vot.Option) + } + return out +} + // Returns whether 2 votes are equal -func (voteA Vote) Equals(voteB Vote) bool { - return voteA.Voter.Equals(voteB.Voter) && voteA.ProposalID == voteB.ProposalID && voteA.Option == voteB.Option +func (v Vote) Equals(comp Vote) bool { + return v.Voter.Equals(comp.Voter) && v.ProposalID == comp.ProposalID && v.Option == comp.Option } // Returns whether a vote is empty -func (voteA Vote) Empty() bool { - voteB := Vote{} - return voteA.Equals(voteB) +func (v Vote) Empty() bool { + return v.Equals(Vote{}) } // Deposit @@ -34,15 +48,30 @@ type Deposit struct { Amount sdk.Coins `json:"amount"` // Deposit amount } +func (d Deposit) String() string { + return fmt.Sprintf("Deposit by %s on Proposal %d is for the amount %s", + d.Depositor, d.ProposalID, d.Amount) +} + +// Deposits is a collection of depoist +type Deposits []Deposit + +func (d Deposits) String() string { + out := fmt.Sprintf("Deposits for Proposal %d:", d[0].ProposalID) + for _, dep := range d { + out += fmt.Sprintf("\n %s: %s", dep.Depositor, dep.Amount) + } + return out +} + // Returns whether 2 deposits are equal -func (depositA Deposit) Equals(depositB Deposit) bool { - return depositA.Depositor.Equals(depositB.Depositor) && depositA.ProposalID == depositB.ProposalID && depositA.Amount.IsEqual(depositB.Amount) +func (d Deposit) Equals(comp Deposit) bool { + return d.Depositor.Equals(comp.Depositor) && d.ProposalID == comp.ProposalID && d.Amount.IsEqual(comp.Amount) } // Returns whether a deposit is empty -func (depositA Deposit) Empty() bool { - depositB := Deposit{} - return depositA.Equals(depositB) +func (d Deposit) Empty() bool { + return d.Equals(Deposit{}) } // Type that represents VoteOption as a byte diff --git a/x/gov/params.go b/x/gov/params.go index 20cf2f839379..15692041a96b 100644 --- a/x/gov/params.go +++ b/x/gov/params.go @@ -1,6 +1,7 @@ package gov import ( + "fmt" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,6 +13,12 @@ type DepositParams struct { MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months } +func (dp DepositParams) String() string { + return fmt.Sprintf(`Deposit Params: + Min Deposit: %s + Max Deposit Period: %s`, dp.MinDeposit, dp.MaxDepositPeriod) +} + // Checks equality of DepositParams func (dp DepositParams) Equal(dp2 DepositParams) bool { return dp.MinDeposit.IsEqual(dp2.MinDeposit) && dp.MaxDepositPeriod == dp2.MaxDepositPeriod @@ -25,7 +32,41 @@ type TallyParams struct { GovernancePenalty sdk.Dec `json:"governance_penalty"` // Penalty if validator does not vote } +func (tp TallyParams) String() string { + return fmt.Sprintf(`Tally Params: + Quorum: %s + Threshold: %s + Veto: %s + Governance Penalty: %s`, tp.Quorum, + tp.Threshold, tp.Veto, tp.GovernancePenalty) +} + // Param around Voting in governance type VotingParams struct { VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period. } + +func (vp VotingParams) String() string { + return fmt.Sprintf(`Voting Params: + Voting Period: %s`, vp.VotingPeriod) +} + +// Params returns all of the governance params +type Params struct { + VotingParams VotingParams `json:"voting_params"` + TallyParams TallyParams `json:"tally_params"` + DepositParams DepositParams `json:"deposit_params"` +} + +func (gp Params) String() string { + return gp.VotingParams.String() + "\n" + + gp.TallyParams.String() + "\n" + gp.DepositParams.String() +} + +func NewParams(vp VotingParams, tp TallyParams, dp DepositParams) Params { + return Params{ + VotingParams: vp, + DepositParams: dp, + TallyParams: tp, + } +} diff --git a/x/gov/proposals.go b/x/gov/proposals.go index fd50e079dd91..e5dccfb02cf0 100644 --- a/x/gov/proposals.go +++ b/x/gov/proposals.go @@ -3,6 +3,7 @@ package gov import ( "encoding/json" "fmt" + "strings" "time" "github.com/pkg/errors" @@ -45,6 +46,21 @@ type Proposal interface { GetVotingEndTime() time.Time SetVotingEndTime(time.Time) + + String() string +} + +// Proposals is an array of proposal +type Proposals []Proposal + +func (p Proposals) String() string { + out := "ID - (Status) [Type] Title\n" + for _, prop := range p { + out += fmt.Sprintf("%d - (%s) [%s] %s\n", + prop.GetProposalID(), prop.GetStatus(), + prop.GetProposalType(), prop.GetTitle()) + } + return strings.TrimSpace(out) } // checks if two proposals are equal @@ -119,6 +135,20 @@ func (tp *TextProposal) SetVotingEndTime(votingEndTime time.Time) { tp.VotingEndTime = votingEndTime } +func (tp TextProposal) String() string { + return fmt.Sprintf(`Proposal %d: + Title: %s + Type: %s + Status: %s + Submit Time: %s + Deposit End Time: %s + Total Deposit: %s + Voting Start Time: %s + Voting End Time: %s`, tp.ProposalID, tp.Title, tp.ProposalType, + tp.Status, tp.SubmitTime, tp.DepositEndTime, + tp.TotalDeposit, tp.VotingStartTime, tp.VotingEndTime) +} + //----------------------------------------------------------- // ProposalQueue type ProposalQueue []uint64 @@ -343,9 +373,17 @@ func EmptyTallyResult() TallyResult { } // checks if two proposals are equal -func (resultA TallyResult) Equals(resultB TallyResult) bool { - return (resultA.Yes.Equal(resultB.Yes) && - resultA.Abstain.Equal(resultB.Abstain) && - resultA.No.Equal(resultB.No) && - resultA.NoWithVeto.Equal(resultB.NoWithVeto)) +func (tr TallyResult) Equals(comp TallyResult) bool { + return (tr.Yes.Equal(comp.Yes) && + tr.Abstain.Equal(comp.Abstain) && + tr.No.Equal(comp.No) && + tr.NoWithVeto.Equal(comp.NoWithVeto)) +} + +func (tr TallyResult) String() string { + return fmt.Sprintf(`Tally Result: + Yes: %s + Abstain: %s + No: %s + NoWithVeto: %s`, tr.Yes, tr.Abstain, tr.No, tr.NoWithVeto) } diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index e174567ddf08..fa5f882cc69e 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -4,8 +4,6 @@ import ( "fmt" "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" // XXX fix @@ -15,67 +13,49 @@ import ( // GetCmdQuerySigningInfo implements the command to query signing info. func GetCmdQuerySigningInfo(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "signing-info [validator-pubkey]", Short: "Query a validator's signing information", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + pk, err := sdk.GetConsPubKeyBech32(args[0]) if err != nil { return err } key := slashing.GetValidatorSigningInfoKey(sdk.ConsAddress(pk.Address())) - cliCtx := context.NewCLIContext().WithCodec(cdc) res, err := cliCtx.QueryStore(key, storeName) if err != nil { return err } - signingInfo := new(slashing.ValidatorSigningInfo) + var signingInfo slashing.ValidatorSigningInfo cdc.MustUnmarshalBinaryLengthPrefixed(res, signingInfo) - - switch viper.Get(cli.OutputFlag) { - - case "text": - human := signingInfo.HumanReadableString() - fmt.Println(human) - - case "json": - // parse out the signing info - output, err := codec.MarshalJSONIndent(cdc, signingInfo) - if err != nil { - return err - } - fmt.Println(string(output)) - } - - return nil + return cliCtx.PrintOutput(signingInfo) }, } - - return cmd } // GetCmdQueryParams implements a command to fetch slashing parameters. func GetCmdQueryParams(cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "params", Short: "Query the current slashing parameters", RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - route := fmt.Sprintf("custom/%s/parameters", slashing.QuerierRoute) + route := fmt.Sprintf("custom/%s/parameters", slashing.QuerierRoute) res, err := cliCtx.QueryWithData(route, nil) if err != nil { return err } - fmt.Println(string(res)) - return nil + var params slashing.Params + cdc.MustUnmarshalJSON(res, ¶ms) + return cliCtx.PrintOutput(params) }, } - - return cmd } diff --git a/x/slashing/params.go b/x/slashing/params.go index 4e43c43de7fd..12afad7e9180 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -1,6 +1,7 @@ package slashing import ( + "fmt" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -42,6 +43,19 @@ type Params struct { SlashFractionDowntime sdk.Dec `json:"slash-fraction-downtime"` } +func (p Params) String() string { + return fmt.Sprintf(`Slashing Params: + MaxEvidenceAge: %s + SignedBlocksWindow: %d + MinSignedPerWindow: %s + DowntimeJailDuration: %s + SlashFractionDoubleSign: %d + SlashFractionDowntime: %d`, p.MaxEvidenceAge, + p.SignedBlocksWindow, p.MinSignedPerWindow, + p.DowntimeJailDuration, p.SlashFractionDoubleSign, + p.SlashFractionDowntime) +} + // Implements params.ParamStruct func (p *Params) KeyValuePairs() params.KeyValuePairs { return params.KeyValuePairs{ diff --git a/x/slashing/signing_info.go b/x/slashing/signing_info.go index e8e20706558d..26c9501f549f 100644 --- a/x/slashing/signing_info.go +++ b/x/slashing/signing_info.go @@ -111,7 +111,12 @@ type ValidatorSigningInfo struct { } // Return human readable signing info -func (i ValidatorSigningInfo) HumanReadableString() string { - return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %v, missed blocks counter: %d", - i.StartHeight, i.IndexOffset, i.JailedUntil, i.MissedBlocksCounter) +func (i ValidatorSigningInfo) String() string { + return fmt.Sprintf(`Start Height: %d +Index Offset: %d +Jailed Until: %v +Tombstoned: %t +Missed Blocks Counter: %d`, + i.StartHeight, i.IndexOffset, i.JailedUntil, + i.Tombstoned, i.MissedBlocksCounter) } diff --git a/x/staking/client/cli/query.go b/x/staking/client/cli/query.go index e1aac2466e4f..5d2b20df1a44 100644 --- a/x/staking/client/cli/query.go +++ b/x/staking/client/cli/query.go @@ -4,8 +4,6 @@ import ( "fmt" "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" @@ -16,588 +14,376 @@ import ( // GetCmdQueryValidator implements the validator query command. func GetCmdQueryValidator(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "validator [operator-addr]", Short: "Query a validator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + addr, err := sdk.ValAddressFromBech32(args[0]) if err != nil { return err } - key := staking.GetValidatorKey(addr) - cliCtx := context.NewCLIContext().WithCodec(cdc) - - res, err := cliCtx.QueryStore(key, storeName) + res, err := cliCtx.QueryStore(staking.GetValidatorKey(addr), storeName) if err != nil { return err - } else if len(res) == 0 { - return fmt.Errorf("No validator found with address %s", args[0]) - } - - validator := types.MustUnmarshalValidator(cdc, res) - - switch viper.Get(cli.OutputFlag) { - case "text": - human, err := validator.HumanReadableString() - if err != nil { - return err - } - fmt.Println(human) - - case "json": - // parse out the validator - output, err := codec.MarshalJSONIndent(cdc, validator) - if err != nil { - return err - } - - fmt.Println(string(output)) } - // TODO: output with proofs / machine parseable etc. - return nil + return cliCtx.PrintOutput(types.MustUnmarshalValidator(cdc, res)) }, } - - return cmd } // GetCmdQueryValidators implements the query all validators command. func GetCmdQueryValidators(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "validators", Short: "Query for all validators", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - key := staking.ValidatorsKey cliCtx := context.NewCLIContext().WithCodec(cdc) - resKVs, err := cliCtx.QuerySubspace(key, storeName) + resKVs, err := cliCtx.QuerySubspace(staking.ValidatorsKey, storeName) if err != nil { return err } - // parse out the validators - var validators []staking.Validator + var validators staking.Validators for _, kv := range resKVs { - validator := types.MustUnmarshalValidator(cdc, kv.Value) - validators = append(validators, validator) - } - - switch viper.Get(cli.OutputFlag) { - case "text": - for _, validator := range validators { - resp, err := validator.HumanReadableString() - if err != nil { - return err - } - - fmt.Println(resp) - } - case "json": - output, err := codec.MarshalJSONIndent(cdc, validators) - if err != nil { - return err - } - - fmt.Println(string(output)) - return nil + validators = append(validators, types.MustUnmarshalValidator(cdc, kv.Value)) } - // TODO: output with proofs / machine parseable etc. - return nil + return cliCtx.PrintOutput(validators) }, } - - return cmd } // GetCmdQueryValidatorUnbondingDelegations implements the query all unbonding delegatations from a validator command. func GetCmdQueryValidatorUnbondingDelegations(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "unbonding-delegations-from [operator-addr]", Short: "Query all unbonding delegatations from a validator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + valAddr, err := sdk.ValAddressFromBech32(args[0]) if err != nil { return err } - cliCtx := context.NewCLIContext().WithCodec(cdc) - params := staking.NewQueryValidatorParams(valAddr) - - bz, err := cdc.MarshalJSON(params) + bz, err := cdc.MarshalJSON(staking.NewQueryValidatorParams(valAddr)) if err != nil { return err } - res, err := cliCtx.QueryWithData( - fmt.Sprintf("custom/%s/validatorUnbondingDelegations", storeKey), - bz) + route := fmt.Sprintf("custom/%s/%s", storeKey, staking.QueryValidatorUnbondingDelegations) + res, err := cliCtx.QueryWithData(route, bz) if err != nil { return err } - fmt.Println(string(res)) - return nil + var ubds staking.UnbondingDelegations + cdc.MustUnmarshalJSON(res, &ubds) + return cliCtx.PrintOutput(ubds) }, } - - return cmd } // GetCmdQueryValidatorRedelegations implements the query all redelegatations from a validator command. func GetCmdQueryValidatorRedelegations(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "redelegations-from [operator-addr]", Short: "Query all outgoing redelegatations from a validator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + valAddr, err := sdk.ValAddressFromBech32(args[0]) if err != nil { return err } - cliCtx := context.NewCLIContext().WithCodec(cdc) - params := staking.NewQueryValidatorParams(valAddr) - - bz, err := cdc.MarshalJSON(params) + bz, err := cdc.MarshalJSON(staking.NewQueryValidatorParams(valAddr)) if err != nil { return err } - res, err := cliCtx.QueryWithData( - fmt.Sprintf("custom/%s/validatorRedelegations", storeKey), - bz) + route := fmt.Sprintf("custom/%s/%s", storeKey, staking.QueryValidatorRedelegations) + res, err := cliCtx.QueryWithData(route, bz) if err != nil { return err } - fmt.Println(string(res)) - return nil + var reds staking.Redelegations + cdc.MustUnmarshalJSON(res, &reds) + return cliCtx.PrintOutput(reds) }, } - - return cmd } // GetCmdQueryDelegation the query delegation command. func GetCmdQueryDelegation(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "delegation", + return &cobra.Command{ + Use: "delegation [delegator-addr] [validator-addr]", Short: "Query a delegation based on address and validator address", + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + valAddr, err := sdk.ValAddressFromBech32(args[1]) if err != nil { return err } - delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator)) + delAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } - key := staking.GetDelegationKey(delAddr, valAddr) - cliCtx := context.NewCLIContext().WithCodec(cdc) - - res, err := cliCtx.QueryStore(key, storeName) + res, err := cliCtx.QueryStore(staking.GetDelegationKey(delAddr, valAddr), storeName) if err != nil { return err } - // parse out the delegation delegation, err := types.UnmarshalDelegation(cdc, res) if err != nil { return err } - switch viper.Get(cli.OutputFlag) { - case "text": - resp, err := delegation.HumanReadableString() - if err != nil { - return err - } - - fmt.Println(resp) - case "json": - output, err := codec.MarshalJSONIndent(cdc, delegation) - if err != nil { - return err - } - - fmt.Println(string(output)) - return nil - } - - return nil + return cliCtx.PrintOutput(delegation) }, } - - cmd.Flags().AddFlagSet(fsValidator) - cmd.Flags().AddFlagSet(fsDelegator) - - return cmd } // GetCmdQueryDelegations implements the command to query all the delegations // made from one delegator. func GetCmdQueryDelegations(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "delegations [delegator-addr]", Short: "Query all delegations made from one delegator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + delegatorAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } - key := staking.GetDelegationsKey(delegatorAddr) - cliCtx := context.NewCLIContext().WithCodec(cdc) - - resKVs, err := cliCtx.QuerySubspace(key, storeName) + resKVs, err := cliCtx.QuerySubspace(staking.GetDelegationsKey(delegatorAddr), storeName) if err != nil { return err } - // parse out the validators - var delegations []staking.Delegation + var delegations staking.Delegations for _, kv := range resKVs { - delegation := types.MustUnmarshalDelegation(cdc, kv.Value) - delegations = append(delegations, delegation) + delegations = append(delegations, types.MustUnmarshalDelegation(cdc, kv.Value)) } - output, err := codec.MarshalJSONIndent(cdc, delegations) - if err != nil { - return err - } - - fmt.Println(string(output)) - - // TODO: output with proofs / machine parseable etc. - return nil + return cliCtx.PrintOutput(delegations) }, } - - return cmd } // GetCmdQueryValidatorDelegations implements the command to query all the // delegations to a specific validator. func GetCmdQueryValidatorDelegations(storeKey string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "delegations-to [validator-addr]", Short: "Query all delegations made to one validator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + validatorAddr, err := sdk.ValAddressFromBech32(args[0]) if err != nil { return err } - params := staking.NewQueryValidatorParams(validatorAddr) - - bz, err := cdc.MarshalJSON(params) + bz, err := cdc.MarshalJSON(staking.NewQueryValidatorParams(validatorAddr)) if err != nil { return err } - cliCtx := context.NewCLIContext().WithCodec(cdc) - - res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/validatorDelegations", storeKey), bz) + route := fmt.Sprintf("custom/%s/%s", storeKey, staking.QueryValidatorDelegations) + res, err := cliCtx.QueryWithData(route, bz) if err != nil { return err } - fmt.Println(string(res)) - return nil + var dels staking.Delegations + cdc.MustUnmarshalJSON(res, &dels) + return cliCtx.PrintOutput(dels) }, } - - return cmd } // GetCmdQueryUnbondingDelegation implements the command to query a single // unbonding-delegation record. func GetCmdQueryUnbondingDelegation(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "unbonding-delegation", + return &cobra.Command{ + Use: "unbonding-delegation [delegator-addr] [validator-addr]", Short: "Query an unbonding-delegation record based on delegator and validator address", + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + valAddr, err := sdk.ValAddressFromBech32(args[1]) if err != nil { return err } - delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator)) + delAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } - key := staking.GetUBDKey(delAddr, valAddr) - cliCtx := context.NewCLIContext().WithCodec(cdc) - - res, err := cliCtx.QueryStore(key, storeName) + res, err := cliCtx.QueryStore(staking.GetUBDKey(delAddr, valAddr), storeName) if err != nil { return err } - // parse out the unbonding delegation - ubd := types.MustUnmarshalUBD(cdc, res) - - switch viper.Get(cli.OutputFlag) { - case "text": - resp, err := ubd.HumanReadableString() - if err != nil { - return err - } + return cliCtx.PrintOutput(types.MustUnmarshalUBD(cdc, res)) - fmt.Println(resp) - case "json": - output, err := codec.MarshalJSONIndent(cdc, ubd) - if err != nil { - return err - } - - fmt.Println(string(output)) - return nil - } - - return nil }, } - - cmd.Flags().AddFlagSet(fsValidator) - cmd.Flags().AddFlagSet(fsDelegator) - - return cmd } // GetCmdQueryUnbondingDelegations implements the command to query all the // unbonding-delegation records for a delegator. func GetCmdQueryUnbondingDelegations(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "unbonding-delegations [delegator-addr]", Short: "Query all unbonding-delegations records for one delegator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + delegatorAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } - key := staking.GetUBDsKey(delegatorAddr) - cliCtx := context.NewCLIContext().WithCodec(cdc) - - resKVs, err := cliCtx.QuerySubspace(key, storeName) + resKVs, err := cliCtx.QuerySubspace(staking.GetUBDsKey(delegatorAddr), storeName) if err != nil { return err } - // parse out the unbonding delegations - var ubds []staking.UnbondingDelegation + var ubds staking.UnbondingDelegations for _, kv := range resKVs { - ubd := types.MustUnmarshalUBD(cdc, kv.Value) - ubds = append(ubds, ubd) + ubds = append(ubds, types.MustUnmarshalUBD(cdc, kv.Value)) } - output, err := codec.MarshalJSONIndent(cdc, ubds) - if err != nil { - return err - } - - fmt.Println(string(output)) - - // TODO: output with proofs / machine parseable etc. - return nil + return cliCtx.PrintOutput(ubds) }, } - - return cmd } // GetCmdQueryRedelegation implements the command to query a single // redelegation record. func GetCmdQueryRedelegation(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "redelegation", + return &cobra.Command{ + Use: "redelegation [delegator-addr] [validator-src-addr] [validator-dst-addr]", Short: "Query a redelegation record based on delegator and a source and destination validator address", + Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) error { - valSrcAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorSrc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + valSrcAddr, err := sdk.ValAddressFromBech32(args[1]) if err != nil { return err } - valDstAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorDst)) + valDstAddr, err := sdk.ValAddressFromBech32(args[2]) if err != nil { return err } - delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator)) + delAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } - key := staking.GetREDKey(delAddr, valSrcAddr, valDstAddr) - cliCtx := context.NewCLIContext().WithCodec(cdc) - - res, err := cliCtx.QueryStore(key, storeName) + res, err := cliCtx.QueryStore(staking.GetREDKey(delAddr, valSrcAddr, valDstAddr), storeName) if err != nil { return err } - // parse out the unbonding delegation - red := types.MustUnmarshalRED(cdc, res) - - switch viper.Get(cli.OutputFlag) { - case "text": - resp, err := red.HumanReadableString() - if err != nil { - return err - } - - fmt.Println(resp) - case "json": - output, err := codec.MarshalJSONIndent(cdc, red) - if err != nil { - return err - } - - fmt.Println(string(output)) - return nil - } - - return nil + return cliCtx.PrintOutput(types.MustUnmarshalRED(cdc, res)) }, } - - cmd.Flags().AddFlagSet(fsRedelegation) - cmd.Flags().AddFlagSet(fsDelegator) - - return cmd } // GetCmdQueryRedelegations implements the command to query all the // redelegation records for a delegator. func GetCmdQueryRedelegations(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "redelegations [delegator-addr]", Short: "Query all redelegations records for one delegator", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := context.NewCLIContext().WithCodec(cdc) + delegatorAddr, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } - key := staking.GetREDsKey(delegatorAddr) - cliCtx := context.NewCLIContext().WithCodec(cdc) - - resKVs, err := cliCtx.QuerySubspace(key, storeName) + resKVs, err := cliCtx.QuerySubspace(staking.GetREDsKey(delegatorAddr), storeName) if err != nil { return err } - // parse out the validators - var reds []staking.Redelegation + var reds staking.Redelegations for _, kv := range resKVs { - red := types.MustUnmarshalRED(cdc, kv.Value) - reds = append(reds, red) - } - - output, err := codec.MarshalJSONIndent(cdc, reds) - if err != nil { - return err + reds = append(reds, types.MustUnmarshalRED(cdc, kv.Value)) } - fmt.Println(string(output)) - - // TODO: output with proofs / machine parseable etc. - return nil + return cliCtx.PrintOutput(reds) }, } - - return cmd } // GetCmdQueryPool implements the pool query command. func GetCmdQueryPool(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ + return &cobra.Command{ Use: "pool", Short: "Query the current staking pool values", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - key := staking.PoolKey cliCtx := context.NewCLIContext().WithCodec(cdc) - res, err := cliCtx.QueryStore(key, storeName) + res, err := cliCtx.QueryStore(staking.PoolKey, storeName) if err != nil { return err } - pool := types.MustUnmarshalPool(cdc, res) - - switch viper.Get(cli.OutputFlag) { - case "text": - human := pool.HumanReadableString() - - fmt.Println(human) - - case "json": - // parse out the pool - output, err := codec.MarshalJSONIndent(cdc, pool) - if err != nil { - return err - } - - fmt.Println(string(output)) - } - return nil + return cliCtx.PrintOutput(types.MustUnmarshalPool(cdc, res)) }, } - - return cmd } // GetCmdQueryPool implements the params query command. func GetCmdQueryParams(storeName string, cdc *codec.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "parameters", + return &cobra.Command{ + Use: "params", Short: "Query the current staking parameters information", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { cliCtx := context.NewCLIContext().WithCodec(cdc) - bz, err := cliCtx.QueryWithData("custom/staking/"+staking.QueryParameters, nil) - if err != nil { - return err - } - var params staking.Params - err = cdc.UnmarshalJSON(bz, ¶ms) + route := fmt.Sprintf("custom/%s/%s", storeName, staking.QueryParameters) + bz, err := cliCtx.QueryWithData(route, nil) if err != nil { return err } - switch viper.Get(cli.OutputFlag) { - case "text": - human := params.HumanReadableString() - - fmt.Println(human) - - case "json": - // parse out the params - output, err := codec.MarshalJSONIndent(cdc, params) - if err != nil { - return err - } - - fmt.Println(string(output)) - } - return nil + var params staking.Params + cdc.MustUnmarshalJSON(bz, ¶ms) + return cliCtx.PrintOutput(params) }, } - - return cmd } diff --git a/x/staking/querier/querier.go b/x/staking/querier/querier.go index 4d8ad619cd3b..e842c2197f3a 100644 --- a/x/staking/querier/querier.go +++ b/x/staking/querier/querier.go @@ -17,6 +17,7 @@ const ( QueryDelegatorUnbondingDelegations = "delegatorUnbondingDelegations" QueryRedelegations = "redelegations" QueryValidatorDelegations = "validatorDelegations" + QueryValidatorRedelegations = "validatorRedelegations" QueryValidatorUnbondingDelegations = "validatorUnbondingDelegations" QueryDelegator = "delegator" QueryDelegation = "delegation" diff --git a/x/staking/staking.go b/x/staking/staking.go index 81b78107d1cc..53d37fd06cfc 100644 --- a/x/staking/staking.go +++ b/x/staking/staking.go @@ -11,11 +11,15 @@ import ( type ( Keeper = keeper.Keeper Validator = types.Validator + Validators = types.Validators Description = types.Description Commission = types.Commission Delegation = types.Delegation + Delegations = types.Delegations UnbondingDelegation = types.UnbondingDelegation + UnbondingDelegations = types.UnbondingDelegations Redelegation = types.Redelegation + Redelegations = types.Redelegations Params = types.Params Pool = types.Pool MsgCreateValidator = types.MsgCreateValidator @@ -94,6 +98,8 @@ var ( const ( QueryValidators = querier.QueryValidators QueryValidator = querier.QueryValidator + QueryValidatorDelegations = querier.QueryValidatorDelegations + QueryValidatorRedelegations = querier.QueryValidatorRedelegations QueryValidatorUnbondingDelegations = querier.QueryValidatorUnbondingDelegations QueryDelegation = querier.QueryDelegation QueryUnbondingDelegation = querier.QueryUnbondingDelegation diff --git a/x/staking/types/delegation.go b/x/staking/types/delegation.go index 87a4759932c3..e46f89624633 100644 --- a/x/staking/types/delegation.go +++ b/x/staking/types/delegation.go @@ -3,6 +3,7 @@ package types import ( "bytes" "fmt" + "strings" "time" "github.com/cosmos/cosmos-sdk/codec" @@ -83,16 +84,23 @@ func (d Delegation) GetDelegatorAddr() sdk.AccAddress { return d.DelegatorAddr } func (d Delegation) GetValidatorAddr() sdk.ValAddress { return d.ValidatorAddr } func (d Delegation) GetShares() sdk.Dec { return d.Shares } -// HumanReadableString returns a human readable string representation of a -// Delegation. An error is returned if the Delegation's delegator or validator -// addresses cannot be Bech32 encoded. -func (d Delegation) HumanReadableString() (string, error) { - resp := "Delegation \n" - resp += fmt.Sprintf("Delegator: %s\n", d.DelegatorAddr) - resp += fmt.Sprintf("Validator: %s\n", d.ValidatorAddr) - resp += fmt.Sprintf("Shares: %s\n", d.Shares.String()) +// String returns a human readable string representation of a Delegation. +func (d Delegation) String() string { + return fmt.Sprintf(`Delegation: + Delegator: %s + Validator: %s + Shares: %s`, d.DelegatorAddr, + d.ValidatorAddr, d.Shares) +} + +// Delegations is a collection of delegations +type Delegations []Delegation - return resp, nil +func (d Delegations) String() (out string) { + for _, del := range d { + out += del.String() + "\n" + } + return strings.TrimSpace(out) } //________________________________________________________________________ @@ -183,21 +191,30 @@ func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool { return bytes.Equal(bz1, bz2) } -// HumanReadableString returns a human readable string representation of an -// UnbondingDelegation. An error is returned if the UnbondingDelegation's -// delegator or validator addresses cannot be Bech32 encoded. -func (d UnbondingDelegation) HumanReadableString() (string, error) { - resp := "Unbonding Delegation \n" - resp += fmt.Sprintf("Delegator: %s\n", d.DelegatorAddr) - resp += fmt.Sprintf("Validator: %s\n", d.ValidatorAddr) - for _, entry := range d.Entries { - resp += "Unbonding Delegation Entry\n" - resp += fmt.Sprintf("Creation height: %v\n", entry.CreationHeight) - resp += fmt.Sprintf("Min time to unbond (unix): %v\n", entry.CompletionTime) - resp += fmt.Sprintf("Expected balance: %s", entry.Balance.String()) +// String returns a human readable string representation of an UnbondingDelegation. +func (d UnbondingDelegation) String() string { + out := fmt.Sprintf(`Unbonding Delegations between: + Delegator: %s + Validator: %s + Entries:`, d.DelegatorAddr, d.ValidatorAddr) + for i, entry := range d.Entries { + out += fmt.Sprintf(` Unbonding Delegation %d: + Creation Height: %v + Min time to unbond (unix): %v + Expected balance: %s`, i, entry.CreationHeight, + entry.CompletionTime, entry.Balance) } + return out +} + +// UnbondingDelegations is a collection of UnbondingDelegation +type UnbondingDelegations []UnbondingDelegation - return resp, nil +func (ubds UnbondingDelegations) String() (out string) { + for _, u := range ubds { + out += u.String() + "\n" + } + return strings.TrimSpace(out) } // Redelegation reflects a delegation's passive re-delegation queue. @@ -296,19 +313,30 @@ func (d Redelegation) Equal(d2 Redelegation) bool { return bytes.Equal(bz1, bz2) } -// HumanReadableString returns a human readable string representation of a -// Redelegation. An error is returned if the UnbondingDelegation's delegator or -// validator addresses cannot be Bech32 encoded. -func (d Redelegation) HumanReadableString() (string, error) { - resp := "Redelegation \n" - resp += fmt.Sprintf("Delegator: %s\n", d.DelegatorAddr) - resp += fmt.Sprintf("Source Validator: %s\n", d.ValidatorSrcAddr) - resp += fmt.Sprintf("Destination Validator: %s\n", d.ValidatorDstAddr) - for _, entry := range d.Entries { - resp += fmt.Sprintf("Creation height: %v\n", entry.CreationHeight) - resp += fmt.Sprintf("Min time to unbond (unix): %v\n", entry.CompletionTime) - resp += fmt.Sprintf("Source shares: %s\n", entry.SharesSrc.String()) - resp += fmt.Sprintf("Destination shares: %s", entry.SharesDst.String()) +// String returns a human readable string representation of a Redelegation. +func (d Redelegation) String() string { + out := fmt.Sprintf(`Redelegations between: + Delegator: %s + Source Validator: %s + Destination Validator: %s + Entries:`, d.DelegatorAddr, d.ValidatorSrcAddr, d.ValidatorDstAddr) + for i, entry := range d.Entries { + out += fmt.Sprintf(` Redelegation %d: + Creation height: %v + Min time to unbond (unix): %v + Source shares: %s + Dest Shares: %s`, i, entry.CreationHeight, + entry.CompletionTime, entry.SharesSrc, entry.SharesDst) + } + return out +} + +// Redelegations are a collection of Redelegation +type Redelegations []Redelegation + +func (d Redelegations) String() (out string) { + for _, red := range d { + out += red.String() + "\n" } - return resp, nil + return strings.TrimSpace(out) } diff --git a/x/staking/types/delegation_test.go b/x/staking/types/delegation_test.go index 95f58d678252..a2a637685a06 100644 --- a/x/staking/types/delegation_test.go +++ b/x/staking/types/delegation_test.go @@ -23,14 +23,9 @@ func TestDelegationEqual(t *testing.T) { require.False(t, ok) } -func TestDelegationHumanReadableString(t *testing.T) { +func TestDelegationString(t *testing.T) { d := NewDelegation(sdk.AccAddress(addr1), addr2, sdk.NewDec(100)) - - // NOTE: Being that the validator's keypair is random, we cannot test the - // actual contents of the string. - valStr, err := d.HumanReadableString() - require.Nil(t, err) - require.NotEmpty(t, valStr) + require.NotEmpty(t, d.String()) } func TestUnbondingDelegationEqual(t *testing.T) { @@ -48,15 +43,11 @@ func TestUnbondingDelegationEqual(t *testing.T) { require.False(t, ok) } -func TestUnbondingDelegationHumanReadableString(t *testing.T) { +func TestUnbondingDelegationString(t *testing.T) { ubd := NewUnbondingDelegation(sdk.AccAddress(addr1), addr2, 0, time.Unix(0, 0), sdk.NewInt64Coin(DefaultBondDenom, 0)) - // NOTE: Being that the validator's keypair is random, we cannot test the - // actual contents of the string. - valStr, err := ubd.HumanReadableString() - require.Nil(t, err) - require.NotEmpty(t, valStr) + require.NotEmpty(t, ubd.String()) } func TestRedelegationEqual(t *testing.T) { @@ -78,14 +69,10 @@ func TestRedelegationEqual(t *testing.T) { require.False(t, ok) } -func TestRedelegationHumanReadableString(t *testing.T) { +func TestRedelegationString(t *testing.T) { r := NewRedelegation(sdk.AccAddress(addr1), addr2, addr3, 0, time.Unix(0, 0), sdk.NewInt64Coin(DefaultBondDenom, 0), sdk.NewDec(10), sdk.NewDec(20)) - // NOTE: Being that the validator's keypair is random, we cannot test the - // actual contents of the string. - valStr, err := r.HumanReadableString() - require.Nil(t, err) - require.NotEmpty(t, valStr) + require.NotEmpty(t, r.String()) } diff --git a/x/staking/types/params.go b/x/staking/types/params.go index 481390bda2a4..7120085e046e 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -65,15 +65,13 @@ func DefaultParams() Params { } } -// HumanReadableString returns a human readable string representation of the -// parameters. -func (p Params) HumanReadableString() string { - - resp := "Params \n" - resp += fmt.Sprintf("Unbonding Time: %s\n", p.UnbondingTime) - resp += fmt.Sprintf("Max Validators: %d\n", p.MaxValidators) - resp += fmt.Sprintf("Bonded Coin Denomination: %s\n", p.BondDenom) - return resp +// String returns a human readable string representation of the parameters. +func (p Params) String() string { + return fmt.Sprintf(`Params: + Unbonding Time: %s) + Max Validators: %d) + Bonded Coin Denomination: %s`, p.UnbondingTime, + p.MaxValidators, p.BondDenom) } // unmarshal the current staking params value from store key or panic diff --git a/x/staking/types/pool.go b/x/staking/types/pool.go index 0ae9f26c4ec3..3f56285204ad 100644 --- a/x/staking/types/pool.go +++ b/x/staking/types/pool.go @@ -10,8 +10,8 @@ import ( // Pool - dynamic parameters of the current state type Pool struct { - NotBondedTokens sdk.Int `json:"not_bonded_tokens"` // tokens which are not bonded in a validator - BondedTokens sdk.Int `json:"bonded_tokens"` // reserve of bonded tokens + NotBondedTokens sdk.Int `json:"not_bonded_tokens"` // tokens which are not bonded in a validator + BondedTokens sdk.Int `json:"bonded_tokens"` // reserve of bonded tokens } // nolint @@ -24,8 +24,8 @@ func (p Pool) Equal(p2 Pool) bool { // initial pool for testing func InitialPool() Pool { return Pool{ - NotBondedTokens: sdk.ZeroInt(), - BondedTokens: sdk.ZeroInt(), + NotBondedTokens: sdk.ZeroInt(), + BondedTokens: sdk.ZeroInt(), } } @@ -68,16 +68,15 @@ func (p Pool) bondedTokensToNotBonded(bondedTokens sdk.Int) Pool { return p } -// HumanReadableString returns a human readable string representation of a -// pool. -func (p Pool) HumanReadableString() string { - - resp := "Pool \n" - resp += fmt.Sprintf("Not-Bonded Tokens: %s\n", p.NotBondedTokens) - resp += fmt.Sprintf("Bonded Tokens: %s\n", p.BondedTokens) - resp += fmt.Sprintf("Token Supply: %s\n", p.TokenSupply()) - resp += fmt.Sprintf("Bonded Ratio: %v\n", p.BondedRatio()) - return resp +// String returns a human readable string representation of a pool. +func (p Pool) String() string { + return fmt.Sprintf(`Pool: + Loose Tokens: %s + Bonded Tokens: %s + Token Supply: %s + Bonded Ratio: %v`, p.NotBondedTokens, + p.BondedTokens, p.TokenSupply(), + p.BondedRatio()) } // unmarshal the current pool value from store key or panics diff --git a/x/staking/types/validator.go b/x/staking/types/validator.go index 8333ebbb5245..ea8dafe2bed1 100644 --- a/x/staking/types/validator.go +++ b/x/staking/types/validator.go @@ -3,6 +3,7 @@ package types import ( "bytes" "fmt" + "strings" "time" abci "github.com/tendermint/tendermint/abci/types" @@ -38,6 +39,16 @@ type Validator struct { Commission Commission `json:"commission"` // commission parameters } +// Validators is a collection of Validator +type Validators []Validator + +func (v Validators) String() (out string) { + for _, val := range v { + out += val.String() + "\n" + } + return strings.TrimSpace(out) +} + // NewValidator - initialize a new validator func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Description) Validator { return Validator{ @@ -75,29 +86,27 @@ func UnmarshalValidator(cdc *codec.Codec, value []byte) (validator Validator, er return validator, err } -// HumanReadableString returns a human readable string representation of a -// validator. An error is returned if the operator or the operator's public key -// cannot be converted to Bech32 format. -func (v Validator) HumanReadableString() (string, error) { +// String returns a human readable string representation of a validator. +func (v Validator) String() string { bechConsPubKey, err := sdk.Bech32ifyConsPub(v.ConsPubKey) if err != nil { - return "", err + panic(err) } - - resp := "Validator \n" - resp += fmt.Sprintf("Operator Address: %s\n", v.OperatorAddr) - resp += fmt.Sprintf("Validator Consensus Pubkey: %s\n", bechConsPubKey) - resp += fmt.Sprintf("Jailed: %v\n", v.Jailed) - resp += fmt.Sprintf("Status: %s\n", sdk.BondStatusToString(v.Status)) - resp += fmt.Sprintf("Tokens: %s\n", v.Tokens) - resp += fmt.Sprintf("Delegator Shares: %s\n", v.DelegatorShares.String()) - resp += fmt.Sprintf("Description: %s\n", v.Description) - resp += fmt.Sprintf("Bond Height: %d\n", v.BondHeight) - resp += fmt.Sprintf("Unbonding Height: %d\n", v.UnbondingHeight) - resp += fmt.Sprintf("Minimum Unbonding Time: %v\n", v.UnbondingCompletionTime) - resp += fmt.Sprintf("Commission: {%s}\n", v.Commission) - - return resp, nil + return fmt.Sprintf(`Validator + Operator Address: %s + Validator Consensus Pubkey: %s + Jailed: %v + Status: %s + Tokens: %s + Delegator Shares: %s + Description: %s + Bond Height: %d + Unbonding Height: %d + Unbonding Completion Time: %v + Commission: %s`, v.OperatorAddr, bechConsPubKey, + v.Jailed, sdk.BondStatusToString(v.Status), v.Tokens, + v.DelegatorShares, v.Description, v.BondHeight, + v.UnbondingHeight, v.UnbondingCompletionTime, v.Commission) } //___________________________________________________________________ diff --git a/x/staking/types/validator_test.go b/x/staking/types/validator_test.go index 1094222cec6c..d216131b8440 100644 --- a/x/staking/types/validator_test.go +++ b/x/staking/types/validator_test.go @@ -245,16 +245,6 @@ func TestPossibleOverflow(t *testing.T) { msg, newValidator.DelegatorShareExRate()) } -func TestHumanReadableString(t *testing.T) { - validator := NewValidator(addr1, pk1, Description{}) - - // NOTE: Being that the validator's keypair is random, we cannot test the - // actual contents of the string. - valStr, err := validator.HumanReadableString() - require.Nil(t, err) - require.NotEmpty(t, valStr) -} - func TestValidatorMarshalUnmarshalJSON(t *testing.T) { validator := NewValidator(addr1, pk1, Description{}) js, err := codec.Cdc.MarshalJSON(validator)