Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add proto compatible x/distribution tx cli #5941

Merged
merged 8 commits into from
Apr 8, 2020
233 changes: 232 additions & 1 deletion x/distribution/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package cli
import (
"bufio"
"fmt"
"github.com/cosmos/cosmos-sdk/client/tx"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -34,6 +35,237 @@ const (
MaxMessagesPerTxDefault = 5
)

// NewTxCmd returns a root CLI command handler for all x/distribution transaction commands.
func NewTxCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command {
distTxCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Distribution transactions subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

distTxCmd.AddCommand(flags.PostCommands(
NewWithdrawRewardsCmd(m, txg, ar),
NewWithdrawAllRewardsCmd(m, txg, ar),
NewSetWithdrawAddrCmd(m, txg, ar),
NewFundCommunityPoolCmd(m, txg, ar),
)...)

return distTxCmd
}

type newGenerateOrBroadcastFunc func(ctx context.CLIContext, txf tx.Factory, msgs ...sdk.Msg) error

func newSplitAndApply(
newGenerateOrBroadcast newGenerateOrBroadcastFunc,
cliCtx context.CLIContext,
txBldr tx.Factory,
msgs []sdk.Msg,
chunkSize int,
) error {
if chunkSize == 0 {
return newGenerateOrBroadcast(cliCtx, txBldr, msgs...)
}

// split messages into slices of length chunkSize
totalMessages := len(msgs)
for i := 0; i < len(msgs); i += chunkSize {

sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
sliceEnd := i + chunkSize
if sliceEnd > totalMessages {
sliceEnd = totalMessages
}

msgChunk := msgs[i:sliceEnd]
if err := newGenerateOrBroadcast(cliCtx, txBldr, msgChunk...); err != nil {
return err
}
}

return nil
}

func NewWithdrawRewardsCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw-rewards [validator-addr]",
Short: "Withdraw rewards from a given delegation address, and optionally withdraw validator commission if the delegation address given is a validator operator",
Long: strings.TrimSpace(
fmt.Sprintf(`Withdraw rewards from a given delegation address,
and optionally withdraw validator commission if the delegation address given is a validator operator.

Example:
$ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey
$ %s tx distribution withdraw-rewards cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj --from mykey --commission
`,
version.ClientName, version.ClientName,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txf := tx.NewFactoryFromCLI(inBuf).
WithTxGenerator(txg).
WithAccountRetriever(ar)
cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m)

delAddr := cliCtx.GetFromAddress()
valAddr, err := sdk.ValAddressFromBech32(args[0])
if err != nil {
return err
}

msgs := []sdk.Msg{types.NewMsgWithdrawDelegatorReward(delAddr, valAddr)}
if viper.GetBool(flagCommission) {
msgs = append(msgs, types.NewMsgWithdrawValidatorCommission(valAddr))
}
fedekunze marked this conversation as resolved.
Show resolved Hide resolved

for _, msg := range msgs {
if err := msg.ValidateBasic(); err != nil {
return err
}
}

return tx.GenerateOrBroadcastTx(cliCtx, txf, msgs...)
},
}
cmd.Flags().Bool(flagCommission, false, "also withdraw validator's commission")
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
return flags.PostCommands(cmd)[0]
}

func NewWithdrawAllRewardsCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw-all-rewards",
Short: "withdraw all delegations rewards for a delegator",
Long: strings.TrimSpace(
fmt.Sprintf(`Withdraw all rewards for a single delegator.

Example:
$ %s tx distribution withdraw-all-rewards --from mykey
`,
version.ClientName,
),
),
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txf := tx.NewFactoryFromCLI(inBuf).
WithTxGenerator(txg).
WithAccountRetriever(ar)
cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be NewCLIContextWithInput as args[0] actually doesn't point to anything - this will probably cause an out of bounds panic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review @aaronc, I see there's same issue in multiple modules. I addressed them all in a seperate PR


delAddr := cliCtx.GetFromAddress()

// The transaction cannot be generated offline since it requires a query
// to get all the validators.
if cliCtx.Offline {
return fmt.Errorf("cannot generate tx in offline mode")
}

msgs, err := common.WithdrawAllDelegatorRewards(cliCtx, types.QuerierRoute, delAddr)
if err != nil {
return err
}

chunkSize := viper.GetInt(flagMaxMessagesPerTx)
return newSplitAndApply(tx.GenerateOrBroadcastTx, cliCtx, txf, msgs, chunkSize)
},
}
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
return flags.PostCommands(cmd)[0]
}

func NewSetWithdrawAddrCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command {
cmd := &cobra.Command{
Use: "set-withdraw-addr [withdraw-addr]",
Short: "change the default withdraw address for rewards associated with an address",
Long: strings.TrimSpace(
fmt.Sprintf(`Set the withdraw address for rewards associated with a delegator address.

Example:
$ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p --from mykey
`,
version.ClientName,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txf := tx.NewFactoryFromCLI(inBuf).
WithTxGenerator(txg).
WithAccountRetriever(ar)
cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m)

delAddr := cliCtx.GetFromAddress()
withdrawAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}

msg := types.NewMsgSetWithdrawAddress(delAddr, withdrawAddr)
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
if err := msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTx(cliCtx, txf, msg)
},
}
return flags.PostCommands(cmd)[0]
}

func NewFundCommunityPoolCmd(m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever) *cobra.Command {
cmd := &cobra.Command{
Use: "community-pool-spend [proposal-file]",
Args: cobra.ExactArgs(1),
Short: "Submit a community pool spend proposal",
Long: strings.TrimSpace(
fmt.Sprintf(`Submit a community pool spend proposal along with an initial deposit.
The proposal details must be supplied via a JSON file.

Example:
$ %s tx gov submit-proposal community-pool-spend <path/to/proposal.json> --from=<key_or_address>

Where proposal.json contains:

{
"title": "Community Pool Spend",
"description": "Pay me some Atoms!",
"recipient": "cosmos1s5afhd6gxevu37mkqcvvsj8qeylhn0rz46zdlq",
"amount": "1000stake",
"deposit": "1000stake"
}
`,
version.ClientName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txf := tx.NewFactoryFromCLI(inBuf).
WithTxGenerator(txg).
WithAccountRetriever(ar)
cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithMarshaler(m)

sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
depositorAddr := cliCtx.GetFromAddress()
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
amount, err := sdk.ParseCoins(args[0])
if err != nil {
return err
}

msg := types.NewMsgFundCommunityPool(amount, depositorAddr)
if err := msg.ValidateBasic(); err != nil {
return err
}

return tx.GenerateOrBroadcastTx(cliCtx, txf, msg)
},
}
return flags.PostCommands(cmd)[0]
}

// ---------------------------------------------------------------------------
sahith-narahari marked this conversation as resolved.
Show resolved Hide resolved
// Deprecated
//
// TODO: Remove once client-side Protobuf migration has been completed.
// ---------------------------------------------------------------------------
// GetTxCmd returns the transaction commands for this module
func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
distTxCmd := &cobra.Command{
Expand Down Expand Up @@ -184,7 +416,6 @@ $ %s tx distribution set-withdraw-addr cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {

inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
Expand Down
Loading