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