cosmos-sdk/client/cmd.go

335 lines
11 KiB
Go
Raw Normal View History

package client
import (
"fmt"
2020-04-04 11:24:11 -07:00
"strings"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// ClientContextKey defines the context key used to retrieve a client.Context from
// a command's Context.
const ClientContextKey = sdk.ContextKey("client.context")
// SetCmdClientContextHandler is to be used in a command pre-hook execution to
// read flags that populate a Context and sets that to the command's Context.
func SetCmdClientContextHandler(clientCtx Context, cmd *cobra.Command) (err error) {
clientCtx, err = ReadPersistentCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
return SetCmdClientContext(cmd, clientCtx)
}
// ValidateCmd returns unknown command error or Help display if help flag set
func ValidateCmd(cmd *cobra.Command, args []string) error {
2020-04-04 11:24:11 -07:00
var unknownCmd string
var skipNext bool
for _, arg := range args {
2020-04-04 11:24:11 -07:00
// search for help flag
if arg == "--help" || arg == "-h" {
2020-04-04 11:24:11 -07:00
return cmd.Help()
}
// check if the current arg is a flag
switch {
case len(arg) > 0 && (arg[0] == '-'):
// the next arg should be skipped if the current arg is a
// flag and does not use "=" to assign the flag's value
if !strings.Contains(arg, "=") {
skipNext = true
} else {
skipNext = false
}
case skipNext:
// skip current arg
skipNext = false
case unknownCmd == "":
// unknown command found
// continue searching for help flag
unknownCmd = arg
}
}
2020-04-04 11:24:11 -07:00
// return the help screen if no unknown command is found
if unknownCmd != "" {
err := fmt.Sprintf("unknown command \"%s\" for \"%s\"", unknownCmd, cmd.CalledAs())
// build suggestions for unknown argument
2020-04-04 11:24:11 -07:00
if suggestions := cmd.SuggestionsFor(unknownCmd); len(suggestions) > 0 {
err += "\n\nDid you mean this?\n"
for _, s := range suggestions {
err += fmt.Sprintf("\t%v\n", s)
}
}
return errors.New(err)
}
return cmd.Help()
}
// ReadPersistentCommandFlags returns a Context with fields set for "persistent"
// or common flags that do not necessarily change with context.
//
// Note, the provided clientCtx may have field pre-populated. The following order
// of precedence occurs:
//
// - client.Context field not pre-populated & flag not set: uses default flag value
// - client.Context field not pre-populated & flag set: uses set flag value
// - client.Context field pre-populated & flag not set: uses pre-populated value
// - client.Context field pre-populated & flag set: uses set flag value
func ReadPersistentCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, error) {
if clientCtx.OutputFormat == "" || flagSet.Changed(cli.OutputFlag) {
output, _ := flagSet.GetString(cli.OutputFlag)
clientCtx = clientCtx.WithOutputFormat(output)
}
fix: --home flag parsing (#10226) <!-- The default pull request template is for types feat, fix, or refactor. For other templates, add one of the following parameters to the url: - template=docs.md - template=other.md --> ## Description Closes: #XXXX <!-- Add a description of the changes that this PR introduces and the files that are the most critical to review. --> --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [x] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [x] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [x] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [x] reviewed state machine logic - [x] reviewed API design and naming - [x] reviewed documentation is accurate - [x] reviewed tests and test coverage - [x] manually tested (if applicable)
2021-09-30 05:01:56 -07:00
if clientCtx.HomeDir == "" || flagSet.Changed(flags.FlagHome) {
homeDir, _ := flagSet.GetString(flags.FlagHome)
clientCtx = clientCtx.WithHomeDir(homeDir)
}
if !clientCtx.Simulate || flagSet.Changed(flags.FlagDryRun) {
dryRun, _ := flagSet.GetBool(flags.FlagDryRun)
clientCtx = clientCtx.WithSimulation(dryRun)
}
2020-10-08 10:41:35 -07:00
if clientCtx.KeyringDir == "" || flagSet.Changed(flags.FlagKeyringDir) {
keyringDir, _ := flagSet.GetString(flags.FlagKeyringDir)
// The keyring directory is optional and falls back to the home directory
// if omitted.
if keyringDir == "" {
keyringDir = clientCtx.HomeDir
}
clientCtx = clientCtx.WithKeyringDir(keyringDir)
}
if clientCtx.ChainID == "" || flagSet.Changed(flags.FlagChainID) {
chainID, _ := flagSet.GetString(flags.FlagChainID)
clientCtx = clientCtx.WithChainID(chainID)
}
if clientCtx.Keyring == nil || flagSet.Changed(flags.FlagKeyringBackend) {
keyringBackend, _ := flagSet.GetString(flags.FlagKeyringBackend)
if keyringBackend != "" {
kr, err := NewKeyringFromBackend(clientCtx, keyringBackend)
if err != nil {
return clientCtx, err
}
clientCtx = clientCtx.WithKeyring(kr)
}
}
if clientCtx.Client == nil || flagSet.Changed(flags.FlagNode) {
rpcURI, _ := flagSet.GetString(flags.FlagNode)
if rpcURI != "" {
clientCtx = clientCtx.WithNodeURI(rpcURI)
client, err := NewClientFromNode(rpcURI)
if err != nil {
return clientCtx, err
}
clientCtx = clientCtx.WithClient(client)
}
}
return clientCtx, nil
}
// readQueryCommandFlags returns an updated Context with fields set based on flags
// defined in AddQueryFlagsToCmd. An error is returned if any flag query fails.
//
// Note, the provided clientCtx may have field pre-populated. The following order
// of precedence occurs:
//
// - client.Context field not pre-populated & flag not set: uses default flag value
// - client.Context field not pre-populated & flag set: uses set flag value
// - client.Context field pre-populated & flag not set: uses pre-populated value
// - client.Context field pre-populated & flag set: uses set flag value
func readQueryCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, error) {
if clientCtx.Height == 0 || flagSet.Changed(flags.FlagHeight) {
height, _ := flagSet.GetInt64(flags.FlagHeight)
clientCtx = clientCtx.WithHeight(height)
}
if !clientCtx.UseLedger || flagSet.Changed(flags.FlagUseLedger) {
useLedger, _ := flagSet.GetBool(flags.FlagUseLedger)
clientCtx = clientCtx.WithUseLedger(useLedger)
}
return ReadPersistentCommandFlags(clientCtx, flagSet)
}
// readTxCommandFlags returns an updated Context with fields set based on flags
// defined in AddTxFlagsToCmd. An error is returned if any flag query fails.
//
// Note, the provided clientCtx may have field pre-populated. The following order
// of precedence occurs:
//
// - client.Context field not pre-populated & flag not set: uses default flag value
// - client.Context field not pre-populated & flag set: uses set flag value
// - client.Context field pre-populated & flag not set: uses pre-populated value
// - client.Context field pre-populated & flag set: uses set flag value
func readTxCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, error) {
clientCtx, err := ReadPersistentCommandFlags(clientCtx, flagSet)
if err != nil {
return clientCtx, err
}
if !clientCtx.GenerateOnly || flagSet.Changed(flags.FlagGenerateOnly) {
genOnly, _ := flagSet.GetBool(flags.FlagGenerateOnly)
clientCtx = clientCtx.WithGenerateOnly(genOnly)
}
if !clientCtx.Offline || flagSet.Changed(flags.FlagOffline) {
offline, _ := flagSet.GetBool(flags.FlagOffline)
clientCtx = clientCtx.WithOffline(offline)
}
if !clientCtx.UseLedger || flagSet.Changed(flags.FlagUseLedger) {
useLedger, _ := flagSet.GetBool(flags.FlagUseLedger)
clientCtx = clientCtx.WithUseLedger(useLedger)
}
if clientCtx.BroadcastMode == "" || flagSet.Changed(flags.FlagBroadcastMode) {
bMode, _ := flagSet.GetString(flags.FlagBroadcastMode)
clientCtx = clientCtx.WithBroadcastMode(bMode)
}
if !clientCtx.SkipConfirm || flagSet.Changed(flags.FlagSkipConfirmation) {
skipConfirm, _ := flagSet.GetBool(flags.FlagSkipConfirmation)
clientCtx = clientCtx.WithSkipConfirmation(skipConfirm)
}
if clientCtx.SignModeStr == "" || flagSet.Changed(flags.FlagSignMode) {
signModeStr, _ := flagSet.GetString(flags.FlagSignMode)
clientCtx = clientCtx.WithSignModeStr(signModeStr)
}
fix!: Add `--fee-payer` CLI flag, rename `--fee-account` to `--fee-granter` (#10625) <!-- The default pull request template is for types feat, fix, or refactor. For other templates, add one of the following parameters to the url: - template=docs.md - template=other.md --> ## Description Closes: #10626 <!-- Add a description of the changes that this PR introduces and the files that are the most critical to review. --> Changes: - Added `--fee-payer` CLI flag: - The flag is used to populate the corresponding `context` property. - Context in its turn is used to set `fee-payer` during transaction building. - `--fee-account` CLI flag is renamed to `--fee-granter`: - With the flag added it becomes unclear whether `--fee-account` stands for `payer` or `granter`. - Renaming to `--fee-granter` makes things more explicit. - This is CLI breaking change. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [x] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [x] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [x] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [x] added a changelog entry to `CHANGELOG.md` - [x] included comments for [documenting Go code](https://blog.golang.org/godoc) - [x] updated the relevant documentation or specification - [x] reviewed "Files changed" and left comments if necessary - [x] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
2021-12-01 03:47:40 -08:00
if clientCtx.FeePayer == nil || flagSet.Changed(flags.FlagFeePayer) {
payer, _ := flagSet.GetString(flags.FlagFeePayer)
if payer != "" {
payerAcc, err := sdk.AccAddressFromBech32(payer)
if err != nil {
return clientCtx, err
}
clientCtx = clientCtx.WithFeePayerAddress(payerAcc)
}
}
if clientCtx.FeeGranter == nil || flagSet.Changed(flags.FlagFeeGranter) {
granter, _ := flagSet.GetString(flags.FlagFeeGranter)
Add fee grant module (#8061) * Add docs * Add BasicFeeAllowance implementation * Add expiration structs and complete basic fee * Add delegation messages, add validation logic * Add keeper and helper structs * Add alias and handler to top level * Add delegation module * Add basic querier * Add types tests * Add types tests * More internal test coverage * Solid internal test coverage * Expose Querier to top level module * Add FeeAccount to auth/types, like StdTx, SignDoc * Fix all tests in x/auth * All tests pass * Appease the Golang Linter * Add fee-account command line flag * Start on DelegatedDeductFeeDecorator * Cleanup the Decorator * Wire up delegation module in simapp * add basic test for decorator (no delegation) * Table tests for deduct fees * Table tests over all conditions of delegated fee decorator * Build full ante handler stack and test it * Start genesis * Implement Genesis * Rename package delegation to subkeys * Clarify antes test cases, handle empty account w/o fees * Allow paying delegated fees with no account * Pull mempool into delegated ante, for control on StdFee * Use custom DelegatedTx, DelegatedFee for subkeys * Revert all changes to x/auth.StdTx * Appease scopelint * Register DelegatedTx with codec * Address PR comments * Remove unnecessary DelegatedMempoolFeeDecorator * Cleaned up errors in querier * Clean up message sign bytes * Minor PR comments * Replace GetAllFees... with Iterator variants * PrepareForExport adjusts grant expiration height * Panic on de/serialization error in keeper * Move custom ante handler chain to tests, update docs * More cleanup * More doc cleanup * Renamed subkeys module to fee_grant * Rename subkeys/delegation to fee grant in all strings * Modify Msg and Keeper methods to use Grant not Delegate * Add PeriodicFeeAllowance * Update aliases * Cover all accept cases for PeriodicFeeAllowance * Et tu scopelint? * Update docs as requested * Remove error return from GetFeeGrant * Code cleanup as requested by PR * Updated all errors to use new sdk/errors package * Use test suite for keeper tests * Clean up alias.go file * Define expected interfaces in exported, rather than importing from account * Remove dependency on auth/ante * Improve godoc, Logger * Cleaned up ExpiresAt * Improve error reporting with UseGrantedFee * Enforce period limit subset of basic limit * Add events * Rename fee_grant to feegrant * Ensure KeeperTestSuite actually runs * Move types/tx to types * Update alias file, include ante * I do need nolint in alias.go * Properly emit events in the handler. Use cosmos-sdk in amino types * Update godoc * Linting... * Update errors * Update pkg doc and fix ante-handler order * Merge PR #5782: Migrate x/feegrant to proto * fix errors * proto changes * proto changes * fix errors * fix errors * genesis state changed to proto * fix keeper tests * fix test * fixed tests * fix tests * updated expected keepers * updated ante tests * lint * deleted alias.go * tx updated to proto tx * remove explicit signmode * tests * Added `cli/query.go` * Added tx.go in cli * updated `module.go` * resolve errors in tx.go * Add fee payer gentx func * updated tx * fixed error * WIP: cli tests * fix query error * fix tests * Unused types and funcs * fix tests * rename helper func to create tx * remove unused * update tx cfg * fix cli tests * added simulations * Add `decoder.go` * fix build fail * added init genesis code * update tx.go * fixed LGTM alert * modified cli * remove gogoproto extensions * change acc address type to string * lint * fix simulations * Add gen simulations * remove legacy querier * remove legacy code * add grpc queries tests * fix simulations * update module.go * lint * register feegrant NewSimulationManager * fix sims * fix sims * add genesis test * add periodic grant * updated cmd * changed times * updated flags * removed days as period clock * added condition for period and exp * add periodic fee cli tests * udpated tests * fix lint * fix tests * fix sims * renaming to `fee_grant` * review changes * fix test * add condition for duplicate grants * fix tests * add `genTxWithFeeGranter` in tests * fix simulation * one of changes & test fixes * fix test * fix lint * changed package name `feegrant` to `fee_grant` * review comments * review changes * review change * review changes * added fee-account in flags * address review changes * read fee granter from cli * updated create account with mnemonic * Address review comments * move `simapp/ante` file to `feegrant/ante` * update keeper logic to create account * update docs * fix tests * update `serviceMsgClientConn` from `msgservice` * review changes * add test case for using more fees than allowed * eliminate panic checks from keeper * fix lint * change store keys string to bytes * fix tests * review changes * review changes * udpate docs * make spend limit optional * fix tests * fix tests * review changes * add norace tag * proto-docs * add docs Co-authored-by: Ethan Frey <ethanfrey@users.noreply.github.com> Co-authored-by: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Co-authored-by: Aleksandr Bezobchuk <aleks.bezobchuk@gmail.com> Co-authored-by: SaReN <sahithnarahari@gmail.com> Co-authored-by: aleem1413 <aleem@vitwit.com> Co-authored-by: MD Aleem <72057206+aleem1314@users.noreply.github.com> Co-authored-by: Anil Kumar Kammari <anil@vitwit.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2021-01-29 11:54:51 -08:00
if granter != "" {
granterAcc, err := sdk.AccAddressFromBech32(granter)
if err != nil {
return clientCtx, err
}
clientCtx = clientCtx.WithFeeGranterAddress(granterAcc)
}
}
if clientCtx.From == "" || flagSet.Changed(flags.FlagFrom) {
from, _ := flagSet.GetString(flags.FlagFrom)
fromAddr, fromName, keyType, err := GetFromFields(clientCtx.Keyring, from, clientCtx.GenerateOnly)
if err != nil {
return clientCtx, err
}
clientCtx = clientCtx.WithFrom(from).WithFromAddress(fromAddr).WithFromName(fromName)
// If the `from` signer account is a ledger key, we need to use
// SIGN_MODE_AMINO_JSON, because ledger doesn't support proto yet.
// ref: https://github.com/cosmos/cosmos-sdk/issues/8109
if keyType == keyring.TypeLedger && clientCtx.SignModeStr != flags.SignModeLegacyAminoJSON {
fmt.Println("Default sign-mode 'direct' not supported by Ledger, using sign-mode 'amino-json'.")
clientCtx = clientCtx.WithSignModeStr(flags.SignModeLegacyAminoJSON)
}
}
feat: add cli for tips transactions (#10311) <!-- The default pull request template is for types feat, fix, or refactor. For other templates, add one of the following parameters to the url: - template=docs.md - template=other.md --> ## Description Closes: #10264 This PR makes 2 changes in the CLI: ### 1. Add an `--aux` flag to all tx command. ```bash simd tx bank send <from> <to> <amount> --aux (optional: --tip <tipAmt> --tipper <tipper>) ``` This will print an AuxSignerData instead of broadcasting the tx. ### 2. Add a new `aux-to-fee` subcommand ```bash simd tx aux-to-fee <aux_signer_data.json> ``` This takes the output of the previous command, and broadcasts a 2-signer tx. <!-- Add a description of the changes that this PR introduces and the files that are the most critical to review. --> --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
2021-12-07 10:02:21 -08:00
if !clientCtx.IsAux || flagSet.Changed(flags.FlagAux) {
isAux, _ := flagSet.GetBool(flags.FlagAux)
clientCtx = clientCtx.WithAux(isAux)
if isAux {
// If the user didn't explicity set an --output flag, use JSON by
// default.
if clientCtx.OutputFormat == "" || !flagSet.Changed(cli.OutputFlag) {
clientCtx = clientCtx.WithOutputFormat("json")
}
// If the user didn't explicity set a --sign-mode flag, use
// DIRECT_AUX by default.
if clientCtx.SignModeStr == "" || !flagSet.Changed(flags.FlagSignMode) {
clientCtx = clientCtx.WithSignModeStr(flags.SignModeDirectAux)
}
}
}
return clientCtx, nil
}
// GetClientQueryContext returns a Context from a command with fields set based on flags
// defined in AddQueryFlagsToCmd. An error is returned if any flag query fails.
//
// - client.Context field not pre-populated & flag not set: uses default flag value
// - client.Context field not pre-populated & flag set: uses set flag value
// - client.Context field pre-populated & flag not set: uses pre-populated value
// - client.Context field pre-populated & flag set: uses set flag value
func GetClientQueryContext(cmd *cobra.Command) (Context, error) {
ctx := GetClientContextFromCmd(cmd)
return readQueryCommandFlags(ctx, cmd.Flags())
}
// GetClientTxContext returns a Context from a command with fields set based on flags
// defined in AddTxFlagsToCmd. An error is returned if any flag query fails.
//
// - client.Context field not pre-populated & flag not set: uses default flag value
// - client.Context field not pre-populated & flag set: uses set flag value
// - client.Context field pre-populated & flag not set: uses pre-populated value
// - client.Context field pre-populated & flag set: uses set flag value
func GetClientTxContext(cmd *cobra.Command) (Context, error) {
ctx := GetClientContextFromCmd(cmd)
return readTxCommandFlags(ctx, cmd.Flags())
}
// GetClientContextFromCmd returns a Context from a command or an empty Context
// if it has not been set.
func GetClientContextFromCmd(cmd *cobra.Command) Context {
if v := cmd.Context().Value(ClientContextKey); v != nil {
clientCtxPtr := v.(*Context)
return *clientCtxPtr
}
return Context{}
}
// SetCmdClientContext sets a command's Context value to the provided argument.
func SetCmdClientContext(cmd *cobra.Command, clientCtx Context) error {
v := cmd.Context().Value(ClientContextKey)
if v == nil {
return errors.New("client context not set")
}
clientCtxPtr := v.(*Context)
*clientCtxPtr = clientCtx
return nil
}