Browse Source

limit /tx_search output

Refs #909
pull/1567/head
Anton Kaliaev 7 years ago
parent
commit
a6b74b82d1
No known key found for this signature in database GPG Key ID: 7B6881D965918214
9 changed files with 94 additions and 51 deletions
  1. +8
    -6
      rpc/client/httpclient.go
  2. +1
    -1
      rpc/client/interface.go
  3. +2
    -2
      rpc/client/localclient.go
  4. +7
    -7
      rpc/client/rpc_test.go
  5. +6
    -0
      rpc/core/README.md
  6. +20
    -0
      rpc/core/pipe.go
  7. +1
    -1
      rpc/core/routes.go
  8. +43
    -34
      rpc/core/tx.go
  9. +6
    -0
      rpc/core/types/responses.go

+ 8
- 6
rpc/client/httpclient.go View File

@ -204,17 +204,19 @@ func (c *HTTP) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
return result, nil
}
func (c *HTTP) TxSearch(query string, prove bool) ([]*ctypes.ResultTx, error) {
results := new([]*ctypes.ResultTx)
func (c *HTTP) TxSearch(query string, prove bool, page, perPage int) (*ctypes.ResultTxSearch, error) {
result := new(ctypes.ResultTxSearch)
params := map[string]interface{}{
"query": query,
"prove": prove,
"query": query,
"prove": prove,
"page": page,
"per_page": perPage,
}
_, err := c.rpc.Call("tx_search", params, results)
_, err := c.rpc.Call("tx_search", params, result)
if err != nil {
return nil, errors.Wrap(err, "TxSearch")
}
return *results, nil
return result, nil
}
func (c *HTTP) Validators(height *int64) (*ctypes.ResultValidators, error) {


+ 1
- 1
rpc/client/interface.go View File

@ -50,7 +50,7 @@ type SignClient interface {
Commit(height *int64) (*ctypes.ResultCommit, error)
Validators(height *int64) (*ctypes.ResultValidators, error)
Tx(hash []byte, prove bool) (*ctypes.ResultTx, error)
TxSearch(query string, prove bool) ([]*ctypes.ResultTx, error)
TxSearch(query string, prove bool, page, perPage int) (*ctypes.ResultTxSearch, error)
}
// HistoryClient shows us data from genesis to now in large chunks.


+ 2
- 2
rpc/client/localclient.go View File

@ -128,8 +128,8 @@ func (Local) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
return core.Tx(hash, prove)
}
func (Local) TxSearch(query string, prove bool) ([]*ctypes.ResultTx, error) {
return core.TxSearch(query, prove)
func (Local) TxSearch(query string, prove bool, page, perPage int) (*ctypes.ResultTxSearch, error) {
return core.TxSearch(query, prove, page, perPage)
}
func (c *Local) Subscribe(ctx context.Context, subscriber string, query tmpubsub.Query, out chan<- interface{}) error {


+ 7
- 7
rpc/client/rpc_test.go View File

@ -334,11 +334,11 @@ func TestTxSearch(t *testing.T) {
// now we query for the tx.
// since there's only one tx, we know index=0.
results, err := c.TxSearch(fmt.Sprintf("tx.hash='%v'", txHash), true)
result, err := c.TxSearch(fmt.Sprintf("tx.hash='%v'", txHash), true, 1, 30)
require.Nil(t, err, "%+v", err)
require.Len(t, results, 1)
require.Len(t, result.Txs, 1)
ptx := results[0]
ptx := result.Txs[0]
assert.EqualValues(t, txHeight, ptx.Height)
assert.EqualValues(t, tx, ptx.Tx)
assert.Zero(t, ptx.Index)
@ -352,14 +352,14 @@ func TestTxSearch(t *testing.T) {
}
// we query for non existing tx
results, err = c.TxSearch(fmt.Sprintf("tx.hash='%X'", anotherTxHash), false)
result, err = c.TxSearch(fmt.Sprintf("tx.hash='%X'", anotherTxHash), false, 1, 30)
require.Nil(t, err, "%+v", err)
require.Len(t, results, 0)
require.Len(t, result.Txs, 0)
// we query using a tag (see kvstore application)
results, err = c.TxSearch("app.creator='jae'", false)
result, err = c.TxSearch("app.creator='jae'", false, 1, 30)
require.Nil(t, err, "%+v", err)
if len(results) == 0 {
if len(result.Txs) == 0 {
t.Fatal("expected a lot of transactions")
}
}


+ 6
- 0
rpc/core/README.md View File

@ -13,3 +13,9 @@ go get github.com/melekes/godoc2md
godoc2md -template rpc/core/doc_template.txt github.com/tendermint/tendermint/rpc/core | grep -v -e "pipe.go" -e "routes.go" -e "dev.go" | sed 's$/src/target$https://github.com/tendermint/tendermint/tree/master/rpc/core$'
```
## Pagination
Requests that return multiple items will be paginated to 30 items by default.
You can specify further pages with the ?page parameter. You can also set a
custom page size up to 100 with the ?per_page parameter.

+ 20
- 0
rpc/core/pipe.go View File

@ -14,6 +14,12 @@ import (
"github.com/tendermint/tmlibs/log"
)
const (
// see README
defaultPerPage = 30
maxPerPage = 100
)
var subscribeTimeout = 5 * time.Second
//----------------------------------------------
@ -117,3 +123,17 @@ func SetLogger(l log.Logger) {
func SetEventBus(b *types.EventBus) {
eventBus = b
}
func validatePage(page int) int {
if page < 1 {
return 1
}
return page
}
func validatePerPage(perPage int) int {
if perPage < 1 || perPage > maxPerPage {
return defaultPerPage
}
return perPage
}

+ 1
- 1
rpc/core/routes.go View File

@ -22,7 +22,7 @@ var Routes = map[string]*rpc.RPCFunc{
"block_results": rpc.NewRPCFunc(BlockResults, "height"),
"commit": rpc.NewRPCFunc(Commit, "height"),
"tx": rpc.NewRPCFunc(Tx, "hash,prove"),
"tx_search": rpc.NewRPCFunc(TxSearch, "query,prove"),
"tx_search": rpc.NewRPCFunc(TxSearch, "query,prove,page,per_page"),
"validators": rpc.NewRPCFunc(Validators, "height"),
"dump_consensus_state": rpc.NewRPCFunc(DumpConsensusState, ""),
"consensus_state": rpc.NewRPCFunc(ConsensusState, ""),


+ 43
- 34
rpc/core/tx.go View File

@ -6,6 +6,7 @@ import (
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/state/txindex/null"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
tmquery "github.com/tendermint/tmlibs/pubsub/query"
)
@ -104,7 +105,8 @@ func Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
}, nil
}
// TxSearch allows you to query for multiple transactions results.
// TxSearch allows you to query for multiple transactions results. It returns a
// list of transactions (maximum ?per_page entries) and the total count.
//
// ```shell
// curl "localhost:46657/tx_search?query=\"account.owner='Ivan'\"&prove=true"
@ -120,43 +122,46 @@ func Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
//
// ```json
// {
// "result": [
// {
// "proof": {
// "Proof": {
// "aunts": [
// "J3LHbizt806uKnABNLwG4l7gXCA=",
// "iblMO/M1TnNtlAefJyNCeVhjAb0=",
// "iVk3ryurVaEEhdeS0ohAJZ3wtB8=",
// "5hqMkTeGqpct51ohX0lZLIdsn7Q=",
// "afhsNxFnLlZgFDoyPpdQSe0bR8g="
// ]
// },
// "Data": "mvZHHa7HhZ4aRT0xMDA=",
// "RootHash": "F6541223AA46E428CB1070E9840D2C3DF3B6D776",
// "Total": 32,
// "Index": 31
// },
// "tx": "mvZHHa7HhZ4aRT0xMDA=",
// "tx_result": {},
// "index": 31,
// "height": 12,
// "hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF"
// }
// ],
// "jsonrpc": "2.0",
// "id": "",
// "jsonrpc": "2.0"
// "result": {
// "txs": [
// {
// "proof": {
// "Proof": {
// "aunts": [
// "J3LHbizt806uKnABNLwG4l7gXCA=",
// "iblMO/M1TnNtlAefJyNCeVhjAb0=",
// "iVk3ryurVaEEhdeS0ohAJZ3wtB8=",
// "5hqMkTeGqpct51ohX0lZLIdsn7Q=",
// "afhsNxFnLlZgFDoyPpdQSe0bR8g="
// ]
// },
// "Data": "mvZHHa7HhZ4aRT0xMDA=",
// "RootHash": "F6541223AA46E428CB1070E9840D2C3DF3B6D776",
// "Total": 32,
// "Index": 31
// },
// "tx": "mvZHHa7HhZ4aRT0xMDA=",
// "tx_result": {},
// "index": 31,
// "height": 12,
// "hash": "2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF"
// }
// ],
// "total_count": 1
// }
// }
// ```
//
// Returns transactions matching the given query.
//
// ### Query Parameters
//
// | Parameter | Type | Default | Required | Description |
// |-----------+--------+---------+----------+-----------------------------------------------------------|
// | query | string | "" | true | Query |
// | prove | bool | false | false | Include proofs of the transactions inclusion in the block |
// | page | int | 1 | false | Page number (1-based) |
// | per_page | int | 30 | false | Number of entries per page (max: 100) |
//
// ### Returns
//
@ -166,7 +171,7 @@ func Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
// - `index`: `int` - index of the transaction
// - `height`: `int` - height of the block where this transaction was in
// - `hash`: `[]byte` - hash of the transaction
func TxSearch(query string, prove bool) ([]*ctypes.ResultTx, error) {
func TxSearch(query string, prove bool, page, perPage int) (*ctypes.ResultTxSearch, error) {
// if index is disabled, return error
if _, ok := txIndexer.(*null.TxIndex); ok {
return nil, fmt.Errorf("Transaction indexing is disabled")
@ -182,11 +187,15 @@ func TxSearch(query string, prove bool) ([]*ctypes.ResultTx, error) {
return nil, err
}
// TODO: we may want to consider putting a maximum on this length and somehow
// informing the user that things were truncated.
apiResults := make([]*ctypes.ResultTx, len(results))
totalCount := len(results)
page = validatePage(page)
perPage = validatePerPage(perPage)
skipCount := (page - 1) * perPage
apiResults := make([]*ctypes.ResultTx, cmn.MinInt(perPage, totalCount-skipCount))
var proof types.TxProof
for i, r := range results {
for i := 0; i < len(apiResults); i++ {
r := results[skipCount+i]
height := r.Height
index := r.Index
@ -205,5 +214,5 @@ func TxSearch(query string, prove bool) ([]*ctypes.ResultTx, error) {
}
}
return apiResults, nil
return &ctypes.ResultTxSearch{Txs: apiResults, TotalCount: totalCount}, nil
}

+ 6
- 0
rpc/core/types/responses.go View File

@ -172,6 +172,12 @@ type ResultTx struct {
Proof types.TxProof `json:"proof,omitempty"`
}
// Result of searching for txs
type ResultTxSearch struct {
Txs []*ResultTx `json:"txs"`
TotalCount int `json:"total_count"`
}
// List of mempool txs
type ResultUnconfirmedTxs struct {
N int `json:"n_txs"`


Loading…
Cancel
Save