Add Query routing to rootMultiStore

This commit is contained in:
Ethan Frey 2018-01-30 15:20:38 +01:00 committed by Ethan Buchman
parent 57b28d95de
commit bc325c4d1c
5 changed files with 71 additions and 2 deletions

View File

@ -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 /<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) {

View File

@ -19,3 +19,4 @@ type CacheWrap = types.CacheWrap
type CommitID = types.CommitID
type StoreKey = types.StoreKey
type StoreType = types.StoreType
type Queryable = types.Queryable

View File

@ -2,8 +2,9 @@ package types
import (
"fmt"
"github.com/tendermint/go-crypto"
"runtime"
"github.com/tendermint/go-crypto"
)
type CodeType uint32

View File

@ -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,
}
}

View File

@ -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