Add Query routing to rootMultiStore
This commit is contained in:
parent
57b28d95de
commit
bc325c4d1c
|
@ -2,10 +2,13 @@ package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/ripemd160"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
"github.com/tendermint/tmlibs/merkle"
|
"github.com/tendermint/tmlibs/merkle"
|
||||||
"golang.org/x/crypto/ripemd160"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
@ -28,6 +31,7 @@ type rootMultiStore struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ CommitMultiStore = (*rootMultiStore)(nil)
|
var _ CommitMultiStore = (*rootMultiStore)(nil)
|
||||||
|
var _ Queryable = (*rootMultiStore)(nil)
|
||||||
|
|
||||||
func NewCommitMultiStore(db dbm.DB) *rootMultiStore {
|
func NewCommitMultiStore(db dbm.DB) *rootMultiStore {
|
||||||
return &rootMultiStore{
|
return &rootMultiStore{
|
||||||
|
@ -185,6 +189,52 @@ func (rs *rootMultiStore) GetStoreByName(name string) Store {
|
||||||
return rs.stores[key]
|
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 /<storeName>[/<subpath>]
|
||||||
|
// 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) {
|
func (rs *rootMultiStore) loadCommitStoreFromParams(id CommitID, params storeParams) (store CommitStore, err error) {
|
||||||
|
|
|
@ -19,3 +19,4 @@ type CacheWrap = types.CacheWrap
|
||||||
type CommitID = types.CommitID
|
type CommitID = types.CommitID
|
||||||
type StoreKey = types.StoreKey
|
type StoreKey = types.StoreKey
|
||||||
type StoreType = types.StoreType
|
type StoreType = types.StoreType
|
||||||
|
type Queryable = types.Queryable
|
||||||
|
|
|
@ -2,8 +2,9 @@ package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/tendermint/go-crypto"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/tendermint/go-crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CodeType uint32
|
type CodeType uint32
|
||||||
|
|
|
@ -38,3 +38,11 @@ type Result struct {
|
||||||
func (res Result) IsOK() bool {
|
func (res Result) IsOK() bool {
|
||||||
return res.Code.IsOK()
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package types
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
abci "github.com/tendermint/abci/types"
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,6 +26,14 @@ type CommitStore interface {
|
||||||
Store
|
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
|
// MultiStore
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue