From acbc0717d4206514e4094468d710ed2fe2358aaa Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 29 Nov 2017 13:42:11 -0600 Subject: [PATCH] add client methods --- rpc/client/httpclient.go | 17 ++++++++++++++-- rpc/client/interface.go | 1 + rpc/client/localclient.go | 4 ++++ rpc/client/rpc_test.go | 41 +++++++++++++++++++++++++++++++++++++++ rpc/core/routes.go | 2 +- state/txindex/kv/kv.go | 6 +++++- 6 files changed, 67 insertions(+), 4 deletions(-) diff --git a/rpc/client/httpclient.go b/rpc/client/httpclient.go index 47c99fd3..5ceace97 100644 --- a/rpc/client/httpclient.go +++ b/rpc/client/httpclient.go @@ -163,17 +163,30 @@ func (c *HTTP) Commit(height *int) (*ctypes.ResultCommit, error) { func (c *HTTP) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) { result := new(ctypes.ResultTx) - query := map[string]interface{}{ + params := map[string]interface{}{ "hash": hash, "prove": prove, } - _, err := c.rpc.Call("tx", query, result) + _, err := c.rpc.Call("tx", params, result) if err != nil { return nil, errors.Wrap(err, "Tx") } return result, nil } +func (c *HTTP) TxSearch(query string, prove bool) ([]*ctypes.ResultTx, error) { + results := new([]*ctypes.ResultTx) + params := map[string]interface{}{ + "query": query, + "prove": prove, + } + _, err := c.rpc.Call("tx_search", params, results) + if err != nil { + return nil, errors.Wrap(err, "TxSearch") + } + return *results, nil +} + func (c *HTTP) Validators(height *int) (*ctypes.ResultValidators, error) { result := new(ctypes.ResultValidators) _, err := c.rpc.Call("validators", map[string]interface{}{"height": height}, result) diff --git a/rpc/client/interface.go b/rpc/client/interface.go index 443ea89d..c0d7e052 100644 --- a/rpc/client/interface.go +++ b/rpc/client/interface.go @@ -50,6 +50,7 @@ type SignClient interface { Commit(height *int) (*ctypes.ResultCommit, error) Validators(height *int) (*ctypes.ResultValidators, error) Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) + TxSearch(query string, prove bool) ([]*ctypes.ResultTx, error) } // HistoryClient shows us data from genesis to now in large chunks. diff --git a/rpc/client/localclient.go b/rpc/client/localclient.go index 55a0e0fb..d5444007 100644 --- a/rpc/client/localclient.go +++ b/rpc/client/localclient.go @@ -124,6 +124,10 @@ 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 (c *Local) Subscribe(ctx context.Context, query string, out chan<- interface{}) error { q, err := tmquery.New(query) if err != nil { diff --git a/rpc/client/rpc_test.go b/rpc/client/rpc_test.go index b6b3d9e2..6eab5b85 100644 --- a/rpc/client/rpc_test.go +++ b/rpc/client/rpc_test.go @@ -1,6 +1,7 @@ package client_test import ( + "fmt" "strings" "testing" @@ -294,3 +295,43 @@ func TestTx(t *testing.T) { } } } + +func TestTxSearch(t *testing.T) { + // first we broadcast a tx + c := getHTTPClient() + _, _, tx := MakeTxKV() + bres, err := c.BroadcastTxCommit(tx) + require.Nil(t, err, "%+v", err) + + txHeight := bres.Height + txHash := bres.Hash + + anotherTxHash := types.Tx("a different tx").Hash() + + for i, c := range GetClients() { + t.Logf("client %d", i) + + // 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) + require.Nil(t, err, "%+v", err) + require.Len(t, results, 1) + + ptx := results[0] + assert.EqualValues(t, txHeight, ptx.Height) + assert.EqualValues(t, tx, ptx.Tx) + assert.Zero(t, ptx.Index) + assert.True(t, ptx.TxResult.Code.IsOK()) + + // time to verify the proof + proof := ptx.Proof + if assert.EqualValues(t, tx, proof.Data) { + assert.True(t, proof.Proof.Verify(proof.Index, proof.Total, txHash, proof.RootHash)) + } + + // we query for non existing tx + results, err = c.TxSearch(fmt.Sprintf("tx.hash='%X'", anotherTxHash), false) + require.Nil(t, err, "%+v", err) + require.Len(t, results, 0) + } +} diff --git a/rpc/core/routes.go b/rpc/core/routes.go index 2ae352c1..111c010a 100644 --- a/rpc/core/routes.go +++ b/rpc/core/routes.go @@ -19,7 +19,7 @@ var Routes = map[string]*rpc.RPCFunc{ "block": rpc.NewRPCFunc(Block, "height"), "commit": rpc.NewRPCFunc(Commit, "height"), "tx": rpc.NewRPCFunc(Tx, "hash,prove"), - "tx_search": rpc.NewRPCFunc(Tx, "query,prove"), + "tx_search": rpc.NewRPCFunc(TxSearch, "query,prove"), "validators": rpc.NewRPCFunc(Validators, "height"), "dump_consensus_state": rpc.NewRPCFunc(DumpConsensusState, ""), "unconfirmed_txs": rpc.NewRPCFunc(UnconfirmedTxs, ""), diff --git a/state/txindex/kv/kv.go b/state/txindex/kv/kv.go index 53d07325..e5ae048c 100644 --- a/state/txindex/kv/kv.go +++ b/state/txindex/kv/kv.go @@ -111,7 +111,11 @@ func (txi *TxIndex) Search(q *query.Query) ([]*types.TxResult, error) { return nil, errors.Wrap(err, "error during searching for a hash in the query") } else if ok { res, err := txi.Get(hash) - return []*types.TxResult{res}, errors.Wrap(err, "error while retrieving the result") + if res == nil { + return []*types.TxResult{}, nil + } else { + return []*types.TxResult{res}, errors.Wrap(err, "error while retrieving the result") + } } // conditions to skip because they're handled before "everything else"