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 }