cosmos-sdk/client/tx/search.go

163 lines
3.7 KiB
Go
Raw Normal View History

package tx
import (
"errors"
"fmt"
"net/http"
"net/url"
"strings"
2018-03-02 01:24:07 -08:00
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
2018-03-02 01:24:07 -08:00
"github.com/cosmos/cosmos-sdk/wire"
2018-08-06 11:11:30 -07:00
"github.com/spf13/cobra"
"github.com/spf13/viper"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
const (
flagTags = "tag"
flagAny = "any"
)
2018-02-28 17:57:38 -08:00
// default client command to search through tagged transactions
2018-04-18 21:49:24 -07:00
func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "txs",
Short: "Search for all transactions that match the given tags",
2018-04-18 21:49:24 -07:00
RunE: func(cmd *cobra.Command, args []string) error {
tags := viper.GetStringSlice(flagTags)
2018-08-06 11:11:30 -07:00
cliCtx := context.NewCLIContext().WithCodec(cdc)
txs, err := searchTxs(cliCtx, cdc, tags)
if err != nil {
return err
}
2018-08-06 11:11:30 -07:00
output, err := cdc.MarshalJSON(txs)
2018-04-18 21:49:24 -07:00
if err != nil {
return err
}
2018-08-06 11:11:30 -07:00
2018-04-18 21:49:24 -07:00
fmt.Println(string(output))
return nil
},
}
2018-04-18 21:49:24 -07:00
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
2018-04-18 21:49:24 -07:00
2018-02-28 17:57:38 -08:00
// TODO: change this to false once proofs built in
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
cmd.Flags().StringSlice(flagTags, nil, "Tags that must match (may provide multiple)")
cmd.Flags().Bool(flagAny, false, "Return transactions that match ANY tag, rather than ALL")
return cmd
}
func searchTxs(cliCtx context.CLIContext, cdc *wire.Codec, tags []string) ([]Info, error) {
if len(tags) == 0 {
return nil, errors.New("must declare at least one tag to search")
}
2018-08-06 11:11:30 -07:00
// XXX: implement ANY
query := strings.Join(tags, " AND ")
2018-08-06 11:11:30 -07:00
// get the node
2018-08-06 11:11:30 -07:00
node, err := cliCtx.GetNode()
2018-02-28 15:26:39 -08:00
if err != nil {
return nil, err
}
prove := !viper.GetBool(client.FlagTrustNode)
2018-08-06 11:11:30 -07:00
2018-05-20 07:35:19 -07:00
// TODO: take these as args
page := 0
perPage := 100
res, err := node.TxSearch(query, prove, page, perPage)
if err != nil {
return nil, err
}
info, err := FormatTxResults(cdc, res.Txs)
if err != nil {
return nil, err
}
return info, nil
}
// parse the indexed txs into an array of Info
func FormatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]Info, error) {
var err error
out := make([]Info, len(res))
for i := range res {
2018-02-28 17:57:38 -08:00
out[i], err = formatTxResult(cdc, res[i])
if err != nil {
return nil, err
}
}
return out, nil
}
2018-04-18 21:49:24 -07:00
/////////////////////////////////////////
// REST
2018-04-18 21:49:24 -07:00
// Search Tx REST Handler
2018-08-06 11:11:30 -07:00
func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
tag := r.FormValue("tag")
2018-03-14 05:01:55 -07:00
if tag == "" {
w.WriteHeader(400)
w.Write([]byte("You need to provide at least a tag as a key=value pair to search for. Postfix the key with _bech32 to search bech32-encoded addresses or public keys"))
2018-03-14 05:01:55 -07:00
return
}
2018-08-06 11:11:30 -07:00
keyValue := strings.Split(tag, "=")
key := keyValue[0]
2018-08-06 11:11:30 -07:00
value, err := url.QueryUnescape(keyValue[1])
if err != nil {
w.WriteHeader(400)
w.Write([]byte("Could not decode address: " + err.Error()))
return
}
2018-08-06 11:11:30 -07:00
if strings.HasSuffix(key, "_bech32") {
bech32address := strings.Trim(value, "'")
prefix := strings.Split(bech32address, "1")[0]
bz, err := sdk.GetFromBech32(bech32address, prefix)
if err != nil {
w.WriteHeader(400)
w.Write([]byte(err.Error()))
return
}
2018-07-06 00:06:53 -07:00
tag = strings.TrimRight(key, "_bech32") + "='" + sdk.AccAddress(bz).String() + "'"
}
2018-03-14 05:01:55 -07:00
2018-08-06 11:11:30 -07:00
txs, err := searchTxs(cliCtx, cdc, []string{tag})
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
if len(txs) == 0 {
w.Write([]byte("[]"))
return
}
output, err := cdc.MarshalJSON(txs)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}