From 3a5a7a776e0ccce955418815f8a7aa0f42f71eb1 Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Thu, 12 Jul 2018 00:27:50 -0700 Subject: [PATCH] fixed all tests --- Gopkg.lock | 6 +- Gopkg.toml | 2 +- abci/example/kvstore/kvstore.go | 26 ++++++-- abci/example/kvstore/kvstore_test.go | 21 ++++--- consensus/common_test.go | 2 +- crypto/merkle/proof.go | 28 +++------ crypto/merkle/proof_simple_value.go | 34 ++++++---- lite/errors/errors.go | 21 +++++++ lite/proxy/errors.go | 24 -------- lite/proxy/proof.go | 23 +++++++ lite/proxy/query.go | 31 ++++++---- lite/proxy/query_test.go | 92 +++++++++++++++++----------- lite/proxy/wrapper.go | 7 ++- rpc/client/mock/abci.go | 4 ++ rpc/client/mock/abci_test.go | 6 ++ rpc/client/rpc_test.go | 2 +- rpc/core/abci.go | 11 ++-- 17 files changed, 210 insertions(+), 130 deletions(-) delete mode 100644 lite/proxy/errors.go create mode 100644 lite/proxy/proof.go diff --git a/Gopkg.lock b/Gopkg.lock index 5571ea0bb..3afb2ec4d 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -308,8 +308,8 @@ ".", "sha256truncated" ] - revision = "8ca620e7e401976d0324938c9a361cf78bca9770" - version = "v0.9.3-rc0" + revision = "866a229a90d86b07af23ffa156c3fa1396416574" + version = "v0.10.0-rc1" [[projects]] name = "github.com/tendermint/tmlibs" @@ -432,6 +432,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "e473d5da80b2f997f7b1e42ff6eb0fff055fa0ff9ab1a9f0bd01ed239b479fe3" + inputs-digest = "ece6ed2d29c510b27b489c93a94e68e4aa5db840c16c6b8b7563d81fed4072fe" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 010b1512a..60eafd94c 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -75,7 +75,7 @@ [[constraint]] name = "github.com/tendermint/iavl" - version = "0.9.3-rc0" + version = "0.10.0-rc1" [[override]] name = "github.com/tendermint/tmlibs" diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index 65fe6c833..f7c10de40 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -8,6 +8,7 @@ import ( "github.com/tendermint/iavl" "github.com/tendermint/tendermint/abci/example/code" "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/merkle" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" ) @@ -107,27 +108,42 @@ func (app *KVStoreApplication) Commit() types.ResponseCommit { func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { key := reqQuery.Data + height := app.state.Height + if reqQuery.Height != 0 { + height = reqQuery.Height + } if reqQuery.Prove { - value, proof, err := app.state.tree.GetWithProof(key) + value, proof, err := app.state.tree.GetVersionedWithProof(key, height) if err != nil { resQuery.Code = code.CodeTypeUnknownError resQuery.Log = err.Error() return } + resQuery.Height = height resQuery.Index = proof.LeftIndex() // TODO make Proof return index - resQuery.Key = reqQuery.Data + resQuery.Key = key resQuery.Value = value if value != nil { + resQuery.Proof = &merkle.Proof{ + // XXX key encoding + Ops: []merkle.ProofOp{iavl.NewIAVLValueOp(string(key), proof).ProofOp()}, + } resQuery.Log = "exists" } else { + resQuery.Proof = &merkle.Proof{ + // XXX key encoding + Ops: []merkle.ProofOp{iavl.NewIAVLAbsenceOp(string(key), proof).ProofOp()}, + } resQuery.Log = "does not exist" } return } else { - index, value := app.state.tree.Get64(key) - resQuery.Index = index - resQuery.Key = reqQuery.Data + index, value := app.state.tree.GetVersioned(key, height) + resQuery.Height = height + resQuery.Index = int64(index) // TODO GetVersioned64? + resQuery.Key = key resQuery.Value = value + resQuery.Proof = nil if value != nil { resQuery.Log = "exists" } else { diff --git a/abci/example/kvstore/kvstore_test.go b/abci/example/kvstore/kvstore_test.go index 809e8eb5f..a2731c644 100644 --- a/abci/example/kvstore/kvstore_test.go +++ b/abci/example/kvstore/kvstore_test.go @@ -18,11 +18,13 @@ import ( ) func testKVStore(t *testing.T, app types.Application, tx []byte, key, value string) { - ar := app.DeliverTx(tx) - require.False(t, ar.IsErr(), ar) + rdtx := app.DeliverTx(tx) + require.False(t, rdtx.IsErr(), rdtx) // repeating tx doesn't raise error - ar = app.DeliverTx(tx) - require.False(t, ar.IsErr(), ar) + rdtx = app.DeliverTx(tx) + require.False(t, rdtx.IsErr(), rdtx) + rc := app.Commit() + require.NotNil(t, rc.Data) // make sure query is fine resQuery := app.Query(types.RequestQuery{ @@ -281,13 +283,16 @@ func runClientTests(t *testing.T, client abcicli.Client) { } func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) { - ar, err := app.DeliverTxSync(tx) + rdtx, err := app.DeliverTxSync(tx) require.NoError(t, err) - require.False(t, ar.IsErr(), ar) + require.False(t, rdtx.IsErr(), rdtx) // repeating tx doesn't raise error - ar, err = app.DeliverTxSync(tx) + rdtx, err = app.DeliverTxSync(tx) require.NoError(t, err) - require.False(t, ar.IsErr(), ar) + require.False(t, rdtx.IsErr(), rdtx) + rc, err := app.CommitSync() + require.NoError(t, err) + require.NotNil(t, rc.Data) // make sure query is fine resQuery, err := app.QuerySync(types.RequestQuery{ diff --git a/consensus/common_test.go b/consensus/common_test.go index 8c5aa6c92..c63fd9e3d 100644 --- a/consensus/common_test.go +++ b/consensus/common_test.go @@ -39,7 +39,7 @@ const ( // genesis, chain_id, priv_val var config *cfg.Config // NOTE: must be reset for each _test.go file -var ensureTimeout = time.Second * 1 // must be in seconds because CreateEmptyBlocksInterval is +var ensureTimeout = time.Second * 5 // must be in seconds because CreateEmptyBlocksInterval is func ensureDir(dir string, mode os.FileMode) { if err := cmn.EnsureDir(dir, mode); err != nil { diff --git a/crypto/merkle/proof.go b/crypto/merkle/proof.go index 51d891a98..331591866 100644 --- a/crypto/merkle/proof.go +++ b/crypto/merkle/proof.go @@ -2,7 +2,6 @@ package merkle import ( "bytes" - "reflect" "github.com/tendermint/go-amino" cmn "github.com/tendermint/tmlibs/common" @@ -72,20 +71,6 @@ func NewProofRuntime() *ProofRuntime { } } -func (prt *ProofRuntime) RegisterAminoOpDecoder(typ string, opType reflect.Type) { - prt.RegisterOpDecoder( - typ, - func(pop ProofOp) (ProofOperator, error) { - newOp := reflect.New(opType).Elem().Interface() - err := cdc.UnmarshalBinary(pop.Data, &newOp) - if err != nil { - return nil, cmn.ErrorWrap(err, "decoding ProofOp.Data") - } - return newOp.(ProofOperator), nil - }, - ) -} - func (prt *ProofRuntime) RegisterOpDecoder(typ string, dec OpDecoder) { _, ok := prt.decoders[typ] if ok { @@ -120,6 +105,14 @@ func (prt *ProofRuntime) VerifyValue(proof *Proof, root []byte, value []byte, ke return prt.Verify(proof, root, [][]byte{value}, keys...) } +// XXX Reorder value/keys, and figure out how to merge keys into a single string +// after figuring out encoding between bytes/string. +// TODO In the long run we'll need a method of classifcation of ops, +// whether existence or absence or perhaps a third? +func (prt *ProofRuntime) VerifyAbsence(proof *Proof, root []byte, keys ...string) (err error) { + return prt.Verify(proof, root, nil, keys...) +} + // XXX Reorder value/keys, and figure out how to merge keys into a single string // after figuring out encoding between bytes/string. func (prt *ProofRuntime) Verify(proof *Proof, root []byte, args [][]byte, keys ...string) (err error) { @@ -136,9 +129,6 @@ func (prt *ProofRuntime) Verify(proof *Proof, root []byte, args [][]byte, keys . // defined in the IAVL package. func DefaultProofRuntime() (prt *ProofRuntime) { prt = NewProofRuntime() - prt.RegisterAminoOpDecoder( - ProofOpSimpleValue, - reflect.TypeOf(SimpleValueOp{}), - ) + prt.RegisterOpDecoder(ProofOpSimpleValue, SimpleValueOpDecoder) return } diff --git a/crypto/merkle/proof_simple_value.go b/crypto/merkle/proof_simple_value.go index 2e1ae2c60..b7fb4fb21 100644 --- a/crypto/merkle/proof_simple_value.go +++ b/crypto/merkle/proof_simple_value.go @@ -21,7 +21,7 @@ const ProofOpSimpleValue = "simple:v" // If the produced root hash matches the expected hash, the // proof is good. type SimpleValueOp struct { - // encoded in ProofOp.Key, not .Data + // Encoded in ProofOp.Key. key string // To encode in ProofOp.Data @@ -37,6 +37,27 @@ func NewSimpleValueOp(key string, proof *SimpleProof) SimpleValueOp { } } +func SimpleValueOpDecoder(pop ProofOp) (ProofOperator, error) { + if pop.Type != ProofOpSimpleValue { + return nil, cmn.NewError("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpSimpleValue) + } + var op SimpleValueOp // a bit strange as we'll discard this, but it works. + err := cdc.UnmarshalBinary(pop.Data, &op) + if err != nil { + return nil, cmn.ErrorWrap(err, "decoding ProofOp.Data into SimpleValueOp") + } + return NewSimpleValueOp(pop.Key, op.Proof), nil +} + +func (op SimpleValueOp) ProofOp() ProofOp { + bz := cdc.MustMarshalBinary(op) + return ProofOp{ + Type: ProofOpSimpleValue, + Key: op.key, + Data: bz, + } +} + func (op SimpleValueOp) String() string { return fmt.Sprintf("SimpleValueOp{%v}", op.GetKey()) } @@ -50,7 +71,7 @@ func (op SimpleValueOp) Run(args [][]byte) ([][]byte, error) { hasher.Write(value) // does not error vhash := hasher.Sum(nil) - // Wrap to hash the KVPair. + // Wrap to hash the KVPair. hasher = tmhash.New() encodeByteSlice(hasher, []byte(op.key)) // does not error encodeByteSlice(hasher, []byte(vhash)) // does not error @@ -68,12 +89,3 @@ func (op SimpleValueOp) Run(args [][]byte) ([][]byte, error) { func (op SimpleValueOp) GetKey() string { return op.key } - -func (op SimpleValueOp) ProofOp() ProofOp { - bz := cdc.MustMarshalBinary(op) - return ProofOp{ - Type: ProofOpSimpleValue, - Key: op.key, - Data: bz, - } -} diff --git a/lite/errors/errors.go b/lite/errors/errors.go index c38ecf88f..d3c1e1317 100644 --- a/lite/errors/errors.go +++ b/lite/errors/errors.go @@ -41,6 +41,12 @@ func (e errMissingValidators) Error() string { e.chainID, e.height) } +type errEmptyTree struct{} + +func (e errEmptyTree) Error() string { + return "Tree is empty" +} + //---------------------------------------- // Methods for above error types @@ -110,3 +116,18 @@ func IsErrMissingValidators(err error) bool { } return false } + +//----------------- +// ErrEmptyTree + +func ErrEmptyTree() error { + return cmn.ErrorWrap(errEmptyTree{}, "") +} + +func IsErrEmptyTree(err error) bool { + if err_, ok := err.(cmn.Error); ok { + _, ok := err_.Data().(errEmptyTree) + return ok + } + return false +} diff --git a/lite/proxy/errors.go b/lite/proxy/errors.go deleted file mode 100644 index 9af72a54c..000000000 --- a/lite/proxy/errors.go +++ /dev/null @@ -1,24 +0,0 @@ -package proxy - -import ( - cmn "github.com/tendermint/tmlibs/common" -) - -type errNoData struct{} - -func (e errNoData) Error() string { - return "No data returned for query" -} - -// IsErrNoData checks whether an error is due to a query returning empty data -func IsErrNoData(err error) bool { - if err_, ok := err.(cmn.Error); ok { - _, ok := err_.Data().(errNoData) - return ok - } - return false -} - -func ErrNoData() error { - return cmn.ErrorWrap(errNoData{}, "") -} diff --git a/lite/proxy/proof.go b/lite/proxy/proof.go new file mode 100644 index 000000000..a9024bc48 --- /dev/null +++ b/lite/proxy/proof.go @@ -0,0 +1,23 @@ +package proxy + +import ( + "github.com/tendermint/iavl" + "github.com/tendermint/tendermint/crypto/merkle" +) + +func defaultProofRuntime() *merkle.ProofRuntime { + prt := merkle.NewProofRuntime() + prt.RegisterOpDecoder( + merkle.ProofOpSimpleValue, + merkle.SimpleValueOpDecoder, + ) + prt.RegisterOpDecoder( + iavl.ProofOpIAVLValue, + iavl.IAVLValueOpDecoder, + ) + prt.RegisterOpDecoder( + iavl.ProofOpIAVLAbsence, + iavl.IAVLAbsenceOpDecoder, + ) + return prt +} diff --git a/lite/proxy/query.go b/lite/proxy/query.go index 51fc83944..5edf4324c 100644 --- a/lite/proxy/query.go +++ b/lite/proxy/query.go @@ -7,6 +7,7 @@ import ( "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/lite" + lerr "github.com/tendermint/tendermint/lite/errors" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/types" @@ -16,7 +17,7 @@ import ( // a valid proof, as defined by the certifier. // // If there is any error in checking, returns an error. -func GetWithProof(key []byte, reqHeight int64, node rpcclient.Client, +func GetWithProof(prt *merkle.ProofRuntime, key []byte, reqHeight int64, node rpcclient.Client, cert lite.Certifier) ( val cmn.HexBytes, height int64, proof *merkle.Proof, err error) { @@ -25,7 +26,7 @@ func GetWithProof(key []byte, reqHeight int64, node rpcclient.Client, return } - res, err := GetWithProofOptions("/key", key, + res, err := GetWithProofOptions(prt, "/key", key, rpcclient.ABCIQueryOptions{Height: int64(reqHeight), Prove: true}, node, cert) if err != nil { @@ -38,7 +39,8 @@ func GetWithProof(key []byte, reqHeight int64, node rpcclient.Client, } // GetWithProofOptions is useful if you want full access to the ABCIQueryOptions. -func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOptions, +// XXX Usage of path? It's not used, and sometimes it's /, sometimes /key, sometimes /store. +func GetWithProofOptions(prt *merkle.ProofRuntime, path string, key []byte, opts rpcclient.ABCIQueryOptions, node rpcclient.Client, cert lite.Certifier) ( *ctypes.ResultABCIQuery, error) { @@ -57,8 +59,9 @@ func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOption err = cmn.NewError("Query error for key %d: %d", key, resp.Code) return nil, err } + if len(resp.Key) == 0 || resp.Proof == nil { - return nil, ErrNoData() + return nil, lerr.ErrEmptyTree() } if resp.Height == 0 { return nil, cmn.NewError("Height returned is zero") @@ -70,21 +73,25 @@ func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOption return nil, err } - if len(resp.Value) > 0 { - // Validate the proof against the certified header to ensure data integrity. - // XXX Pass this in somehow so iavl can be registered. + // Validate the proof against the certified header to ensure data integrity. + if resp.Value != nil { + // Value exists // XXX How do we encode the key into a string... - prt := merkle.NewProofRuntime() err = prt.VerifyValue(resp.Proof, signedHeader.AppHash, resp.Value, string(resp.Key)) if err != nil { - return nil, cmn.ErrorWrap(err, "Couldn't verify proof") + return nil, cmn.ErrorWrap(err, "Couldn't verify value proof") } return &ctypes.ResultABCIQuery{Response: resp}, nil } else { - return nil, cmn.NewError("proof of absence not yet supported") + // Value absent + // Validate the proof against the certified header to ensure data integrity. + // XXX How do we encode the key into a string... + err = prt.VerifyAbsence(resp.Proof, signedHeader.AppHash, string(resp.Key)) + if err != nil { + return nil, cmn.ErrorWrap(err, "Couldn't verify absence proof") + } + return &ctypes.ResultABCIQuery{Response: resp}, nil } - - return &ctypes.ResultABCIQuery{Response: resp}, ErrNoData() } // GetCertifiedCommit gets the signed header for a given height and certifies diff --git a/lite/proxy/query_test.go b/lite/proxy/query_test.go index ca8d713d3..9bff128fb 100644 --- a/lite/proxy/query_test.go +++ b/lite/proxy/query_test.go @@ -4,13 +4,12 @@ import ( "fmt" "os" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/example/kvstore" - - "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/lite" certclient "github.com/tendermint/tendermint/lite/client" nm "github.com/tendermint/tendermint/node" @@ -21,6 +20,7 @@ import ( var node *nm.Node var chainID = "tendermint_test" // TODO use from config. +var waitForEventTimeout = 5 * time.Second // TODO fix tests!! @@ -42,64 +42,82 @@ func kvstoreTx(k, v []byte) []byte { func TestAppProofs(t *testing.T) { assert, require := assert.New(t), require.New(t) + prt := defaultProofRuntime() cl := client.NewLocal(node) client.WaitForHeight(cl, 1, nil) + // This sets up our trust on the node based on some past point. + source := certclient.NewProvider(chainID, cl) + seed, err := source.LatestFullCommit(chainID, 1, 1) + require.NoError(err, "%#v", err) + cert := lite.NewBaseCertifier(chainID, seed.Height(), seed.Validators) + + // Wait for tx confirmation. + done := make(chan int64) + go func() { + evtTyp := types.EventTx + _, err = client.WaitForOneEvent(cl, evtTyp, waitForEventTimeout) + require.Nil(err, "%#v", err) + close(done) + }() + + // Submit a transaction. k := []byte("my-key") v := []byte("my-value") - tx := kvstoreTx(k, v) br, err := cl.BroadcastTxCommit(tx) - require.NoError(err, "%+v", err) + require.NoError(err, "%#v", err) require.EqualValues(0, br.CheckTx.Code, "%#v", br.CheckTx) require.EqualValues(0, br.DeliverTx.Code) brh := br.Height - // This sets up our trust on the node based on some past point. - source := certclient.NewProvider(chainID, cl) - seed, err := source.LatestFullCommit(chainID, brh-2, brh-2) - require.NoError(err, "%+v", err) - cert := lite.NewBaseCertifier("my-chain", seed.Height(), seed.Validators) - - client.WaitForHeight(cl, 3, nil) + // Fetch latest after tx commit. + <-done latest, err := source.LatestFullCommit(chainID, 1, 1<<63-1) - require.NoError(err, "%+v", err) + require.NoError(err, "%#v", err) rootHash := latest.SignedHeader.AppHash + if rootHash == nil { + // Fetch one block later, AppHash hasn't been committed yet. + // TODO find a way to avoid doing this. + client.WaitForHeight(cl, latest.SignedHeader.Height+1, nil) + latest, err = source.LatestFullCommit(chainID, latest.SignedHeader.Height+1, 1<<63-1) + require.NoError(err, "%#v", err) + rootHash = latest.SignedHeader.AppHash + } require.NotNil(rootHash) // verify a query before the tx block has no data (and valid non-exist proof) - bs, height, proof, err := GetWithProof(k, brh-1, cl, cert) - require.NotNil(err) - require.NotNil(proof) - // XXX test proof - require.True(IsErrNoData(err), err.Error()) + bs, height, proof, err := GetWithProof(prt, k, brh-1, cl, cert) + require.NoError(err, "%#v", err) + // require.NotNil(proof) + // TODO: Ensure that *some* keys will be there, ensuring that proof is nil, + // (currently there's a race condition) + // and ensure that proof proves absence of k. require.Nil(bs) // but given that block it is good - bs, height, proof, err = GetWithProof(k, brh, cl, cert) - require.NoError(err, "%+v", err) + bs, height, proof, err = GetWithProof(prt, k, brh, cl, cert) + require.NoError(err, "%#v", err) require.NotNil(proof) - require.True(height >= int64(latest.Height())) - - prt := merkle.NewProofRuntime() + require.Equal(height, brh) assert.EqualValues(v, bs) - err = prt.VerifyValue(proof, rootHash, k, string(bs)) - assert.NoError(err, "%+v", err) + err = prt.VerifyValue(proof, rootHash, bs, string(k)) // XXX key encoding + assert.NoError(err, "%#v", err) // Test non-existing key. missing := []byte("my-missing-key") - bs, _, proof, err = GetWithProof(missing, 0, cl, cert) - require.True(IsErrNoData(err)) + bs, _, proof, err = GetWithProof(prt, missing, 0, cl, cert) + require.NoError(err) require.Nil(bs) require.NotNil(proof) - err = prt.VerifyValue(proof, rootHash, missing, "") // XXX VerifyAbsence() - assert.NoError(err, "%+v", err) - err = prt.VerifyValue(proof, rootHash, k, "") // XXX VerifyAbsence() - assert.Error(err) + err = prt.Verify(proof, rootHash, nil, string(missing)) // XXX VerifyAbsence(), keyencoding + assert.NoError(err, "%#v", err) + err = prt.Verify(proof, rootHash, nil, string(k)) // XXX VerifyAbsence(), keyencoding + assert.Error(err, "%#v", err) } -func _TestTxProofs(t *testing.T) { +func TestTxProofs(t *testing.T) { assert, require := assert.New(t), require.New(t) cl := client.NewLocal(node) @@ -107,15 +125,15 @@ func _TestTxProofs(t *testing.T) { tx := kvstoreTx([]byte("key-a"), []byte("value-a")) br, err := cl.BroadcastTxCommit(tx) - require.NoError(err, "%+v", err) + require.NoError(err, "%#v", err) require.EqualValues(0, br.CheckTx.Code, "%#v", br.CheckTx) require.EqualValues(0, br.DeliverTx.Code) brh := br.Height source := certclient.NewProvider(chainID, cl) seed, err := source.LatestFullCommit(chainID, brh-2, brh-2) - require.NoError(err, "%+v", err) - cert := lite.NewBaseCertifier("my-chain", seed.Height(), seed.Validators) + require.NoError(err, "%#v", err) + cert := lite.NewBaseCertifier(chainID, seed.Height(), seed.Validators) // First let's make sure a bogus transaction hash returns a valid non-existence proof. key := types.Tx([]byte("bogus")).Hash() @@ -126,12 +144,12 @@ func _TestTxProofs(t *testing.T) { // Now let's check with the real tx hash. key = types.Tx(tx).Hash() res, err = cl.Tx(key, true) - require.NoError(err, "%+v", err) + require.NoError(err, "%#v", err) require.NotNil(res) err = res.Proof.Validate(key) - assert.NoError(err, "%+v", err) + assert.NoError(err, "%#v", err) commit, err := GetCertifiedCommit(br.Height, cl, cert) - require.Nil(err, "%+v", err) + require.Nil(err, "%#v", err) require.Equal(res.Proof.RootHash, commit.Header.DataHash) } diff --git a/lite/proxy/wrapper.go b/lite/proxy/wrapper.go index c8cfa3eae..cde6a6e61 100644 --- a/lite/proxy/wrapper.go +++ b/lite/proxy/wrapper.go @@ -3,6 +3,7 @@ package proxy import ( cmn "github.com/tendermint/tmlibs/common" + "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/lite" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" @@ -15,6 +16,7 @@ var _ rpcclient.Client = Wrapper{} type Wrapper struct { rpcclient.Client cert *lite.InquiringCertifier + prt *merkle.ProofRuntime } // SecureClient uses a given certifier to wrap an connection to an untrusted @@ -22,7 +24,8 @@ type Wrapper struct { // // If it is wrapping an HTTP rpcclient, it will also wrap the websocket interface func SecureClient(c rpcclient.Client, cert *lite.InquiringCertifier) Wrapper { - wrap := Wrapper{c, cert} + prt := defaultProofRuntime() + wrap := Wrapper{c, cert, prt} // TODO: no longer possible as no more such interface exposed.... // if we wrap http client, then we can swap out the event switch to filter // if hc, ok := c.(*rpcclient.HTTP); ok { @@ -36,7 +39,7 @@ func SecureClient(c rpcclient.Client, cert *lite.InquiringCertifier) Wrapper { func (w Wrapper) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { - res, err := GetWithProofOptions(path, data, opts, w.Client, w.cert) + res, err := GetWithProofOptions(w.prt, path, data, opts, w.Client, w.cert) return res, err } diff --git a/rpc/client/mock/abci.go b/rpc/client/mock/abci.go index 6c1c94582..307e3c3a5 100644 --- a/rpc/client/mock/abci.go +++ b/rpc/client/mock/abci.go @@ -35,6 +35,9 @@ func (a ABCIApp) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts clien 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 +45,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 } diff --git a/rpc/client/mock/abci_test.go b/rpc/client/mock/abci_test.go index 80b15623e..e8e0c921b 100644 --- a/rpc/client/mock/abci_test.go +++ b/rpc/client/mock/abci_test.go @@ -173,6 +173,12 @@ 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{Prove: true}) qres := _qres.Response diff --git a/rpc/client/rpc_test.go b/rpc/client/rpc_test.go index 71547947f..6689135e5 100644 --- a/rpc/client/rpc_test.go +++ b/rpc/client/rpc_test.go @@ -359,7 +359,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") diff --git a/rpc/core/abci.go b/rpc/core/abci.go index c07724d58..ab78d6b1a 100644 --- a/rpc/core/abci.go +++ b/rpc/core/abci.go @@ -10,7 +10,7 @@ import ( // Query the application for some information. // // ```shell -// curl 'localhost:26657/abci_query?path=""&data="abcd"&trusted=false' +// curl 'localhost:26657/abci_query?path=""&data="abcd"&prove=false' // ``` // // ```go @@ -27,7 +27,6 @@ import ( // "response": { // "log": "exists", // "height": 0, -// "proof": "010114FED0DAD959F36091AD761C922ABA3CBF1D8349990101020103011406AA2262E2F448242DF2C2607C3CDC705313EE3B0001149D16177BC71E445476174622EA559715C293740C", // "value": "61626364", // "key": "61626364", // "index": -1, @@ -45,14 +44,14 @@ import ( // |-----------+--------+---------+----------+------------------------------------------------| // | path | string | false | false | Path to the data ("/a/b/c") | // | data | []byte | false | true | Data | -// | height | int64 | 0 | false | Height (0 means latest) | -// | trusted | bool | false | false | Does not include a proof of the data inclusion | -func ABCIQuery(path string, data cmn.HexBytes, height int64, trusted bool) (*ctypes.ResultABCIQuery, error) { +// | height | int64 | 0 | false | Height (0 means latest) | +// | prove | bool | false | false | Includes proof if true | +func ABCIQuery(path string, data cmn.HexBytes, height int64, prove bool) (*ctypes.ResultABCIQuery, error) { resQuery, err := proxyAppQuery.QuerySync(abci.RequestQuery{ Path: path, Data: data, Height: height, - Prove: !trusted, + Prove: prove, }) if err != nil { return nil, err