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 }