github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/auth/client/utils/query.go (about)

     1  package utils
     2  
     3  import (
     4  	"encoding/hex"
     5  	"errors"
     6  	"strings"
     7  	"time"
     8  
     9  	ctypes "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/core/types"
    10  
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context"
    12  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
    13  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    14  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types"
    15  )
    16  
    17  type ParseAppTxHandler func(cdc *codec.CodecProxy, txBytes []byte) (sdk.Tx, error)
    18  
    19  var paresAppTx ParseAppTxHandler
    20  
    21  func SetParseAppTx(hanlder ParseAppTxHandler) {
    22  	paresAppTx = hanlder
    23  }
    24  
    25  // QueryTxsByEvents performs a search for transactions for a given set of events
    26  // via the Tendermint RPC. An event takes the form of:
    27  // "{eventAttribute}.{attributeKey} = '{attributeValue}'". Each event is
    28  // concatenated with an 'AND' operand. It returns a slice of Info object
    29  // containing txs and metadata. An error is returned if the query fails.
    30  func QueryTxsByEvents(cliCtx context.CLIContext, events []string, page, limit int) (*sdk.SearchTxsResult, error) {
    31  	if len(events) == 0 {
    32  		return nil, errors.New("must declare at least one event to search")
    33  	}
    34  
    35  	if page <= 0 {
    36  		return nil, errors.New("page must greater than 0")
    37  	}
    38  
    39  	if limit <= 0 {
    40  		return nil, errors.New("limit must greater than 0")
    41  	}
    42  
    43  	// XXX: implement ANY
    44  	query := strings.Join(events, " AND ")
    45  
    46  	node, err := cliCtx.GetNode()
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	prove := !cliCtx.TrustNode
    52  
    53  	resTxs, err := node.TxSearch(query, prove, page, limit, "")
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	if prove {
    59  		for _, tx := range resTxs.Txs {
    60  			err := ValidateTxResult(cliCtx, tx)
    61  			if err != nil {
    62  				return nil, err
    63  			}
    64  		}
    65  	}
    66  
    67  	resBlocks, err := getBlocksForTxResults(cliCtx, resTxs.Txs)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	txs, err := formatTxResults(cliCtx.CodecProy, resTxs.Txs, resBlocks)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	result := sdk.NewSearchTxsResult(resTxs.TotalCount, len(txs), page, limit, txs)
    78  
    79  	return &result, nil
    80  }
    81  
    82  // QueryTx queries for a single transaction by a hash string in hex format. An
    83  // error is returned if the transaction does not exist or cannot be queried.
    84  func QueryTx(cliCtx context.CLIContext, hashHexStr string) (sdk.TxResponse, error) {
    85  	// strip 0x prefix
    86  	if strings.HasPrefix(hashHexStr, "0x") {
    87  		hashHexStr = hashHexStr[2:]
    88  	}
    89  
    90  	hash, err := hex.DecodeString(hashHexStr)
    91  	if err != nil {
    92  		return sdk.TxResponse{}, err
    93  	}
    94  
    95  	node, err := cliCtx.GetNode()
    96  	if err != nil {
    97  		return sdk.TxResponse{}, err
    98  	}
    99  
   100  	resTx, err := node.Tx(hash, !cliCtx.TrustNode)
   101  	if err != nil {
   102  		return sdk.TxResponse{}, err
   103  	}
   104  
   105  	if !cliCtx.TrustNode {
   106  		if err = ValidateTxResult(cliCtx, resTx); err != nil {
   107  			return sdk.TxResponse{}, err
   108  		}
   109  	}
   110  
   111  	resBlocks, err := getBlocksForTxResults(cliCtx, []*ctypes.ResultTx{resTx})
   112  	if err != nil {
   113  		return sdk.TxResponse{}, err
   114  	}
   115  
   116  	out, err := formatTxResult(cliCtx.CodecProy, resTx, resBlocks[resTx.Height])
   117  	if err != nil {
   118  		return out, err
   119  	}
   120  
   121  	return out, nil
   122  }
   123  
   124  // formatTxResults parses the indexed txs into a slice of TxResponse objects.
   125  func formatTxResults(cdc *codec.CodecProxy, resTxs []*ctypes.ResultTx, resBlocks map[int64]*ctypes.ResultBlock) ([]sdk.TxResponse, error) {
   126  	var err error
   127  	out := make([]sdk.TxResponse, len(resTxs))
   128  	for i := range resTxs {
   129  		out[i], err = formatTxResult(cdc, resTxs[i], resBlocks[resTxs[i].Height])
   130  		if err != nil {
   131  			return nil, err
   132  		}
   133  	}
   134  
   135  	return out, nil
   136  }
   137  
   138  // ValidateTxResult performs transaction verification.
   139  func ValidateTxResult(cliCtx context.CLIContext, resTx *ctypes.ResultTx) error {
   140  	if !cliCtx.TrustNode {
   141  		check, err := cliCtx.Verify(resTx.Height)
   142  		if err != nil {
   143  			return err
   144  		}
   145  		err = resTx.Proof.Validate(check.Header.DataHash, resTx.Height)
   146  		if err != nil {
   147  			return err
   148  		}
   149  	}
   150  	return nil
   151  }
   152  
   153  func getBlocksForTxResults(cliCtx context.CLIContext, resTxs []*ctypes.ResultTx) (map[int64]*ctypes.ResultBlock, error) {
   154  	node, err := cliCtx.GetNode()
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	resBlocks := make(map[int64]*ctypes.ResultBlock)
   160  
   161  	for _, resTx := range resTxs {
   162  		if _, ok := resBlocks[resTx.Height]; !ok {
   163  			resBlock, err := node.Block(&resTx.Height)
   164  			if err != nil {
   165  				return nil, err
   166  			}
   167  
   168  			resBlocks[resTx.Height] = resBlock
   169  		}
   170  	}
   171  
   172  	return resBlocks, nil
   173  }
   174  
   175  func formatTxResult(cdc *codec.CodecProxy, resTx *ctypes.ResultTx, resBlock *ctypes.ResultBlock) (sdk.TxResponse, error) {
   176  	tx, err := parseTx(cdc, resTx.Tx)
   177  	if err != nil {
   178  		return sdk.TxResponse{}, err
   179  	}
   180  
   181  	return sdk.NewResponseResultTx(resTx, tx, resBlock.Block.Time.Format(time.RFC3339)), nil
   182  }
   183  
   184  func parseTx(cdc *codec.CodecProxy, txBytes []byte) (sdk.Tx, error) {
   185  	var tx types.StdTx
   186  	err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
   187  	if err != nil && paresAppTx != nil {
   188  		return paresAppTx(cdc, txBytes)
   189  	}
   190  
   191  	return &tx, nil
   192  }