General Merkle Proof (#2298)

* first commit

finalize rebase

add protoc_merkle to Makefile

* in progress

* fix kvstore

* fix tests

* remove iavl dependency

* fix tx_test

* fix test_abci_cli

fix test_apps

* fix test_apps

* fix test_cover

* rm rebase residue

* address comment in progress

* finalize rebase
This commit is contained in:
Joon
2018-09-29 09:03:19 +09:00
committed by Ethan Buchman
parent fc073746a0
commit 71a34adfe5
38 changed files with 1867 additions and 749 deletions

View File

@@ -75,7 +75,7 @@ func (c *HTTP) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuer
func (c *HTTP) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
result := new(ctypes.ResultABCIQuery)
_, err := c.rpc.Call("abci_query",
map[string]interface{}{"path": path, "data": data, "height": opts.Height, "trusted": opts.Trusted},
map[string]interface{}{"path": path, "data": data, "height": opts.Height, "prove": opts.Prove},
result)
if err != nil {
return nil, errors.Wrap(err, "ABCIQuery")

View File

@@ -61,7 +61,7 @@ func (c *Local) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQue
}
func (Local) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
return core.ABCIQuery(path, data, opts.Height, opts.Trusted)
return core.ABCIQuery(path, data, opts.Height, opts.Prove)
}
func (Local) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {

View File

@@ -31,10 +31,18 @@ func (a ABCIApp) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQu
}
func (a ABCIApp) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
q := a.App.Query(abci.RequestQuery{Data: data, Path: path, Height: opts.Height, Prove: opts.Trusted})
q := a.App.Query(abci.RequestQuery{
Data: data,
Path: path,
Height: opts.Height,
Prove: opts.Prove,
})
return &ctypes.ResultABCIQuery{q}, nil
}
// NOTE: Caller should call a.App.Commit() separately,
// this function does not actually wait for a commit.
// TODO: Make it wait for a commit and set res.Height appropriately.
func (a ABCIApp) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
res := ctypes.ResultBroadcastTxCommit{}
res.CheckTx = a.App.CheckTx(tx)
@@ -42,6 +50,7 @@ func (a ABCIApp) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit
return &res, nil
}
res.DeliverTx = a.App.DeliverTx(tx)
res.Height = -1 // TODO
return &res, nil
}
@@ -86,7 +95,7 @@ func (m ABCIMock) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQ
}
func (m ABCIMock) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
res, err := m.Query.GetResponse(QueryArgs{path, data, opts.Height, opts.Trusted})
res, err := m.Query.GetResponse(QueryArgs{path, data, opts.Height, opts.Prove})
if err != nil {
return nil, err
}
@@ -133,10 +142,10 @@ func NewABCIRecorder(client client.ABCIClient) *ABCIRecorder {
}
type QueryArgs struct {
Path string
Data cmn.HexBytes
Height int64
Trusted bool
Path string
Data cmn.HexBytes
Height int64
Prove bool
}
func (r *ABCIRecorder) addCall(call Call) {
@@ -161,7 +170,7 @@ func (r *ABCIRecorder) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts
res, err := r.Client.ABCIQueryWithOptions(path, data, opts)
r.addCall(Call{
Name: "abci_query",
Args: QueryArgs{path, data, opts.Height, opts.Trusted},
Args: QueryArgs{path, data, opts.Height, opts.Prove},
Response: res,
Error: err,
})

View File

@@ -51,7 +51,7 @@ func TestABCIMock(t *testing.T) {
assert.Equal("foobar", err.Error())
// query always returns the response
_query, err := m.ABCIQueryWithOptions("/", nil, client.ABCIQueryOptions{Trusted: true})
_query, err := m.ABCIQueryWithOptions("/", nil, client.ABCIQueryOptions{Prove: false})
query := _query.Response
require.Nil(err)
require.NotNil(query)
@@ -98,7 +98,7 @@ func TestABCIRecorder(t *testing.T) {
_, err := r.ABCIInfo()
assert.Nil(err, "expected no err on info")
_, err = r.ABCIQueryWithOptions("path", cmn.HexBytes("data"), client.ABCIQueryOptions{Trusted: false})
_, err = r.ABCIQueryWithOptions("path", cmn.HexBytes("data"), client.ABCIQueryOptions{Prove: false})
assert.NotNil(err, "expected error on query")
require.Equal(2, len(r.Calls))
@@ -122,7 +122,7 @@ func TestABCIRecorder(t *testing.T) {
require.True(ok)
assert.Equal("path", qa.Path)
assert.EqualValues("data", qa.Data)
assert.False(qa.Trusted)
assert.False(qa.Prove)
// now add some broadcasts (should all err)
txs := []types.Tx{{1}, {2}, {3}}
@@ -173,9 +173,17 @@ func TestABCIApp(t *testing.T) {
require.NotNil(res.DeliverTx)
assert.True(res.DeliverTx.IsOK())
// commit
// TODO: This may not be necessary in the future
if res.Height == -1 {
m.App.Commit()
}
// check the key
_qres, err := m.ABCIQueryWithOptions("/key", cmn.HexBytes(key), client.ABCIQueryOptions{Trusted: true})
_qres, err := m.ABCIQueryWithOptions("/key", cmn.HexBytes(key), client.ABCIQueryOptions{Prove: true})
qres := _qres.Response
require.Nil(err)
assert.EqualValues(value, qres.Value)
// XXX Check proof
}

View File

@@ -1,3 +1,5 @@
package mock
/*
package mock returns a Client implementation that
accepts various (mock) implementations of the various methods.
@@ -11,7 +13,6 @@ For real clients, you probably want the "http" package. If you
want to directly call a tendermint node in process, you can use the
"local" package.
*/
package mock
import (
"reflect"
@@ -87,7 +88,7 @@ func (c Client) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQue
}
func (c Client) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
return core.ABCIQuery(path, data, opts.Height, opts.Trusted)
return core.ABCIQuery(path, data, opts.Height, opts.Prove)
}
func (c Client) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {

View File

@@ -166,10 +166,10 @@ func TestAppCalls(t *testing.T) {
if err := client.WaitForHeight(c, apph, nil); err != nil {
t.Error(err)
}
_qres, err := c.ABCIQueryWithOptions("/key", k, client.ABCIQueryOptions{Trusted: true})
_qres, err := c.ABCIQueryWithOptions("/key", k, client.ABCIQueryOptions{Prove: false})
qres := _qres.Response
if assert.Nil(err) && assert.True(qres.IsOK()) {
// assert.Equal(k, data.GetKey()) // only returned for proofs
assert.Equal(k, qres.Key)
assert.EqualValues(v, qres.Value)
}
@@ -221,10 +221,12 @@ func TestAppCalls(t *testing.T) {
assert.Equal(block.Block.LastCommit, commit2.Commit)
// and we got a proof that works!
_pres, err := c.ABCIQueryWithOptions("/key", k, client.ABCIQueryOptions{Trusted: false})
_pres, err := c.ABCIQueryWithOptions("/key", k, client.ABCIQueryOptions{Prove: true})
pres := _pres.Response
assert.Nil(err)
assert.True(pres.IsOK())
// XXX Test proof
}
}
@@ -310,7 +312,7 @@ func TestTx(t *testing.T) {
// time to verify the proof
proof := ptx.Proof
if tc.prove && assert.EqualValues(t, tx, proof.Data) {
assert.True(t, proof.Proof.Verify(proof.Index, proof.Total, txHash, proof.RootHash))
assert.NoError(t, proof.Proof.Verify(proof.RootHash, txHash))
}
}
}
@@ -348,7 +350,7 @@ func TestTxSearch(t *testing.T) {
// 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))
assert.NoError(t, proof.Proof.Verify(proof.RootHash, txHash))
}
// query by height
@@ -362,7 +364,7 @@ func TestTxSearch(t *testing.T) {
require.Len(t, result.Txs, 0)
// we query using a tag (see kvstore application)
result, err = c.TxSearch("app.creator='jae'", false, 1, 30)
result, err = c.TxSearch("app.creator='Cosmoshi Netowoko'", false, 1, 30)
require.Nil(t, err, "%+v", err)
if len(result.Txs) == 0 {
t.Fatal("expected a lot of transactions")

View File

@@ -3,10 +3,9 @@ package client
// ABCIQueryOptions can be used to provide options for ABCIQuery call other
// than the DefaultABCIQueryOptions.
type ABCIQueryOptions struct {
Height int64
Trusted bool
Height int64
Prove 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}
// DefaultABCIQueryOptions are latest height (0) and prove false.
var DefaultABCIQueryOptions = ABCIQueryOptions{Height: 0, Prove: false}