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.

263 lines
6.5 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
  1. package core
  2. import (
  3. "fmt"
  4. "time"
  5. abci "github.com/tendermint/abci/types"
  6. data "github.com/tendermint/go-wire/data"
  7. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  8. "github.com/tendermint/tendermint/types"
  9. )
  10. //-----------------------------------------------------------------------------
  11. // NOTE: tx should be signed, but this is only checked at the app level (not by Tendermint!)
  12. // Returns right away, with no response
  13. //
  14. // ```shell
  15. // curl 'localhost:46657/broadcast_tx_async?tx="123"'
  16. // ```
  17. //
  18. // ```go
  19. // client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
  20. // result, err := client.BroadcastTxAsync("123")
  21. // ```
  22. //
  23. // > The above command returns JSON structured like this:
  24. //
  25. // ```json
  26. // {
  27. // "error": "",
  28. // "result": {
  29. // "hash": "E39AAB7A537ABAA237831742DCE1117F187C3C52",
  30. // "log": "",
  31. // "data": "",
  32. // "code": 0
  33. // },
  34. // "id": "",
  35. // "jsonrpc": "2.0"
  36. // }
  37. // ```
  38. //
  39. // ### Query Parameters
  40. //
  41. // | Parameter | Type | Default | Required | Description |
  42. // |-----------+------+---------+----------+-----------------|
  43. // | tx | Tx | nil | true | The transaction |
  44. func BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  45. err := mempool.CheckTx(tx, nil)
  46. if err != nil {
  47. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  48. }
  49. return &ctypes.ResultBroadcastTx{Hash: tx.Hash()}, nil
  50. }
  51. // Returns with the response from CheckTx.
  52. //
  53. // ```shell
  54. // curl 'localhost:46657/broadcast_tx_sync?tx="456"'
  55. // ```
  56. //
  57. // ```go
  58. // client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
  59. // result, err := client.BroadcastTxSync("456")
  60. // ```
  61. //
  62. // > The above command returns JSON structured like this:
  63. //
  64. // ```json
  65. // {
  66. // "jsonrpc": "2.0",
  67. // "id": "",
  68. // "result": {
  69. // "code": 0,
  70. // "data": "",
  71. // "log": "",
  72. // "hash": "0D33F2F03A5234F38706E43004489E061AC40A2E"
  73. // },
  74. // "error": ""
  75. // }
  76. // ```
  77. //
  78. // ### Query Parameters
  79. //
  80. // | Parameter | Type | Default | Required | Description |
  81. // |-----------+------+---------+----------+-----------------|
  82. // | tx | Tx | nil | true | The transaction |
  83. func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  84. resCh := make(chan *abci.Response, 1)
  85. err := mempool.CheckTx(tx, func(res *abci.Response) {
  86. resCh <- res
  87. })
  88. if err != nil {
  89. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  90. }
  91. res := <-resCh
  92. r := res.GetCheckTx()
  93. return &ctypes.ResultBroadcastTx{
  94. Code: r.Code,
  95. Data: r.Data,
  96. Log: r.Log,
  97. Hash: tx.Hash(),
  98. }, nil
  99. }
  100. // CONTRACT: only returns error if mempool.BroadcastTx errs (ie. problem with the app)
  101. // or if we timeout waiting for tx to commit.
  102. // If CheckTx or DeliverTx fail, no error will be returned, but the returned result
  103. // will contain a non-OK ABCI code.
  104. //
  105. // ```shell
  106. // curl 'localhost:46657/broadcast_tx_commit?tx="789"'
  107. // ```
  108. //
  109. // ```go
  110. // client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
  111. // result, err := client.BroadcastTxCommit("789")
  112. // ```
  113. //
  114. // > The above command returns JSON structured like this:
  115. //
  116. // ```json
  117. // {
  118. // "error": "",
  119. // "result": {
  120. // "height": 26682,
  121. // "hash": "75CA0F856A4DA078FC4911580360E70CEFB2EBEE",
  122. // "deliver_tx": {
  123. // "log": "",
  124. // "data": "",
  125. // "code": 0
  126. // },
  127. // "check_tx": {
  128. // "log": "",
  129. // "data": "",
  130. // "code": 0
  131. // }
  132. // },
  133. // "id": "",
  134. // "jsonrpc": "2.0"
  135. // }
  136. // ```
  137. //
  138. // ### Query Parameters
  139. //
  140. // | Parameter | Type | Default | Required | Description |
  141. // |-----------+------+---------+----------+-----------------|
  142. // | tx | Tx | nil | true | The transaction |
  143. func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
  144. // subscribe to tx being committed in block
  145. deliverTxResCh := make(chan types.EventDataTx, 1)
  146. types.AddListenerForEvent(eventSwitch, "rpc", types.EventStringTx(tx), func(data types.TMEventData) {
  147. deliverTxResCh <- data.Unwrap().(types.EventDataTx)
  148. })
  149. // broadcast the tx and register checktx callback
  150. checkTxResCh := make(chan *abci.Response, 1)
  151. err := mempool.CheckTx(tx, func(res *abci.Response) {
  152. checkTxResCh <- res
  153. })
  154. if err != nil {
  155. logger.Error("err", "err", err)
  156. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  157. }
  158. checkTxRes := <-checkTxResCh
  159. checkTxR := checkTxRes.GetCheckTx()
  160. if checkTxR.Code != abci.CodeType_OK {
  161. // CheckTx failed!
  162. return &ctypes.ResultBroadcastTxCommit{
  163. CheckTx: checkTxR.Result(),
  164. DeliverTx: abci.Result{},
  165. Hash: tx.Hash(),
  166. }, nil
  167. }
  168. // Wait for the tx to be included in a block,
  169. // timeout after something reasonable.
  170. // TODO: configurable?
  171. timer := time.NewTimer(60 * 2 * time.Second)
  172. select {
  173. case deliverTxRes := <-deliverTxResCh:
  174. // The tx was included in a block.
  175. deliverTxR := &abci.ResponseDeliverTx{
  176. Code: deliverTxRes.Code,
  177. Data: deliverTxRes.Data,
  178. Log: deliverTxRes.Log,
  179. }
  180. logger.Info("DeliverTx passed ", "tx", data.Bytes(tx), "response", deliverTxR)
  181. return &ctypes.ResultBroadcastTxCommit{
  182. CheckTx: checkTxR.Result(),
  183. DeliverTx: deliverTxR.Result(),
  184. Hash: tx.Hash(),
  185. Height: deliverTxRes.Height,
  186. }, nil
  187. case <-timer.C:
  188. logger.Error("failed to include tx")
  189. return &ctypes.ResultBroadcastTxCommit{
  190. CheckTx: checkTxR.Result(),
  191. DeliverTx: abci.Result{},
  192. Hash: tx.Hash(),
  193. }, fmt.Errorf("Timed out waiting for transaction to be included in a block")
  194. }
  195. panic("Should never happen!")
  196. }
  197. // Get unconfirmed transactions including their number.
  198. //
  199. // ```shell
  200. // curl 'localhost:46657/unconfirmed_txs'
  201. // ```
  202. //
  203. // ```go
  204. // client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
  205. // result, err := client.UnconfirmedTxs()
  206. // ```
  207. //
  208. // > The above command returns JSON structured like this:
  209. //
  210. // ```json
  211. // {
  212. // "error": "",
  213. // "result": {
  214. // "txs": [],
  215. // "n_txs": 0
  216. // },
  217. // "id": "",
  218. // "jsonrpc": "2.0"
  219. // }
  220. // ```
  221. func UnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
  222. txs := mempool.Reap(-1)
  223. return &ctypes.ResultUnconfirmedTxs{len(txs), txs}, nil
  224. }
  225. // Get number of unconfirmed transactions.
  226. //
  227. // ```shell
  228. // curl 'localhost:46657/num_unconfirmed_txs'
  229. // ```
  230. //
  231. // ```go
  232. // client := client.NewHTTP("tcp://0.0.0.0:46657", "/websocket")
  233. // result, err := client.UnconfirmedTxs()
  234. // ```
  235. //
  236. // > The above command returns JSON structured like this:
  237. //
  238. // ```json
  239. // {
  240. // "error": "",
  241. // "result": {
  242. // "txs": null,
  243. // "n_txs": 0
  244. // },
  245. // "id": "",
  246. // "jsonrpc": "2.0"
  247. // }
  248. // ```
  249. func NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
  250. return &ctypes.ResultUnconfirmedTxs{N: mempool.Size()}, nil
  251. }