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.

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