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.

133 lines
3.5 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/tx/null"
  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 _, ok := env.TxIndexer.(*null.TxIndex); ok {
  20. return nil, fmt.Errorf("transaction indexing is disabled")
  21. }
  22. r, err := env.TxIndexer.Get(hash)
  23. if err != nil {
  24. return nil, err
  25. }
  26. if r == nil {
  27. return nil, fmt.Errorf("tx (%X) not found", hash)
  28. }
  29. height := r.Height
  30. index := r.Index
  31. var proof types.TxProof
  32. if prove {
  33. block := env.BlockStore.LoadBlock(height)
  34. proof = block.Data.Txs.Proof(int(index)) // XXX: overflow on 32-bit machines
  35. }
  36. return &ctypes.ResultTx{
  37. Hash: hash,
  38. Height: height,
  39. Index: index,
  40. TxResult: r.Result,
  41. Tx: r.Tx,
  42. Proof: proof,
  43. }, nil
  44. }
  45. // TxSearch allows you to query for multiple transactions results. It returns a
  46. // list of transactions (maximum ?per_page entries) and the total count.
  47. // More: https://docs.tendermint.com/master/rpc/#/Info/tx_search
  48. func (env *Environment) TxSearch(
  49. ctx *rpctypes.Context,
  50. query string,
  51. prove bool,
  52. pagePtr, perPagePtr *int,
  53. orderBy string,
  54. ) (*ctypes.ResultTxSearch, error) {
  55. // if index is disabled, return error
  56. if _, ok := env.TxIndexer.(*null.TxIndex); ok {
  57. return nil, errors.New("transaction indexing is disabled")
  58. }
  59. q, err := tmquery.New(query)
  60. if err != nil {
  61. return nil, err
  62. }
  63. results, err := env.TxIndexer.Search(ctx.Context(), q)
  64. if err != nil {
  65. return nil, err
  66. }
  67. // sort results (must be done before pagination)
  68. switch orderBy {
  69. case "desc", "":
  70. sort.Slice(results, func(i, j int) bool {
  71. if results[i].Height == results[j].Height {
  72. return results[i].Index > results[j].Index
  73. }
  74. return results[i].Height > results[j].Height
  75. })
  76. case "asc":
  77. sort.Slice(results, func(i, j int) bool {
  78. if results[i].Height == results[j].Height {
  79. return results[i].Index < results[j].Index
  80. }
  81. return results[i].Height < results[j].Height
  82. })
  83. default:
  84. return nil, fmt.Errorf("%w: expected order_by to be either `asc` or `desc` or empty", ctypes.ErrInvalidRequest)
  85. }
  86. // paginate results
  87. totalCount := len(results)
  88. perPage := env.validatePerPage(perPagePtr)
  89. page, err := validatePage(pagePtr, perPage, totalCount)
  90. if err != nil {
  91. return nil, err
  92. }
  93. skipCount := validateSkipCount(page, perPage)
  94. pageSize := tmmath.MinInt(perPage, totalCount-skipCount)
  95. apiResults := make([]*ctypes.ResultTx, 0, pageSize)
  96. for i := skipCount; i < skipCount+pageSize; i++ {
  97. r := results[i]
  98. var proof types.TxProof
  99. if prove {
  100. block := env.BlockStore.LoadBlock(r.Height)
  101. proof = block.Data.Txs.Proof(int(r.Index)) // XXX: overflow on 32-bit machines
  102. }
  103. apiResults = append(apiResults, &ctypes.ResultTx{
  104. Hash: types.Tx(r.Tx).Hash(),
  105. Height: r.Height,
  106. Index: r.Index,
  107. TxResult: r.Result,
  108. Tx: r.Tx,
  109. Proof: proof,
  110. })
  111. }
  112. return &ctypes.ResultTxSearch{Txs: apiResults, TotalCount: totalCount}, nil
  113. }