From 57b28d95de858bc15eaef43c2e56d87366cdab14 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 30 Jan 2018 14:59:28 +0100 Subject: [PATCH 1/9] Add GetStoreByName to MultiStore to help with Query lookups --- store/cachemultistore.go | 25 +++++++++++++++++++++---- store/rootmultistore.go | 16 ++++++++++++++++ types/store.go | 2 ++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/store/cachemultistore.go b/store/cachemultistore.go index b53899b3d..837e52dfe 100644 --- a/store/cachemultistore.go +++ b/store/cachemultistore.go @@ -10,14 +10,18 @@ import ( // cacheMultiStore holds many cache-wrapped stores. // Implements MultiStore. type cacheMultiStore struct { - db CacheKVStore - stores map[StoreKey]CacheWrap + db CacheKVStore + stores map[StoreKey]CacheWrap + keysByName map[string]StoreKey } +var _ CacheMultiStore = cacheMultiStore{} + func newCacheMultiStoreFromRMS(rms *rootMultiStore) cacheMultiStore { cms := cacheMultiStore{ - db: NewCacheKVStore(dbStoreAdapter{rms.db}), - stores: make(map[StoreKey]CacheWrap, len(rms.stores)), + db: NewCacheKVStore(dbStoreAdapter{rms.db}), + stores: make(map[StoreKey]CacheWrap, len(rms.stores)), + keysByName: rms.keysByName, } for key, store := range rms.stores { cms.stores[key] = store.CacheWrap() @@ -68,3 +72,16 @@ func (cms cacheMultiStore) GetStore(key StoreKey) Store { func (cms cacheMultiStore) GetKVStore(key StoreKey) KVStore { return cms.stores[key].(KVStore) } + +// GetStoreByName will first convert the original name to +// a special key, before looking up the CommitStore. +// This is not exposed to the extensions (which will need the +// StoreKey), but is useful in main, and particularly app.Query, +// in order to convert human strings into CommitStores. +func (cms cacheMultiStore) GetStoreByName(name string) Store { + key := cms.keysByName[name] + if key == nil { + return nil + } + return cms.stores[key].(Store) +} diff --git a/store/rootmultistore.go b/store/rootmultistore.go index f964a1fd5..2a0c831d8 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -24,6 +24,7 @@ type rootMultiStore struct { lastCommitID CommitID storesParams map[StoreKey]storeParams stores map[StoreKey]CommitStore + keysByName map[string]StoreKey } var _ CommitMultiStore = (*rootMultiStore)(nil) @@ -33,6 +34,7 @@ func NewCommitMultiStore(db dbm.DB) *rootMultiStore { db: db, storesParams: make(map[StoreKey]storeParams), stores: make(map[StoreKey]CommitStore), + keysByName: make(map[string]StoreKey), } } @@ -53,6 +55,7 @@ func (rs *rootMultiStore) MountStoreWithDB(key StoreKey, typ StoreType, db dbm.D db: db, typ: typ, } + rs.keysByName[key.Name()] = key } // Implements CommitMultiStore. @@ -169,6 +172,19 @@ func (rs *rootMultiStore) GetKVStore(key StoreKey) KVStore { return rs.stores[key].(KVStore) } +// GetStoreByName will first convert the original name to +// a special key, before looking up the CommitStore. +// This is not exposed to the extensions (which will need the +// StoreKey), but is useful in main, and particularly app.Query, +// in order to convert human strings into CommitStores. +func (rs *rootMultiStore) GetStoreByName(name string) Store { + key := rs.keysByName[name] + if key == nil { + return nil + } + return rs.stores[key] +} + //---------------------------------------- func (rs *rootMultiStore) loadCommitStoreFromParams(id CommitID, params storeParams) (store CommitStore, err error) { diff --git a/types/store.go b/types/store.go index f9e8c912a..5847091a4 100644 --- a/types/store.go +++ b/types/store.go @@ -39,6 +39,8 @@ type MultiStore interface { // Convenience for fetching substores. GetStore(StoreKey) Store GetKVStore(StoreKey) KVStore + + GetStoreByName(string) Store } // From MultiStore.CacheMultiStore().... From bc325c4d1cdf499f219c79596db0b4a58c1523f5 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 30 Jan 2018 15:20:38 +0100 Subject: [PATCH 2/9] Add Query routing to rootMultiStore --- store/rootmultistore.go | 52 ++++++++++++++++++++++++++++++++++++++++- store/types.go | 1 + types/errors.go | 3 ++- types/result.go | 8 +++++++ types/store.go | 9 +++++++ 5 files changed, 71 insertions(+), 2 deletions(-) diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 2a0c831d8..3e6fde5c3 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -2,10 +2,13 @@ package store import ( "fmt" + "strings" + "golang.org/x/crypto/ripemd160" + + abci "github.com/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/merkle" - "golang.org/x/crypto/ripemd160" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -28,6 +31,7 @@ type rootMultiStore struct { } var _ CommitMultiStore = (*rootMultiStore)(nil) +var _ Queryable = (*rootMultiStore)(nil) func NewCommitMultiStore(db dbm.DB) *rootMultiStore { return &rootMultiStore{ @@ -185,6 +189,52 @@ func (rs *rootMultiStore) GetStoreByName(name string) Store { return rs.stores[key] } +//---------------------- Query ------------------ + +func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { + // Query just routes this to a substore. + path := req.Path + storeName, subpath, err := parsePath(path) + if err != nil { + return err.Result().ToQuery() + } + + store := rs.GetStoreByName(storeName) + if store == nil { + msg := fmt.Sprintf("no such store: %s", storeName) + return sdk.ErrUnknownRequest(msg).Result().ToQuery() + } + query, ok := store.(Queryable) + if !ok { + msg := fmt.Sprintf("store %s doesn't support queries", storeName) + return sdk.ErrUnknownRequest(msg).Result().ToQuery() + } + + // trim the path and make the query + req.Path = subpath + res := query.Query(req) + + // Note: later we have to think about adding information about + // the multistore -> store path to the proof + return res +} + +// parsePath expects a format like /[/] +// Must start with /, subpath may be empty +// Returns error if it doesn't start with / +func parsePath(path string) (storeName string, subpath string, err sdk.Error) { + if !strings.HasPrefix(path, "/") { + err = sdk.ErrUnknownRequest(fmt.Sprintf("invalid path: %s", path)) + return + } + paths := strings.SplitN(path[1:], "/", 2) + storeName = paths[0] + if len(paths) == 2 { + subpath = paths[1] + } + return +} + //---------------------------------------- func (rs *rootMultiStore) loadCommitStoreFromParams(id CommitID, params storeParams) (store CommitStore, err error) { diff --git a/store/types.go b/store/types.go index e6946fb4d..ec842d9cf 100644 --- a/store/types.go +++ b/store/types.go @@ -19,3 +19,4 @@ type CacheWrap = types.CacheWrap type CommitID = types.CommitID type StoreKey = types.StoreKey type StoreType = types.StoreType +type Queryable = types.Queryable diff --git a/types/errors.go b/types/errors.go index 3f93045f6..a87814931 100644 --- a/types/errors.go +++ b/types/errors.go @@ -2,8 +2,9 @@ package types import ( "fmt" - "github.com/tendermint/go-crypto" "runtime" + + "github.com/tendermint/go-crypto" ) type CodeType uint32 diff --git a/types/result.go b/types/result.go index 412a9778d..c1afec00c 100644 --- a/types/result.go +++ b/types/result.go @@ -38,3 +38,11 @@ type Result struct { func (res Result) IsOK() bool { return res.Code.IsOK() } + +// ToQuery allows us to return sdk.Error.Result() in query responses +func (res Result) ToQuery() abci.ResponseQuery { + return abci.ResponseQuery{ + Code: uint32(res.Code), + Log: res.Log, + } +} diff --git a/types/store.go b/types/store.go index 5847091a4..e9894d0d6 100644 --- a/types/store.go +++ b/types/store.go @@ -3,6 +3,7 @@ package types import ( "fmt" + abci "github.com/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" ) @@ -25,6 +26,14 @@ type CommitStore interface { Store } +// Queryable allows a Store to expose internal state to the abci.Query +// interface. Multistore can route requests to the proper Store. +// +// This is an optional, but useful extension to any CommitStore +type Queryable interface { + Query(abci.RequestQuery) abci.ResponseQuery +} + //---------------------------------------- // MultiStore From 512c601adcfb4040a000c0948c5ba98941d4cd79 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 30 Jan 2018 15:30:25 +0100 Subject: [PATCH 3/9] Add tests for query path routing --- store/rootmultistore.go | 2 +- store/rootmultistore_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 3e6fde5c3..62131611b 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -230,7 +230,7 @@ func parsePath(path string) (storeName string, subpath string, err sdk.Error) { paths := strings.SplitN(path[1:], "/", 2) storeName = paths[0] if len(paths) == 2 { - subpath = paths[1] + subpath = "/" + paths[1] } return } diff --git a/store/rootmultistore_test.go b/store/rootmultistore_test.go index 99e905062..d2cc44230 100644 --- a/store/rootmultistore_test.go +++ b/store/rootmultistore_test.go @@ -20,6 +20,14 @@ func TestMultistoreCommitLoad(t *testing.T) { commitID := CommitID{} checkStore(t, store, commitID, commitID) + // make sure we can get stores by name + s1 := store.GetStoreByName("store1") + assert.NotNil(t, s1) + s3 := store.GetStoreByName("store3") + assert.NotNil(t, s3) + s77 := store.GetStoreByName("store77") + assert.Nil(t, s77) + // make a few commits and check them nCommits := int64(3) for i := int64(0); i < nCommits; i++ { @@ -62,6 +70,27 @@ func TestMultistoreCommitLoad(t *testing.T) { checkStore(t, store, commitID, commitID) } +func TestParsePath(t *testing.T) { + _, _, err := parsePath("foo") + assert.Error(t, err) + + store, subpath, err := parsePath("/foo") + assert.NoError(t, err) + assert.Equal(t, store, "foo") + assert.Equal(t, subpath, "") + + store, subpath, err = parsePath("/fizz/bang/baz") + assert.NoError(t, err) + assert.Equal(t, store, "fizz") + assert.Equal(t, subpath, "/bang/baz") + + substore, subsubpath, err := parsePath(subpath) + assert.NoError(t, err) + assert.Equal(t, substore, "bang") + assert.Equal(t, subsubpath, "/baz") + +} + //----------------------------------------------------------------------- // utils From 31f00742e56a4cb5886faf0e9294a2108c884c06 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 30 Jan 2018 19:37:03 +0100 Subject: [PATCH 4/9] Add query to iavl store --- store/iavlstore.go | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/store/iavlstore.go b/store/iavlstore.go index 59b520954..52deef367 100644 --- a/store/iavlstore.go +++ b/store/iavlstore.go @@ -4,6 +4,7 @@ import ( "fmt" "sync" + abci "github.com/tendermint/abci/types" "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -31,6 +32,7 @@ func LoadIAVLStore(db dbm.DB, id CommitID) (CommitStore, error) { var _ KVStore = (*iavlStore)(nil) var _ CommitStore = (*iavlStore)(nil) +var _ Queryable = (*iavlStore)(nil) // iavlStore Implements KVStore and CommitStore. type iavlStore struct { @@ -123,6 +125,55 @@ func (st *iavlStore) ReverseIterator(start, end []byte) Iterator { return newIAVLIterator(st.tree.Tree(), start, end, false) } +// Query implements ABCI interface, allows queries +// +// by default we will return from (latest height -1), +// as we will have merkle proofs immediately (header height = data height + 1) +// If latest-1 is not present, use latest (which must be present) +// if you care to have the latest data to see a tx results, you must +// explicitly set the height you want to see +func (st *iavlStore) Query(req abci.RequestQuery) (res abci.ResponseQuery) { + if len(req.Data) == 0 { + msg := "Query cannot be zero length" + return sdk.ErrTxParse(msg).Result().ToQuery() + } + + tree := st.tree + height := req.Height + if height == 0 { + latest := tree.Version64() + if tree.VersionExists(latest - 1) { + height = latest - 1 + } else { + height = latest + } + } + // store the height we chose in the response + res.Height = height + + switch req.Path { + case "/store", "/key": // Get by key + key := req.Data // Data holds the key bytes + res.Key = key + if req.Prove { + value, proof, err := tree.GetVersionedWithProof(key, height) + if err != nil { + res.Log = err.Error() + break + } + res.Value = value + res.Proof = proof.Bytes() + } else { + _, res.Value = tree.GetVersioned(key, height) + } + + default: + msg := fmt.Sprintf("Unexpected Query path: %v", req.Path) + return sdk.ErrUnknownRequest(msg).Result().ToQuery() + } + return +} + //---------------------------------------- // Implements Iterator. From 44c39043f12e84119839281d4fec7288e04b860f Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 30 Jan 2018 19:59:05 +0100 Subject: [PATCH 5/9] Test iavlStore query --- store/iavlstore_test.go | 64 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/store/iavlstore_test.go b/store/iavlstore_test.go index 80731c24e..c426e4d8a 100644 --- a/store/iavlstore_test.go +++ b/store/iavlstore_test.go @@ -5,10 +5,12 @@ import ( "github.com/stretchr/testify/assert" + abci "github.com/tendermint/abci/types" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" - "github.com/tendermint/iavl" + sdk "github.com/cosmos/cosmos-sdk/types" ) var ( @@ -79,3 +81,63 @@ func TestIAVLIterator(t *testing.T) { i += 1 } } + +func TestIAVLStoreQuery(t *testing.T) { + db := dbm.NewMemDB() + tree := iavl.NewVersionedTree(db, cacheSize) + iavlStore := newIAVLStore(tree, numHistory) + + k, v := []byte("wind"), []byte("blows") + k2, v2 := []byte("water"), []byte("flows") + v3 := []byte("is cold") + // k3, v3 := []byte("earth"), []byte("soes") + // k4, v4 := []byte("fire"), []byte("woes") + + cid := iavlStore.Commit() + ver := cid.Version + query := abci.RequestQuery{Path: "/key", Data: k, Height: ver} + + // set data without commit, doesn't show up + iavlStore.Set(k, v) + qres := iavlStore.Query(query) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Nil(t, qres.Value) + + // commit it, but still don't see on old version + cid = iavlStore.Commit() + qres = iavlStore.Query(query) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Nil(t, qres.Value) + + // but yes on the new version + query.Height = cid.Version + qres = iavlStore.Query(query) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, v, qres.Value) + + // modify + iavlStore.Set(k2, v2) + iavlStore.Set(k, v3) + cid = iavlStore.Commit() + + // query will return old values, as height is fixed + qres = iavlStore.Query(query) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, v, qres.Value) + + // update to latest in the query and we are happy + query.Height = cid.Version + qres = iavlStore.Query(query) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, v3, qres.Value) + query2 := abci.RequestQuery{Path: "/key", Data: k2, Height: cid.Version} + qres = iavlStore.Query(query2) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, v2, qres.Value) + + // default (height 0) will show latest -1 + query0 := abci.RequestQuery{Path: "/store", Data: k} + qres = iavlStore.Query(query0) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, v, qres.Value) +} From 8765fa32fada2d97235c43c4688d5134617a2cb0 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 30 Jan 2018 20:01:25 +0100 Subject: [PATCH 6/9] Expose rootMultiStore query in BaseApp --- baseapp/baseapp.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 1727c2a42..c4f326b08 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -199,9 +199,14 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC } // Implements ABCI. +// Delegates to CommitMultiStore if it implements Queryable func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { - // TODO: See app/query.go - return + query, ok := app.cms.(sdk.Queryable) + if !ok { + msg := "application doesn't support queries" + return sdk.ErrUnknownRequest(msg).Result().ToQuery() + } + return query.Query(req) } // Implements ABCI. From c73f08c84578622e532128db2cf803ad6a3f0942 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 2 Feb 2018 15:43:03 +0100 Subject: [PATCH 7/9] Make GetStoreByName private, as only needed by MultiStore Query --- store/cachemultistore.go | 13 ------------- store/rootmultistore.go | 6 +++--- store/rootmultistore_test.go | 6 +++--- types/store.go | 2 -- 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/store/cachemultistore.go b/store/cachemultistore.go index 837e52dfe..b1a754881 100644 --- a/store/cachemultistore.go +++ b/store/cachemultistore.go @@ -72,16 +72,3 @@ func (cms cacheMultiStore) GetStore(key StoreKey) Store { func (cms cacheMultiStore) GetKVStore(key StoreKey) KVStore { return cms.stores[key].(KVStore) } - -// GetStoreByName will first convert the original name to -// a special key, before looking up the CommitStore. -// This is not exposed to the extensions (which will need the -// StoreKey), but is useful in main, and particularly app.Query, -// in order to convert human strings into CommitStores. -func (cms cacheMultiStore) GetStoreByName(name string) Store { - key := cms.keysByName[name] - if key == nil { - return nil - } - return cms.stores[key].(Store) -} diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 62131611b..4b0ad4375 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -176,12 +176,12 @@ func (rs *rootMultiStore) GetKVStore(key StoreKey) KVStore { return rs.stores[key].(KVStore) } -// GetStoreByName will first convert the original name to +// getStoreByName will first convert the original name to // a special key, before looking up the CommitStore. // This is not exposed to the extensions (which will need the // StoreKey), but is useful in main, and particularly app.Query, // in order to convert human strings into CommitStores. -func (rs *rootMultiStore) GetStoreByName(name string) Store { +func (rs *rootMultiStore) getStoreByName(name string) Store { key := rs.keysByName[name] if key == nil { return nil @@ -199,7 +199,7 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { return err.Result().ToQuery() } - store := rs.GetStoreByName(storeName) + store := rs.getStoreByName(storeName) if store == nil { msg := fmt.Sprintf("no such store: %s", storeName) return sdk.ErrUnknownRequest(msg).Result().ToQuery() diff --git a/store/rootmultistore_test.go b/store/rootmultistore_test.go index d2cc44230..a8145d80e 100644 --- a/store/rootmultistore_test.go +++ b/store/rootmultistore_test.go @@ -21,11 +21,11 @@ func TestMultistoreCommitLoad(t *testing.T) { checkStore(t, store, commitID, commitID) // make sure we can get stores by name - s1 := store.GetStoreByName("store1") + s1 := store.getStoreByName("store1") assert.NotNil(t, s1) - s3 := store.GetStoreByName("store3") + s3 := store.getStoreByName("store3") assert.NotNil(t, s3) - s77 := store.GetStoreByName("store77") + s77 := store.getStoreByName("store77") assert.Nil(t, s77) // make a few commits and check them diff --git a/types/store.go b/types/store.go index e9894d0d6..6802a4bf1 100644 --- a/types/store.go +++ b/types/store.go @@ -48,8 +48,6 @@ type MultiStore interface { // Convenience for fetching substores. GetStore(StoreKey) Store GetKVStore(StoreKey) KVStore - - GetStoreByName(string) Store } // From MultiStore.CacheMultiStore().... From b21081c83a92bd1a6b227653ea6d0f55f3e8bc9e Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 2 Feb 2018 16:22:49 +0100 Subject: [PATCH 8/9] Test query routing in rootMultiStore --- store/rootmultistore_test.go | 63 ++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/store/rootmultistore_test.go b/store/rootmultistore_test.go index a8145d80e..333f0f5af 100644 --- a/store/rootmultistore_test.go +++ b/store/rootmultistore_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + abci "github.com/tendermint/abci/types" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/merkle" @@ -91,6 +92,68 @@ func TestParsePath(t *testing.T) { } +func TestMultiStoreQuery(t *testing.T) { + db := dbm.NewMemDB() + multi := newMultiStoreWithMounts(db) + err := multi.LoadLatestVersion() + assert.Nil(t, err) + + k, v := []byte("wind"), []byte("blows") + k2, v2 := []byte("water"), []byte("flows") + // v3 := []byte("is cold") + + cid := multi.Commit() + + // make sure we can get by name + garbage := multi.getStoreByName("bad-name") + assert.Nil(t, garbage) + + // set and commit data in one store + store1 := multi.getStoreByName("store1").(KVStore) + store1.Set(k, v) + + // and another + store2 := multi.getStoreByName("store2").(KVStore) + store2.Set(k2, v2) + + // commit the multistore + cid = multi.Commit() + ver := cid.Version + + // bad path + query := abci.RequestQuery{Path: "/key", Data: k, Height: ver} + qres := multi.Query(query) + assert.Equal(t, uint32(sdk.CodeUnknownRequest), qres.Code) + + query.Path = "h897fy32890rf63296r92" + qres = multi.Query(query) + assert.Equal(t, uint32(sdk.CodeUnknownRequest), qres.Code) + + // invalid store name + query.Path = "/garbage/key" + qres = multi.Query(query) + assert.Equal(t, uint32(sdk.CodeUnknownRequest), qres.Code) + + // valid query with data + query.Path = "/store1/key" + qres = multi.Query(query) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, v, qres.Value) + + // valid but empty + query.Path = "/store2/key" + query.Prove = true + qres = multi.Query(query) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Nil(t, qres.Value) + + // store2 data + query.Data = k2 + qres = multi.Query(query) + assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, v2, qres.Value) +} + //----------------------------------------------------------------------- // utils From d48c8192076d87ccca01a412a702a1e34c0b60c8 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 6 Feb 2018 17:18:22 -0500 Subject: [PATCH 9/9] minor things --- baseapp/baseapp.go | 4 ++-- store/rootmultistore.go | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index c4f326b08..5ac7be1b5 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -201,12 +201,12 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC // Implements ABCI. // Delegates to CommitMultiStore if it implements Queryable func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { - query, ok := app.cms.(sdk.Queryable) + queryable, ok := app.cms.(sdk.Queryable) if !ok { msg := "application doesn't support queries" return sdk.ErrUnknownRequest(msg).Result().ToQuery() } - return query.Query(req) + return queryable.Query(req) } // Implements ABCI. diff --git a/store/rootmultistore.go b/store/rootmultistore.go index 4b0ad4375..dd6361ea1 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -191,6 +191,10 @@ func (rs *rootMultiStore) getStoreByName(name string) Store { //---------------------- Query ------------------ +// Query calls substore.Query with the same `req` where `req.Path` is +// modified to remove the substore prefix. +// Ie. `req.Path` here is `//`, and trimmed to `/` for the substore. +// TODO: add proof for `multistore -> substore`. func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { // Query just routes this to a substore. path := req.Path @@ -204,7 +208,7 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { msg := fmt.Sprintf("no such store: %s", storeName) return sdk.ErrUnknownRequest(msg).Result().ToQuery() } - query, ok := store.(Queryable) + queryable, ok := store.(Queryable) if !ok { msg := fmt.Sprintf("store %s doesn't support queries", storeName) return sdk.ErrUnknownRequest(msg).Result().ToQuery() @@ -212,10 +216,7 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { // trim the path and make the query req.Path = subpath - res := query.Query(req) - - // Note: later we have to think about adding information about - // the multistore -> store path to the proof + res := queryable.Query(req) return res }