2020-01-24 08:40:56 -08:00
|
|
|
package client
|
2019-04-02 18:09:37 -07:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/hex"
|
|
|
|
"errors"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2019-04-04 07:36:39 -07:00
|
|
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
|
|
|
|
2020-06-01 05:46:03 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
2019-04-02 18:09:37 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2019-06-15 05:34:11 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
2019-04-02 18:09:37 -07:00
|
|
|
)
|
|
|
|
|
2019-06-28 06:32:47 -07:00
|
|
|
// QueryTxsByEvents performs a search for transactions for a given set of events
|
|
|
|
// via the Tendermint RPC. An event takes the form of:
|
|
|
|
// "{eventAttribute}.{attributeKey} = '{attributeValue}'". Each event is
|
|
|
|
// concatenated with an 'AND' operand. It returns a slice of Info object
|
|
|
|
// containing txs and metadata. An error is returned if the query fails.
|
2020-02-14 06:04:05 -08:00
|
|
|
// If an empty string is provided it will order txs by asc
|
2020-06-01 05:46:03 -07:00
|
|
|
func QueryTxsByEvents(clientCtx client.Context, events []string, page, limit int, orderBy string) (*sdk.SearchTxsResult, error) {
|
2019-06-28 06:32:47 -07:00
|
|
|
if len(events) == 0 {
|
|
|
|
return nil, errors.New("must declare at least one event to search")
|
2019-04-02 18:09:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if page <= 0 {
|
|
|
|
return nil, errors.New("page must greater than 0")
|
|
|
|
}
|
|
|
|
|
|
|
|
if limit <= 0 {
|
|
|
|
return nil, errors.New("limit must greater than 0")
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX: implement ANY
|
2019-06-28 06:32:47 -07:00
|
|
|
query := strings.Join(events, " AND ")
|
2019-04-02 18:09:37 -07:00
|
|
|
|
2020-06-01 05:46:03 -07:00
|
|
|
node, err := clientCtx.GetNode()
|
2019-04-02 18:09:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-07-22 23:44:18 -07:00
|
|
|
// TODO: this may not always need to be proven
|
|
|
|
// https://github.com/cosmos/cosmos-sdk/issues/6807
|
|
|
|
resTxs, err := node.TxSearch(query, true, page, limit, orderBy)
|
2019-04-02 18:09:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-06-01 05:46:03 -07:00
|
|
|
resBlocks, err := getBlocksForTxResults(clientCtx, resTxs.Txs)
|
2019-04-02 18:09:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-10 12:41:21 -07:00
|
|
|
txs, err := formatTxResults(clientCtx.LegacyAmino, resTxs.Txs, resBlocks)
|
2019-04-02 18:09:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-05-04 04:09:03 -07:00
|
|
|
result := sdk.NewSearchTxsResult(resTxs.TotalCount, len(txs), page, limit, txs)
|
|
|
|
|
|
|
|
return &result, nil
|
2019-04-02 18:09:37 -07:00
|
|
|
}
|
|
|
|
|
2019-06-15 05:34:11 -07:00
|
|
|
// QueryTx queries for a single transaction by a hash string in hex format. An
|
|
|
|
// error is returned if the transaction does not exist or cannot be queried.
|
2020-07-17 10:17:21 -07:00
|
|
|
func QueryTx(clientCtx client.Context, hashHexStr string) (*sdk.TxResponse, error) {
|
2019-06-15 05:34:11 -07:00
|
|
|
hash, err := hex.DecodeString(hashHexStr)
|
|
|
|
if err != nil {
|
2020-07-17 10:17:21 -07:00
|
|
|
return nil, err
|
2019-06-15 05:34:11 -07:00
|
|
|
}
|
|
|
|
|
2020-06-01 05:46:03 -07:00
|
|
|
node, err := clientCtx.GetNode()
|
2019-06-15 05:34:11 -07:00
|
|
|
if err != nil {
|
2020-07-17 10:17:21 -07:00
|
|
|
return nil, err
|
2019-06-15 05:34:11 -07:00
|
|
|
}
|
|
|
|
|
2020-07-22 23:44:18 -07:00
|
|
|
//TODO: this may not always need to be proven
|
|
|
|
// https://github.com/cosmos/cosmos-sdk/issues/6807
|
|
|
|
resTx, err := node.Tx(hash, true)
|
2019-06-15 05:34:11 -07:00
|
|
|
if err != nil {
|
2020-07-17 10:17:21 -07:00
|
|
|
return nil, err
|
2019-06-15 05:34:11 -07:00
|
|
|
}
|
|
|
|
|
2020-06-01 05:46:03 -07:00
|
|
|
resBlocks, err := getBlocksForTxResults(clientCtx, []*ctypes.ResultTx{resTx})
|
2019-06-15 05:34:11 -07:00
|
|
|
if err != nil {
|
2020-07-17 10:17:21 -07:00
|
|
|
return nil, err
|
2019-06-15 05:34:11 -07:00
|
|
|
}
|
|
|
|
|
2020-08-10 12:41:21 -07:00
|
|
|
out, err := formatTxResult(clientCtx.LegacyAmino, resTx, resBlocks[resTx.Height])
|
2019-06-15 05:34:11 -07:00
|
|
|
if err != nil {
|
|
|
|
return out, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
2019-04-02 18:09:37 -07:00
|
|
|
// formatTxResults parses the indexed txs into a slice of TxResponse objects.
|
2020-08-10 12:41:21 -07:00
|
|
|
func formatTxResults(cdc *codec.LegacyAmino, resTxs []*ctypes.ResultTx, resBlocks map[int64]*ctypes.ResultBlock) ([]*sdk.TxResponse, error) {
|
2019-04-02 18:09:37 -07:00
|
|
|
var err error
|
2020-07-17 10:17:21 -07:00
|
|
|
out := make([]*sdk.TxResponse, len(resTxs))
|
2019-04-02 18:09:37 -07:00
|
|
|
for i := range resTxs {
|
|
|
|
out[i], err = formatTxResult(cdc, resTxs[i], resBlocks[resTxs[i].Height])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
2020-06-01 05:46:03 -07:00
|
|
|
func getBlocksForTxResults(clientCtx client.Context, resTxs []*ctypes.ResultTx) (map[int64]*ctypes.ResultBlock, error) {
|
|
|
|
node, err := clientCtx.GetNode()
|
2019-04-02 18:09:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
resBlocks := make(map[int64]*ctypes.ResultBlock)
|
|
|
|
|
|
|
|
for _, resTx := range resTxs {
|
|
|
|
if _, ok := resBlocks[resTx.Height]; !ok {
|
|
|
|
resBlock, err := node.Block(&resTx.Height)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
resBlocks[resTx.Height] = resBlock
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return resBlocks, nil
|
|
|
|
}
|
|
|
|
|
2020-08-10 12:41:21 -07:00
|
|
|
func formatTxResult(cdc *codec.LegacyAmino, resTx *ctypes.ResultTx, resBlock *ctypes.ResultBlock) (*sdk.TxResponse, error) {
|
2019-04-02 18:09:37 -07:00
|
|
|
tx, err := parseTx(cdc, resTx.Tx)
|
|
|
|
if err != nil {
|
2020-07-17 10:17:21 -07:00
|
|
|
return nil, err
|
2019-04-02 18:09:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return sdk.NewResponseResultTx(resTx, tx, resBlock.Block.Time.Format(time.RFC3339)), nil
|
|
|
|
}
|
|
|
|
|
2020-08-10 12:41:21 -07:00
|
|
|
func parseTx(cdc *codec.LegacyAmino, txBytes []byte) (sdk.Tx, error) {
|
2019-06-15 05:34:11 -07:00
|
|
|
var tx types.StdTx
|
2019-04-02 18:09:37 -07:00
|
|
|
|
2020-03-13 12:58:43 -07:00
|
|
|
err := cdc.UnmarshalBinaryBare(txBytes, &tx)
|
2019-04-02 18:09:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return tx, nil
|
|
|
|
}
|