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.

114 lines
3.4 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. func BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  14. err := mempool.CheckTx(tx, nil)
  15. if err != nil {
  16. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  17. }
  18. return &ctypes.ResultBroadcastTx{Hash: tx.Hash()}, nil
  19. }
  20. // Returns with the response from CheckTx
  21. func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  22. resCh := make(chan *abci.Response, 1)
  23. err := mempool.CheckTx(tx, func(res *abci.Response) {
  24. resCh <- res
  25. })
  26. if err != nil {
  27. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  28. }
  29. res := <-resCh
  30. r := res.GetCheckTx()
  31. return &ctypes.ResultBroadcastTx{
  32. Code: r.Code,
  33. Data: r.Data,
  34. Log: r.Log,
  35. Hash: tx.Hash(),
  36. }, nil
  37. }
  38. // CONTRACT: only returns error if mempool.BroadcastTx errs (ie. problem with the app)
  39. // or if we timeout waiting for tx to commit.
  40. // If CheckTx or DeliverTx fail, no error will be returned, but the returned result
  41. // will contain a non-OK ABCI code.
  42. func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
  43. // subscribe to tx being committed in block
  44. deliverTxResCh := make(chan types.EventDataTx, 1)
  45. types.AddListenerForEvent(eventSwitch, "rpc", types.EventStringTx(tx), func(data types.TMEventData) {
  46. deliverTxResCh <- data.Unwrap().(types.EventDataTx)
  47. })
  48. // broadcast the tx and register checktx callback
  49. checkTxResCh := make(chan *abci.Response, 1)
  50. err := mempool.CheckTx(tx, func(res *abci.Response) {
  51. checkTxResCh <- res
  52. })
  53. if err != nil {
  54. logger.Error("err", "err", err)
  55. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  56. }
  57. checkTxRes := <-checkTxResCh
  58. checkTxR := checkTxRes.GetCheckTx()
  59. if checkTxR.Code != abci.CodeType_OK {
  60. // CheckTx failed!
  61. return &ctypes.ResultBroadcastTxCommit{
  62. CheckTx: checkTxR.Result(),
  63. DeliverTx: abci.Result{},
  64. Hash: tx.Hash(),
  65. }, nil
  66. }
  67. // Wait for the tx to be included in a block,
  68. // timeout after something reasonable.
  69. // TODO: configureable?
  70. timer := time.NewTimer(60 * 2 * time.Second)
  71. select {
  72. case deliverTxRes := <-deliverTxResCh:
  73. // The tx was included in a block.
  74. deliverTxR := &abci.ResponseDeliverTx{
  75. Code: deliverTxRes.Code,
  76. Data: deliverTxRes.Data,
  77. Log: deliverTxRes.Log,
  78. }
  79. logger.Info("DeliverTx passed ", "tx", data.Bytes(tx), "response", deliverTxR)
  80. return &ctypes.ResultBroadcastTxCommit{
  81. CheckTx: checkTxR.Result(),
  82. DeliverTx: deliverTxR.Result(),
  83. Hash: tx.Hash(),
  84. Height: deliverTxRes.Height,
  85. }, nil
  86. case <-timer.C:
  87. logger.Error("failed to include tx")
  88. return &ctypes.ResultBroadcastTxCommit{
  89. CheckTx: checkTxR.Result(),
  90. DeliverTx: abci.Result{},
  91. Hash: tx.Hash(),
  92. }, fmt.Errorf("Timed out waiting for transaction to be included in a block")
  93. }
  94. panic("Should never happen!")
  95. }
  96. func UnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
  97. txs := mempool.Reap(-1)
  98. return &ctypes.ResultUnconfirmedTxs{len(txs), txs}, nil
  99. }
  100. func NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
  101. return &ctypes.ResultUnconfirmedTxs{N: mempool.Size()}, nil
  102. }