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.

141 lines
4.0 KiB

7 years ago
  1. package core
  2. import (
  3. "errors"
  4. "fmt"
  5. "sort"
  6. tmmath "github.com/tendermint/tendermint/libs/math"
  7. tmquery "github.com/tendermint/tendermint/libs/pubsub/query"
  8. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  9. rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types"
  10. "github.com/tendermint/tendermint/state/indexer"
  11. "github.com/tendermint/tendermint/types"
  12. )
  13. // Tx allows you to query the transaction results. `nil` could mean the
  14. // transaction is in the mempool, invalidated, or was not sent in the first
  15. // place.
  16. // More: https://docs.tendermint.com/master/rpc/#/Info/tx
  17. func (env *Environment) Tx(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error) {
  18. // if index is disabled, return error
  19. if !indexer.KVSinkEnabled(env.EventSinks) {
  20. return nil, errors.New("transaction querying is disabled due to no kvEventSink")
  21. }
  22. for _, sink := range env.EventSinks {
  23. if sink.Type() == indexer.KV {
  24. r, err := sink.GetTxByHash(hash)
  25. if r == nil {
  26. return nil, fmt.Errorf("tx (%X) not found, err: %w", hash, err)
  27. }
  28. height := r.Height
  29. index := r.Index
  30. var proof types.TxProof
  31. if prove {
  32. block := env.BlockStore.LoadBlock(height)
  33. proof = block.Data.Txs.Proof(int(index)) // XXX: overflow on 32-bit machines
  34. }
  35. return &ctypes.ResultTx{
  36. Hash: hash,
  37. Height: height,
  38. Index: index,
  39. TxResult: r.Result,
  40. Tx: r.Tx,
  41. Proof: proof,
  42. }, nil
  43. }
  44. }
  45. return nil, fmt.Errorf("transaction querying is disabled on this node due to the KV event sink being disabled")
  46. }
  47. // TxSearch allows you to query for multiple transactions results. It returns a
  48. // list of transactions (maximum ?per_page entries) and the total count.
  49. // More: https://docs.tendermint.com/master/rpc/#/Info/tx_search
  50. func (env *Environment) TxSearch(
  51. ctx *rpctypes.Context,
  52. query string,
  53. prove bool,
  54. pagePtr, perPagePtr *int,
  55. orderBy string,
  56. ) (*ctypes.ResultTxSearch, error) {
  57. if !indexer.KVSinkEnabled(env.EventSinks) {
  58. return nil, fmt.Errorf("transaction searching is disabled due to no kvEventSink")
  59. }
  60. q, err := tmquery.New(query)
  61. if err != nil {
  62. return nil, err
  63. }
  64. for _, sink := range env.EventSinks {
  65. if sink.Type() == indexer.KV {
  66. results, err := sink.SearchTxEvents(ctx.Context(), q)
  67. if err != nil {
  68. return nil, err
  69. }
  70. // sort results (must be done before pagination)
  71. switch orderBy {
  72. case "desc", "":
  73. sort.Slice(results, func(i, j int) bool {
  74. if results[i].Height == results[j].Height {
  75. return results[i].Index > results[j].Index
  76. }
  77. return results[i].Height > results[j].Height
  78. })
  79. case "asc":
  80. sort.Slice(results, func(i, j int) bool {
  81. if results[i].Height == results[j].Height {
  82. return results[i].Index < results[j].Index
  83. }
  84. return results[i].Height < results[j].Height
  85. })
  86. default:
  87. return nil, fmt.Errorf("expected order_by to be either `asc` or `desc` or empty: %w", ctypes.ErrInvalidRequest)
  88. }
  89. // paginate results
  90. totalCount := len(results)
  91. perPage := env.validatePerPage(perPagePtr)
  92. page, err := validatePage(pagePtr, perPage, totalCount)
  93. if err != nil {
  94. return nil, err
  95. }
  96. skipCount := validateSkipCount(page, perPage)
  97. pageSize := tmmath.MinInt(perPage, totalCount-skipCount)
  98. apiResults := make([]*ctypes.ResultTx, 0, pageSize)
  99. for i := skipCount; i < skipCount+pageSize; i++ {
  100. r := results[i]
  101. var proof types.TxProof
  102. if prove {
  103. block := env.BlockStore.LoadBlock(r.Height)
  104. proof = block.Data.Txs.Proof(int(r.Index)) // XXX: overflow on 32-bit machines
  105. }
  106. apiResults = append(apiResults, &ctypes.ResultTx{
  107. Hash: types.Tx(r.Tx).Hash(),
  108. Height: r.Height,
  109. Index: r.Index,
  110. TxResult: r.Result,
  111. Tx: r.Tx,
  112. Proof: proof,
  113. })
  114. }
  115. return &ctypes.ResultTxSearch{Txs: apiResults, TotalCount: totalCount}, nil
  116. }
  117. }
  118. return nil, fmt.Errorf("transaction searching is disabled on this node due to the KV event sink being disabled")
  119. }