You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

219 lines
6.2 KiB

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