github.com/cosmos/cosmos-sdk@v0.50.10/x/auth/tx/query.go (about) 1 package tx 2 3 import ( 4 "context" 5 "encoding/hex" 6 "errors" 7 "fmt" 8 "time" 9 10 coretypes "github.com/cometbft/cometbft/rpc/core/types" 11 12 "github.com/cosmos/cosmos-sdk/client" 13 codectypes "github.com/cosmos/cosmos-sdk/codec/types" 14 sdk "github.com/cosmos/cosmos-sdk/types" 15 querytypes "github.com/cosmos/cosmos-sdk/types/query" 16 ) 17 18 // QueryTxsByEvents retrieves a list of paginated transactions from CometBFT's 19 // TxSearch RPC method given a set of pagination criteria and an events query. 20 // Note, the events query must be valid based on CometBFT's query semantics. 21 // An error is returned if the query or parsing fails or if the query is empty. 22 // 23 // Note, if an empty orderBy is provided, the default behavior is ascending. If 24 // negative values are provided for page or limit, defaults will be used. 25 func QueryTxsByEvents(clientCtx client.Context, page, limit int, query, orderBy string) (*sdk.SearchTxsResult, error) { 26 if len(query) == 0 { 27 return nil, errors.New("query cannot be empty") 28 } 29 30 // CometBFT node.TxSearch that is used for querying txs defines pages 31 // starting from 1, so we default to 1 if not provided in the request. 32 if page <= 0 { 33 page = 1 34 } 35 36 if limit <= 0 { 37 limit = querytypes.DefaultLimit 38 } 39 40 node, err := clientCtx.GetNode() 41 if err != nil { 42 return nil, err 43 } 44 45 resTxs, err := node.TxSearch(context.Background(), query, false, &page, &limit, orderBy) 46 if err != nil { 47 return nil, fmt.Errorf("failed to search for txs: %w", err) 48 } 49 50 resBlocks, err := getBlocksForTxResults(clientCtx, resTxs.Txs) 51 if err != nil { 52 return nil, err 53 } 54 55 txs, err := formatTxResults(clientCtx.TxConfig, resTxs.Txs, resBlocks) 56 if err != nil { 57 return nil, err 58 } 59 60 return sdk.NewSearchTxsResult(uint64(resTxs.TotalCount), uint64(len(txs)), uint64(page), uint64(limit), txs), nil 61 } 62 63 // QueryTx queries for a single transaction by a hash string in hex format. An 64 // error is returned if the transaction does not exist or cannot be queried. 65 func QueryTx(clientCtx client.Context, hashHexStr string) (*sdk.TxResponse, error) { 66 hash, err := hex.DecodeString(hashHexStr) 67 if err != nil { 68 return nil, err 69 } 70 71 node, err := clientCtx.GetNode() 72 if err != nil { 73 return nil, err 74 } 75 76 // TODO: this may not always need to be proven 77 // https://github.com/cosmos/cosmos-sdk/issues/6807 78 resTx, err := node.Tx(context.Background(), hash, true) 79 if err != nil { 80 return nil, err 81 } 82 83 resBlocks, err := getBlocksForTxResults(clientCtx, []*coretypes.ResultTx{resTx}) 84 if err != nil { 85 return nil, err 86 } 87 88 out, err := mkTxResult(clientCtx.TxConfig, resTx, resBlocks[resTx.Height]) 89 if err != nil { 90 return out, err 91 } 92 93 return out, nil 94 } 95 96 // formatTxResults parses the indexed txs into a slice of TxResponse objects. 97 func formatTxResults(txConfig client.TxConfig, resTxs []*coretypes.ResultTx, resBlocks map[int64]*coretypes.ResultBlock) ([]*sdk.TxResponse, error) { 98 var err error 99 out := make([]*sdk.TxResponse, len(resTxs)) 100 for i := range resTxs { 101 out[i], err = mkTxResult(txConfig, resTxs[i], resBlocks[resTxs[i].Height]) 102 if err != nil { 103 return nil, err 104 } 105 } 106 107 return out, nil 108 } 109 110 func getBlocksForTxResults(clientCtx client.Context, resTxs []*coretypes.ResultTx) (map[int64]*coretypes.ResultBlock, error) { 111 node, err := clientCtx.GetNode() 112 if err != nil { 113 return nil, err 114 } 115 116 resBlocks := make(map[int64]*coretypes.ResultBlock) 117 118 for _, resTx := range resTxs { 119 if _, ok := resBlocks[resTx.Height]; !ok { 120 resBlock, err := node.Block(context.Background(), &resTx.Height) 121 if err != nil { 122 return nil, err 123 } 124 125 resBlocks[resTx.Height] = resBlock 126 } 127 } 128 129 return resBlocks, nil 130 } 131 132 func mkTxResult(txConfig client.TxConfig, resTx *coretypes.ResultTx, resBlock *coretypes.ResultBlock) (*sdk.TxResponse, error) { 133 txb, err := txConfig.TxDecoder()(resTx.Tx) 134 if err != nil { 135 return nil, err 136 } 137 p, ok := txb.(intoAny) 138 if !ok { 139 return nil, fmt.Errorf("expecting a type implementing intoAny, got: %T", txb) 140 } 141 any := p.AsAny() 142 return sdk.NewResponseResultTx(resTx, any, resBlock.Block.Time.Format(time.RFC3339)), nil 143 } 144 145 // Deprecated: this interface is used only internally for scenario we are 146 // deprecating (StdTxConfig support) 147 type intoAny interface { 148 AsAny() *codectypes.Any 149 }