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.

112 lines
3.6 KiB

9 years ago
  1. package core
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/tendermint/go-events"
  6. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  7. "github.com/tendermint/tendermint/types"
  8. tmsp "github.com/tendermint/tmsp/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 := mempoolReactor.BroadcastTx(tx, nil)
  15. if err != nil {
  16. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  17. }
  18. return &ctypes.ResultBroadcastTx{}, nil
  19. }
  20. // Returns with the response from CheckTx
  21. func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  22. resCh := make(chan *tmsp.Response, 1)
  23. err := mempoolReactor.BroadcastTx(tx, func(res *tmsp.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. }, nil
  36. }
  37. // CONTRACT: returns error==nil iff the tx is included in a block.
  38. //
  39. // If CheckTx fails, return with the response from CheckTx AND an error.
  40. // Else, block until the tx is included in a block,
  41. // and return the result of AppendTx (with no error).
  42. // Even if AppendTx fails, so long as the tx is included in a block this function
  43. // will not return an error - it is the caller's responsibility to check res.Code.
  44. // The function times out after five minutes and returns the result of CheckTx and an error.
  45. // TODO: smarter timeout logic or someway to cancel (tx not getting committed is a sign of a larger problem!)
  46. func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
  47. // subscribe to tx being committed in block
  48. appendTxResCh := make(chan *tmsp.Response, 1)
  49. eventSwitch.AddListenerForEvent("rpc", types.EventStringTx(tx), func(data events.EventData) {
  50. appendTxResCh <- data.(*tmsp.Response)
  51. })
  52. // broadcast the tx and register checktx callback
  53. checkTxResCh := make(chan *tmsp.Response, 1)
  54. err := mempoolReactor.BroadcastTx(tx, func(res *tmsp.Response) {
  55. checkTxResCh <- res
  56. })
  57. if err != nil {
  58. return nil, fmt.Errorf("Error broadcasting transaction: %v", err)
  59. }
  60. checkTxRes := <-checkTxResCh
  61. checkTxR := checkTxRes.GetCheckTx()
  62. if r := checkTxR; r.Code != tmsp.CodeType_OK {
  63. // CheckTx failed!
  64. return &ctypes.ResultBroadcastTx{
  65. Code: r.Code,
  66. Data: r.Data,
  67. Log: r.Log,
  68. }, fmt.Errorf("Check tx failed with non-zero code: %s. Data: %X; Log: %s", r.Code.String(), r.Data, r.Log)
  69. }
  70. // Wait for the tx to be included in a block,
  71. // timeout after something reasonable.
  72. timer := time.NewTimer(60 * 5 * time.Second)
  73. select {
  74. case appendTxRes := <-appendTxResCh:
  75. // The tx was included in a block.
  76. // NOTE we don't return an error regardless of the AppendTx code;
  77. // clients must check this to see if they need to send a new tx!
  78. r := appendTxRes.GetAppendTx()
  79. return &ctypes.ResultBroadcastTx{
  80. Code: r.Code,
  81. Data: r.Data,
  82. Log: r.Log,
  83. }, nil
  84. case <-timer.C:
  85. r := checkTxR
  86. return &ctypes.ResultBroadcastTx{
  87. Code: r.Code,
  88. Data: r.Data,
  89. Log: r.Log,
  90. }, fmt.Errorf("Timed out waiting for transaction to be included in a block")
  91. }
  92. panic("Should never happen!")
  93. }
  94. func UnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
  95. txs := mempoolReactor.Mempool.Reap(0)
  96. return &ctypes.ResultUnconfirmedTxs{len(txs), txs}, nil
  97. }
  98. func NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
  99. return &ctypes.ResultUnconfirmedTxs{N: mempoolReactor.Mempool.Size()}, nil
  100. }