Browse Source

Merge pull request #734 from tendermint/482-support-historical-abci-queries

support historical abci queries
pull/743/head
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
340f33b475
10 changed files with 91 additions and 33 deletions
  1. +6
    -2
      rpc/client/httpclient.go
  2. +2
    -1
      rpc/client/interface.go
  3. +6
    -2
      rpc/client/localclient.go
  4. +23
    -10
      rpc/client/mock/abci.go
  5. +5
    -4
      rpc/client/mock/abci_test.go
  6. +6
    -2
      rpc/client/mock/client.go
  7. +19
    -2
      rpc/client/rpc_test.go
  8. +12
    -0
      rpc/client/types.go
  9. +11
    -9
      rpc/core/abci.go
  10. +1
    -1
      rpc/core/routes.go

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

@ -69,10 +69,14 @@ func (c *HTTP) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
return result, nil return result, nil
} }
func (c *HTTP) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
func (c *HTTP) ABCIQuery(path string, data data.Bytes) (*ctypes.ResultABCIQuery, error) {
return c.ABCIQueryWithOptions(path, data, DefaultABCIQueryOptions)
}
func (c *HTTP) ABCIQueryWithOptions(path string, data data.Bytes, opts ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
result := new(ctypes.ResultABCIQuery) result := new(ctypes.ResultABCIQuery)
_, err := c.rpc.Call("abci_query", _, err := c.rpc.Call("abci_query",
map[string]interface{}{"path": path, "data": data, "prove": prove},
map[string]interface{}{"path": path, "data": data, "height": opts.Height, "trusted": opts.Trusted},
result) result)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "ABCIQuery") return nil, errors.Wrap(err, "ABCIQuery")


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

@ -31,7 +31,8 @@ import (
type ABCIClient interface { type ABCIClient interface {
// reading from abci app // reading from abci app
ABCIInfo() (*ctypes.ResultABCIInfo, error) ABCIInfo() (*ctypes.ResultABCIInfo, error)
ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error)
ABCIQuery(path string, data data.Bytes) (*ctypes.ResultABCIQuery, error)
ABCIQueryWithOptions(path string, data data.Bytes, opts ABCIQueryOptions) (*ctypes.ResultABCIQuery, error)
// writing to abci app // writing to abci app
BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error)


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

@ -57,8 +57,12 @@ func (c Local) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
return core.ABCIInfo() return core.ABCIInfo()
} }
func (c Local) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
return core.ABCIQuery(path, data, prove)
func (c Local) ABCIQuery(path string, data data.Bytes) (*ctypes.ResultABCIQuery, error) {
return c.ABCIQueryWithOptions(path, data, DefaultABCIQueryOptions)
}
func (c Local) ABCIQueryWithOptions(path string, data data.Bytes, opts ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
return core.ABCIQuery(path, data, opts.Height, opts.Trusted)
} }
func (c Local) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) { func (c Local) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {


+ 23
- 10
rpc/client/mock/abci.go View File

@ -24,8 +24,12 @@ func (a ABCIApp) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
return &ctypes.ResultABCIInfo{a.App.Info(abci.RequestInfo{version.Version})}, nil return &ctypes.ResultABCIInfo{a.App.Info(abci.RequestInfo{version.Version})}, nil
} }
func (a ABCIApp) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
q := a.App.Query(abci.RequestQuery{data, path, 0, prove})
func (a ABCIApp) ABCIQuery(path string, data data.Bytes) (*ctypes.ResultABCIQuery, error) {
return a.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
}
func (a ABCIApp) ABCIQueryWithOptions(path string, data data.Bytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
q := a.App.Query(abci.RequestQuery{data, path, opts.Height, opts.Trusted})
return &ctypes.ResultABCIQuery{q.Result()}, nil return &ctypes.ResultABCIQuery{q.Result()}, nil
} }
@ -79,8 +83,12 @@ func (m ABCIMock) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
return &ctypes.ResultABCIInfo{res.(abci.ResponseInfo)}, nil return &ctypes.ResultABCIInfo{res.(abci.ResponseInfo)}, nil
} }
func (m ABCIMock) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
res, err := m.Query.GetResponse(QueryArgs{path, data, prove})
func (m ABCIMock) ABCIQuery(path string, data data.Bytes) (*ctypes.ResultABCIQuery, error) {
return m.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
}
func (m ABCIMock) ABCIQueryWithOptions(path string, data data.Bytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
res, err := m.Query.GetResponse(QueryArgs{path, data, opts.Height, opts.Trusted})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -131,9 +139,10 @@ func (r *ABCIRecorder) _assertABCIClient() client.ABCIClient {
} }
type QueryArgs struct { type QueryArgs struct {
Path string
Data data.Bytes
Prove bool
Path string
Data data.Bytes
Height uint64
Trusted bool
} }
func (r *ABCIRecorder) addCall(call Call) { func (r *ABCIRecorder) addCall(call Call) {
@ -150,11 +159,15 @@ func (r *ABCIRecorder) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
return res, err return res, err
} }
func (r *ABCIRecorder) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
res, err := r.Client.ABCIQuery(path, data, prove)
func (r *ABCIRecorder) ABCIQuery(path string, data data.Bytes) (*ctypes.ResultABCIQuery, error) {
return r.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
}
func (r *ABCIRecorder) ABCIQueryWithOptions(path string, data data.Bytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
res, err := r.Client.ABCIQueryWithOptions(path, data, opts)
r.addCall(Call{ r.addCall(Call{
Name: "abci_query", Name: "abci_query",
Args: QueryArgs{path, data, prove},
Args: QueryArgs{path, data, opts.Height, opts.Trusted},
Response: res, Response: res,
Error: err, Error: err,
}) })


+ 5
- 4
rpc/client/mock/abci_test.go View File

@ -12,6 +12,7 @@ import (
"github.com/tendermint/abci/example/dummy" "github.com/tendermint/abci/example/dummy"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
data "github.com/tendermint/go-wire/data" data "github.com/tendermint/go-wire/data"
"github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/rpc/client/mock" "github.com/tendermint/tendermint/rpc/client/mock"
ctypes "github.com/tendermint/tendermint/rpc/core/types" ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
@ -50,7 +51,7 @@ func TestABCIMock(t *testing.T) {
assert.Equal("foobar", err.Error()) assert.Equal("foobar", err.Error())
// query always returns the response // query always returns the response
query, err := m.ABCIQuery("/", nil, false)
query, err := m.ABCIQueryWithOptions("/", nil, client.ABCIQueryOptions{Trusted: true})
require.Nil(err) require.Nil(err)
require.NotNil(query) require.NotNil(query)
assert.EqualValues(key, query.Key) assert.EqualValues(key, query.Key)
@ -92,7 +93,7 @@ func TestABCIRecorder(t *testing.T) {
require.Equal(0, len(r.Calls)) require.Equal(0, len(r.Calls))
r.ABCIInfo() r.ABCIInfo()
r.ABCIQuery("path", data.Bytes("data"), true)
r.ABCIQueryWithOptions("path", data.Bytes("data"), client.ABCIQueryOptions{Trusted: false})
require.Equal(2, len(r.Calls)) require.Equal(2, len(r.Calls))
info := r.Calls[0] info := r.Calls[0]
@ -115,7 +116,7 @@ func TestABCIRecorder(t *testing.T) {
require.True(ok) require.True(ok)
assert.Equal("path", qa.Path) assert.Equal("path", qa.Path)
assert.EqualValues("data", qa.Data) assert.EqualValues("data", qa.Data)
assert.True(qa.Prove)
assert.False(qa.Trusted)
// now add some broadcasts // now add some broadcasts
txs := []types.Tx{{1}, {2}, {3}} txs := []types.Tx{{1}, {2}, {3}}
@ -164,7 +165,7 @@ func TestABCIApp(t *testing.T) {
assert.True(res.DeliverTx.Code.IsOK()) assert.True(res.DeliverTx.Code.IsOK())
// check the key // check the key
qres, err := m.ABCIQuery("/key", data.Bytes(key), false)
qres, err := m.ABCIQueryWithOptions("/key", data.Bytes(key), client.ABCIQueryOptions{Trusted: true})
require.Nil(err) require.Nil(err)
assert.EqualValues(value, qres.Value) assert.EqualValues(value, qres.Value)
} }

+ 6
- 2
rpc/client/mock/client.go View File

@ -84,8 +84,12 @@ func (c Client) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
return core.ABCIInfo() return core.ABCIInfo()
} }
func (c Client) ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
return core.ABCIQuery(path, data, prove)
func (c Client) ABCIQuery(path string, data data.Bytes) (*ctypes.ResultABCIQuery, error) {
return c.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions)
}
func (c Client) ABCIQueryWithOptions(path string, data data.Bytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
return core.ABCIQuery(path, data, opts.Height, opts.Trusted)
} }
func (c Client) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) { func (c Client) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {


+ 19
- 2
rpc/client/rpc_test.go View File

@ -98,6 +98,23 @@ func TestGenesisAndValidators(t *testing.T) {
} }
} }
func TestABCIQuery(t *testing.T) {
for i, c := range GetClients() {
// write something
k, v, tx := MakeTxKV()
bres, err := c.BroadcastTxCommit(tx)
require.Nil(t, err, "%d: %+v", i, err)
apph := bres.Height + 1 // this is where the tx will be applied to the state
// wait before querying
client.WaitForHeight(c, apph, nil)
qres, err := c.ABCIQuery("/key", k)
if assert.Nil(t, err) && assert.True(t, qres.Code.IsOK()) {
assert.EqualValues(t, v, qres.Value)
}
}
}
// Make some app checks // Make some app checks
func TestAppCalls(t *testing.T) { func TestAppCalls(t *testing.T) {
assert, require := assert.New(t), require.New(t) assert, require := assert.New(t), require.New(t)
@ -124,7 +141,7 @@ func TestAppCalls(t *testing.T) {
// wait before querying // wait before querying
client.WaitForHeight(c, apph, nil) client.WaitForHeight(c, apph, nil)
qres, err := c.ABCIQuery("/key", k, false)
qres, err := c.ABCIQueryWithOptions("/key", k, client.ABCIQueryOptions{Trusted: true})
if assert.Nil(err) && assert.True(qres.Code.IsOK()) { if assert.Nil(err) && assert.True(qres.Code.IsOK()) {
// assert.Equal(k, data.GetKey()) // only returned for proofs // assert.Equal(k, data.GetKey()) // only returned for proofs
assert.EqualValues(v, qres.Value) assert.EqualValues(v, qres.Value)
@ -172,7 +189,7 @@ func TestAppCalls(t *testing.T) {
assert.Equal(block.Block.LastCommit, commit2.Commit) assert.Equal(block.Block.LastCommit, commit2.Commit)
// and we got a proof that works! // and we got a proof that works!
pres, err := c.ABCIQuery("/key", k, true)
pres, err := c.ABCIQueryWithOptions("/key", k, client.ABCIQueryOptions{Trusted: false})
if assert.Nil(err) && assert.True(pres.Code.IsOK()) { if assert.Nil(err) && assert.True(pres.Code.IsOK()) {
proof, err := iavl.ReadProof(pres.Proof) proof, err := iavl.ReadProof(pres.Proof)
if assert.Nil(err) { if assert.Nil(err) {


+ 12
- 0
rpc/client/types.go View File

@ -0,0 +1,12 @@
package client
// ABCIQueryOptions can be used to provide options for ABCIQuery call other
// than the DefaultABCIQueryOptions.
type ABCIQueryOptions struct {
Height uint64
Trusted bool
}
// DefaultABCIQueryOptions are latest height (0) and trusted equal to false
// (which will result in a proof being returned).
var DefaultABCIQueryOptions = ABCIQueryOptions{Height: 0, Trusted: false}

+ 11
- 9
rpc/core/abci.go View File

@ -41,16 +41,18 @@ import (
// //
// ### Query Parameters // ### Query Parameters
// //
// | Parameter | Type | Default | Required | Description |
// |-----------+--------+---------+----------+---------------------------------------|
// | path | string | false | false | Path to the data ("/a/b/c") |
// | data | []byte | false | true | Data |
// | prove | bool | false | false | Include a proof of the data inclusion |
func ABCIQuery(path string, data data.Bytes, prove bool) (*ctypes.ResultABCIQuery, error) {
// | Parameter | Type | Default | Required | Description |
// |-----------+--------+---------+----------+------------------------------------------------|
// | path | string | false | false | Path to the data ("/a/b/c") |
// | data | []byte | false | true | Data |
// | height | uint64 | 0 | false | Height (0 means latest) |
// | trusted | bool | false | false | Does not include a proof of the data inclusion |
func ABCIQuery(path string, data data.Bytes, height uint64, trusted bool) (*ctypes.ResultABCIQuery, error) {
resQuery, err := proxyAppQuery.QuerySync(abci.RequestQuery{ resQuery, err := proxyAppQuery.QuerySync(abci.RequestQuery{
Path: path,
Data: data,
Prove: prove,
Path: path,
Data: data,
Height: height,
Prove: !trusted,
}) })
if err != nil { if err != nil {
return nil, err return nil, err


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

@ -29,7 +29,7 @@ var Routes = map[string]*rpc.RPCFunc{
"broadcast_tx_async": rpc.NewRPCFunc(BroadcastTxAsync, "tx"), "broadcast_tx_async": rpc.NewRPCFunc(BroadcastTxAsync, "tx"),
// abci API // abci API
"abci_query": rpc.NewRPCFunc(ABCIQuery, "path,data,prove"),
"abci_query": rpc.NewRPCFunc(ABCIQuery, "path,data,height,prove"),
"abci_info": rpc.NewRPCFunc(ABCIInfo, ""), "abci_info": rpc.NewRPCFunc(ABCIInfo, ""),
} }


Loading…
Cancel
Save