github.com/Finschia/finschia-sdk@v0.49.1/x/auth/client/cli/query.go (about)

     1  package cli
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	octypes "github.com/Finschia/ostracon/types"
     9  	"github.com/spf13/cobra"
    10  
    11  	"github.com/Finschia/finschia-sdk/client"
    12  	"github.com/Finschia/finschia-sdk/client/flags"
    13  	sdk "github.com/Finschia/finschia-sdk/types"
    14  	"github.com/Finschia/finschia-sdk/types/errors"
    15  	"github.com/Finschia/finschia-sdk/types/query"
    16  	"github.com/Finschia/finschia-sdk/version"
    17  	authtx "github.com/Finschia/finschia-sdk/x/auth/tx"
    18  	"github.com/Finschia/finschia-sdk/x/auth/types"
    19  )
    20  
    21  const (
    22  	flagEvents = "events"
    23  	flagType   = "type"
    24  
    25  	typeHash   = "hash"
    26  	typeAccSeq = "acc_seq"
    27  	typeSig    = "signature"
    28  
    29  	eventFormat = "{eventType}.{eventAttribute}={value}"
    30  )
    31  
    32  // GetQueryCmd returns the transaction commands for this module
    33  func GetQueryCmd() *cobra.Command {
    34  	cmd := &cobra.Command{
    35  		Use:                        types.ModuleName,
    36  		Short:                      "Querying commands for the auth module",
    37  		DisableFlagParsing:         true,
    38  		SuggestionsMinimumDistance: 2,
    39  		RunE:                       client.ValidateCmd,
    40  	}
    41  
    42  	cmd.AddCommand(
    43  		GetAccountCmd(),
    44  		GetAccountsCmd(),
    45  		QueryParamsCmd(),
    46  		QueryModuleAccountByNameCmd(),
    47  	)
    48  
    49  	return cmd
    50  }
    51  
    52  // QueryParamsCmd returns the command handler for evidence parameter querying.
    53  func QueryParamsCmd() *cobra.Command {
    54  	cmd := &cobra.Command{
    55  		Use:   "params",
    56  		Short: "Query the current auth parameters",
    57  		Args:  cobra.NoArgs,
    58  		Long: strings.TrimSpace(`Query the current auth parameters:
    59  
    60  $ <appd> query auth params
    61  `),
    62  		RunE: func(cmd *cobra.Command, args []string) error {
    63  			clientCtx, err := client.GetClientQueryContext(cmd)
    64  			if err != nil {
    65  				return err
    66  			}
    67  
    68  			queryClient := types.NewQueryClient(clientCtx)
    69  			res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{})
    70  			if err != nil {
    71  				return err
    72  			}
    73  
    74  			return clientCtx.PrintProto(&res.Params)
    75  		},
    76  	}
    77  
    78  	flags.AddQueryFlagsToCmd(cmd)
    79  
    80  	return cmd
    81  }
    82  
    83  // GetAccountCmd returns a query account that will display the state of the
    84  // account at a given address.
    85  func GetAccountCmd() *cobra.Command {
    86  	cmd := &cobra.Command{
    87  		Use:   "account [address]",
    88  		Short: "Query for account by address",
    89  		Args:  cobra.ExactArgs(1),
    90  		RunE: func(cmd *cobra.Command, args []string) error {
    91  			clientCtx, err := client.GetClientQueryContext(cmd)
    92  			if err != nil {
    93  				return err
    94  			}
    95  			key, err := sdk.AccAddressFromBech32(args[0])
    96  			if err != nil {
    97  				return err
    98  			}
    99  
   100  			queryClient := types.NewQueryClient(clientCtx)
   101  			res, err := queryClient.Account(cmd.Context(), &types.QueryAccountRequest{Address: key.String()})
   102  			if err != nil {
   103  				return err
   104  			}
   105  
   106  			return clientCtx.PrintProto(res.Account)
   107  		},
   108  	}
   109  
   110  	flags.AddQueryFlagsToCmd(cmd)
   111  
   112  	return cmd
   113  }
   114  
   115  // GetAccountsCmd returns a query command that will display a list of accounts
   116  func GetAccountsCmd() *cobra.Command {
   117  	cmd := &cobra.Command{
   118  		Use:   "accounts",
   119  		Args:  cobra.NoArgs,
   120  		Short: "Query all the accounts",
   121  		RunE: func(cmd *cobra.Command, args []string) error {
   122  			clientCtx, err := client.GetClientQueryContext(cmd)
   123  			if err != nil {
   124  				return err
   125  			}
   126  
   127  			pageReq, err := client.ReadPageRequest(cmd.Flags())
   128  			if err != nil {
   129  				return err
   130  			}
   131  
   132  			queryClient := types.NewQueryClient(clientCtx)
   133  			res, err := queryClient.Accounts(cmd.Context(), &types.QueryAccountsRequest{Pagination: pageReq})
   134  			if err != nil {
   135  				return err
   136  			}
   137  
   138  			return clientCtx.PrintProto(res)
   139  		},
   140  	}
   141  
   142  	flags.AddQueryFlagsToCmd(cmd)
   143  	flags.AddPaginationFlagsToCmd(cmd, "all-accounts")
   144  
   145  	return cmd
   146  }
   147  
   148  // QueryModuleAccountByNameCmd returns a command to
   149  func QueryModuleAccountByNameCmd() *cobra.Command {
   150  	cmd := &cobra.Command{
   151  		Use:     "module-account [module-name]",
   152  		Short:   "Query module account info by module name",
   153  		Args:    cobra.ExactArgs(1),
   154  		Example: fmt.Sprintf("%s q auth module-account auth", version.AppName),
   155  		RunE: func(cmd *cobra.Command, args []string) error {
   156  			clientCtx, err := client.GetClientQueryContext(cmd)
   157  			if err != nil {
   158  				return err
   159  			}
   160  
   161  			moduleName := args[0]
   162  			if len(moduleName) == 0 {
   163  				return fmt.Errorf("module name should not be empty")
   164  			}
   165  
   166  			queryClient := types.NewQueryClient(clientCtx)
   167  
   168  			res, err := queryClient.ModuleAccountByName(context.Background(), &types.QueryModuleAccountByNameRequest{Name: moduleName})
   169  			if err != nil {
   170  				return err
   171  			}
   172  
   173  			return clientCtx.PrintProto(res)
   174  		},
   175  	}
   176  
   177  	flags.AddQueryFlagsToCmd(cmd)
   178  
   179  	return cmd
   180  }
   181  
   182  // QueryTxsByEventsCmd returns a command to search through transactions by events.
   183  func QueryTxsByEventsCmd() *cobra.Command {
   184  	cmd := &cobra.Command{
   185  		Use:   "txs",
   186  		Args:  cobra.NoArgs,
   187  		Short: "Query for paginated transactions that match a set of events",
   188  		Long: strings.TrimSpace(
   189  			fmt.Sprintf(`
   190  Search for transactions that match the exact given events where results are paginated.
   191  Each event takes the form of '%s'. Please refer
   192  to each module's documentation for the full set of events to query for. Each module
   193  documents its respective events under 'xx_events.md'.
   194  
   195  Example:
   196  $ %s query txs --%s 'message.sender=link1...&message.action=withdraw_delegator_reward' --page 1 --limit 30
   197  `, eventFormat, version.AppName, flagEvents),
   198  		),
   199  		RunE: func(cmd *cobra.Command, args []string) error {
   200  			clientCtx, err := client.GetClientQueryContext(cmd)
   201  			if err != nil {
   202  				return err
   203  			}
   204  			eventsRaw, _ := cmd.Flags().GetString(flagEvents)
   205  			eventsStr := strings.Trim(eventsRaw, "'")
   206  
   207  			var events []string
   208  			if strings.Contains(eventsStr, "&") {
   209  				events = strings.Split(eventsStr, "&")
   210  			} else {
   211  				events = append(events, eventsStr)
   212  			}
   213  
   214  			var tmEvents []string
   215  
   216  			for _, event := range events {
   217  				if !strings.Contains(event, "=") {
   218  					return fmt.Errorf("invalid event; event %s should be of the format: %s", event, eventFormat)
   219  				} else if strings.Count(event, "=") > 1 {
   220  					return fmt.Errorf("invalid event; event %s should be of the format: %s", event, eventFormat)
   221  				}
   222  
   223  				tokens := strings.Split(event, "=")
   224  				if tokens[0] == octypes.TxHeightKey {
   225  					event = fmt.Sprintf("%s=%s", tokens[0], tokens[1])
   226  				} else {
   227  					event = fmt.Sprintf("%s='%s'", tokens[0], tokens[1])
   228  				}
   229  
   230  				tmEvents = append(tmEvents, event)
   231  			}
   232  
   233  			page, _ := cmd.Flags().GetInt(flags.FlagPage)
   234  			limit, _ := cmd.Flags().GetInt(flags.FlagLimit)
   235  
   236  			txs, err := authtx.QueryTxsByEvents(clientCtx, tmEvents, page, limit, "")
   237  			if err != nil {
   238  				return err
   239  			}
   240  
   241  			return clientCtx.PrintProto(txs)
   242  		},
   243  	}
   244  
   245  	flags.AddQueryFlagsToCmd(cmd)
   246  	cmd.Flags().Int(flags.FlagPage, query.DefaultPage, "Query a specific page of paginated results")
   247  	cmd.Flags().Int(flags.FlagLimit, query.DefaultLimit, "Query number of transactions results per page returned")
   248  	cmd.Flags().String(flagEvents, "", fmt.Sprintf("list of transaction events in the form of %s", eventFormat))
   249  	_ = cmd.MarkFlagRequired(flagEvents)
   250  
   251  	return cmd
   252  }
   253  
   254  // QueryTxCmd implements the default command for a tx query.
   255  func QueryTxCmd() *cobra.Command {
   256  	cmd := &cobra.Command{
   257  		Use:   "tx --type=[hash|acc_seq|signature] [hash|acc_seq|signature]",
   258  		Short: "Query for a transaction by hash, \"<addr>/<seq>\" combination or comma-separated signatures in a committed block",
   259  		Long: strings.TrimSpace(fmt.Sprintf(`
   260  Example:
   261  $ %s query tx <hash>
   262  $ %s query tx --%s=%s <addr>/<sequence>
   263  $ %s query tx --%s=%s <sig1_base64>,<sig2_base64...>
   264  `,
   265  			version.AppName,
   266  			version.AppName, flagType, typeAccSeq,
   267  			version.AppName, flagType, typeSig)),
   268  		Args: cobra.ExactArgs(1),
   269  		RunE: func(cmd *cobra.Command, args []string) error {
   270  			clientCtx, err := client.GetClientQueryContext(cmd)
   271  			if err != nil {
   272  				return err
   273  			}
   274  
   275  			typ, _ := cmd.Flags().GetString(flagType)
   276  
   277  			switch typ {
   278  			case typeHash:
   279  				{
   280  					if args[0] == "" {
   281  						return fmt.Errorf("argument should be a tx hash")
   282  					}
   283  
   284  					// If hash is given, then query the tx by hash.
   285  					output, err := authtx.QueryTx(clientCtx, args[0])
   286  					if err != nil {
   287  						return err
   288  					}
   289  
   290  					if output.Empty() {
   291  						return fmt.Errorf("no transaction found with hash %s", args[0])
   292  					}
   293  
   294  					return clientCtx.PrintProto(output)
   295  				}
   296  			case typeSig:
   297  				{
   298  					sigParts, err := parseSigArgs(args)
   299  					if err != nil {
   300  						return err
   301  					}
   302  					tmEvents := make([]string, len(sigParts))
   303  					for i, sig := range sigParts {
   304  						tmEvents[i] = fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeySignature, sig)
   305  					}
   306  
   307  					txs, err := authtx.QueryTxsByEvents(clientCtx, tmEvents, query.DefaultPage, query.DefaultLimit, "")
   308  					if err != nil {
   309  						return err
   310  					}
   311  					if len(txs.Txs) == 0 {
   312  						return fmt.Errorf("found no txs matching given signatures")
   313  					}
   314  					if len(txs.Txs) > 1 {
   315  						// This case means there's a bug somewhere else in the code. Should not happen.
   316  						return errors.ErrLogic.Wrapf("found %d txs matching given signatures", len(txs.Txs))
   317  					}
   318  
   319  					return clientCtx.PrintProto(txs.Txs[0])
   320  				}
   321  			case typeAccSeq:
   322  				{
   323  					if args[0] == "" {
   324  						return fmt.Errorf("`acc_seq` type takes an argument '<addr>/<seq>'")
   325  					}
   326  
   327  					tmEvents := []string{
   328  						fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeyAccountSequence, args[0]),
   329  					}
   330  					txs, err := authtx.QueryTxsByEvents(clientCtx, tmEvents, query.DefaultPage, query.DefaultLimit, "")
   331  					if err != nil {
   332  						return err
   333  					}
   334  					if len(txs.Txs) == 0 {
   335  						return fmt.Errorf("found no txs matching given address and sequence combination")
   336  					}
   337  					if len(txs.Txs) > 1 {
   338  						// This case means there's a bug somewhere else in the code. Should not happen.
   339  						return fmt.Errorf("found %d txs matching given address and sequence combination", len(txs.Txs))
   340  					}
   341  
   342  					return clientCtx.PrintProto(txs.Txs[0])
   343  				}
   344  			default:
   345  				return fmt.Errorf("unknown --%s value %s", flagType, typ)
   346  			}
   347  		},
   348  	}
   349  
   350  	flags.AddQueryFlagsToCmd(cmd)
   351  	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))
   352  
   353  	return cmd
   354  }
   355  
   356  // parseSigArgs parses comma-separated signatures from the CLI arguments.
   357  func parseSigArgs(args []string) ([]string, error) {
   358  	if len(args) != 1 || args[0] == "" {
   359  		return nil, fmt.Errorf("argument should be comma-separated signatures")
   360  	}
   361  
   362  	return strings.Split(args[0], ","), nil
   363  }