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.

108 lines
3.1 KiB

9 years ago
  1. package core
  2. import (
  3. "fmt"
  4. "time"
  5. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  6. "github.com/tendermint/tendermint/types"
  7. tmsp "github.com/tendermint/tmsp/types"
  8. )
  9. //-----------------------------------------------------------------------------
  10. // NOTE: tx should be signed, but this is only checked at the app level (not by Tendermint!)
  11. // Returns right away, with no response
  12. func BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  13. err := mempool.CheckTx(tx, nil)
  14. if err != nil {
  15. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  16. }
  17. return &ctypes.ResultBroadcastTx{}, nil
  18. }
  19. // Returns with the response from CheckTx
  20. func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  21. resCh := make(chan *tmsp.Response, 1)
  22. err := mempool.CheckTx(tx, func(res *tmsp.Response) {
  23. resCh <- res
  24. })
  25. if err != nil {
  26. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  27. }
  28. res := <-resCh
  29. r := res.GetCheckTx()
  30. return &ctypes.ResultBroadcastTx{
  31. Code: r.Code,
  32. Data: r.Data,
  33. Log: r.Log,
  34. }, nil
  35. }
  36. // CONTRACT: only returns error if mempool.BroadcastTx errs (ie. problem with the app)
  37. // or if we timeout waiting for tx to commit.
  38. // If CheckTx or AppendTx fail, no error will be returned, but the returned result
  39. // will contain a non-OK TMSP code.
  40. func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
  41. // subscribe to tx being committed in block
  42. appendTxResCh := make(chan types.EventDataTx, 1)
  43. types.AddListenerForEvent(eventSwitch, "rpc", types.EventStringTx(tx), func(data types.TMEventData) {
  44. appendTxResCh <- data.(types.EventDataTx)
  45. })
  46. // broadcast the tx and register checktx callback
  47. checkTxResCh := make(chan *tmsp.Response, 1)
  48. err := mempool.CheckTx(tx, func(res *tmsp.Response) {
  49. checkTxResCh <- res
  50. })
  51. if err != nil {
  52. log.Error("err", "err", err)
  53. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  54. }
  55. checkTxRes := <-checkTxResCh
  56. checkTxR := checkTxRes.GetCheckTx()
  57. if checkTxR.Code != tmsp.CodeType_OK {
  58. // CheckTx failed!
  59. return &ctypes.ResultBroadcastTxCommit{
  60. CheckTx: checkTxR,
  61. AppendTx: nil,
  62. }, nil
  63. }
  64. // Wait for the tx to be included in a block,
  65. // timeout after something reasonable.
  66. // TODO: configureable?
  67. timer := time.NewTimer(60 * 2 * time.Second)
  68. select {
  69. case appendTxRes := <-appendTxResCh:
  70. // The tx was included in a block.
  71. appendTxR := &tmsp.ResponseAppendTx{
  72. Code: appendTxRes.Code,
  73. Data: appendTxRes.Data,
  74. Log: appendTxRes.Log,
  75. }
  76. log.Error("appendtx passed ", "r", appendTxR)
  77. return &ctypes.ResultBroadcastTxCommit{
  78. CheckTx: checkTxR,
  79. AppendTx: appendTxR,
  80. }, nil
  81. case <-timer.C:
  82. log.Error("failed to include tx")
  83. return &ctypes.ResultBroadcastTxCommit{
  84. CheckTx: checkTxR,
  85. AppendTx: nil,
  86. }, fmt.Errorf("Timed out waiting for transaction to be included in a block")
  87. }
  88. panic("Should never happen!")
  89. }
  90. func UnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
  91. txs := mempool.Reap(-1)
  92. return &ctypes.ResultUnconfirmedTxs{len(txs), txs}, nil
  93. }
  94. func NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
  95. return &ctypes.ResultUnconfirmedTxs{N: mempool.Size()}, nil
  96. }