github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/client/cli/query.go (about)

     1  package cli
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/spf13/cobra"
     8  
     9  	"github.com/cosmos/cosmos-sdk/client"
    10  	"github.com/cosmos/cosmos-sdk/client/flags"
    11  	sdk "github.com/cosmos/cosmos-sdk/types"
    12  	"github.com/cosmos/cosmos-sdk/types/errors"
    13  	querytypes "github.com/cosmos/cosmos-sdk/types/query"
    14  	"github.com/cosmos/cosmos-sdk/version"
    15  	authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
    16  )
    17  
    18  const (
    19  	FlagQuery   = "query"
    20  	FlagType    = "type"
    21  	FlagOrderBy = "order_by"
    22  
    23  	TypeHash   = "hash"
    24  	TypeAccSeq = "acc_seq"
    25  	TypeSig    = "signature"
    26  	TypeHeight = "height"
    27  
    28  	EventFormat = "{eventType}.{eventAttribute}={value}"
    29  )
    30  
    31  // QueryTxsByEventsCmd returns a command to search through transactions by events.
    32  func QueryTxsByEventsCmd() *cobra.Command {
    33  	cmd := &cobra.Command{
    34  		Use:   "txs",
    35  		Short: "Query for paginated transactions that match a set of events",
    36  		Long: `Search for transactions that match the exact given events where results are paginated.
    37  The events query is directly passed to Tendermint's RPC TxSearch method and must
    38  conform to Tendermint's query syntax.
    39  
    40  Please refer to each module's documentation for the full set of events to query
    41  for. Each module documents its respective events under 'xx_events.md'.
    42  `,
    43  		Example: fmt.Sprintf(
    44  			"$ %s query txs --query \"message.sender='cosmos1...' AND message.action='withdraw_delegator_reward' AND tx.height > 7\" --page 1 --limit 30",
    45  			version.AppName,
    46  		),
    47  		RunE: func(cmd *cobra.Command, args []string) error {
    48  			clientCtx, err := client.GetClientQueryContext(cmd)
    49  			if err != nil {
    50  				return err
    51  			}
    52  
    53  			query, _ := cmd.Flags().GetString(FlagQuery)
    54  			page, _ := cmd.Flags().GetInt(flags.FlagPage)
    55  			limit, _ := cmd.Flags().GetInt(flags.FlagLimit)
    56  			orderBy, _ := cmd.Flags().GetString(FlagOrderBy)
    57  
    58  			txs, err := authtx.QueryTxsByEvents(clientCtx, page, limit, query, orderBy)
    59  			if err != nil {
    60  				return err
    61  			}
    62  
    63  			return clientCtx.PrintProto(txs)
    64  		},
    65  	}
    66  
    67  	flags.AddQueryFlagsToCmd(cmd)
    68  	cmd.Flags().Int(flags.FlagPage, querytypes.DefaultPage, "Query a specific page of paginated results")
    69  	cmd.Flags().Int(flags.FlagLimit, querytypes.DefaultLimit, "Query number of transactions results per page returned")
    70  	cmd.Flags().String(FlagQuery, "", "The transactions events query per Tendermint's query semantics")
    71  	cmd.Flags().String(FlagOrderBy, "", "The ordering semantics (asc|dsc)")
    72  	_ = cmd.MarkFlagRequired(FlagQuery)
    73  
    74  	return cmd
    75  }
    76  
    77  // QueryTxCmd implements the default command for a tx query.
    78  func QueryTxCmd() *cobra.Command {
    79  	cmd := &cobra.Command{
    80  		Use:   "tx --type=[hash|acc_seq|signature] [hash|acc_seq|signature]",
    81  		Short: "Query for a transaction by hash, \"<addr>/<seq>\" combination or comma-separated signatures in a committed block",
    82  		Long: strings.TrimSpace(fmt.Sprintf(`
    83  Example:
    84  $ %s query tx <hash>
    85  $ %s query tx --%s=%s <addr>/<sequence>
    86  $ %s query tx --%s=%s <sig1_base64>,<sig2_base64...>
    87  `,
    88  			version.AppName,
    89  			version.AppName, FlagType, TypeAccSeq,
    90  			version.AppName, FlagType, TypeSig)),
    91  		Args: cobra.ExactArgs(1),
    92  		RunE: func(cmd *cobra.Command, args []string) error {
    93  			clientCtx, err := client.GetClientQueryContext(cmd)
    94  			if err != nil {
    95  				return err
    96  			}
    97  
    98  			typ, _ := cmd.Flags().GetString(FlagType)
    99  
   100  			switch typ {
   101  			case TypeHash:
   102  				if args[0] == "" {
   103  					return fmt.Errorf("argument should be a tx hash")
   104  				}
   105  
   106  				// if hash is given, then query the tx by hash
   107  				output, err := authtx.QueryTx(clientCtx, args[0])
   108  				if err != nil {
   109  					return err
   110  				}
   111  
   112  				if output.Empty() {
   113  					return fmt.Errorf("no transaction found with hash %s", args[0])
   114  				}
   115  
   116  				return clientCtx.PrintProto(output)
   117  
   118  			case TypeSig:
   119  				sigParts, err := ParseSigArgs(args)
   120  				if err != nil {
   121  					return err
   122  				}
   123  
   124  				events := make([]string, len(sigParts))
   125  				for i, sig := range sigParts {
   126  					events[i] = fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeySignature, sig)
   127  				}
   128  
   129  				query := strings.Join(events, " AND ")
   130  
   131  				txs, err := authtx.QueryTxsByEvents(clientCtx, querytypes.DefaultPage, querytypes.DefaultLimit, query, "")
   132  				if err != nil {
   133  					return err
   134  				}
   135  
   136  				if len(txs.Txs) == 0 {
   137  					return fmt.Errorf("found no txs matching given signatures")
   138  				}
   139  				if len(txs.Txs) > 1 {
   140  					// This case means there's a bug somewhere else in the code as this
   141  					// should not happen.
   142  					return errors.ErrLogic.Wrapf("found %d txs matching given signatures", len(txs.Txs))
   143  				}
   144  
   145  				return clientCtx.PrintProto(txs.Txs[0])
   146  
   147  			case TypeAccSeq:
   148  				if args[0] == "" {
   149  					return fmt.Errorf("`acc_seq` type takes an argument '<addr>/<seq>'")
   150  				}
   151  
   152  				query := fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeyAccountSequence, args[0])
   153  
   154  				txs, err := authtx.QueryTxsByEvents(clientCtx, querytypes.DefaultPage, querytypes.DefaultLimit, query, "")
   155  				if err != nil {
   156  					return err
   157  				}
   158  
   159  				if len(txs.Txs) == 0 {
   160  					return fmt.Errorf("found no txs matching given address and sequence combination")
   161  				}
   162  				if len(txs.Txs) > 1 {
   163  					// This case means there's a bug somewhere else in the code as this
   164  					// should not happen.
   165  					return fmt.Errorf("found %d txs matching given address and sequence combination", len(txs.Txs))
   166  				}
   167  
   168  				return clientCtx.PrintProto(txs.Txs[0])
   169  
   170  			default:
   171  				return fmt.Errorf("unknown --%s value %s", FlagType, typ)
   172  			}
   173  		},
   174  	}
   175  
   176  	flags.AddQueryFlagsToCmd(cmd)
   177  	cmd.Flags().String(FlagType, TypeHash, fmt.Sprintf("The type to be used when querying tx, can be one of \"%s\", \"%s\", \"%s\"", TypeHash, TypeAccSeq, TypeSig))
   178  
   179  	return cmd
   180  }
   181  
   182  // ParseSigArgs parses comma-separated signatures from the CLI arguments.
   183  func ParseSigArgs(args []string) ([]string, error) {
   184  	if len(args) != 1 || args[0] == "" {
   185  		return nil, fmt.Errorf("argument should be comma-separated signatures")
   186  	}
   187  
   188  	return strings.Split(args[0], ","), nil
   189  }