From 1d1a95656a185586d5aeba1787a102fffecbe6e3 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 31 Jul 2018 18:48:32 -0700 Subject: [PATCH] custom queriables --- baseapp/baseapp.go | 65 +++++++++++++++++++++++++++++++++--------- baseapp/queryrouter.go | 51 +++++++++++++++++++++++++++++++++ types/queryable.go | 7 +++++ x/gov/queryable.go | 56 ++++++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 14 deletions(-) create mode 100644 baseapp/queryrouter.go create mode 100644 types/queryable.go create mode 100644 x/gov/queryable.go diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index cf63f1f4d2..22f5927909 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -41,13 +41,14 @@ const ( // BaseApp reflects the ABCI application implementation. type BaseApp struct { // initialized on creation - Logger log.Logger - name string // application name from abci.Info - db dbm.DB // common DB backend - cms sdk.CommitMultiStore // Main (uncached) state - router Router // handle any kind of message - codespacer *sdk.Codespacer // handle module codespacing - txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx + Logger log.Logger + name string // application name from abci.Info + db dbm.DB // common DB backend + cms sdk.CommitMultiStore // Main (uncached) state + router Router // handle any kind of message + queryrouter QueryRouter // router for redirecting query calls + codespacer *sdk.Codespacer // handle module codespacing + txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx anteHandler sdk.AnteHandler // ante handler for fee and auth @@ -84,13 +85,14 @@ var _ abci.Application = (*BaseApp)(nil) // Accepts variable number of option functions, which act on the BaseApp to set configuration choices func NewBaseApp(name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp)) *BaseApp { app := &BaseApp{ - Logger: logger, - name: name, - db: db, - cms: store.NewCommitMultiStore(db), - router: NewRouter(), - codespacer: sdk.NewCodespacer(), - txDecoder: txDecoder, + Logger: logger, + name: name, + db: db, + cms: store.NewCommitMultiStore(db), + router: NewRouter(), + queryrouter: NewQueryRouter(), + codespacer: sdk.NewCodespacer(), + txDecoder: txDecoder, } // Register the undefined & root codespaces, which should not be used by @@ -135,6 +137,31 @@ func (app *BaseApp) MountStore(key sdk.StoreKey, typ sdk.StoreType) { app.cms.MountStoreWithDB(key, typ, nil) } +<<<<<<< HEAD +======= +// nolint - Set functions +func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) { + app.initChainer = initChainer +} +func (app *BaseApp) SetBeginBlocker(beginBlocker sdk.BeginBlocker) { + app.beginBlocker = beginBlocker +} +func (app *BaseApp) SetEndBlocker(endBlocker sdk.EndBlocker) { + app.endBlocker = endBlocker +} +func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) { + app.anteHandler = ah +} +func (app *BaseApp) SetAddrPeerFilter(pf sdk.PeerFilter) { + app.addrPeerFilter = pf +} +func (app *BaseApp) SetPubKeyPeerFilter(pf sdk.PeerFilter) { + app.pubkeyPeerFilter = pf +} +func (app *BaseApp) Router() Router { return app.router } +func (app *BaseApp) QueryRouter() QueryRouter { return app.queryrouter } + +>>>>>>> custom queriables // load latest application version func (app *BaseApp) LoadLatestVersion(mainKey sdk.StoreKey) error { err := app.cms.LoadLatestVersion() @@ -291,6 +318,8 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { return handleQueryStore(app, path, req) case "p2p": return handleQueryP2P(app, path, req) + case "custom": + return handleQueryCustom(app, path, req) } msg := "unknown query path" @@ -362,6 +391,14 @@ func handleQueryP2P(app *BaseApp, path []string, req abci.RequestQuery) (res abc return sdk.ErrUnknownRequest(msg).QueryResult() } +func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res abci.ResponseQuery) { + // "/custom" prefix for keeper queries + queryable := app.queryrouter.Route(path[1]) + ctx := app.checkState.ctx + res, err := queryable.Query(ctx, path[2:], req) + return +} + // BeginBlock implements the ABCI application interface. func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) { if app.cms.TracingEnabled() { diff --git a/baseapp/queryrouter.go b/baseapp/queryrouter.go new file mode 100644 index 0000000000..0a6b4dfb19 --- /dev/null +++ b/baseapp/queryrouter.go @@ -0,0 +1,51 @@ +package baseapp + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// QueryRouter provides queryables for each query path. +type QueryRouter interface { + AddRoute(r string, h sdk.CustomQueryable) (rtr QueryRouter) + Route(path string) (h sdk.CustomQueryable) +} + +// map a transaction type to a handler and an initgenesis function +type queryroute struct { + r string + h sdk.CustomQueryable +} + +type queryrouter struct { + routes []queryroute +} + +// nolint +// NewRouter - create new router +// TODO either make Function unexported or make return type (router) Exported +func NewQueryRouter() *queryrouter { + return &queryrouter{ + routes: make([]queryroute, 0), + } +} + +// AddRoute - TODO add description +func (rtr *queryrouter) AddRoute(r string, h sdk.CustomQueryable) QueryRouter { + if !isAlphaNumeric(r) { + panic("route expressions can only contain alphanumeric characters") + } + rtr.routes = append(rtr.routes, queryroute{r, h}) + + return rtr +} + +// Route - TODO add description +// TODO handle expressive matches. +func (rtr *queryrouter) Route(path string) (h sdk.CustomQueryable) { + for _, route := range rtr.routes { + if route.r == path { + return route.h + } + } + return nil +} diff --git a/types/queryable.go b/types/queryable.go new file mode 100644 index 0000000000..9ad36b8d28 --- /dev/null +++ b/types/queryable.go @@ -0,0 +1,7 @@ +package types + +import abci "github.com/tendermint/tendermint/abci/types" + +type CustomQueryable interface { + Query(ctx Context, path []string, req abci.RequestQuery) (res []byte, err Error) +} diff --git a/x/gov/queryable.go b/x/gov/queryable.go new file mode 100644 index 0000000000..059d0d1dbb --- /dev/null +++ b/x/gov/queryable.go @@ -0,0 +1,56 @@ +package gov + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/tendermint/abci/types" +) + +type Querier struct { + keeper Keeper +} + +func NewQuerier(keeper Keeper) { + return Querier{ + keeper: keeper, + } +} + +func (keeper Keeper) Query(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + switch path[0] { + case "tally": + return QueryTally(ctx, path[1:], req) + case "proposal": + return handleMsgSubmitProposal(ctx, keeper, msg) + case MsgVote: + return handleMsgVote(ctx, keeper, msg) + default: + errMsg := "Unrecognized gov msg type" + return sdk.ErrUnknownRequest(errMsg).Result() + } +} + +func QueryProposal(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + var proposalID int64 + err := keeper.cdc.UnmarshalBinary(req.Data, proposalID) + if err != nil { + return []byte{}, sdk.ErrUnknownRequest() + } + proposal := keeper.GetProposal(ctx, proposalID) + if proposal == nil { + return []byte{}, ErrUnknownProposal(DefaultCodespace, proposalID) + } + return keeper.cdc.MustMarshalBinary(proposal), nil +} + +func QueryTally(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { + var proposalID int64 + err := keeper.cdc.UnmarshalBinary(req.Data, proposalID) + if err != nil { + return []byte{}, sdk.ErrUnknownRequest() + } + proposal := keeper.GetProposal(ctx, proposalID) + if proposal == nil { + return []byte{}, ErrUnknownProposal(DefaultCodespace, proposalID) + } + passes, _ := tally(ctx, keeper, proposal) +}