github.com/evdatsion/aphelion-dpos-bft@v0.32.1/rpc/core/tx.go (about) 1 package core 2 3 import ( 4 "fmt" 5 6 cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common" 7 8 tmquery "github.com/evdatsion/aphelion-dpos-bft/libs/pubsub/query" 9 ctypes "github.com/evdatsion/aphelion-dpos-bft/rpc/core/types" 10 rpctypes "github.com/evdatsion/aphelion-dpos-bft/rpc/lib/types" 11 "github.com/evdatsion/aphelion-dpos-bft/state/txindex/null" 12 "github.com/evdatsion/aphelion-dpos-bft/types" 13 ) 14 15 // Tx allows you to query the transaction results. `nil` could mean the 16 // transaction is in the mempool, invalidated, or was not sent in the first 17 // place. 18 // 19 // ```shell 20 // curl "localhost:26657/tx?hash=0xF87370F68C82D9AC7201248ECA48CEC5F16FFEC99C461C1B2961341A2FE9C1C8" 21 // ``` 22 // 23 // ```go 24 // client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket") 25 // err := client.Start() 26 // if err != nil { 27 // // handle error 28 // } 29 // defer client.Stop() 30 // hashBytes, err := hex.DecodeString("F87370F68C82D9AC7201248ECA48CEC5F16FFEC99C461C1B2961341A2FE9C1C8") 31 // tx, err := client.Tx(hashBytes, true) 32 // ``` 33 // 34 // > The above command returns JSON structured like this: 35 // 36 // ```json 37 // { 38 // "error": "", 39 // "result": { 40 // "proof": { 41 // "Proof": { 42 // "aunts": [] 43 // }, 44 // "Data": "YWJjZA==", 45 // "RootHash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF", 46 // "Total": "1", 47 // "Index": "0" 48 // }, 49 // "tx": "YWJjZA==", 50 // "tx_result": { 51 // "log": "", 52 // "data": "", 53 // "code": "0" 54 // }, 55 // "index": "0", 56 // "height": "52", 57 // "hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF" 58 // }, 59 // "id": "", 60 // "jsonrpc": "2.0" 61 // } 62 // ``` 63 // 64 // Returns a transaction matching the given transaction hash. 65 // 66 // ### Query Parameters 67 // 68 // | Parameter | Type | Default | Required | Description | 69 // |-----------+--------+---------+----------+-----------------------------------------------------------| 70 // | hash | []byte | nil | true | The transaction hash | 71 // | prove | bool | false | false | Include a proof of the transaction inclusion in the block | 72 // 73 // ### Returns 74 // 75 // - `proof`: the `types.TxProof` object 76 // - `tx`: `[]byte` - the transaction 77 // - `tx_result`: the `abci.Result` object 78 // - `index`: `int` - index of the transaction 79 // - `height`: `int` - height of the block where this transaction was in 80 // - `hash`: `[]byte` - hash of the transaction 81 func Tx(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) { 82 83 // if index is disabled, return error 84 if _, ok := txIndexer.(*null.TxIndex); ok { 85 return nil, fmt.Errorf("Transaction indexing is disabled") 86 } 87 88 r, err := txIndexer.Get(hash) 89 if err != nil { 90 return nil, err 91 } 92 93 if r == nil { 94 return nil, fmt.Errorf("Tx (%X) not found", hash) 95 } 96 97 height := r.Height 98 index := r.Index 99 100 var proof types.TxProof 101 if prove { 102 block := blockStore.LoadBlock(height) 103 proof = block.Data.Txs.Proof(int(index)) // XXX: overflow on 32-bit machines 104 } 105 106 return &ctypes.ResultTx{ 107 Hash: hash, 108 Height: height, 109 Index: uint32(index), 110 TxResult: r.Result, 111 Tx: r.Tx, 112 Proof: proof, 113 }, nil 114 } 115 116 // TxSearch allows you to query for multiple transactions results. It returns a 117 // list of transactions (maximum ?per_page entries) and the total count. 118 // 119 // ```shell 120 // curl "localhost:26657/tx_search?query=\"account.owner='Ivan'\"&prove=true" 121 // ``` 122 // 123 // ```go 124 // client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket") 125 // err := client.Start() 126 // if err != nil { 127 // // handle error 128 // } 129 // defer client.Stop() 130 // q, err := tmquery.New("account.owner='Ivan'") 131 // tx, err := client.TxSearch(q, true) 132 // ``` 133 // 134 // > The above command returns JSON structured like this: 135 // 136 // ```json 137 // { 138 // "jsonrpc": "2.0", 139 // "id": "", 140 // "result": { 141 // "txs": [ 142 // { 143 // "proof": { 144 // "Proof": { 145 // "aunts": [ 146 // "J3LHbizt806uKnABNLwG4l7gXCA=", 147 // "iblMO/M1TnNtlAefJyNCeVhjAb0=", 148 // "iVk3ryurVaEEhdeS0ohAJZ3wtB8=", 149 // "5hqMkTeGqpct51ohX0lZLIdsn7Q=", 150 // "afhsNxFnLlZgFDoyPpdQSe0bR8g=" 151 // ] 152 // }, 153 // "Data": "mvZHHa7HhZ4aRT0xMDA=", 154 // "RootHash": "F6541223AA46E428CB1070E9840D2C3DF3B6D776", 155 // "Total": "32", 156 // "Index": "31" 157 // }, 158 // "tx": "mvZHHa7HhZ4aRT0xMDA=", 159 // "tx_result": {}, 160 // "index": "31", 161 // "height": "12", 162 // "hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF" 163 // } 164 // ], 165 // "total_count": "1" 166 // } 167 // } 168 // ``` 169 // 170 // ### Query Parameters 171 // 172 // | Parameter | Type | Default | Required | Description | 173 // |-----------+--------+---------+----------+-----------------------------------------------------------| 174 // | query | string | "" | true | Query | 175 // | prove | bool | false | false | Include proofs of the transactions inclusion in the block | 176 // | page | int | 1 | false | Page number (1-based) | 177 // | per_page | int | 30 | false | Number of entries per page (max: 100) | 178 // 179 // ### Returns 180 // 181 // - `proof`: the `types.TxProof` object 182 // - `tx`: `[]byte` - the transaction 183 // - `tx_result`: the `abci.Result` object 184 // - `index`: `int` - index of the transaction 185 // - `height`: `int` - height of the block where this transaction was in 186 // - `hash`: `[]byte` - hash of the transaction 187 func TxSearch(ctx *rpctypes.Context, query string, prove bool, page, perPage int) (*ctypes.ResultTxSearch, error) { 188 // if index is disabled, return error 189 if _, ok := txIndexer.(*null.TxIndex); ok { 190 return nil, fmt.Errorf("Transaction indexing is disabled") 191 } 192 193 q, err := tmquery.New(query) 194 if err != nil { 195 return nil, err 196 } 197 198 results, err := txIndexer.Search(q) 199 if err != nil { 200 return nil, err 201 } 202 203 totalCount := len(results) 204 perPage = validatePerPage(perPage) 205 page = validatePage(page, perPage, totalCount) 206 skipCount := validateSkipCount(page, perPage) 207 208 apiResults := make([]*ctypes.ResultTx, cmn.MinInt(perPage, totalCount-skipCount)) 209 var proof types.TxProof 210 // if there's no tx in the results array, we don't need to loop through the apiResults array 211 for i := 0; i < len(apiResults); i++ { 212 r := results[skipCount+i] 213 height := r.Height 214 index := r.Index 215 216 if prove { 217 block := blockStore.LoadBlock(height) 218 proof = block.Data.Txs.Proof(int(index)) // XXX: overflow on 32-bit machines 219 } 220 221 apiResults[i] = &ctypes.ResultTx{ 222 Hash: r.Tx.Hash(), 223 Height: height, 224 Index: index, 225 TxResult: r.Result, 226 Tx: r.Tx, 227 Proof: proof, 228 } 229 } 230 231 return &ctypes.ResultTxSearch{Txs: apiResults, TotalCount: totalCount}, nil 232 }